From e5b233f11daa6dbed9841d6aee9a77c82d5fe61f Mon Sep 17 00:00:00 2001 From: Miika Pekkarinen Date: Tue, 8 Oct 2024 18:23:05 +0300 Subject: [PATCH] - Revert the compressor frequency sensor patch. - Add a new sensor for current input power in Watts. - Add a new sensor for total consumed energy in kWh. - Add a new sensor for total indoor unit runtime in hours. - Try to prevent outside air temperature sensor from changing to incorrect values when it's unavailable. --- components/cn105/Globals.h | 8 ++- components/cn105/climate.py | 51 +++++++++++++++++++ components/cn105/cn105.cpp | 17 ++++++- components/cn105/cn105.h | 17 ++++++- .../cn105/compressor_frequency_sensor.h | 4 +- components/cn105/extraComponents.cpp | 15 ++++++ components/cn105/hp_readings.cpp | 48 ++++++++++++----- components/cn105/input_power_sensor.h | 19 +++++++ components/cn105/kwh_sensor.h | 19 +++++++ .../cn105/outside_air_temperature_sensor.h | 2 + components/cn105/runtime_hours_sensor.h | 19 +++++++ 11 files changed, 201 insertions(+), 18 deletions(-) create mode 100644 components/cn105/input_power_sensor.h create mode 100644 components/cn105/kwh_sensor.h create mode 100644 components/cn105/runtime_hours_sensor.h diff --git a/components/cn105/Globals.h b/components/cn105/Globals.h index 68a5095..b82f4ce 100644 --- a/components/cn105/Globals.h +++ b/components/cn105/Globals.h @@ -248,13 +248,19 @@ struct heatpumpStatus { bool operating; // if true, the heatpump is operating to reach the desired temperature heatpumpTimers timers; 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 3407170..dc6f892 100644 --- a/components/cn105/climate.py +++ b/components/cn105/climate.py @@ -35,6 +35,9 @@ 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" @@ -60,6 +63,18 @@ "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 ) @@ -96,6 +111,18 @@ def valid_uart(uart): {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)} ) @@ -142,6 +169,9 @@ def valid_uart(uart): cv.Optional(CONF_HORIZONTAL_SWING_SELECT): SELECT_SCHEMA, cv.Optional(CONF_VERTICAL_SWING_SELECT): SELECT_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, @@ -219,6 +249,27 @@ 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 diff --git a/components/cn105/cn105.cpp b/components/cn105/cn105.cpp index ba6acb4..6459ad1 100644 --- a/components/cn105/cn105.cpp +++ b/components/cn105/cn105.cpp @@ -26,13 +26,19 @@ 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->powerRequestWithoutResponses = 0; // power request is not supported by all heatpump #112 @@ -87,6 +93,15 @@ void CN105Climate::set_debounce_delay(uint32_t delay) { 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; } diff --git a/components/cn105/cn105.h b/components/cn105/cn105.h index cf90a9c..948c95d 100644 --- a/components/cn105/cn105.h +++ b/components/cn105/cn105.h @@ -4,6 +4,9 @@ #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" @@ -34,6 +37,9 @@ 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); @@ -56,6 +62,12 @@ 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 @@ -63,6 +75,9 @@ class CN105Climate : public climate::Climate, public Component, public uart::UAR uptime::HpUpTimeConnectionSensor* hp_uptime_connection_sensor_ = nullptr; float get_compressor_frequency(); + float get_input_power(); + float get_kwh(); + float get_runtime_hours(); bool is_operating(); // checks if the field has changed @@ -289,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, 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; 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/extraComponents.cpp b/components/cn105/extraComponents.cpp index de23e94..5f1245b 100644 --- a/components/cn105/extraComponents.cpp +++ b/components/cn105/extraComponents.cpp @@ -57,6 +57,21 @@ 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; diff --git a/components/cn105/hp_readings.cpp b/components/cn105/hp_readings.cpp index 39d8537..873aa98 100644 --- a/components/cn105/hp_readings.cpp +++ b/components/cn105/hp_readings.cpp @@ -228,19 +228,18 @@ void CN105Climate::getRoomTemperatureFromResponsePacket() { //ESP_LOGD("Decoder", "[0x03 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 ?? ?? ?? CT CT + // 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? - // CT = increasing counter (unknown function) + // RM = indoor unit operating time in minutes - if (data[5] != 0x00) { - receivedStatus.outsideAirTemperature = (float)(data[5] - 128) / 2; + if (data[5] > 1) { + receivedStatus.outsideAirTemperature = (float)(data[5] - 128) / 2; } else { - receivedStatus.outsideAirTemperature = -1; + receivedStatus.outsideAirTemperature = NAN; } if (data[6] != 0x00) { @@ -251,12 +250,16 @@ void CN105Climate::getRoomTemperatureFromResponsePacket() { 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); } @@ -264,11 +267,13 @@ 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 CF CF ?? CT ?? + // OP IP IP EU EU ?? // OP = operating status (1 = compressor running, 0 = standby) - // CF = compressor frequency in 16-bit integer, 1 decimal accuracy - // (frequency in float = value / 10) - // CT = slowly increasing counter, unknown function + // 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]"); @@ -277,14 +282,14 @@ void CN105Climate::getOperatingAndCompressorFreqFromResponsePacket() { // reset counter (because a reply indicates it is connected) this->nonResponseCounter = 0; receivedStatus.operating = data[4]; - if (data[5] || data[6]) - receivedStatus.compressorFrequency = (float)((data[5] << 8) | data[6]) / 10; - else - receivedStatus.compressorFrequency = (float)data[3]; + 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); } @@ -435,6 +440,9 @@ 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; @@ -446,6 +454,18 @@ void CN105Climate::statusChanged(heatpumpStatus status) { 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); } 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 index a253216..4806cd3 100644 --- a/components/cn105/outside_air_temperature_sensor.h +++ b/components/cn105/outside_air_temperature_sensor.h @@ -10,6 +10,8 @@ namespace esphome { 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); + } + }; + +}