diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..b7e6d22 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,42 @@ +name: Build + +on: + push: + branches: + - main + workflow_dispatch: + pull_request: + +jobs: + test: + name: Build + runs-on: ubuntu-latest + strategy: + fail-fast: false + max-parallel: 2 + matrix: + version: [dev, 2024.8] + variant: [esp32-test, hp-debug] + container: + image: ghcr.io/esphome/esphome:${{ matrix.version }} + env: + USERNAME: test + PASSWORD: github-run + steps: + - uses: actions/checkout@v4 + - name: Generate random secret + env: + keys: >- + mqtt_password ota_pwd + wifi_ssid wifi_password wifi_ssid3 wifi_password3 + enc_keys: encryption_key_sejour encryption_key + run: | + for key in $keys ; do + value=`head -c 100 /dev/urandom | base64 | cut -c 1-24 | head -n1` + echo "${key}: ${value}" >> secrets.yaml + done + for key in $enc_keys ; do + value=`head -c 32 /dev/urandom | base64` + echo "${key}: ${value}" >> secrets.yaml + done + - run: esphome compile ${{ matrix.variant }}.yaml diff --git a/README.md b/README.md index 1204e77..f635074 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # Mitsubishi CN105 ESPHome -This component is an adaptation of [geoffdavis's esphome-mitsubishiheatpump](https://github.com/geoffdavis/esphome-mitsubishiheatpump). Its purpose is to integrate the Mitsubishi heat pump protocol (enabled by the [SwiCago library](https://github.com/SwiCago/HeatPump)) directly into the ESPHome component classes for a more seamless integration. + +This project is a firmware for ESP32 microcontrollers supporting UART communication via the CN105 Mitsubishi connector. Its purpose is to enable complete control of a compatible Mitsubishi heat pump through Home Assistant, a web interface, or any MQTT client. + +It uses the ESPHome framework and is compatible with the Arduino framework and ESP-IDF. + +This component version is an adaptation of [geoffdavis's esphome-mitsubishiheatpump](https://github.com/geoffdavis/esphome-mitsubishiheatpump). Its purpose is to integrate the Mitsubishi heat pump protocol (enabled by the [SwiCago library](https://github.com/SwiCago/HeatPump)) directly into the ESPHome component classes for a more seamless integration. The intended use case is for owners of a Mitsubishi Electric heat pump or air conditioner that includes a CN105 communication port to directly control their air handler or indoor unit using local communication through a web browser, or most commonly, the [HomeAssistant](https://www.home-assistant.io/) home automation platform. Installation requires the use of a WiFi capable ESP32 or ESP8266 device, modified to include a 5 pin plug to connect to the heat pump indoor unit. ESPHome is used to load the custom firmware onto the device, and the web browser or HomeAssistant software is used to send temperature setpoints, external temperature references, and settings to the heat pump. Installation requires basic soldering skills, and basic skills in flashing a firmware to a microcontroller (though ESPHome makes this as painless as possible). @@ -8,48 +13,16 @@ The benefits include fully local control over your heat pump system, without rel ### Warning: Use at your own risk. This is an unofficial implementation of the reverse-engineered Mitsubishi protocol based on the Swicago library. The authors and contributors have extensively tested this firmware across several similar implementations and forks. However, it's important to note that not all units support every feature. While free to use, it is at your own risk. If you are seeking an officially supported method to remotely control your Mitsubishi device via WiFi, a commercial solution is available [here](https://www.mitsubishi-electric.co.nz/wifi/). -## What's New - -### Breaking Changes - -#### Warning: a big redesign has been released - -Thank you all for your feedbacks, openning issues is the key to reach a good stability as quick as possible. Don't hesitate! -Here the last release, labeled ["Stable Build"](https://github.com/echavet/MitsubishiCN105ESPHome/releases/tag/v1.3) - -```yaml -external_components: - - source: github://echavet/MitsubishiCN105ESPHome@v1.2.2 -``` - -Previous one, without the big redesign was: -```yaml -external_components: - - source: github://echavet/MitsubishiCN105ESPHome@v1.1.3 -``` - -#### Warning: esp-idf framework support feature has been merged to main branch - -This is a major change in UART configuration (I should have changed the major number of the version tag. Sorry I didn't!). But that's not so scary! If you upgrade to the head of main you will just have to change the way you configure the UART in your yaml files. Look at the Step 4 in this document. - -The reason is issue https://github.com/echavet/MitsubishiCN105ESPHome/issues/6. The old configuration did not allow to use ESP32 ESP-IDF framework, which improves reliability of the hardware UART. - -If you don't want this change you must configure your external_components to point to the [v1.0.3](https://github.com/echavet/MitsubishiCN105ESPHome/tree/v1.0.3) tree this way: - -```yaml -external_components: - - source: github://echavet/MitsubishiCN105ESPHome@v1.0.3 -``` - -### Other New Features +### New Features - Additional components for supported units: vane orientation (fully supporting the Swicago map), compressor frequency for energy monitoring, and i-see sensor. -- Enhanced UART communication with the Heatpump to eliminate delays in the ESPHome loop(), which was a limitation of the original [SwiCago library](https://github.com/SwiCago/HeatPump). -- Byte-by-byte reading within the loop() function ensures no data loss or lag, as the component continuously reads without blocking ESPHome. -- UART writes are followed by non-blocking reads. The responses are accumulated byte-by-byte in the loop() method and processed when complete, allowing command stacking without delays for a more responsive UI. +- Additional diagnostic sensors for understanding the behavior of the indoor units while in AUTO mode +- Additional sensors for power usage and outdoor temperature (not supported by all units) - Code is divided into distinct concerns for better readability. - Extensive logging for easier troubleshooting and development. - Ongoing refactoring to further improve the code quality. -- Additional diagnostic sensors for understanding the behavior of the indoor units while in AUTO mode +- Enhanced UART communication with the Heatpump to eliminate delays in the ESPHome loop(), which was a limitation of the original [SwiCago library](https://github.com/SwiCago/HeatPump). +- Byte-by-byte reading within the loop() function ensures no data loss or lag, as the component continuously reads without blocking ESPHome. +- UART writes are followed by non-blocking reads. The responses are accumulated byte-by-byte in the loop() method and processed when complete, allowing command stacking without delays for a more responsive UI. ### Retained Features @@ -68,10 +41,13 @@ This project maintains all functionalities of the original [geoffdavis](https:// ## Supported Microcontrollers +**Caution:** ESP8266 boards such as the WeMos D1 Mini clones (LOLIN in particular) tend to be unreliable in this application, and may require an external voltage regulator to work. While some users have successfully used ESP8266 based devices, if you are purchasing new hardware for use with this project, it is recommended to focus on the more modern and powerful ESP32-S3 based devices. + - Generic ESP32 Dev Kit (ESP32): tested -- WeMos D1 Mini (ESP8266): tested - M5Stack ATOM Lite : tested - M5Stack ATOM S3 Lite: tested w/ [modifications](https://github.com/echavet/MitsubishiCN105ESPHome/discussions/83) +- M5Stack StampS3 +- WeMos D1 Mini Pro (ESP8266): tested (but not currently recommended, see above) ## Supported Mitsubishi Climate Units @@ -84,6 +60,8 @@ Units tested by project contributors include: - `MSZ-GLxxNA` - `MSZ-AP20VGK` (https://github.com/echavet/MitsubishiCN105ESPHome/discussions/83) - `MSZ-AP42VGK` +- `MSZ-AY35VGKP` +- `MSZ-FSXXNA` ## Usage @@ -98,36 +76,36 @@ Add a new device in your ESPHome dashboard. Create a yaml configuration file for - [Getting Started with ESPHome and HomeAssistant](https://esphome.io/guides/getting_started_hassio) - [Installing ESPHome Locally](https://esphome.io/guides/installing_esphome) -Note: This code utilizes features in ESPHome 1.18.0, including various Fan modes and [external components](https://esphome.io/components/external_components.html). +Note: This code uses the ESPHome [external components](https://esphome.io/components/external_components.html) integration feature. This means the project is not part of the ESPHome framework, it is an external component. ### Step 3: Configure the board and UART settings Your ESPHome device configuration file starts with common defaults for ESPHome. To these defaults, add these minimum sections: -#### For ESP8266-based Devices +#### For ESP32-based Devices ```yaml -esp8266: - board: d1_mini +esp32: + board: esp32doit-devkit-v1 #or esp32-s3-devkitc-1 + framework: + type: esp-idf uart: id: HP_UART baud_rate: 2400 - tx_pin: 1 - rx_pin: 3 + tx_pin: GPIO17 + rx_pin: GPIO16 ``` -#### For ESP32-based Devices +#### For ESP8266-based Devices ```yaml -esp32: - board: esp32doit-devkit-v1 - framework: - type: esp-idf +esp8266: + board: d1_mini uart: id: HP_UART baud_rate: 2400 - tx_pin: GPIO17 - rx_pin: GPIO16 + tx_pin: 1 + rx_pin: 3 ``` ### Step 4: Configure the climate component @@ -142,15 +120,28 @@ external_components: # Climate entity configuration climate: - platform: cn105 + id: hp name: "My Heat Pump" - update_interval: 4s + update_interval: 4s # update interval can be adjusted after a first run and logs monitoring # Default logging level logger: - hardware_uart: UART1 # This line can be removed for ESP32 devices +# hardware_uart: UART1 # Uncomment this line for ESP8266 devices level: INFO ``` +#### Adjusting the `update_interval` +An ESPHome firmware implements the esphome::Component interface to be integrated into the Inversion Of Control mechanism of the ESPHome framework. +The main method of this process is the `loop()` method. MitsubishiCN105ESPHome performs a series of exchanges with the heat pump through a cycle. This cycle is timed, and its duration is displayed in the logs, provided the `CYCLE` logger is set to at least `INFO`. + +If this is the case, you will see logs in the form: +``` +[09:48:36][I][CYCLE:052]: 6: Cycle ended in 1.2 seconds (with timeout?: NO) +``` + +This will give you a good idea of your microcontroller's performance in completing an entire cycle. It is unnecessary to set the `update_interval` below this value. +In this example, setting an `update_interval` to 1500ms could be a fine tuned value. + ### Step 5: Optional components and variables These optional additional configurations add customization and additional capabilities. The examples below assume you have added a substitutions component to your configuration file to allow for easy renaming, and that you have added a `secrets.yaml` file to your ESPHome configuration to hide private variables like your random API keys, OTA passwords, and Wifi passwords. @@ -179,44 +170,54 @@ climate: max_temperature: 31 temperature_step: target_temperature: 1 - current_temperature: 0.1 + current_temperature: 0.5 + # Timeout and communication settings + remote_temperature_timeout: 30min + update_interval: 4s + debounce_delay : 100ms + # Various optional sensors, not all sensors are supported by all heatpumps compressor_frequency_sensor: - name: ${name} Compressor Frequency + name: Compressor Frequency + entity_category: diagnostic + disabled_by_default: true + outside_air_temperature_sensor: + name: Outside Air Temp + disabled_by_default: true vertical_vane_select: - name: ${name} Vertical Vane + name: Vertical Vane + disabled_by_default: false horizontal_vane_select: - name: ${name} Horizontal Vane + name: Horizontal Vane + disabled_by_default: true isee_sensor: - name: ${name} ISEE Sensor - remote_temperature_timeout: 30min - debounce_delay : 500ms - update_interval: 4s + name: ISEE Sensor + disabled_by_default: true + stage_sensor: + name: Stage + entity_category: diagnostic + disabled_by_default: true + sub_mode_sensor: + name: Sub Mode + entity_category: diagnostic + disabled_by_default: true + auto_sub_mode_sensor: + name: Auto Sub Mode + entity_category: diagnostic + disabled_by_default: true + input_power_sensor: + name: Input Power + disabled_by_default: true + kwh_sensor: + name: Energy Usage + disabled_by_default: true + runtime_hours_sensor: + name: Runtime Hours + entity_category: diagnostic + disabled_by_default: true ``` Note: An `update_interval` between 1s and 4s is recommended, because the underlying process divides this into three separate requests which need time to complete. If some updates get "missed" from your heatpump, consider making this interval longer. -#### External temperature support -This example extends to default `api:` component to add a `set_remote_temperature` service that can be called from within HomeAssistant, allowing you to send a remote temperature value to the heat pump. This replaces the heat pump's internal temperature measurement with an external temperature measurement as the Mitsubishi wireless thermostats do, allowing you to more precisely control room comfort. You will need to include an automation in HomeAssistant to periodically call the service and update the temperature with `set_remote_temperature`, or disable remote temperature with `use_internal_temperature`. Example automations linked below. - -```yaml -api: - encryption: - key: !secret api_key - services: - - service: set_remote_temperature - variables: - temperature: float - then: -# Select between the C version and the F version -# Uncomment just ONE of the below lines. The top receives the temperature value in C, -# the bottom receives the value in F, converting to C here. - - lambda: 'id(hp).set_remote_temperature(temperature);' -# - lambda: 'id(hp).set_remote_temperature((temperature - 32.0) * (5.0 / 9.0));' - - service: use_internal_temperature - then: - - lambda: 'id(hp).set_remote_temperature(0);' -``` - #### Logger granularity This firmware supports detailed log granularity for troubleshooting. Below is the full list of logger components and recommended defaults. @@ -280,26 +281,26 @@ esphome: friendly_name: My Heatpump 1 # For ESP8266 Devices -esp8266: - board: d1_mini - -uart: - id: HP_UART - baud_rate: 2400 - tx_pin: 1 - rx_pin: 3 - -# For ESP32 Devices -#esp32: -# board: esp32doit-devkit-v1 -# framework: -# type: esp-idf +#esp8266: +# board: d1_mini # #uart: # id: HP_UART # baud_rate: 2400 -# tx_pin: GPIO17 -# rx_pin: GPIO16 +# tx_pin: 1 +# rx_pin: 3 + +# For ESP32 Devices +esp32: + board: esp32doit-devkit-v1 + framework: + type: esp-idf + +uart: + id: HP_UART + baud_rate: 2400 + tx_pin: GPIO17 + rx_pin: GPIO16 external_components: - source: github://echavet/MitsubishiCN105ESPHome @@ -324,6 +325,7 @@ api: key: !secret api_key ota: + platform: esphome # Required for ESPhome 2024.6.0 and greater password: !secret ota_password wifi: @@ -351,32 +353,33 @@ This example includes all the bells and whistles, optional components, remote te substitutions: name: heatpump-1 friendly_name: My Heatpump 1 + remote_temp_sensor: sensor.my_room_temperature # Homeassistant sensor providing remote temperature esphome: name: ${name} friendly_name: ${friendly_name} # For ESP8266 Devices -esp8266: - board: d1_mini - -uart: - id: HP_UART - baud_rate: 2400 - tx_pin: 1 - rx_pin: 3 - -# For ESP32 Devices -#esp32: -# board: esp32doit-devkit-v1 -# framework: -# type: esp-idf +#esp8266: +# board: d1_mini # #uart: # id: HP_UART # baud_rate: 2400 -# tx_pin: GPIO17 -# rx_pin: GPIO16 +# tx_pin: 1 +# rx_pin: 3 + +# For ESP32 Devices +esp32: + board: esp32doit-devkit-v1 + framework: + type: esp-idf + +uart: + id: HP_UART + baud_rate: 2400 + tx_pin: GPIO17 + rx_pin: GPIO16 external_components: - source: github://echavet/MitsubishiCN105ESPHome @@ -438,21 +441,34 @@ logger: api: encryption: key: !secret api_key - services: - - service: set_remote_temperature - variables: - temperature: float - then: -# Select between the C version and the F version -# Uncomment just ONE of the below lines. The top receives the temperature value in C, -# the bottom receives the value in F, converting to C here. - - lambda: 'id(hp).set_remote_temperature(temperature);' -# - lambda: 'id(hp).set_remote_temperature((temperature - 32.0) * (5.0 / 9.0));' - - service: use_internal_temperature + +sensor: + - platform: homeassistant + name: "Remote Temperature Sensor" + entity_id: ${remote_temp_sensor} # Replace with your HomeAssistant remote sensor entity id, or include in substitutions + internal: false + disabled_by_default: true + device_class: temperature + state_class: measurement + unit_of_measurement: "°C" + filters: + # Uncomment the lambda line to convert F to C on incoming temperature + # - lambda: return (x - 32) * (5.0/9.0); + - clamp: # Limits values to range accepted by Mitsubishi units + min_value: 1 + max_value: 40 + ignore_out_of_range: true + - throttle: 30s + on_value: then: - - lambda: 'id(hp).set_remote_temperature(0);' + - logger.log: + level: INFO + format: "Remote temperature received from HA: %.1f C" + args: [ 'x' ] + - lambda: 'id(hp).set_remote_temperature(x);' ota: + platform: esphome # Required for ESPhome 2024.6.0 and greater # Enable Web server. web_server: @@ -467,25 +483,25 @@ time: text_sensor: # Expose ESPHome version as sensor. - platform: version - name: ${name} ESPHome Version + name: ESPHome Version # Expose WiFi information as sensors. - platform: wifi_info ip_address: - name: ${name} IP + name: IP ssid: - name: ${name} SSID + name: SSID bssid: - name: ${name} BSSID + name: BSSID # Sensors with general information. sensor: # Uptime sensor. - platform: uptime - name: ${name} Uptime + name: Uptime # WiFi Signal sensor. - platform: wifi_signal - name: ${name} WiFi Signal + name: WiFi Signal update_interval: 120s # Create a button to restart the unit from HomeAssistant. Rarely needed, but can be handy. @@ -493,6 +509,12 @@ button: - platform: restart name: "Restart ${friendly_name}" +# Creates the sensor used to receive the remote temperature from Home Assistant +# Uses sensor selected in substitutions area at top of config +# Customize the filters to your application: +# Uncomment the first line to convert F to C when remote temps are sent +# If you have a fast or noisy sensor, consider some of the other filter +# options such as throttle_average. climate: - platform: cn105 id: hp @@ -503,40 +525,93 @@ climate: max_temperature: 31 temperature_step: target_temperature: 1 - current_temperature: 0.1 + current_temperature: 0.5 + # Timeout and communication settings + remote_temperature_timeout: 30min + update_interval: 4s + debounce_delay : 100ms + # Various optional sensors, not all sensors are supported by all heatpumps compressor_frequency_sensor: - name: ${name} Compressor Frequency + name: Compressor Frequency + entity_category: diagnostic + disabled_by_default: true + outside_air_temperature_sensor: + name: Outside Air Temp + disabled_by_default: true vertical_vane_select: - name: ${name} Vertical Vane + name: Vertical Vane + disabled_by_default: false horizontal_vane_select: - name: ${name} Horizontal Vane + name: Horizontal Vane + disabled_by_default: true isee_sensor: - name: ${name} ISEE Sensor - remote_temperature_timeout: 30min - debounce_delay : 500ms - update_interval: 4s + name: ISEE Sensor + disabled_by_default: true + stage_sensor: + name: Stage + entity_category: diagnostic + disabled_by_default: true + sub_mode_sensor: + name: Sub Mode + entity_category: diagnostic + disabled_by_default: true + auto_sub_mode_sensor: + name: Auto Sub Mode + entity_category: diagnostic + disabled_by_default: true + input_power_sensor: + name: Input Power + disabled_by_default: true + kwh_sensor: + name: Energy Usage + disabled_by_default: true + runtime_hours_sensor: + name: Runtime Hours + entity_category: diagnostic + disabled_by_default: true ``` ## Methods for updating external temperature -There are several methods for updating the unit with an remote temperature value. +There are several methods for updating the unit with an remote temperature value. This replaces the heat pump's internal temperature measurement with an external temperature measurement as the Mitsubishi wireless thermostats do, allowing you to more precisely control room comfort and improve energy efficiency by increasing cycle length. + +### Recommended - Get external temperature from a [HomeAssistant Sensor](https://esphome.io/components/sensor/homeassistant.html) through the HomeAssistant API -### Get external temperature from a [HomeAssistant Sensor](https://esphome.io/components/sensor/homeassistant.html) through the HomeAssistant API +Creates the sensor used to receive the remote temperature from Home Assistant. Uses sensor selected in substitutions area at top of config or manually entered into the sensor configuration. When the HomeAssistant sensor updates, it will send the new value to the ESP device, which will update the heatpump's remote temperature value. + +Customize the filters to your application: +- Uncomment the first line to convert F to C when remote temps are sent. +- If you have a fast or noisy sensor, consider some of the other filter options such as throttle_average. ```yaml sensor: - platform: homeassistant - id: current_temp - entity_id: sensor.my_temperature_sensor - internal: true + name: "Remote Temperature Sensor" + entity_id: ${remote_temp_sensor} # Replace with your HomeAssistant remote sensor entity id, or include in substitutions + internal: false + disabled_by_default: true + device_class: temperature + state_class: measurement + unit_of_measurement: "°C" + filters: + # Uncomment the lambda line to convert F to C on incoming temperature + # - lambda: return (x - 32) * (5.0/9.0); + - clamp: # Limits values to range accepted by Mitsubishi units + min_value: 1 + max_value: 40 + ignore_out_of_range: true + - throttle: 30s on_value: then: - - lambda: |- - id(hp).set_remote_temperature(x); + - logger.log: + level: INFO + format: "Remote temperature received from HA: %.1f C" + args: [ 'x' ] + - lambda: 'id(hp).set_remote_temperature(x);' ``` -### Get external temperature from a networked sensor with a throttle filter +### Alternate - Get external temperature from a networked sensor with a throttle filter ```yaml sensor: @@ -551,11 +626,57 @@ sensor: throttle_average: 90s on_value: then: - - lambda: 'id(use_your_name).set_remote_temperature(x);' + - lambda: 'id(hp).set_remote_temperature(x);' +``` + +### Alternate - HomeAssistant Action + +This example extends to default `api:` component to add a `set_remote_temperature` action that can be called from within HomeAssistant, allowing you to send a remote temperature value to the heat pump. You will need to include an automation in HomeAssistant to periodically call the action and update the temperature with `set_remote_temperature`, or disable remote temperature with `use_internal_temperature`. No longer recommended as the default method of updating remote temperature. + +```yaml +api: + encryption: + key: !secret api_key + services: + - service: set_remote_temperature + variables: + temperature: float + then: +# Select between the C version and the F version +# Uncomment just ONE of the below lines. The top receives the temperature value in C, +# the bottom receives the value in F, converting to C here. + - lambda: 'id(hp).set_remote_temperature(temperature);' +# - lambda: 'id(hp).set_remote_temperature((temperature - 32.0) * (5.0 / 9.0));' + - service: use_internal_temperature + then: + - lambda: 'id(hp).set_remote_temperature(0);' ``` ## Diagnostic Sensors +### Outside Air Temperature + +This sensor reads the outdoor unit's air temperature reading, in 1.0 degree C increments. Not all outdoor units support this sensor. Some outdoor units will send an accurate value while the unit is operating, or in heat/cool mode, but will send -63.5C when offline. + +```yaml + outside_air_temperature_sensor: + name: Outside Air Temperature +``` + +Compatible units (as reported by users): + +| Indoor | Outdoor | Temperature | +|-----------------|------------------|-----------------------------------------| +| MSZ-AP25VGD | MXZ-4F80VGD | Works | +| MSZ-AP35VGD | MUZ-AP35VG | Works but reports -63.5C when idle | +| MSZ-AP60VGD | MUZ-AP60VG | Works | +| MSZ-AP71VGD | MUZ-AP71VG | Works but reports -63.5C when idle | +| MSZ-AY35VGKP | MUZ-AY35VG | Works | +| MSZ-GLxxNA | MXZ-SM42NAMHZ | Works | +| MSZ-RW25VG-SC1 | MUZ-RW25VGHZ-SC1 | Works | +| | MUZ-FD25NA | Not working | +| MSZ-LN35 | MUZ-LN35 | Not working | + ### Auto and Stage Sensors The below sensors were added recently based on the work of others in sorting out other messages and bytes. The names are likely to change as we work to determine exactly what the units are doing. @@ -590,12 +711,6 @@ sensor: lambda: |- return (bool) id(hp).isUARTConnected_; update_interval: 30s - - platform: template - name: "dg_hp_connected" - entity_category: DIAGNOSTIC - lambda: |- - return (bool) id(hp).isUARTConnected_; - update_interval: 30s - platform: template name: "dg_complete_cycles" entity_category: DIAGNOSTIC @@ -632,12 +747,6 @@ sensor: update_interval: 60s ``` -## Update external temperature using a HomeAssistant automation blueprint - -Coming Soon. - -For more configuration options, see the provided [hp-debug.yaml](https://github.com/echavet/MitsubishiCN105ESPHome/blob/main/hp-debug.yaml) and [hp-sejour.yaml](https://github.com/echavet/MitsubishiCN105ESPHome/blob/main/hp-sejour.yaml) examples or refer to the original project. - ## Other Implementations - [esphome-mitsubishiheatpump](https://github.com/geoffdavis/esphome-mitsubishiheatpump) - The original esphome project from which this one is forked. diff --git a/components/cn105/Globals.h b/components/cn105/Globals.h index 85687aa..b82f4ce 100644 --- a/components/cn105/Globals.h +++ b/components/cn105/Globals.h @@ -189,7 +189,7 @@ struct wantedHeatpumpSettings : heatpumpSettings { hasChanged = false; hasBeenSent = false; //nb_deffered_requests = 0; - //lastChange = 0; + //lastChange = 0; } wantedHeatpumpSettings& operator=(const wantedHeatpumpSettings& other) { @@ -203,7 +203,7 @@ struct wantedHeatpumpSettings : heatpumpSettings { wantedHeatpumpSettings& operator=(const heatpumpSettings& other) { if (this != &other) { // self-assignment protection - heatpumpSettings::operator=(other); // Copie des membres de base + heatpumpSettings::operator=(other); // Copie des membres de base } return *this; } @@ -244,15 +244,23 @@ struct heatpumpTimers { struct heatpumpStatus { float roomTemperature; + float outsideAirTemperature; bool operating; // if true, the heatpump is operating to reach the desired temperature heatpumpTimers timers; - int compressorFrequency; + float compressorFrequency; + float inputPower; + float kWh; + float runtimeHours; bool operator==(const heatpumpStatus& other) const { return roomTemperature == other.roomTemperature && + outsideAirTemperature == other.outsideAirTemperature && operating == other.operating && //timers == other.timers && // Assurez-vous que l'opérateur == est également défini pour heatpumpTimers - compressorFrequency == other.compressorFrequency; + compressorFrequency == other.compressorFrequency && + inputPower == other.inputPower && + kWh == other.kWh && + runtimeHours == other.runtimeHours; } bool operator!=(const heatpumpStatus& other) const { diff --git a/components/cn105/climate.py b/components/cn105/climate.py index 9646810..dc6f892 100644 --- a/components/cn105/climate.py +++ b/components/cn105/climate.py @@ -35,6 +35,10 @@ CONF_HORIZONTAL_SWING_SELECT = "horizontal_vane_select" CONF_VERTICAL_SWING_SELECT = "vertical_vane_select" CONF_COMPRESSOR_FREQUENCY_SENSOR = "compressor_frequency_sensor" +CONF_INPUT_POWER_SENSOR = "input_power_sensor" +CONF_KWH_SENSOR = "kwh_sensor" +CONF_RUNTIME_HOURS_SENSOR = "runtime_hours_sensor" +CONF_OUTSIDE_AIR_TEMPERATURE_SENSOR = "outside_air_temperature_sensor" CONF_ISEE_SENSOR = "isee_sensor" CONF_STAGE_SENSOR = "stage_sensor" CONF_SUB_MODE_SENSOR = "sub_mode_sensor" @@ -59,6 +63,22 @@ "CompressorFrequencySensor", sensor.Sensor, cg.Component ) +InputPowerSensor = cg.global_ns.class_( + "InputPowerSensor", sensor.Sensor, cg.Component +) + +kWhSensor = cg.global_ns.class_( + "kWhSensor", sensor.Sensor, cg.Component +) + +RuntimeHoursSensor = cg.global_ns.class_( + "RuntimeHoursSensor", sensor.Sensor, cg.Component +) + +OutsideAirTemperatureSensor = cg.global_ns.class_( + "OutsideAirTemperatureSensor", sensor.Sensor, cg.Component +) + ISeeSensor = cg.global_ns.class_("ISeeSensor", binary_sensor.BinarySensor, cg.Component) StageSensor = cg.global_ns.class_("StageSensor", text_sensor.TextSensor, cg.Component) SubModSensor = cg.global_ns.class_("SubModSensor", text_sensor.TextSensor, cg.Component) @@ -87,10 +107,26 @@ def valid_uart(uart): {cv.GenerateID(CONF_ID): cv.declare_id(VaneOrientationSelect)} ) -SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend( +COMPRESSOR_FREQUENCY_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend( {cv.GenerateID(CONF_ID): cv.declare_id(CompressorFrequencySensor)} ) +INPUT_POWER_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend( + {cv.GenerateID(CONF_ID): cv.declare_id(InputPowerSensor)} +) + +KWH_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend( + {cv.GenerateID(CONF_ID): cv.declare_id(kWhSensor)} +) + +RUNTIME_HOURS_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend( + {cv.GenerateID(CONF_ID): cv.declare_id(RuntimeHoursSensor)} +) + +OUTSIDE_AIR_TEMPERATURE_SENSOR_SCHEMA = sensor.SENSOR_SCHEMA.extend( + {cv.GenerateID(CONF_ID): cv.declare_id(OutsideAirTemperatureSensor)} +) + ISEE_SENSOR_SCHEMA = binary_sensor.BINARY_SENSOR_SCHEMA.extend( {cv.GenerateID(CONF_ID): cv.declare_id(ISeeSensor)} ) @@ -132,7 +168,11 @@ def valid_uart(uart): cv.Optional(CONF_UPDATE_INTERVAL, default="2s"): cv.All(cv.update_interval), cv.Optional(CONF_HORIZONTAL_SWING_SELECT): SELECT_SCHEMA, cv.Optional(CONF_VERTICAL_SWING_SELECT): SELECT_SCHEMA, - cv.Optional(CONF_COMPRESSOR_FREQUENCY_SENSOR): SENSOR_SCHEMA, + cv.Optional(CONF_COMPRESSOR_FREQUENCY_SENSOR): COMPRESSOR_FREQUENCY_SENSOR_SCHEMA, + cv.Optional(CONF_INPUT_POWER_SENSOR): INPUT_POWER_SENSOR_SCHEMA, + cv.Optional(CONF_KWH_SENSOR): KWH_SENSOR_SCHEMA, + cv.Optional(CONF_RUNTIME_HOURS_SENSOR): RUNTIME_HOURS_SENSOR_SCHEMA, + cv.Optional(CONF_OUTSIDE_AIR_TEMPERATURE_SENSOR): OUTSIDE_AIR_TEMPERATURE_SENSOR_SCHEMA, cv.Optional(CONF_ISEE_SENSOR): ISEE_SENSOR_SCHEMA, cv.Optional(CONF_STAGE_SENSOR): STAGE_SENSOR_SCHEMA, cv.Optional(CONF_SUB_MODE_SENSOR): SUB_MODE_SENSOR_SCHEMA, @@ -209,6 +249,34 @@ def to_code(config): yield cg.register_component(sensor_, conf) cg.add(var.set_compressor_frequency_sensor(sensor_)) + if CONF_INPUT_POWER_SENSOR in config: + conf = config[CONF_INPUT_POWER_SENSOR] + conf["force_update"] = False + sensor_ = yield sensor.new_sensor(conf) + yield cg.register_component(sensor_, conf) + cg.add(var.set_input_power_sensor(sensor_)) + + if CONF_KWH_SENSOR in config: + conf = config[CONF_KWH_SENSOR] + conf["force_update"] = False + sensor_ = yield sensor.new_sensor(conf) + yield cg.register_component(sensor_, conf) + cg.add(var.set_kwh_sensor(sensor_)) + + if CONF_RUNTIME_HOURS_SENSOR in config: + conf = config[CONF_RUNTIME_HOURS_SENSOR] + conf["force_update"] = False + sensor_ = yield sensor.new_sensor(conf) + yield cg.register_component(sensor_, conf) + cg.add(var.set_runtime_hours_sensor(sensor_)) + + if CONF_OUTSIDE_AIR_TEMPERATURE_SENSOR in config: + conf = config[CONF_OUTSIDE_AIR_TEMPERATURE_SENSOR] + conf["force_update"] = False + sensor_ = yield sensor.new_sensor(conf) + yield cg.register_component(sensor_, conf) + cg.add(var.set_outside_air_temperature_sensor(sensor_)) + if CONF_ISEE_SENSOR in config: conf = config[CONF_ISEE_SENSOR] bsensor_ = yield binary_sensor.new_binary_sensor(conf) diff --git a/components/cn105/climateControls.cpp b/components/cn105/climateControls.cpp index 00bf221..e18d011 100644 --- a/components/cn105/climateControls.cpp +++ b/components/cn105/climateControls.cpp @@ -14,7 +14,7 @@ void CN105Climate::checkPendingWantedSettings() { this->sendWantedSettings(); } -void logCheckWantedSettingsMutex(wantedHeatpumpSettings settings) { +void logCheckWantedSettingsMutex(wantedHeatpumpSettings& settings) { if (settings.hasBeenSent) { ESP_LOGE("control", "Mutex lock faillure: wantedSettings should be locked while sending."); diff --git a/components/cn105/cn105.cpp b/components/cn105/cn105.cpp index 1362ed4..6459ad1 100644 --- a/components/cn105/cn105.cpp +++ b/components/cn105/cn105.cpp @@ -26,15 +26,23 @@ CN105Climate::CN105Climate(uart::UARTComponent* uart) : this->infoMode = 0; this->lastConnectRqTimeMs = 0; this->currentStatus.operating = false; - this->currentStatus.compressorFrequency = -1; + this->currentStatus.compressorFrequency = NAN; + this->currentStatus.inputPower = NAN; + this->currentStatus.kWh = NAN; + this->currentStatus.runtimeHours = NAN; this->tx_pin_ = -1; this->rx_pin_ = -1; this->horizontal_vane_select_ = nullptr; this->vertical_vane_select_ = nullptr; this->compressor_frequency_sensor_ = nullptr; + this->input_power_sensor_ = nullptr; + this->kwh_sensor_ = nullptr; + this->runtime_hours_sensor_ = nullptr; - this->remote_temp_timeout_ = 4294967295; // uint32_t max + this->powerRequestWithoutResponses = 0; // power request is not supported by all heatpump #112 + + this->remote_temp_timeout_ = 4294967295; // uint32_t max this->generateExtraComponents(); this->loopCycle.init(); this->wantedSettings.resetSettings(); @@ -69,19 +77,31 @@ void CN105Climate::set_remote_temp_timeout(uint32_t timeout) { if (timeout == 4294967295) { ESP_LOGI(LOG_ACTION_EVT_TAG, "set_remote_temp_timeout is set to never."); } else { - ESP_LOGI(LOG_ACTION_EVT_TAG, "set_remote_temp_timeout is set to %d", timeout); + //ESP_LOGI(LOG_ACTION_EVT_TAG, "set_remote_temp_timeout is set to %lu", timeout); + log_info_uint32(LOG_ACTION_EVT_TAG, "set_remote_temp_timeout is set to ", timeout); + this->pingExternalTemperature(); } } void CN105Climate::set_debounce_delay(uint32_t delay) { this->debounce_delay_ = delay; - ESP_LOGI(LOG_ACTION_EVT_TAG, "set_debounce_delay is set to %d", delay); + //ESP_LOGI(LOG_ACTION_EVT_TAG, "set_debounce_delay is set to %lu", delay); + log_info_uint32(LOG_ACTION_EVT_TAG, "set_debounce_delay is set to ", delay); } -int CN105Climate::get_compressor_frequency() { +float CN105Climate::get_compressor_frequency() { return currentStatus.compressorFrequency; } +float CN105Climate::get_input_power() { + return currentStatus.inputPower; +} +float CN105Climate::get_kwh() { + return currentStatus.kWh; +} +float CN105Climate::get_runtime_hours() { + return currentStatus.runtimeHours; +} bool CN105Climate::is_operating() { return currentStatus.operating; } @@ -90,8 +110,8 @@ bool CN105Climate::is_operating() { // SERIAL_8E1 void CN105Climate::setupUART() { - ESP_LOGI(TAG, "setupUART() with baudrate %d", this->parent_->get_baud_rate()); - + //ESP_LOGI(TAG, "setupUART() with baudrate %lu", this->parent_->get_baud_rate()); + log_info_uint32(TAG, "setupUART() with baudrate ", this->parent_->get_baud_rate()); this->setHeatpumpConnected(false); this->isUARTConnected_ = false; @@ -168,9 +188,8 @@ bool CN105Climate::isHeatpumpConnectionActive() { // if (lrTimeMs > MAX_DELAY_RESPONSE_FACTOR * this->update_interval_) { // ESP_LOGV(TAG, "Heatpump has not replied for %ld s", lrTimeMs / 1000); // ESP_LOGV(TAG, "We think Heatpump is not connected anymore.."); - // this->disconnectUART(); + // this->disconnectUART(); // } return (lrTimeMs < MAX_DELAY_RESPONSE_FACTOR * this->update_interval_); } - diff --git a/components/cn105/cn105.h b/components/cn105/cn105.h index c932768..2d35200 100644 --- a/components/cn105/cn105.h +++ b/components/cn105/cn105.h @@ -4,6 +4,10 @@ #include "van_orientation_select.h" #include "uptime_connection_sensor.h" #include "compressor_frequency_sensor.h" +#include "input_power_sensor.h" +#include "kwh_sensor.h" +#include "runtime_hours_sensor.h" +#include "outside_air_temperature_sensor.h" #include "auto_sub_mode_sensor.h" #include "isee_sensor.h" #include "stage_sensor.h" @@ -18,7 +22,9 @@ using namespace esphome; -//class VaneOrientationSelect; // Déclaration anticipée, définie dans extraComponents + +void log_info_uint32(const char* tag, const char* msg, uint32_t value, const char* suffix = ""); +void log_debug_uint32(const char* tag, const char* msg, uint32_t value, const char* suffix = ""); class CN105Climate : public climate::Climate, public Component, public uart::UARTDevice { @@ -31,6 +37,10 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR void set_vertical_vane_select(VaneOrientationSelect* vertical_vane_select); void set_horizontal_vane_select(VaneOrientationSelect* horizontal_vane_select); void set_compressor_frequency_sensor(esphome::sensor::Sensor* compressor_frequency_sensor); + void set_input_power_sensor(esphome::sensor::Sensor* input_power_sensor); + void set_kwh_sensor(esphome::sensor::Sensor* kwh_sensor); + void set_runtime_hours_sensor(esphome::sensor::Sensor* runtime_hours_sensor); + void set_outside_air_temperature_sensor(esphome::sensor::Sensor* outside_air_temperature_sensor); void set_isee_sensor(esphome::binary_sensor::BinarySensor* iSee_sensor); void set_stage_sensor(esphome::text_sensor::TextSensor* Stage_sensor); void set_sub_mode_sensor(esphome::text_sensor::TextSensor* Sub_mode_sensor); @@ -52,11 +62,22 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR nullptr; // Select to store manual position of horizontal swing sensor::Sensor* compressor_frequency_sensor_ = nullptr; // Sensor to store compressor frequency + sensor::Sensor* input_power_sensor_ = + nullptr; // Sensor to store compressor frequency + sensor::Sensor* kwh_sensor_ = + nullptr; // Sensor to store compressor frequency + sensor::Sensor* runtime_hours_sensor_ = + nullptr; // Sensor to store compressor frequency + sensor::Sensor* outside_air_temperature_sensor_ = + nullptr; // Outside air temperature - // sensor to monitor heatpump connection time + // sensor to monitor heatpump connection time uptime::HpUpTimeConnectionSensor* hp_uptime_connection_sensor_ = nullptr; - int get_compressor_frequency(); + float get_compressor_frequency(); + float get_input_power(); + float get_kwh(); + float get_runtime_hours(); bool is_operating(); // checks if the field has changed @@ -128,7 +149,7 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR void sendFirstConnectionPacket(); - + void terminateCycle(); //bool can_proceed() override; @@ -216,10 +237,10 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR void prepareInfoPacket(uint8_t* packet, int length); void prepareSetPacket(uint8_t* packet, int length); - void publishStateToHA(heatpumpSettings settings); + void publishStateToHA(heatpumpSettings& settings); void publishWantedSettingsStateToHA(); - void heatpumpUpdate(heatpumpSettings settings); + void heatpumpUpdate(heatpumpSettings& settings); void statusChanged(heatpumpStatus status); @@ -236,8 +257,8 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR void setActionIfOperatingAndCompressorIsActiveTo(climate::ClimateAction action); void hpPacketDebug(uint8_t* packet, unsigned int length, const char* packetDirection); - void debugSettings(const char* settingName, heatpumpSettings settings); - void debugSettings(const char* settingName, wantedHeatpumpSettings settings); + void debugSettings(const char* settingName, heatpumpSettings& settings); + void debugSettings(const char* settingName, wantedHeatpumpSettings& settings); void debugStatus(const char* statusName, heatpumpStatus status); void debugSettingsAndStatus(const char* settingName, heatpumpSettings settings, heatpumpStatus status); void debugClimate(const char* settingName); @@ -283,7 +304,7 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR uint8_t* data; // initialise to all off, then it will update shortly after connect; - heatpumpStatus currentStatus{ 0, false, {TIMER_MODE_MAP[0], 0, 0, 0, 0}, 0 }; + heatpumpStatus currentStatus{ 0, 0, false, {TIMER_MODE_MAP[0], 0, 0, 0, 0}, 0, 0, 0, 0 }; heatpumpFunctions functions; bool tempMode = false; @@ -297,6 +318,8 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR // is the counter > MAX_NON_RESPONSE_REQ then we conclude uart is not connected anymore int nonResponseCounter = 0; + int powerRequestWithoutResponses = 0; + bool isReading = false; bool isWriting = false; diff --git a/components/cn105/componentEntries.cpp b/components/cn105/componentEntries.cpp index def4164..bab6fc5 100644 --- a/components/cn105/componentEntries.cpp +++ b/components/cn105/componentEntries.cpp @@ -26,8 +26,10 @@ void CN105Climate::setup() { this->nbHeatpumpConnections_ = 0; ESP_LOGI(TAG, "tx_pin: %d rx_pin: %d", this->tx_pin_, this->rx_pin_); - ESP_LOGI(TAG, "remote_temp_timeout is set to %d", this->remote_temp_timeout_); - ESP_LOGI(TAG, "debounce_delay is set to %d", this->debounce_delay_); + //ESP_LOGI(TAG, "remote_temp_timeout is set to %lu", this->remote_temp_timeout_); + log_info_uint32(TAG, "remote_temp_timeout is set to ", this->remote_temp_timeout_); + //ESP_LOGI(TAG, "debounce_delay is set to %lu", this->debounce_delay_); + log_info_uint32(TAG, "debounce_delay is set to ", this->debounce_delay_); this->setupUART(); this->sendFirstConnectionPacket(); @@ -39,7 +41,7 @@ void CN105Climate::setup() { * This function is called repeatedly in the main program loop. */ void CN105Climate::loop() { - if (!this->processInput()) { // if we don't get an input: no read op + if (!this->processInput()) { // if we don't get any input: no read op if ((this->wantedSettings.hasChanged) && (!this->loopCycle.isCycleRunning())) { this->checkPendingWantedSettings(); } else { @@ -56,7 +58,9 @@ void CN105Climate::loop() { uint32_t CN105Climate::get_update_interval() const { return this->update_interval_; } void CN105Climate::set_update_interval(uint32_t update_interval) { - ESP_LOGD(TAG, "Setting update interval to %d", update_interval); + //ESP_LOGD(TAG, "Setting update interval to %lu", update_interval); + log_debug_uint32(TAG, "Setting update interval to ", update_interval); + this->update_interval_ = update_interval; this->autoUpdate = (update_interval != 0); } diff --git a/components/cn105/compressor_frequency_sensor.h b/components/cn105/compressor_frequency_sensor.h index ce3fd82..e433c5e 100644 --- a/components/cn105/compressor_frequency_sensor.h +++ b/components/cn105/compressor_frequency_sensor.h @@ -10,8 +10,10 @@ namespace esphome { public: CompressorFrequencySensor() { this->set_unit_of_measurement("Hz"); + this->set_device_class("frequency"); + this->set_state_class(sensor::StateClass::STATE_CLASS_MEASUREMENT); this->set_accuracy_decimals(1); } }; -} \ No newline at end of file +} diff --git a/components/cn105/cycle_management.cpp b/components/cn105/cycle_management.cpp index 3080920..f18ba0f 100644 --- a/components/cn105/cycle_management.cpp +++ b/components/cn105/cycle_management.cpp @@ -29,7 +29,8 @@ void cycleManagement::deferCycle() { uint32_t delay = DEFER_SCHEDULE_UPDATE_LOOP_DELAY; #endif - ESP_LOGI(LOG_CYCLE_TAG, "Defering cycle trigger of %d ms", delay); + //ESP_LOGI(LOG_CYCLE_TAG, "Defering cycle trigger of %lu ms", delay); + log_info_uint32(LOG_CYCLE_TAG, "Defering cycle trigger of ", delay, " ms"); // forces the lastCompleteCycle offset of delay ms to allow a longer rest time lastCompleteCycleMs = CUSTOM_MILLIS + delay; diff --git a/components/cn105/extraComponents.cpp b/components/cn105/extraComponents.cpp index 66fcf61..5f1245b 100644 --- a/components/cn105/extraComponents.cpp +++ b/components/cn105/extraComponents.cpp @@ -57,6 +57,26 @@ void CN105Climate::set_compressor_frequency_sensor( this->compressor_frequency_sensor_ = compressor_frequency_sensor; } +void CN105Climate::set_input_power_sensor( + sensor::Sensor* input_power_sensor) { + this->input_power_sensor_ = input_power_sensor; +} + +void CN105Climate::set_kwh_sensor( + sensor::Sensor* kwh_sensor) { + this->kwh_sensor_ = kwh_sensor; +} + +void CN105Climate::set_runtime_hours_sensor( + sensor::Sensor* runtime_hours_sensor) { + this->runtime_hours_sensor_ = runtime_hours_sensor; +} + +void CN105Climate::set_outside_air_temperature_sensor( + sensor::Sensor* outside_air_temperature_sensor) { + this->outside_air_temperature_sensor_ = outside_air_temperature_sensor; +} + void CN105Climate::set_isee_sensor(esphome::binary_sensor::BinarySensor* iSee_sensor) { this->iSee_sensor_ = iSee_sensor; } diff --git a/components/cn105/hp_readings.cpp b/components/cn105/hp_readings.cpp index 25cd778..8e0415a 100644 --- a/components/cn105/hp_readings.cpp +++ b/components/cn105/hp_readings.cpp @@ -118,7 +118,7 @@ void CN105Climate::processDataPacket() { if (this->checkSum()) { // checkPoint of a heatpump response - this->lastResponseMs = CUSTOM_MILLIS; //esphome::CUSTOM_MILLIS; + this->lastResponseMs = CUSTOM_MILLIS; //esphome::CUSTOM_MILLIS; // processing the specific command processCommand(); @@ -148,7 +148,7 @@ void CN105Climate::getPowerFromResponsePacket() { ESP_LOGD("Decoder", "[0x09 is sub modes]"); heatpumpSettings receivedSettings{}; - receivedSettings.stage = lookupByteMapValue(STAGE_MAP, STAGE, 6, data[4], "current stage for delivery"); + receivedSettings.stage = lookupByteMapValue(STAGE_MAP, STAGE, 7, data[4], "current stage for delivery"); receivedSettings.sub_mode = lookupByteMapValue(SUB_MODE_MAP, SUB_MODE, 4, data[3], "submode"); receivedSettings.auto_sub_mode = lookupByteMapValue(AUTO_SUB_MODE_MAP, AUTO_SUB_MODE, 4, data[5], "auto mode sub mode"); @@ -172,7 +172,7 @@ void CN105Climate::getSettingsFromResponsePacket() { heatpumpSettings receivedSettings{}; ESP_LOGD("Decoder", "[0x02 is settings]"); //02 00 00 01 08 0A 00 07 00 00 03 AA 00 00 00 00 94 - //this->last_received_packet_sensor->publish_state("0x62-> 0x02: Data -> Settings"); + //this->last_received_packet_sensor->publish_state("0x62-> 0x02: Data -> Settings"); receivedSettings.connected = true; // we're here so we're connected (actually not used property) receivedSettings.power = lookupByteMapValue(POWER_MAP, POWER, 2, data[3], "power reading"); receivedSettings.iSee = data[4] > 0x08 ? true : false; @@ -202,10 +202,8 @@ void CN105Climate::getSettingsFromResponsePacket() { this->wideVaneAdj = (data[10] & 0xF0) == 0x80 ? true : false; - if (this->wideVaneAdj) { - receivedSettings.wideVane = lookupByteMapValue(WIDEVANE_MAP, WIDEVANE, 7, data[10] & 0x0F, "wideVane reading", WIDEVANE_MAP[2]); - } - + receivedSettings.wideVane = lookupByteMapValue(WIDEVANE_MAP, WIDEVANE, 7, data[10] & 0x0F, "wideVane reading"); + ESP_LOGD("Decoder", "[wideVane: %s (adj:%d)]", receivedSettings.wideVane, this->wideVaneAdj); /*if ((data[10] != 0) && (this->traits_.supports_swing_mode(climate::CLIMATE_SWING_HORIZONTAL))) { // wideVane is not always supported receivedSettings.wideVane = lookupByteMapValue(WIDEVANE_MAP, WIDEVANE, 7, data[10] & 0x0F, "wideVane reading"); wideVaneAdj = (data[10] & 0xF0) == 0x80 ? true : false; @@ -227,7 +225,20 @@ void CN105Climate::getRoomTemperatureFromResponsePacket() { heatpumpStatus receivedStatus{}; //ESP_LOGD("Decoder", "[0x03 room temperature]"); - //this->last_received_packet_sensor->publish_state("0x62-> 0x03: Data -> Room temperature"); + //this->last_received_packet_sensor->publish_state("0x62-> 0x03: Data -> Room temperature"); + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + // FC 62 01 30 10 03 00 00 0E 00 94 B0 B0 FE 42 00 01 0A 64 00 00 A9 + // RT OT RT SP ?? ?? ?? RM RM RM + // RT = room temperature (in old format and in new format) + // OT = outside air temperature + // SP = room setpoint temperature? + // RM = indoor unit operating time in minutes + + if (data[5] > 1) { + receivedStatus.outsideAirTemperature = (float)(data[5] - 128) / 2; + } else { + receivedStatus.outsideAirTemperature = NAN; + } if (data[6] != 0x00) { int temp = data[6]; @@ -236,16 +247,32 @@ void CN105Climate::getRoomTemperatureFromResponsePacket() { } else { receivedStatus.roomTemperature = lookupByteMapValue(ROOM_TEMP_MAP, ROOM_TEMP, 32, data[3]); } + + receivedStatus.runtimeHours = float((data[11] << 16) | (data[12] << 8) | data[13]) / 60; + ESP_LOGD("Decoder", "[Room °C: %f]", receivedStatus.roomTemperature); + ESP_LOGD("Decoder", "[OAT °C: %f]", receivedStatus.outsideAirTemperature); // no change with this packet to currentStatus for operating and compressorFrequency receivedStatus.operating = currentStatus.operating; receivedStatus.compressorFrequency = currentStatus.compressorFrequency; + receivedStatus.inputPower = currentStatus.inputPower; + receivedStatus.kWh = currentStatus.kWh; this->statusChanged(receivedStatus); - } + void CN105Climate::getOperatingAndCompressorFreqFromResponsePacket() { //FC 62 01 30 10 06 00 00 1A 01 00 00 00 00 00 00 00 00 00 00 00 3C + //MSZ-RW25VGHZ-SC1 / MUZ-RW25VGHZ-SC1 + //FC 62 01 30 10 06 00 00 00 01 00 08 05 50 00 00 42 00 00 00 00 B7 + // OP IP IP EU EU ?? + // OP = operating status (1 = compressor running, 0 = standby) + // IP = Current input power in Watts (16-bit decimal) + // EU = energy usage + // (used energy in kWh = value/10) + // TODO: Currently the maximum size of the counter is not known and + // if the counter extends to other bytes. + // ?? = unknown bytes that appear to have a fixed/constant value heatpumpStatus receivedStatus{}; ESP_LOGD("Decoder", "[0x06 is status]"); //this->last_received_packet_sensor->publish_state("0x62-> 0x06: Data -> Heatpump Status"); @@ -254,19 +281,40 @@ void CN105Climate::getOperatingAndCompressorFreqFromResponsePacket() { this->nonResponseCounter = 0; receivedStatus.operating = data[4]; receivedStatus.compressorFrequency = data[3]; + receivedStatus.inputPower = (data[5] << 8) | data[6]; + receivedStatus.kWh = float((data[7] << 8) | data[8]) / 10; // no change with this packet to roomTemperature receivedStatus.roomTemperature = currentStatus.roomTemperature; + receivedStatus.outsideAirTemperature = currentStatus.outsideAirTemperature; + receivedStatus.runtimeHours = currentStatus.runtimeHours; this->statusChanged(receivedStatus); } +void CN105Climate::terminateCycle() { + if (this->shouldSendExternalTemperature_) { + // We will receive ACK packet for this. + // Sending WantedSettings must be delayed in this case (lastSend timestamp updated). + this->sendRemoteTemperature(); + } + + this->loopCycle.cycleEnded(); + + if (this->hp_uptime_connection_sensor_ != nullptr) { + // if the uptime connection sensor is configured + // we trigger manual update at the end of a cycle. + this->hp_uptime_connection_sensor_->update(); + } + + this->nbCompleteCycles_++; +} void CN105Climate::getDataFromResponsePacket() { switch (this->data[0]) { case 0x02: /* setting information */ ESP_LOGD(LOG_CYCLE_TAG, "2b: Receiving settings response"); this->getSettingsFromResponsePacket(); - // next step is to get the room temperature case 0x03 + // next step is to get the room temperature case 0x03 ESP_LOGD(LOG_CYCLE_TAG, "3a: Sending room °C request (0x03)"); this->buildAndSendRequestPacket(RQST_PKT_ROOM_TEMP); break; @@ -275,7 +323,7 @@ void CN105Climate::getDataFromResponsePacket() { /* room temperature reading */ ESP_LOGD(LOG_CYCLE_TAG, "3b: Receiving room °C response"); this->getRoomTemperatureFromResponsePacket(); - // next step is to get the heatpump status (operating and compressor frequency) case 0x06 + // next step is to get the heatpump status (operating and compressor frequency) case 0x06 ESP_LOGD(LOG_CYCLE_TAG, "4a: Sending status request (0x06)"); this->buildAndSendRequestPacket(RQST_PKT_STATUS); break; @@ -296,32 +344,30 @@ void CN105Climate::getDataFromResponsePacket() { /* status */ ESP_LOGD(LOG_CYCLE_TAG, "4b: Receiving status response"); this->getOperatingAndCompressorFreqFromResponsePacket(); - ESP_LOGD(LOG_CYCLE_TAG, "5a: Sending power request (0x09)"); - this->buildAndSendRequestPacket(RQST_PKT_STANDBY); + + if (this->powerRequestWithoutResponses < 3) { // if more than 3 requests are without reponse, we desactivate the power request (0x09) + ESP_LOGD(LOG_CYCLE_TAG, "5a: Sending power request (0x09)"); + this->buildAndSendRequestPacket(RQST_PKT_STANDBY); + this->powerRequestWithoutResponses++; + } else { + if (this->powerRequestWithoutResponses != 4) { + this->powerRequestWithoutResponses = 4; + ESP_LOGW(LOG_CYCLE_TAG, "power request (0x09) disabled (not supported)"); + } + // in this case, the cycle ends up now + this->terminateCycle(); + } break; case 0x09: /* Power */ ESP_LOGD(LOG_CYCLE_TAG, "5b: Receiving Power/Standby response"); this->getPowerFromResponsePacket(); - //FC 62 01 30 10 09 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 50 - - if (this->shouldSendExternalTemperature_) { - this->sendRemoteTemperature(); - } - - this->loopCycle.cycleEnded(); - - if (this->hp_uptime_connection_sensor_ != nullptr) { - // if the uptime connection sensor is configured - // we trigger manual update at the end of a cycle. - this->hp_uptime_connection_sensor_->update(); - } - - this->nbCompleteCycles_++; - - + //FC 62 01 30 10 09 00 00 00 02 02 00 00 00 00 00 00 00 00 00 00 50 + // reset the powerRequestWithoutResponses to 0 as we had a response + this->powerRequestWithoutResponses = 0; + this->terminateCycle(); break; case 0x10: @@ -373,9 +419,9 @@ void CN105Climate::processCommand() { ESP_LOGI(TAG, "--> Heatpump did reply: connection success! <--"); //this->isHeatpumpConnected_ = true; this->setHeatpumpConnected(true); - // let's say that the last complete cycle was over now + // let's say that the last complete cycle was over now this->loopCycle.lastCompleteCycleMs = CUSTOM_MILLIS; - this->currentSettings.resetSettings(); // each time we connect, we need to reset current setting to force a complete sync with ha component state and receievdSettings + this->currentSettings.resetSettings(); // each time we connect, we need to reset current setting to force a complete sync with ha component state and receievdSettings break; default: break; @@ -392,22 +438,42 @@ void CN105Climate::statusChanged(heatpumpStatus status) { this->currentStatus.operating = status.operating; this->currentStatus.compressorFrequency = status.compressorFrequency; + this->currentStatus.inputPower = status.inputPower; + this->currentStatus.kWh = status.kWh; + this->currentStatus.runtimeHours = status.runtimeHours; this->currentStatus.roomTemperature = status.roomTemperature; + this->currentStatus.outsideAirTemperature = status.outsideAirTemperature; this->current_temperature = currentStatus.roomTemperature; - this->updateAction(); // update action info on HA climate component + this->updateAction(); // update action info on HA climate component this->publish_state(); if (this->compressor_frequency_sensor_ != nullptr) { this->compressor_frequency_sensor_->publish_state(currentStatus.compressorFrequency); } + + if (this->input_power_sensor_ != nullptr) { + this->input_power_sensor_->publish_state(currentStatus.inputPower); + } + + if (this->kwh_sensor_ != nullptr) { + this->kwh_sensor_->publish_state(currentStatus.kWh); + } + + if (this->runtime_hours_sensor_ != nullptr) { + this->runtime_hours_sensor_->publish_state(currentStatus.runtimeHours); + } + + if (this->outside_air_temperature_sensor_ != nullptr) { + this->outside_air_temperature_sensor_->publish_state(currentStatus.outsideAirTemperature); + } } // else no change } -void CN105Climate::publishStateToHA(heatpumpSettings settings) { +void CN105Climate::publishStateToHA(heatpumpSettings& settings) { - if ((this->wantedSettings.mode == nullptr) && (this->wantedSettings.power == nullptr)) { // to prevent overwriting a user demand + if ((this->wantedSettings.mode == nullptr) && (this->wantedSettings.power == nullptr)) { // to prevent overwriting a user demand checkPowerAndModeSettings(settings); } @@ -440,8 +506,8 @@ void CN105Climate::publishStateToHA(heatpumpSettings settings) { } -void CN105Climate::heatpumpUpdate(heatpumpSettings settings) { - // settings correponds to current settings +void CN105Climate::heatpumpUpdate(heatpumpSettings& settings) { + // settings correponds to current settings ESP_LOGV(LOG_SETTINGS_TAG, "Settings received"); this->debugSettings("current", this->currentSettings); @@ -552,7 +618,8 @@ void CN105Climate::checkFanSettings(heatpumpSettings& settings, bool updateCurre if (updateCurrentSettings) { currentSettings.fan = settings.fan; } - if (strcmp(currentSettings.fan, "QUIET") == 0) { + + if (strcmp(settings.fan, "QUIET") == 0) { this->fan_mode = climate::CLIMATE_FAN_QUIET; } else if (strcmp(settings.fan, "1") == 0) { this->fan_mode = climate::CLIMATE_FAN_LOW; @@ -609,4 +676,3 @@ void CN105Climate::checkPowerAndModeSettings(heatpumpSettings& settings, bool up } } } - diff --git a/components/cn105/hp_writings.cpp b/components/cn105/hp_writings.cpp index bca7624..1302df9 100644 --- a/components/cn105/hp_writings.cpp +++ b/components/cn105/hp_writings.cpp @@ -51,7 +51,7 @@ void CN105Climate::sendFirstConnectionPacket() { // ESP_LOGD(TAG, "t°: %f", currentStatus.roomTemperature); // ESP_LOGD(TAG, "operating: %d", currentStatus.operating); -// ESP_LOGD(TAG, "compressor freq: %d", currentStatus.compressorFrequency); +// ESP_LOGD(TAG, "compressor freq: %f", currentStatus.compressorFrequency); // this->updateAction(); // this->publish_state(); @@ -88,6 +88,9 @@ void CN105Climate::writePacket(uint8_t* packet, int length, bool checkIsActive) this->get_hw_serial_()->write_byte((uint8_t)packet[i]); } + // Prevent sending wantedSettings too soon after writing for example the remote temperature update packet + this->lastSend = CUSTOM_MILLIS; + } else { ESP_LOGW(TAG, "could not write as asked, because UART is not connected"); this->reconnectUART(); @@ -231,12 +234,7 @@ void CN105Climate::publishWantedSettingsStateToHA() { } // HA Temp - - if (this->wantedSettings.temperature != -1.0f) { - this->target_temperature = this->wantedSettings.temperature; - //this->currentSettings.temperature = this->wantedSettings.temperature; - } - + this->target_temperature = this->getTemperatureSetting(); // publish to HA this->publish_state(); @@ -280,10 +278,10 @@ void CN105Climate::sendWantedSettings() { #ifdef USE_ESP32 std::lock_guard guard(wantedSettingsMutex); this->sendWantedSettingsDelegate(); -#else +#else this->emulateMutex("WRITE_SETTINGS", std::bind(&CN105Climate::sendWantedSettingsDelegate, this)); -#endif +#endif } else { ESP_LOGD(TAG, "will sendWantedSettings later because we've sent one too recently..."); @@ -384,4 +382,4 @@ void CN105Climate::sendRemoteTemperature() { this->pingExternalTemperature(); -} \ No newline at end of file +} diff --git a/components/cn105/input_power_sensor.h b/components/cn105/input_power_sensor.h new file mode 100644 index 0000000..15025f1 --- /dev/null +++ b/components/cn105/input_power_sensor.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" + + +namespace esphome { + + class InputPowerSensor : public sensor::Sensor, public Component { + public: + InputPowerSensor() { + this->set_unit_of_measurement("W"); + this->set_device_class("power"); + this->set_state_class(sensor::StateClass::STATE_CLASS_MEASUREMENT); + this->set_accuracy_decimals(0); + } + }; + +} diff --git a/components/cn105/kwh_sensor.h b/components/cn105/kwh_sensor.h new file mode 100644 index 0000000..0137d5f --- /dev/null +++ b/components/cn105/kwh_sensor.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" + + +namespace esphome { + + class kWhSensor : public sensor::Sensor, public Component { + public: + kWhSensor() { + this->set_unit_of_measurement("kWh"); + this->set_device_class("energy"); + this->set_state_class(sensor::StateClass::STATE_CLASS_TOTAL_INCREASING); + this->set_accuracy_decimals(1); + } + }; + +} diff --git a/components/cn105/outside_air_temperature_sensor.h b/components/cn105/outside_air_temperature_sensor.h new file mode 100644 index 0000000..4806cd3 --- /dev/null +++ b/components/cn105/outside_air_temperature_sensor.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" + + +namespace esphome { + + class OutsideAirTemperatureSensor : public sensor::Sensor, public Component { + public: + OutsideAirTemperatureSensor() { + this->set_unit_of_measurement("°C"); + this->set_device_class("temperature"); + this->set_state_class(sensor::StateClass::STATE_CLASS_MEASUREMENT); + this->set_accuracy_decimals(1); + } + }; + +} diff --git a/components/cn105/runtime_hours_sensor.h b/components/cn105/runtime_hours_sensor.h new file mode 100644 index 0000000..090694c --- /dev/null +++ b/components/cn105/runtime_hours_sensor.h @@ -0,0 +1,19 @@ +#pragma once + +#include "esphome/components/sensor/sensor.h" +#include "esphome/core/component.h" + + +namespace esphome { + + class RuntimeHoursSensor : public sensor::Sensor, public Component { + public: + RuntimeHoursSensor() { + this->set_unit_of_measurement("h"); + this->set_device_class("duration"); + this->set_state_class(sensor::StateClass::STATE_CLASS_TOTAL_INCREASING); + this->set_accuracy_decimals(2); + } + }; + +} diff --git a/components/cn105/uptime_connection_sensor.cpp b/components/cn105/uptime_connection_sensor.cpp index fa22a26..7f5e509 100644 --- a/components/cn105/uptime_connection_sensor.cpp +++ b/components/cn105/uptime_connection_sensor.cpp @@ -9,7 +9,7 @@ namespace esphome { static const char* const TAG = "uptime.connection.sensor"; void HpUpTimeConnectionSensor::update() { if (connected_) { - UptimeSensor::update(); + UptimeSecondsSensor::update(); } else { this->uptime_ = 0; this->publish_state(0); @@ -31,4 +31,4 @@ namespace esphome { void HpUpTimeConnectionSensor::dump_config() { LOG_SENSOR("", "Uptime Connection Sensor", this); } } // namespace uptime -} // namespace esphome \ No newline at end of file +} // namespace esphome diff --git a/components/cn105/uptime_connection_sensor.h b/components/cn105/uptime_connection_sensor.h index 9314a32..97c2977 100644 --- a/components/cn105/uptime_connection_sensor.h +++ b/components/cn105/uptime_connection_sensor.h @@ -1,10 +1,10 @@ #pragma once -#include "esphome/components/uptime/uptime_sensor.h" +#include "esphome/components/uptime/uptime_seconds_sensor.h" namespace esphome { namespace uptime { - class HpUpTimeConnectionSensor : public UptimeSensor { + class HpUpTimeConnectionSensor : public UptimeSecondsSensor { public: void update() override; std::string unique_id() override; @@ -16,4 +16,4 @@ namespace esphome { bool connected_{ false }; }; } // namespace uptime -} // namespace esphome \ No newline at end of file +} // namespace esphome diff --git a/components/cn105/utils.cpp b/components/cn105/utils.cpp index 204aab3..79494f3 100644 --- a/components/cn105/utils.cpp +++ b/components/cn105/utils.cpp @@ -1,7 +1,20 @@ #include "cn105.h" #include "Globals.h" - +void log_info_uint32(const char* tag, const char* msg, uint32_t value, const char* suffix) { +#if __GNUC__ >= 11 + ESP_LOGI(tag, "%s %lu %s", msg, (unsigned long)value, suffix); +#else + ESP_LOGI(tag, "%s %u %s", msg, (unsigned int)value, suffix); +#endif +} +void log_debug_uint32(const char* tag, const char* msg, uint32_t value, const char* suffix) { +#if __GNUC__ >= 11 + ESP_LOGD(tag, "%s %lu %s", msg, (unsigned long)value, suffix); +#else + ESP_LOGD(tag, "%s %u %s", msg, (unsigned int)value, suffix); +#endif +} bool CN105Climate::hasChanged(const char* before, const char* now, const char* field, bool checkNotNull) { if (now == NULL) { @@ -42,7 +55,7 @@ const char* CN105Climate::getIfNotNull(const char* what, const char* defaultValu return what; } -void CN105Climate::debugSettings(const char* settingName, wantedHeatpumpSettings settings) { +void CN105Climate::debugSettings(const char* settingName, wantedHeatpumpSettings& settings) { #ifdef USE_ESP32 ESP_LOGD(LOG_ACTION_EVT_TAG, "[%s]-> [power: %s, target °C: %.1f, mode: %s, fan: %s, vane: %s, wvane: %s, hasChanged ? -> %s, hasBeenSent ? -> %s]", getIfNotNull(settingName, "unnamed"), @@ -74,7 +87,7 @@ void CN105Climate::debugClimate(const char* settingName) { ESP_LOGD(LOG_SETTINGS_TAG, "[%s]-> [mode: %s, target °C: %.1f, fan: %s, swing: %s]", settingName, LOG_STR_ARG(climate_mode_to_string(this->mode)), // Utilisation de LOG_STR_ARG - this->target_temperature, // Supposant que target_temperature est un float + this->target_temperature, this->fan_mode.has_value() ? LOG_STR_ARG(climate_fan_mode_to_string(this->fan_mode.value())) : "-", LOG_STR_ARG(climate_swing_mode_to_string(this->swing_mode))); } @@ -85,7 +98,7 @@ void CN105Climate::debugClimate(const char* settingName) { -void CN105Climate::debugSettings(const char* settingName, heatpumpSettings settings) { +void CN105Climate::debugSettings(const char* settingName, heatpumpSettings& settings) { #ifdef USE_ESP32 ESP_LOGD(LOG_SETTINGS_TAG, "[%s]-> [power: %s, target °C: %.1f, mode: %s, fan: %s, vane: %s, wvane: %s]", getIfNotNull(settingName, "unnamed"), @@ -112,13 +125,13 @@ void CN105Climate::debugSettings(const char* settingName, heatpumpSettings setti void CN105Climate::debugStatus(const char* statusName, heatpumpStatus status) { #ifdef USE_ESP32 - ESP_LOGI(LOG_STATUS_TAG, "[%s]-> [room C°: %.1f, operating: %s, compressor freq: %2d Hz]", + ESP_LOGI(LOG_STATUS_TAG, "[%s]-> [room C°: %.1f, operating: %s, compressor freq: %.1f Hz]", statusName, status.roomTemperature, status.operating ? "YES" : "NO ", status.compressorFrequency); #else - ESP_LOGI(LOG_STATUS_TAG, "[%-*s]-> [room C°: %.1f, operating: %-*s, compressor freq: %2d Hz]", + ESP_LOGI(LOG_STATUS_TAG, "[%-*s]-> [room C°: %.1f, operating: %-*s, compressor freq: %.1f Hz]", 15, statusName, status.roomTemperature, 3, status.operating ? "YES" : "NO ", @@ -165,7 +178,7 @@ int CN105Climate::lookupByteMapIndex(const int valuesMap[], int len, int lookupV } } ESP_LOGW("lookup", "%s caution value %d not found, returning -1", debugInfo, lookupValue); - esphome::delay(200); + //esphome::delay(200); return -1; } int CN105Climate::lookupByteMapIndex(const char* valuesMap[], int len, const char* lookupValue, const char* debugInfo) { @@ -175,7 +188,7 @@ int CN105Climate::lookupByteMapIndex(const char* valuesMap[], int len, const cha } } ESP_LOGW("lookup", "%s caution value %s not found, returning -1", debugInfo, lookupValue); - esphome::delay(200); + //esphome::delay(200); return -1; } const char* CN105Climate::lookupByteMapValue(const char* valuesMap[], const uint8_t byteMap[], int len, uint8_t byteValue, const char* debugInfo, const char* defaultValue) { @@ -267,7 +280,7 @@ void CN105Climate::logDelegate() { } else { ESP_LOGI("testMutex", "Mutex est déjà verrouillé"); } -#endif +#endif } void CN105Climate::testCase1() { @@ -312,4 +325,5 @@ void CN105Climate::testMutex() { this->testCase1(); } + #endif diff --git a/esp32-test.yaml b/esp32-test.yaml index a1d33e5..78623fb 100644 --- a/esp32-test.yaml +++ b/esp32-test.yaml @@ -1,5 +1,5 @@ substitutions: - name: "esp32-hp" + name: "esp32-hp-test" friendly_name: Clim Sejour esphome: @@ -10,6 +10,9 @@ esp32: board: esp32doit-devkit-v1 framework: type: esp-idf + #version: 5.3.0 + #platform_version: 6.8.0 + #type: arduino @@ -80,7 +83,8 @@ api: key: !secret encryption_key_sejour ota: - password: !secret ota_pwd + - platform: esphome + password: !secret ota_pwd wifi: #ssid: !secret wifi_ssid @@ -110,6 +114,7 @@ time: # this setting is for local component (code is not on github) external_components: +# - source: github://echavet/MitsubishiCN105ESPHome - source: type: local path: components @@ -247,11 +252,11 @@ climate: stage_sensor: name: stage sensor remote_temperature_timeout: 15min - update_interval: 2s # shouldn't be less than 1 second - debounce_delay : 100ms # delay to prevent bouncing + update_interval: 2500ms # shouldn't be less than 1 second + debounce_delay : 120ms # delay to prevent bouncing hp_uptime_connection_sensor: name: ${name} HP Uptime Connection - update_interval: 10s + update_interval: 30s supports: mode: [COOL, HEAT, FAN_ONLY, DRY] fan_mode: [AUTO, QUIET, LOW, MEDIUM, HIGH] @@ -259,6 +264,9 @@ climate: visual: min_temperature: 17 max_temperature: 23 - temperature_step: 1.0 + temperature_step: + target_temperature: 0.5 + current_temperature: 0.1 + diff --git a/hp-debug.yaml b/hp-debug.yaml index 9b24d2d..4c030d8 100644 --- a/hp-debug.yaml +++ b/hp-debug.yaml @@ -50,6 +50,7 @@ api: key: !secret encryption_key ota: +- platform: esphome password: !secret ota_pwd wifi: @@ -115,13 +116,17 @@ text_sensor: # name: ${name} WiFi Signal # update_interval: 60s +uart: + id: HP_UART + baud_rate: 2400 + tx_pin: GPIO1 + rx_pin: GPIO3 + # Configuration pour l'objet 'climate' climate: - platform: cn105 # remplis avec la plateforme de ton choix name: "Clim Seb" id: "clim_seb" - baud_rate: 0 - hardware_uart: UART0 update_interval: 4s # Ajoute d'autres paramètres spécifiques à ton matériel et tes besoins @@ -196,4 +201,4 @@ switch: optimistic: true turn_on_action: - lambda: |- - id(clim_seb).buildAndSendRequestsInfoPackets(); \ No newline at end of file + id(clim_seb).buildAndSendRequestsInfoPackets(); diff --git a/hp-sejour.yaml b/hp-sejour.yaml index 14eb234..70e1bb4 100644 --- a/hp-sejour.yaml +++ b/hp-sejour.yaml @@ -81,8 +81,8 @@ api: key: !secret encryption_key ota: +- platform: esphome password: !secret ota_pwd - wifi: #ssid: !secret wifi_ssid #password: !secret wifi_password