diff --git a/components/panasonic_heatpump/README.md b/components/panasonic_heatpump/README.md index b5bda8e..689ac69 100644 --- a/components/panasonic_heatpump/README.md +++ b/components/panasonic_heatpump/README.md @@ -77,21 +77,34 @@ text_sensor: - platform: panasonic_heatpump top4: name: "Operating Mode State" - + number: - platform: panasonic_heatpump set5: name: "Set Z1 Heat Request Temperature" + min_value: -5.0 + max_value: 5.0 + step: 1.0 select: - platform: panasonic_heatpump + cool_mode: true set2: name: "Set Holiday Mode" switch: - - platform: panasonic_heatpump - set1: - name: "Set Heatpump" + - platform: panasonic_heatpump + set1: + name: "Set Heatpump" + +climate: + - platform: panasonic_heatpump + cool_mode: true + tank: + name: "DHW" + min_temperature: -5.0 + max_temperature: 5.0 + temperature_step: 0.5 ``` ## Configuration variables @@ -413,6 +426,8 @@ text_sensor: ### Numbers All numbers are optional and all default number variables can be applied. +Additionally the options `min_value`, `max_value` and `step` can override the default limits of each set entitiy. +This is usefull for example for `set5` to `set8` if `direct temperature` is configured instead of `compensation curve` (see `top76` and `top81`). Here a list of all supported numbers: ```yaml @@ -525,11 +540,14 @@ switch: ### Selects All selects are optional and all default select variables can be applied. +Additionally the option `cool_mode` can be configured. +If `cool_mode` is set to `true` the entity `set9` will have the additional select options `COOL`, `COOL+TANK`, `AUTO` and `AUTO+TANK`. Here a list of all supported selects: ```yaml select: - platform: panasonic_heatpump + cool_mode: false set2: name: "Set Holiday Mode" set3: @@ -546,6 +564,27 @@ select: name: "Set Bivalent Mode" ``` +### Climates + +All climates are optional and all default climate variables can be applied. +Additionally the option `cool_mode` can be configured. +If `cool_mode` is set to `true` the entity `zone1` and `zone2` will have the additional climate modes `COOL` and `AUTO`. +Additionally the options `min_temperature`, `max_temperature` and `temperature_step` can override the default limits on each climate entitiy. +This is usefull for example for `zone1` and `zone2` if `direct temperature` is configured instead of `compensation curve` (see `top76` and `top81`). +Here a list of all supported climates: + +```yaml +climate: + - platform: panasonic_heatpump + cool_mode: false + tank: + name: "DHW" + zone1: + name: "Zone 1" + zone2: + name: "Zone 2" +``` + ## Custom Entities (For Advanced Users) If you review the [ProtocolByteDecrypt.md](https://github.com/Egyras/HeishaMon/blob/master/ProtocolByteDecrypt.md) file you will find also some TOPs and SETs which are not implemented yet in heishamon. diff --git a/components/panasonic_heatpump/binary_sensor/__init__.py b/components/panasonic_heatpump/binary_sensor/__init__.py index e334744..5b82aa8 100644 --- a/components/panasonic_heatpump/binary_sensor/__init__.py +++ b/components/panasonic_heatpump/binary_sensor/__init__.py @@ -146,10 +146,11 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) async def to_code(config): - hub = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) - for key in TYPES: + parent = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) + for index, key in enumerate(TYPES): if child_config := config.get(key): var = await binary_sensor.new_binary_sensor(child_config) await cg.register_component(var, child_config) - await cg.register_parented(var, config[CONF_PANASONIC_HEATPUMP_ID]) - cg.add(getattr(hub, f"set_{key}_binary_sensor")(var)) + cg.add(var.set_parent(parent)) + cg.add(var.set_id(index)) + cg.add(parent.add_binary_sensor(var)) diff --git a/components/panasonic_heatpump/binary_sensor/panasonic_heatpump_binary_sensor.cpp b/components/panasonic_heatpump/binary_sensor/panasonic_heatpump_binary_sensor.cpp index c2f0f96..433bfdd 100644 --- a/components/panasonic_heatpump/binary_sensor/panasonic_heatpump_binary_sensor.cpp +++ b/components/panasonic_heatpump/binary_sensor/panasonic_heatpump_binary_sensor.cpp @@ -1,5 +1,4 @@ #include "panasonic_heatpump_binary_sensor.h" -#include "esphome/core/log.h" namespace esphome @@ -13,5 +12,156 @@ namespace esphome LOG_BINARY_SENSOR("", "Panasonic Heatpump Binary Sensor", this); delay(10); } + + void PanasonicHeatpumpBinarySensor::publish_new_state(const std::vector& data) + { + if (data.empty()) return; + + bool new_state; + switch (this->id_) + { + case BinarySensorIds::CONF_TOP0: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[4])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP2: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[4])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP3: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[7])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP13: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[5])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP26: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[111])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP60: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[112])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP61: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[112])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP68: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[5])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP69: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[117])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP99: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[24])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP100: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[24])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP108: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[20])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP109: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[20])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP110: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[20])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP119: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[23])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP120: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[23])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP121: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[23])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP122: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[23])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP123: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[116])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP124: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[116])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP129: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[26])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP132: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[26])); + if (this->has_state() && this->state == new_state) return; + break; + } + case BinarySensorIds::CONF_TOP133: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[26])); + if (this->has_state() && this->state == new_state) return; + break; + } + default: return; + }; + + this->publish_state(new_state); + } } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/binary_sensor/panasonic_heatpump_binary_sensor.h b/components/panasonic_heatpump/binary_sensor/panasonic_heatpump_binary_sensor.h index 8d620ba..5adf1e1 100644 --- a/components/panasonic_heatpump/binary_sensor/panasonic_heatpump_binary_sensor.h +++ b/components/panasonic_heatpump/binary_sensor/panasonic_heatpump_binary_sensor.h @@ -1,18 +1,48 @@ #pragma once -#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/core/component.h" +#include "esphome/components/binary_sensor/binary_sensor.h" #include "../panasonic_heatpump.h" +#include "../decode.h" namespace esphome { namespace panasonic_heatpump { - class PanasonicHeatpumpBinarySensor : public binary_sensor::BinarySensor, public Component, public Parented + enum BinarySensorIds : uint8_t + { + CONF_TOP0, + CONF_TOP2, + CONF_TOP3, + CONF_TOP13, + CONF_TOP26, + CONF_TOP60, + CONF_TOP61, + CONF_TOP68, + CONF_TOP69, + CONF_TOP99, + CONF_TOP100, + CONF_TOP108, + CONF_TOP109, + CONF_TOP110, + CONF_TOP119, + CONF_TOP120, + CONF_TOP121, + CONF_TOP122, + CONF_TOP123, + CONF_TOP124, + CONF_TOP129, + CONF_TOP132, + CONF_TOP133, + }; + + class PanasonicHeatpumpBinarySensor : public binary_sensor::BinarySensor, public Component, + public Parented, public PanasonicHeatpumpEntity { public: PanasonicHeatpumpBinarySensor() = default; void dump_config() override; + void publish_new_state(const std::vector& data) override; }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/climate/__init__.py b/components/panasonic_heatpump/climate/__init__.py new file mode 100644 index 0000000..f6c29a1 --- /dev/null +++ b/components/panasonic_heatpump/climate/__init__.py @@ -0,0 +1,78 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import climate +from esphome.components.climate import ( + ClimateMode, + ClimatePreset, +) +from esphome.const import ( + CONF_ID, + CONF_SUPPORTED_MODES, + CONF_SUPPORTED_PRESETS, + CONF_CUSTOM_PRESETS, + CONF_VISUAL, + CONF_MIN_TEMPERATURE, + CONF_MAX_TEMPERATURE, + CONF_TEMPERATURE_STEP, +) +from .. import CONF_PANASONIC_HEATPUMP_ID, PanasonicHeatpumpComponent, panasonic_heatpump_ns + +CONF_COOL_MODE = "cool_mode" +CONF_CLIMATE_TANK = "tank" +CONF_CLIMATE_ZONE1 = "zone1" +CONF_CLIMATE_ZONE2 = "zone2" + +TYPES = [ + CONF_CLIMATE_TANK, + CONF_CLIMATE_ZONE1, + CONF_CLIMATE_ZONE2, +] + +def climate_options(min_temp, max_temp, temp_step) -> cv.Schema: + schema = cv.Schema({ + cv.Optional(CONF_MIN_TEMPERATURE, default=min_temp): cv.float_, + cv.Optional(CONF_MAX_TEMPERATURE, default=max_temp): cv.float_, + cv.Optional(CONF_TEMPERATURE_STEP, default=temp_step): cv.float_, + }) + return schema + +PanasonicHeatpumpClimate = panasonic_heatpump_ns.class_("PanasonicHeatpumpClimate", climate.Climate, cg.Component) + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id( + PanasonicHeatpumpComponent + ), + cv.Optional(CONF_COOL_MODE, default=False): cv.boolean, + + cv.Optional(CONF_CLIMATE_TANK): climate.climate_schema( + PanasonicHeatpumpClimate + ).extend( + climate_options(20.0, 65.0, 0.5) + ), + cv.Optional(CONF_CLIMATE_ZONE1): climate.climate_schema( + PanasonicHeatpumpClimate + ).extend( + climate_options(-5.0, 5.0, 0.5) + ), + cv.Optional(CONF_CLIMATE_ZONE2): climate.climate_schema( + PanasonicHeatpumpClimate + ).extend( + climate_options(-5.0, 5.0, 0.5) + ), + } +).extend(cv.COMPONENT_SCHEMA) + +async def to_code(config): + parent = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) + for index, key in enumerate(TYPES): + if child_config := config.get(key): + var = await climate.new_climate(child_config) + await cg.register_component(var, child_config) + cg.add(var.set_parent(parent)) + cg.add(var.set_id(index)) + cg.add(var.set_min_temperature(child_config[CONF_MIN_TEMPERATURE])) + cg.add(var.set_max_temperature(child_config[CONF_MAX_TEMPERATURE])) + cg.add(var.set_temperature_step(child_config[CONF_TEMPERATURE_STEP])) + cg.add(var.set_cool_mode(config[CONF_COOL_MODE])) + cg.add(parent.add_climate(var)) diff --git a/components/panasonic_heatpump/climate/panasonic_heatpump_climate.cpp b/components/panasonic_heatpump/climate/panasonic_heatpump_climate.cpp new file mode 100644 index 0000000..a5dca9b --- /dev/null +++ b/components/panasonic_heatpump/climate/panasonic_heatpump_climate.cpp @@ -0,0 +1,229 @@ +#include "panasonic_heatpump_climate.h" +#include "esphome/core/log.h" + + +namespace esphome +{ + namespace panasonic_heatpump + { + static const char *const TAG = "panasonic_heatpump.climate"; + + void PanasonicHeatpumpClimate::dump_config() + { + LOG_CLIMATE("", "Panasonic Heatpump Climate", this); + } + + climate::ClimateTraits PanasonicHeatpumpClimate::traits() + { + auto traits = climate::ClimateTraits(); + + //traits.set_supports_action(true); + traits.set_supports_current_temperature(true); + if (this->cool_mode_ && + (this->id_ == ClimateIds::CONF_CLIMATE_ZONE1 || + this->id_ == ClimateIds::CONF_CLIMATE_ZONE2)) + { + traits.set_supports_two_point_target_temperature(true); + this->supported_modes_.insert(climate::CLIMATE_MODE_COOL); + this->supported_modes_.insert(climate::CLIMATE_MODE_AUTO); + } + + traits.set_supported_modes(this->supported_modes_); + traits.set_visual_min_temperature(this->min_temperature_); + traits.set_visual_max_temperature(this->max_temperature_); + traits.set_visual_temperature_step(this->temperature_step_); + + return traits; + } + + void PanasonicHeatpumpClimate::control(const climate::ClimateCall &call) + { + if (call.get_mode().has_value()) + { + int byte6 = this->parent_->getResponseByte(6); + if (byte6 >= 0) + { + climate::ClimateMode new_mode = *call.get_mode(); + uint8_t newByte6 = this->setClimateMode(new_mode, (uint8_t)byte6); + this->parent_->set_command_byte(newByte6, 6); + } + } + + if (call.get_target_temperature().has_value()) + { + float new_temp = *call.get_target_temperature(); + switch (this->id_) + { + case ClimateIds::CONF_CLIMATE_TANK: + this->parent_->set_command_byte(PanasonicCommand::setPlus128(new_temp), 42); // set11 + break; + case ClimateIds::CONF_CLIMATE_ZONE1: + this->parent_->set_command_byte(PanasonicCommand::setPlus128(new_temp), 38); // set5 + break; + case ClimateIds::CONF_CLIMATE_ZONE2: + this->parent_->set_command_byte(PanasonicCommand::setPlus128(new_temp), 40); // set7 + break; + }; + } + + if (call.get_target_temperature_high().has_value()) + { + float new_temp = *call.get_target_temperature_high(); + switch (this->id_) + { + case ClimateIds::CONF_CLIMATE_ZONE1: + this->parent_->set_command_byte(PanasonicCommand::setPlus128(new_temp), 38); // set5 + break; + case ClimateIds::CONF_CLIMATE_ZONE2: + this->parent_->set_command_byte(PanasonicCommand::setPlus128(new_temp), 40); // set7 + break; + }; + } + + if (call.get_target_temperature_low().has_value()) + { + float new_temp = *call.get_target_temperature_low(); + switch (this->id_) + { + case ClimateIds::CONF_CLIMATE_ZONE1: + this->parent_->set_command_byte(PanasonicCommand::setPlus128(new_temp), 39); // set6 + break; + case ClimateIds::CONF_CLIMATE_ZONE2: + this->parent_->set_command_byte(PanasonicCommand::setPlus128(new_temp), 41); // set8 + break; + }; + } + + this->publish_state(); + this->keep_state_ = 2; + } + + void PanasonicHeatpumpClimate::publish_new_state(const std::vector& data) + { + if (this->keep_state_ > 0) + { + this->keep_state_--; + return; + } + if (data.empty()) return; + + uint8_t new_mode; + float new_target_temp_heat; + float new_target_temp_cool; + float new_current_temp; + + new_mode = this->getClimateMode(data[6]); // set9 + switch (this->id_) + { + case ClimateIds::CONF_CLIMATE_TANK: + new_target_temp_heat = PanasonicDecode::getByteMinus128(data[42]); // set11 + new_current_temp = PanasonicDecode::getByteMinus128(data[141]); // top10 + break; + case ClimateIds::CONF_CLIMATE_ZONE1: + new_target_temp_heat = PanasonicDecode::getByteMinus128(data[38]); // set5 + new_target_temp_cool = PanasonicDecode::getByteMinus128(data[39]); // set6 + new_current_temp = PanasonicDecode::getByteMinus128(data[139]); // top56 + break; + case ClimateIds::CONF_CLIMATE_ZONE2: + new_target_temp_heat = PanasonicDecode::getByteMinus128(data[40]); // set7 + new_target_temp_cool = PanasonicDecode::getByteMinus128(data[41]); // set8 + new_current_temp = PanasonicDecode::getByteMinus128(data[140]); // top57 + break; + default: return; + }; + + if (!this->get_traits().get_supports_two_point_target_temperature() && + this->mode == new_mode && + this->target_temperature == new_target_temp_heat && + this->current_temperature == new_current_temp) return; + if (this->get_traits().get_supports_two_point_target_temperature() && + this->mode == new_mode && + this->target_temperature_high == new_target_temp_heat && + this->target_temperature_low == new_target_temp_cool && + this->current_temperature == new_current_temp) return; + + if (new_mode != 255) this->mode = (climate::ClimateMode)new_mode; + //this->action = climate::CLIMATE_ACTION_IDLE; + if (this->get_traits().get_supports_two_point_target_temperature()) + { + this->target_temperature_high = new_target_temp_heat; + this->target_temperature_low = new_target_temp_cool; + } + else + { + this->target_temperature = new_target_temp_heat; + } + this->current_temperature = new_current_temp; + this->publish_state(); + } + + uint8_t PanasonicHeatpumpClimate::getClimateMode(const uint8_t input) + { + switch (this->id_) + { + case ClimateIds::CONF_CLIMATE_TANK: + switch ((uint8_t)(input & 0b110000)) + { + case 0b010000: + return climate::CLIMATE_MODE_OFF; + case 0b100000: + return climate::CLIMATE_MODE_HEAT; + default: return 255; + }; + case ClimateIds::CONF_CLIMATE_ZONE1: + case ClimateIds::CONF_CLIMATE_ZONE2: + switch ((uint8_t)(input & 0b1111)) + { + case 0b0001: + return climate::CLIMATE_MODE_OFF; + case 0b0010: + return climate::CLIMATE_MODE_HEAT; + case 0b0011: + return climate::CLIMATE_MODE_COOL; + case 0b1000: + return climate::CLIMATE_MODE_AUTO; + case 0b1001: + return climate::CLIMATE_MODE_AUTO; // 0x19 = auto-heat + case 0b1010: + return climate::CLIMATE_MODE_AUTO; // 0x1A = auto-cool + default: return 255; + }; + default: return 255; + }; + } + + uint8_t PanasonicHeatpumpClimate::setClimateMode(const climate::ClimateMode mode, uint8_t byte) + { + uint8_t newByte = byte; + switch (this->id_) + { + case ClimateIds::CONF_CLIMATE_TANK: + newByte = newByte & 0b11001111; + switch (mode) + { + case climate::CLIMATE_MODE_OFF: + return newByte + 0b010000; + case climate::CLIMATE_MODE_HEAT: + return newByte + 0b100000; + default: return 0; + }; + case ClimateIds::CONF_CLIMATE_ZONE1: + case ClimateIds::CONF_CLIMATE_ZONE2: + newByte = newByte & 0b11110000; + switch (mode) + { + case climate::CLIMATE_MODE_OFF: + return newByte + 0b0001; + case climate::CLIMATE_MODE_HEAT: + return newByte + 0b0010; + case climate::CLIMATE_MODE_COOL: + return newByte + 0b0011; + case climate::CLIMATE_MODE_AUTO: + return newByte + 0b1000; + default: return 0; + }; + default: return 0; + }; + } + } // namespace panasonic_heatpump +} // namespace esphome diff --git a/components/panasonic_heatpump/climate/panasonic_heatpump_climate.h b/components/panasonic_heatpump/climate/panasonic_heatpump_climate.h new file mode 100644 index 0000000..4c11d90 --- /dev/null +++ b/components/panasonic_heatpump/climate/panasonic_heatpump_climate.h @@ -0,0 +1,46 @@ +#pragma once +#include "esphome/core/component.h" +#include "esphome/components/climate/climate.h" +#include "../panasonic_heatpump.h" +#include "../decode.h" +#include "../commands.h" + + +namespace esphome +{ + namespace panasonic_heatpump + { + enum ClimateIds : uint8_t + { + CONF_CLIMATE_TANK, + CONF_CLIMATE_ZONE1, + CONF_CLIMATE_ZONE2, + }; + + class PanasonicHeatpumpClimate : public climate::Climate, public Component, + public Parented, public PanasonicHeatpumpEntity + { + public: + PanasonicHeatpumpClimate() = default; + void dump_config() override; + climate::ClimateTraits traits() override; + void publish_new_state(const std::vector& data) override; + + void set_cool_mode(bool value) { this->cool_mode_ = value; } + void set_min_temperature(float value) { this->min_temperature_ = value; } + void set_max_temperature(float value) { this->max_temperature_ = value; } + void set_temperature_step(float value) { this->temperature_step_ = value; } + + protected: + void control(const climate::ClimateCall &call) override; + uint8_t getClimateMode(const uint8_t input); + uint8_t setClimateMode(const climate::ClimateMode mode, const uint8_t byte); + + bool cool_mode_ { false }; + float min_temperature_ { -5.0 }; + float max_temperature_ { 5.0 }; + float temperature_step_ { 0.5 }; + std::set supported_modes_ { climate::CLIMATE_MODE_OFF, climate::CLIMATE_MODE_HEAT }; + }; + } // namespace panasonic_heatpump +} // namespace esphome diff --git a/components/panasonic_heatpump/commands.cpp b/components/panasonic_heatpump/commands.cpp index b880e48..b4daff3 100644 --- a/components/panasonic_heatpump/commands.cpp +++ b/components/panasonic_heatpump/commands.cpp @@ -48,32 +48,32 @@ namespace esphome uint8_t PanasonicCommand::setMultiply2(size_t input) { - return input * 2; + return input * 0b10; } uint8_t PanasonicCommand::setMultiply4(size_t input) { - return input * 4; + return input * 0b100; } uint8_t PanasonicCommand::setPlus1Multiply4(size_t input) { - return (input + 1) * 4; + return (input + 1) * 0b100; } uint8_t PanasonicCommand::setPlus1Multiply8(size_t input) { - return (input + 1) * 8; + return (input + 1) * 0b1000; } uint8_t PanasonicCommand::setPlus1Multiply16(size_t input) { - return (input + 1) * 16; + return (input + 1) * 0b10000; } uint8_t PanasonicCommand::setPlus1Multiply64(size_t input) { - return (input + 1) * 64; + return (input + 1) * 0b1000000; } uint8_t PanasonicCommand::setPlus1(size_t input) @@ -81,31 +81,26 @@ namespace esphome return input + 1; } - uint8_t PanasonicCommand::setPlus73(size_t input) - { - return input + 73; - } - uint8_t PanasonicCommand::setPlus128(size_t input) { - return input + 128; + return input + 0b10000000; } uint8_t PanasonicCommand::setOperationMode(size_t input) { switch (input) { - case 0: return 18; // heat-only - case 1: return 19; // cool-only - case 2: return 24; // auto - case 3: return 25; // auto-heat - case 4: return 26; // auto-cool - case 5: return 33; // dhw-only - case 6: return 34; // heat+dhw - case 7: return 35; // cool+dhw - case 8: return 40; // auto-dhw - case 9: return 41; // auto-heat+dhw - case 10: return 42; // auto-cool+dhw + case 0: return 0b100001; // 0x21 = tank + case 1: return 0b010010; // 0x12 = heat + case 2: return 0b100010; // 0x22 = heat+tank + case 3: return 0b010011; // 0x13 = cool + case 4: return 0b100011; // 0x23 = cool+tank + case 5: return 0b011000; // 0x18 = auto + case 6: return 0b101000; // 0x28 = auto+tank + case 7: return 0b011001; // 0x19 = auto-heat + case 8: return 0b101001; // 0x29 = auto-heat+tank + case 9: return 0b011010; // 0x1A = auto-cool + case 10: return 0b101010; // 0x2A = auto-cool+tank default: return 0; // do nothing } } diff --git a/components/panasonic_heatpump/commands.h b/components/panasonic_heatpump/commands.h index 09aa48f..85de7a8 100644 --- a/components/panasonic_heatpump/commands.h +++ b/components/panasonic_heatpump/commands.h @@ -2,10 +2,18 @@ #include #include +#ifndef INIT_REQUEST_SIZE #define INIT_REQUEST_SIZE 8 +#endif +#ifndef INIT_RESPONSE_SIZE #define INIT_RESPONSE_SIZE 51 +#endif +#ifndef DATA_MESSAGE_SIZE #define DATA_MESSAGE_SIZE 111 +#endif +#ifndef OPTIONAL_MESSAGE_SIZE #define OPTIONAL_MESSAGE_SIZE 20 +#endif namespace esphome @@ -25,7 +33,6 @@ namespace esphome static uint8_t setPlus1Multiply16(size_t input); static uint8_t setPlus1Multiply64(size_t input); static uint8_t setPlus1(size_t input); - static uint8_t setPlus73(size_t input); static uint8_t setPlus128(size_t input); static uint8_t setOperationMode(size_t input); static uint8_t temp2hex(float temp); diff --git a/components/panasonic_heatpump/decode.cpp b/components/panasonic_heatpump/decode.cpp index 1536b90..56d045e 100644 --- a/components/panasonic_heatpump/decode.cpp +++ b/components/panasonic_heatpump/decode.cpp @@ -11,19 +11,19 @@ namespace esphome constexpr const char* const PanasonicDecode::InactiveActive[]; constexpr const char* const PanasonicDecode::PumpFlowRateMode[]; constexpr const char* const PanasonicDecode::HolidayState[]; - constexpr const char* const PanasonicDecode::OpModeDesc[]; - constexpr const char* const PanasonicDecode::Powerfulmode[]; - constexpr const char* const PanasonicDecode::Quietmode[]; - constexpr const char* const PanasonicDecode::Valve[]; - constexpr const char* const PanasonicDecode::Valve2[]; + constexpr const char* const PanasonicDecode::OperationMode[]; + constexpr const char* const PanasonicDecode::PowerfulMode[]; + constexpr const char* const PanasonicDecode::QuietMode[]; + constexpr const char* const PanasonicDecode::ThreeWayValve[]; + constexpr const char* const PanasonicDecode::TwoWayValve[]; constexpr const char* const PanasonicDecode::MixingValve[]; - constexpr const char* const PanasonicDecode::ZonesState[]; - constexpr const char* const PanasonicDecode::HeatCoolModeDesc[]; - constexpr const char* const PanasonicDecode::SolarModeDesc[]; - constexpr const char* const PanasonicDecode::ZonesSensorType[]; + constexpr const char* const PanasonicDecode::ZoneState[]; + constexpr const char* const PanasonicDecode::WaterTempControl[]; + constexpr const char* const PanasonicDecode::SolarMode[]; + constexpr const char* const PanasonicDecode::ZoneSensorType[]; constexpr const char* const PanasonicDecode::LiquidType[]; constexpr const char* const PanasonicDecode::ExtPadHeaterType[]; - constexpr const char* const PanasonicDecode::Bivalent[]; + constexpr const char* const PanasonicDecode::BivalentMode[]; constexpr const char* const PanasonicDecode::ModelNames[]; constexpr const uint8_t KnownModels[NUMBER_OF_MODELS][10] = @@ -170,32 +170,32 @@ namespace esphome return (input & 0b1111) - 1; } - int PanasonicDecode::getWordMinus1(uint8_t low, uint8_t hi) + int PanasonicDecode::getWordMinus1(const std::vector& data, uint8_t index) { - return ((hi << 8) + low) - 1; + return ((data[index + 1] << 8) + data[index]) - 1; } - int PanasonicDecode::getUintt16(uint8_t input1, uint8_t input2) + int PanasonicDecode::getUintt16(const std::vector& data, uint8_t index) { - return (static_cast((input2 << 8) | input1)) - 1; + return (static_cast((data[index + 1] << 8) | data[index])) - 1; } // TOP4 // - int PanasonicDecode::getOpMode(uint8_t input) + int PanasonicDecode::getOperationMode(uint8_t input) { switch ((int)(input & 0b111111)) { - case 18: return 0; // heat-only - case 19: return 1; // cool-only - case 24: return 2; // auto - case 25: return 3; // auto-heat - case 26: return 4; // auto-cool - case 33: return 5; // dhw-only - case 34: return 6; // heat+dhw - case 35: return 7; // cool+dhw - case 40: return 8; // auto-dhw - case 41: return 9; // auto-heat+dhw - case 42: return 10; // auto-cool+dhw + case 0b100001: return 0; // 0x21 = tank + case 0b010010: return 1; // 0x12 = heat + case 0b100010: return 2; // 0x22 = heat+tank + case 0b010011: return 3; // 0x13 = cool + case 0b100011: return 4; // 0x23 = cool+tank + case 0b011000: return 5; // 0x18 = auto + case 0b101000: return 6; // 0x28 = auto-tank + case 0b011001: return 7; // 0x19 = auto-heat + case 0b101001: return 8; // 0x29 = auto-heat+tank + case 0b011010: return 9; // 0x1A = auto-cool + case 0b101010: return 10; // 0x2A = auto-cool+tank default: return -1; // unknown } } @@ -222,9 +222,9 @@ namespace esphome // TOP1 // // input1 = data[169] // input2 = data[170] - float PanasonicDecode::getPumpFlow(uint8_t input1, uint8_t input2) + float PanasonicDecode::getPumpFlow(const std::vector& data, uint8_t index) { - return (((float)input1 - 1) / 256) + ((int)input2); + return (((float)data[index] - 1) / 256) + ((int)data[index + 1]); } // TOP5, TOP6 // @@ -269,7 +269,7 @@ namespace esphome if ((index < 0) || (index >= size)) { - return "UNKNOWN"; + return "UNDEFINED"; } return array[index + 1]; diff --git a/components/panasonic_heatpump/decode.h b/components/panasonic_heatpump/decode.h index 4651504..ae088a9 100644 --- a/components/panasonic_heatpump/decode.h +++ b/components/panasonic_heatpump/decode.h @@ -3,8 +3,12 @@ #include #include +#ifndef RESPONSE_MSG_SIZE #define RESPONSE_MSG_SIZE 203 +#endif +#ifndef NUMBER_OF_MODELS #define NUMBER_OF_MODELS 55 +#endif namespace esphome @@ -33,12 +37,12 @@ namespace esphome static int getByteMinus1Times200(uint8_t input); static int getHighNibbleMinus1(uint8_t input); static int getLowNibbleMinus1(uint8_t input); - static int getWordMinus1(uint8_t hi, uint8_t low); - static int getUintt16(uint8_t input1, uint8_t input2); + static int getWordMinus1(const std::vector& data, uint8_t index); + static int getUintt16(const std::vector& data, uint8_t index); - static int getOpMode(uint8_t input); + static int getOperationMode(uint8_t input); static int getModel(const std::vector& data, uint8_t index); - static float getPumpFlow(uint8_t input1, uint8_t input2); + static float getPumpFlow(const std::vector& data, uint8_t index); static float getFractional(uint8_t input, uint8_t shift); static std::string getErrorInfo(uint8_t errorType, uint8_t errorNumber); @@ -50,21 +54,24 @@ namespace esphome static const constexpr char* const OffOn[] = { "2", "Off", "On" }; static const constexpr char* const InactiveActive[] = { "2", "Inactive", "Active" }; static const constexpr char* const PumpFlowRateMode[] = { "2", "DeltaT", "Max flow" }; - static const constexpr char* const Valve[] = { "2", "Room", "DHW" }; - static const constexpr char* const Valve2[] = { "2", "Cool", "Heat" }; - static const constexpr char* const HeatCoolModeDesc[] = { "2", "Comp. Curve", "Direct" }; + static const constexpr char* const ThreeWayValve[] = { "2", "Buffer Tank", "DHW Tank" }; + static const constexpr char* const TwoWayValve[] = { "2", "Cool", "Heat" }; + static const constexpr char* const WaterTempControl[] = { "2", "Comp. Curve", "Direct" }; static const constexpr char* const LiquidType[] = { "2", "Water", "Glycol" }; static const constexpr char* const HolidayState[] = { "3", "Off", "Scheduled", "Active" }; - static const constexpr char* const SolarModeDesc[] = { "3", "Disabled", "Buffer", "DHW" }; + static const constexpr char* const SolarMode[] = { "3", "Disabled", "Buffer Tank", "DHW Tank" }; static const constexpr char* const MixingValve[] = { "4", "Off", "Decrease","Increase", "Invalid" }; - static const constexpr char* const ZonesSensorType[] = { "4", "Water Temperature", "External Thermostat", "Internal Thermostat", "Thermistor" }; - static const constexpr char* const Quietmode[] = { "4", "Off", "Level 1", "Level 2", "Level 3" }; - static const constexpr char* const Powerfulmode[] = { "4", "Off", "30min", "60min", "90min" }; - static const constexpr char* const OpModeDesc[] = { "11", "Heat only", "Cool only", "Auto", "Auto(heat)", "Auto(cool)", "DHW only", - "Heat+DHW", "Cool+DHW", "Auto+DHW", "Auto(heat)+DHW", "Auto(cool)+DHW" }; - static const constexpr char* const ZonesState[] = { "3", "Zone 1", "Zone 2", "Zone 1 & 2" }; + static const constexpr char* const ZoneSensorType[] = { "4", "Water Temperature", "External Thermostat", "Internal Thermostat", "Thermistor" }; + static const constexpr char* const QuietMode[] = { "4", "Off", "Level 1", "Level 2", "Level 3" }; + static const constexpr char* const PowerfulMode[] = { "4", "Off", "30min", "60min", "90min" }; + static const constexpr char* const OperationMode[] = + { + "11", "TANK", "HEAT", "HEAT+TANK", "COOL", "COOL+TANK", "AUTO", "AUTO+TANK", + "AUTO(HEAT)", "AUTO(HEAT)+TANK", "AUTO(COOL)", "AUTO(COOL)+TANK" + }; + static const constexpr char* const ZoneState[] = { "3", "Zone 1", "Zone 2", "Zone 1 & 2" }; static const constexpr char* const ExtPadHeaterType[] = { "3", "Disabled", "Type-A", "Type-B" }; - static const constexpr char* const Bivalent[] = { "3", "Alternative", "Parallel", "Advanced Parallel" }; + static const constexpr char* const BivalentMode[] = { "3", "Alternative", "Parallel", "Advanced Parallel" }; static const constexpr char* const ModelNames[] = { "55", // string representation of number of known models (last model number + 1) diff --git a/components/panasonic_heatpump/helpers.h b/components/panasonic_heatpump/helpers.h index 531f1d5..fc868ab 100644 --- a/components/panasonic_heatpump/helpers.h +++ b/components/panasonic_heatpump/helpers.h @@ -5,14 +5,16 @@ #include #include +#ifndef UART_LOG_CHUNK_SIZE #define UART_LOG_CHUNK_SIZE 120 +#endif namespace esphome { namespace panasonic_heatpump { - enum UartLogDirection + enum UartLogDirection : uint8_t { UART_LOG_RX, UART_LOG_TX, diff --git a/components/panasonic_heatpump/number/__init__.py b/components/panasonic_heatpump/number/__init__.py index 101241b..586eabd 100644 --- a/components/panasonic_heatpump/number/__init__.py +++ b/components/panasonic_heatpump/number/__init__.py @@ -6,6 +6,9 @@ from esphome.const import ( UNIT_KELVIN, UNIT_MINUTE, ENTITY_CATEGORY_CONFIG, + CONF_MIN_VALUE, + CONF_MAX_VALUE, + CONF_STEP, ) from .. import CONF_PANASONIC_HEATPUMP_ID, PanasonicHeatpumpComponent, panasonic_heatpump_ns @@ -16,15 +19,15 @@ CONF_SET7 = "set7" # Set Z2 Heat Request Temperature CONF_SET8 = "set8" # Set Z2 Cool Request Temperature CONF_SET11 = "set11" # Set DHW Temp CONF_SET15 = "set15" # Set Max Pump Duty -CONF_SET16_1 = "set16_1" # Set Zone1 Heat Target High -CONF_SET16_2 = "set16_2" # Set Zone1 Heat Target Low -CONF_SET16_3 = "set16_3" # Set Zone1 Heat Outside Low -CONF_SET16_4 = "set16_4" # Set Zone1 Heat Outside High -CONF_SET16_5 = "set16_5" # Set Zone2 Heat Target High -CONF_SET16_6 = "set16_6" # Set Zone2 Heat Target Low -CONF_SET16_7 = "set16_7" # Set Zone2 Heat Outside Low -CONF_SET16_8 = "set16_8" # Set Zone2 Heat Outside High -CONF_SET16_9 = "set16_9" # Set Zone1 Cool Target High +CONF_SET16_01 = "set16_01" # Set Zone1 Heat Target High +CONF_SET16_02 = "set16_02" # Set Zone1 Heat Target Low +CONF_SET16_03 = "set16_03" # Set Zone1 Heat Outside Low +CONF_SET16_04 = "set16_04" # Set Zone1 Heat Outside High +CONF_SET16_05 = "set16_05" # Set Zone2 Heat Target High +CONF_SET16_06 = "set16_06" # Set Zone2 Heat Target Low +CONF_SET16_07 = "set16_07" # Set Zone2 Heat Outside Low +CONF_SET16_08 = "set16_08" # Set Zone2 Heat Outside High +CONF_SET16_09 = "set16_09" # Set Zone1 Cool Target High CONF_SET16_10 = "set16_10" # Set Zone1 Cool Target Low CONF_SET16_11 = "set16_11" # Set Zone1 Cool Outside Low CONF_SET16_12 = "set16_12" # Set Zone1 Cool Outside High @@ -51,15 +54,15 @@ TYPES = [ CONF_SET8, CONF_SET11, CONF_SET15, - CONF_SET16_1, - CONF_SET16_2, - CONF_SET16_3, - CONF_SET16_4, - CONF_SET16_5, - CONF_SET16_6, - CONF_SET16_7, - CONF_SET16_8, - CONF_SET16_9, + CONF_SET16_01, + CONF_SET16_02, + CONF_SET16_03, + CONF_SET16_04, + CONF_SET16_05, + CONF_SET16_06, + CONF_SET16_07, + CONF_SET16_08, + CONF_SET16_09, CONF_SET16_10, CONF_SET16_11, CONF_SET16_12, @@ -80,210 +83,249 @@ TYPES = [ CONF_SET38, ] -# min_value, max_value, step -CONF_NUMBERS = [ - [ 0, 0, 1, ], - [ 0, 0, 1, ], - [ 0, 0, 1, ], - [ 0, 0, 1, ], - [ 40, 75, 1, ], - [ 64, 254, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ 1, 15, 1, ], - [ 1, 15, 1, ], - [ -12, -2, 1, ], - [ 0, 250, 1, ], - [ 1, 15, 1, ], - [ 1, 15, 1, ], - [ 0, 10, 1, ], - [ 5, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], - [ -15, 35, 1, ], -] +def number_options(min_val, max_val, step) -> cv.Schema: + schema = cv.Schema({ + cv.Optional(CONF_MIN_VALUE, default=min_val): cv.float_, + cv.Optional(CONF_MAX_VALUE, default=max_val): cv.float_, + cv.Optional(CONF_STEP, default=step): cv.float_range(min=1.0, max=10.0), + }) + return schema PanasonicHeatpumpNumber = panasonic_heatpump_ns.class_("PanasonicHeatpumpNumber", number.Number, cg.Component) CONFIG_SCHEMA = cv.Schema( { - cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id(PanasonicHeatpumpComponent), + cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id( + PanasonicHeatpumpComponent + ), cv.Optional(CONF_SET5): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(-5.0, 5.0, 1.0) ), cv.Optional(CONF_SET6): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(-5.0, 5.0, 1.0) ), cv.Optional(CONF_SET7): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(-5.0, 5.0, 1.0) ), cv.Optional(CONF_SET8): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(-5.0, 5.0, 1.0) ), cv.Optional(CONF_SET11): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(40.0, 75.0, 1.0) ), cv.Optional(CONF_SET15): number.number_schema( PanasonicHeatpumpNumber, + ).extend( + number_options(64.0, 254.0, 1.0) ), - cv.Optional(CONF_SET16_1): number.number_schema( + cv.Optional(CONF_SET16_01): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(20.0, 60.0, 1.0) ), - cv.Optional(CONF_SET16_2): number.number_schema( + cv.Optional(CONF_SET16_02): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(20.0, 60.0, 1.0) ), - cv.Optional(CONF_SET16_3): number.number_schema( + cv.Optional(CONF_SET16_03): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(-20.0, 15.0, 1.0) ), - cv.Optional(CONF_SET16_4): number.number_schema( + cv.Optional(CONF_SET16_04): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(-20.0, 15.0, 1.0) ), - cv.Optional(CONF_SET16_5): number.number_schema( + cv.Optional(CONF_SET16_05): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(20.0, 60.0, 1.0) ), - cv.Optional(CONF_SET16_6): number.number_schema( + cv.Optional(CONF_SET16_06): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(20.0, 60.0, 1.0) ), - cv.Optional(CONF_SET16_7): number.number_schema( + cv.Optional(CONF_SET16_07): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(-20.0, 15.0, 1.0) ), - cv.Optional(CONF_SET16_8): number.number_schema( + cv.Optional(CONF_SET16_08): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(-20.0, 15.0, 1.0) ), - cv.Optional(CONF_SET16_9): number.number_schema( + cv.Optional(CONF_SET16_09): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(5.0, 20.0, 1.0) ), cv.Optional(CONF_SET16_10): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(5.0, 20.0, 1.0) ), cv.Optional(CONF_SET16_11): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(15.0, 30.0, 1.0) ), cv.Optional(CONF_SET16_12): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(15.0, 30.0, 1.0) ), cv.Optional(CONF_SET16_13): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(5.0, 20.0, 1.0) ), cv.Optional(CONF_SET16_14): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(5.0, 20.0, 1.0) ), cv.Optional(CONF_SET16_15): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(15.0, 30.0, 1.0) ), cv.Optional(CONF_SET16_16): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, entity_category=ENTITY_CATEGORY_CONFIG, + ).extend( + number_options(15.0, 30.0, 1.0) ), cv.Optional(CONF_SET18): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_KELVIN, + ).extend( + number_options(1.0, 15.0, 1.0) ), cv.Optional(CONF_SET19): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_KELVIN, + ).extend( + number_options(1.0, 15.0, 1.0) ), cv.Optional(CONF_SET20): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_KELVIN, + ).extend( + number_options(112.0, -2.0, 1.0) ), cv.Optional(CONF_SET21): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_MINUTE, + ).extend( + number_options(0.0, 250.0, 1.0) ), cv.Optional(CONF_SET22): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_KELVIN, + ).extend( + number_options(1.0, 15.0, 1.0) ), cv.Optional(CONF_SET23): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_KELVIN, + ).extend( + number_options(1.0, 15.0, 1.0) ), cv.Optional(CONF_SET27): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_KELVIN, + ).extend( + number_options(0.0, 10.0, 1.0) ), cv.Optional(CONF_SET29): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(5.0, 35.0, 1.0) ), cv.Optional(CONF_SET36): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(-15.0, 35.0, 1.0) ), cv.Optional(CONF_SET37): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(-10.0, 0.0, 1.0) ), cv.Optional(CONF_SET38): number.number_schema( PanasonicHeatpumpNumber, unit_of_measurement=UNIT_CELSIUS, + ).extend( + number_options(-10.0, 0.0, 1.0) ), } ).extend(cv.COMPONENT_SCHEMA) async def to_code(config): - hub = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) + parent = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) for index, key in enumerate(TYPES): if child_config := config.get(key): var = await number.new_number( child_config, - min_value=CONF_NUMBERS[index][0], - max_value=CONF_NUMBERS[index][1], - step=CONF_NUMBERS[index][2] + min_value=child_config[CONF_MIN_VALUE], + max_value=child_config[CONF_MAX_VALUE], + step=child_config[CONF_STEP], ) await cg.register_component(var, child_config) - await cg.register_parented(var, config[CONF_PANASONIC_HEATPUMP_ID]) - cg.add(getattr(hub, f"set_{key}_number")(var)) + cg.add(var.set_parent(parent)) cg.add(var.set_id(index)) + cg.add(parent.add_number(var)) diff --git a/components/panasonic_heatpump/number/panasonic_heatpump_number.cpp b/components/panasonic_heatpump/number/panasonic_heatpump_number.cpp index 3a2fc9f..b98f496 100644 --- a/components/panasonic_heatpump/number/panasonic_heatpump_number.cpp +++ b/components/panasonic_heatpump/number/panasonic_heatpump_number.cpp @@ -1,5 +1,4 @@ #include "panasonic_heatpump_number.h" -#include "esphome/core/log.h" namespace esphome @@ -16,8 +15,393 @@ namespace esphome void PanasonicHeatpumpNumber::control(float value) { - this->publish_state(value); - this->parent_->control_number(this, value); + switch (this->id_) + { + case NumberIds::CONF_SET5: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 38); + break; + } + case NumberIds::CONF_SET6: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 39); + break; + } + case NumberIds::CONF_SET7: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 40); + break; + } + case NumberIds::CONF_SET8: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 41); + break; + } + case NumberIds::CONF_SET11: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 42); + break; + } + case NumberIds::CONF_SET15: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1(value), 45); + break; + } + case NumberIds::CONF_SET16_01: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 75); + break; + } + case NumberIds::CONF_SET16_02: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 76); + break; + } + case NumberIds::CONF_SET16_03: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 77); + break; + } + case NumberIds::CONF_SET16_04: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 78); + break; + } + case NumberIds::CONF_SET16_05: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 79); + break; + } + case NumberIds::CONF_SET16_06: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 80); + break; + } + case NumberIds::CONF_SET16_07: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 81); + break; + } + case NumberIds::CONF_SET16_08: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 82); + break; + } + case NumberIds::CONF_SET16_09: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 86); + break; + } + case NumberIds::CONF_SET16_10: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 87); + break; + } + case NumberIds::CONF_SET16_11: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 88); + break; + } + case NumberIds::CONF_SET16_12: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 89); + break; + } + case NumberIds::CONF_SET16_13: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 90); + break; + } + case NumberIds::CONF_SET16_14: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 91); + break; + } + case NumberIds::CONF_SET16_15: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 92); + break; + } + case NumberIds::CONF_SET16_16: + { + this->parent_->set_command_curve(PanasonicCommand::setPlus128(value), 93); + break; + } + case NumberIds::CONF_SET18: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 84); + break; + } + case NumberIds::CONF_SET19: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 94); + break; + } + case NumberIds::CONF_SET20: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 99); + break; + } + case NumberIds::CONF_SET21: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1(value), 104); + break; + } + case NumberIds::CONF_SET22: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 105); + break; + } + case NumberIds::CONF_SET23: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 106); + break; + } + case NumberIds::CONF_SET27: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 59); + break; + } + case NumberIds::CONF_SET29: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 83); + break; + } + case NumberIds::CONF_SET36: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 65); + break; + } + case NumberIds::CONF_SET37: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 66); + break; + } + case NumberIds::CONF_SET38: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus128(value), 68); + break; + } + default: return; + }; + this->publish_state(state); + this->keep_state_ = 2; + } + + void PanasonicHeatpumpNumber::publish_new_state(const std::vector& data) + { + if (this->keep_state_ > 0) + { + this->keep_state_--; + return; + } + if (data.empty()) return; + + float new_state; + switch (this->id_) + { + case NumberIds::CONF_SET11: + { + new_state = PanasonicDecode::getByteMinus128(data[42]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET20: + { + new_state = PanasonicDecode::getByteMinus128(data[99]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET18: + { + new_state = PanasonicDecode::getByteMinus128(data[84]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET19: + { + new_state = PanasonicDecode::getByteMinus128(data[94]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET5: + { + new_state = PanasonicDecode::getByteMinus128(data[38]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET6: + { + new_state = PanasonicDecode::getByteMinus128(data[39]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_01: + { + new_state = PanasonicDecode::getByteMinus128(data[75]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_02: + { + new_state = PanasonicDecode::getByteMinus128(data[76]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_04: + { + new_state = PanasonicDecode::getByteMinus128(data[78]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_03: + { + new_state = PanasonicDecode::getByteMinus128(data[77]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET7: + { + new_state = PanasonicDecode::getByteMinus128(data[40]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET8: + { + new_state = PanasonicDecode::getByteMinus128(data[41]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_09: + { + new_state = PanasonicDecode::getByteMinus128(data[86]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_10: + { + new_state = PanasonicDecode::getByteMinus128(data[87]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_12: + { + new_state = PanasonicDecode::getByteMinus128(data[89]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_11: + { + new_state = PanasonicDecode::getByteMinus128(data[88]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET29: + { + new_state = PanasonicDecode::getByteMinus128(data[83]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_05: + { + new_state = PanasonicDecode::getByteMinus128(data[79]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_06: + { + new_state = PanasonicDecode::getByteMinus128(data[80]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_08: + { + new_state = PanasonicDecode::getByteMinus128(data[82]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_07: + { + new_state = PanasonicDecode::getByteMinus128(data[81]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_13: + { + new_state = PanasonicDecode::getByteMinus128(data[90]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_14: + { + new_state = PanasonicDecode::getByteMinus128(data[91]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_16: + { + new_state = PanasonicDecode::getByteMinus128(data[93]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET16_15: + { + new_state = PanasonicDecode::getByteMinus128(data[92]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET15: + { + new_state = PanasonicDecode::getByteMinus1(data[45]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET21: + { + new_state = PanasonicDecode::getByteMinus1(data[104]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET22: + { + new_state = PanasonicDecode::getByteMinus128(data[105]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET23: + { + new_state = PanasonicDecode::getByteMinus128(data[106]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET27: + { + new_state = PanasonicDecode::getByteMinus128(data[59]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET36: + { + new_state = PanasonicDecode::getByteMinus128(data[65]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET37: + { + new_state = PanasonicDecode::getByteMinus128(data[66]); + if (this->has_state() && this->state == new_state) return; + break; + } + case NumberIds::CONF_SET38: + { + new_state = PanasonicDecode::getByteMinus128(data[68]); + if (this->has_state() && this->state == new_state) return; + break; + } + default: return; + }; + + this->publish_state(new_state); } } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/number/panasonic_heatpump_number.h b/components/panasonic_heatpump/number/panasonic_heatpump_number.h index 5b535fd..0b2cd5e 100644 --- a/components/panasonic_heatpump/number/panasonic_heatpump_number.h +++ b/components/panasonic_heatpump/number/panasonic_heatpump_number.h @@ -1,23 +1,62 @@ #pragma once -#include "esphome/components/number/number.h" #include "esphome/core/component.h" +#include "esphome/components/number/number.h" #include "../panasonic_heatpump.h" +#include "../decode.h" +#include "../commands.h" namespace esphome { namespace panasonic_heatpump { - class PanasonicHeatpumpNumber : public number::Number, public Component, public Parented + enum NumberIds : uint8_t + { + CONF_SET5, + CONF_SET6, + CONF_SET7, + CONF_SET8, + CONF_SET11, + CONF_SET15, + CONF_SET16_01, + CONF_SET16_02, + CONF_SET16_03, + CONF_SET16_04, + CONF_SET16_05, + CONF_SET16_06, + CONF_SET16_07, + CONF_SET16_08, + CONF_SET16_09, + CONF_SET16_10, + CONF_SET16_11, + CONF_SET16_12, + CONF_SET16_13, + CONF_SET16_14, + CONF_SET16_15, + CONF_SET16_16, + CONF_SET18, + CONF_SET19, + CONF_SET20, + CONF_SET21, + CONF_SET22, + CONF_SET23, + CONF_SET27, + CONF_SET29, + CONF_SET36, + CONF_SET37, + CONF_SET38, + }; + + class PanasonicHeatpumpNumber : public number::Number, public Component, + public Parented, public PanasonicHeatpumpEntity { public: PanasonicHeatpumpNumber() = default; void dump_config() override; - void set_id(int id) { this->id_ = id; } + void publish_new_state(const std::vector& data) override; protected: void control(float value) override; - int id_; }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/panasonic_heatpump.cpp b/components/panasonic_heatpump/panasonic_heatpump.cpp index 1b0134a..fdddd58 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.cpp +++ b/components/panasonic_heatpump/panasonic_heatpump.cpp @@ -19,6 +19,7 @@ namespace esphome ESP_LOGCONFIG(TAG, "Setting up Panasonic Heatpump ..."); delay(10); // NOLINT this->check_uart_settings(9600, 1, uart::UART_CONFIG_PARITY_EVEN, 8); + this->update(); } @@ -42,48 +43,69 @@ namespace esphome { bool result = this->check_response(this->heatpump_message_); this->loop_state_ = result ? - LoopState::SET_NUMBER_TRAITS : LoopState::SEND_REQUEST; - break; - } - case LoopState::SET_NUMBER_TRAITS: - { - this->set_number_traits(this->heatpump_message_); - this->loop_state_ = LoopState::PUBLISH_SENSOR; + LoopState::PUBLISH_SENSOR : LoopState::SEND_REQUEST; break; } case LoopState::PUBLISH_SENSOR: { - this->publish_sensor(this->heatpump_message_); + for (auto *entity : this->sensors_) + { + entity->publish_new_state(this->heatpump_message_); + } this->loop_state_ = LoopState::PUBLISH_BINARY_SENSOR; break; } case LoopState::PUBLISH_BINARY_SENSOR: { - this->publish_binary_sensor(this->heatpump_message_); + for (auto *entity : this->binary_sensors_) + { + entity->publish_new_state(this->heatpump_message_); + } this->loop_state_ = LoopState::PUBLISH_TEXT_SENSOR; break; } case LoopState::PUBLISH_TEXT_SENSOR: { - this->publish_text_sensor(this->heatpump_message_); + for (auto *entity : this->text_sensors_) + { + entity->publish_new_state(this->heatpump_message_); + } this->loop_state_ = LoopState::PUBLISH_NUMBER; break; } case LoopState::PUBLISH_NUMBER: { - this->publish_number(this->heatpump_message_); + for (auto *entity : this->numbers_) + { + entity->publish_new_state(this->heatpump_message_); + } this->loop_state_ = LoopState::PUBLISH_SELECT; break; } case LoopState::PUBLISH_SELECT: { - this->publish_select(this->heatpump_message_); + for (auto *entity : this->selects_) + { + entity->publish_new_state(this->heatpump_message_); + } this->loop_state_ = LoopState::PUBLISH_SWITCH; break; } case LoopState::PUBLISH_SWITCH: { - this->publish_switch(this->heatpump_message_); + for (auto *entity : this->switches_) + { + entity->publish_new_state(this->heatpump_message_); + } + this->loop_state_ = LoopState::PUBLISH_CLIMATE; + break; + } + case LoopState::PUBLISH_CLIMATE: + { + for (auto *entity : this->climates_) + { + entity->publish_new_state(this->heatpump_message_); + } this->loop_state_ = LoopState::SEND_REQUEST; break; } @@ -101,16 +123,6 @@ namespace esphome } default: { - // Perform reboot only if a traits (e.g. min/max value of a number entity) was changed the second time. - // The first traits change should happen before controller is connected to home assistant, - // because the default min/max value is 0. - if (this->trait_update_counter_ > 1) - { - ESP_LOGW(TAG, "Min/max values have changed. Rebooting so Home Assistant reconfigures the number component."); - delay(100); // NOLINT - App.safe_reboot(); - } - this->loop_state_ = LoopState::READ_RESPONSE; break; } @@ -281,449 +293,111 @@ namespace esphome return false; } + // Check if the current response is a new response if (this->last_response_count_ == this->current_response_count_) return false; this->last_response_count_ = this->current_response_count_; + return true; } + void PanasonicHeatpumpComponent::set_command_high_nibble(const uint8_t value, const uint8_t index) + { + if (this->next_request_ != RequestType::COMMAND) + { + // initialize the command + this->command_message_.assign(std::begin(PanasonicCommand::CommandMessage), + std::end(PanasonicCommand::CommandMessage)); + } + uint8_t lowNibble = this->heatpump_message_[index] & 0b1111; + uint8_t highNibble = value << 4; + // set command byte + this->command_message_[index] = highNibble + lowNibble; + // calculate and set set checksum (last element) + this->command_message_.back() = PanasonicCommand::calcChecksum(this->command_message_, this->command_message_.size() - 1); + + // command will be send on next loop + this->next_request_ = RequestType::COMMAND; + } + + void PanasonicHeatpumpComponent::set_command_low_nibble(const uint8_t value, const uint8_t index) + { + if (this->next_request_ != RequestType::COMMAND) + { + // initialize the command + this->command_message_.assign(std::begin(PanasonicCommand::CommandMessage), + std::end(PanasonicCommand::CommandMessage)); + } + uint8_t highNibble = this->heatpump_message_[index] & 0b11110000; + uint8_t lowNibble = value & 0b1111; + // set command byte + this->command_message_[index] = highNibble + lowNibble; + // calculate and set set checksum (last element) + this->command_message_.back() = PanasonicCommand::calcChecksum(this->command_message_, this->command_message_.size() - 1); + + // command will be send on next loop + this->next_request_ = RequestType::COMMAND; + } + void PanasonicHeatpumpComponent::set_command_byte(const uint8_t value, const uint8_t index) { if (this->next_request_ != RequestType::COMMAND) { // initialize the command - command_message_.assign(std::begin(PanasonicCommand::CommandMessage), + this->command_message_.assign(std::begin(PanasonicCommand::CommandMessage), std::end(PanasonicCommand::CommandMessage)); } // set command byte - command_message_[index] = value; + this->command_message_[index] = value; // calculate and set set checksum (last element) - command_message_.back() = PanasonicCommand::calcChecksum(command_message_, command_message_.size() - 1); + this->command_message_.back() = PanasonicCommand::calcChecksum(this->command_message_, this->command_message_.size() - 1); // command will be send on next loop this->next_request_ = RequestType::COMMAND; } - void PanasonicHeatpumpComponent::set_command_bytes(const std::vector>& data) + void PanasonicHeatpumpComponent::set_command_curve(const uint8_t value, const uint8_t index) { if (this->next_request_ != RequestType::COMMAND) { // initialize the command - command_message_.assign(std::begin(PanasonicCommand::CommandMessage), + this->command_message_.assign(std::begin(PanasonicCommand::CommandMessage), std::end(PanasonicCommand::CommandMessage)); } - // set command bytes - for (size_t i = 0; i < data.size(); ++i) + + // Set zone 1 curve bytes + if (index == 75 || index == 76 || index == 77 || index == 78 || + index == 86 || index == 87 || index == 88 || index == 89) { - uint8_t value = std::get<0>(data[i]); - uint8_t index = std::get<1>(data[i]); - command_message_[index] = value; + this->command_message_[75] = this->heatpump_message_[75]; + this->command_message_[76] = this->heatpump_message_[76]; + this->command_message_[77] = this->heatpump_message_[77]; + this->command_message_[78] = this->heatpump_message_[78]; + this->command_message_[86] = this->heatpump_message_[86]; + this->command_message_[87] = this->heatpump_message_[87]; + this->command_message_[88] = this->heatpump_message_[88]; + this->command_message_[89] = this->heatpump_message_[89]; } + // Set zone 2 curve bytes + if (index == 79 || index == 80 || index == 81 || index == 82 || + index == 90 || index == 91 || index == 92 || index == 93) + { + this->command_message_[79] = this->heatpump_message_[79]; + this->command_message_[80] = this->heatpump_message_[80]; + this->command_message_[81] = this->heatpump_message_[81]; + this->command_message_[82] = this->heatpump_message_[82]; + this->command_message_[90] = this->heatpump_message_[90]; + this->command_message_[91] = this->heatpump_message_[91]; + this->command_message_[92] = this->heatpump_message_[92]; + this->command_message_[93] = this->heatpump_message_[93]; + } + + // set command byte + this->command_message_[index] = value; // calculate and set set checksum (last element) - command_message_.back() = PanasonicCommand::calcChecksum(command_message_, command_message_.size() - 1); + this->command_message_.back() = PanasonicCommand::calcChecksum(this->command_message_, this->command_message_.size() - 1); // command will be send on next loop this->next_request_ = RequestType::COMMAND; } - - void PanasonicHeatpumpComponent::set_number_traits(const std::vector& data) - { -#ifdef USE_TEXT_SENSOR -#ifdef USE_NUMBER - if (data.empty()) return; - - // traits can be changed anytime, but entities will only be updated in home assistant, - // if the traits was set before connecting to home assistant. If now a traits must be changed later, - // a reboot of the ESP controller is required to see the changes in home assistant. - - bool change_detected = false; - std::string top76 = PanasonicDecode::getTextState( - PanasonicDecode::HeatCoolModeDesc, PanasonicDecode::getBit7and8(data[28])); // Heating Mode - std::string top81 = PanasonicDecode::getTextState( - PanasonicDecode::HeatCoolModeDesc, PanasonicDecode::getBit5and6(data[28])); // Cooling Mode - float set5_min = this->set5_number_->traits.get_min_value(); // Z1 Heat Request Temperature - float set6_min = this->set6_number_->traits.get_min_value(); // Z1 Cool Request Temperature - float set7_min = this->set7_number_->traits.get_min_value(); // Z2 Heat Request Temperature - float set8_min = this->set8_number_->traits.get_min_value(); // Z2 Cool Request Temperature - - if (set5_min >= 0.0 && top76 == PanasonicDecode::HeatCoolModeDesc[1]) - { - this->set5_number_->traits.set_min_value(-5.0); - this->set5_number_->traits.set_max_value(5.0); - change_detected = true; - } - if (set6_min >= 0.0 && top81 == PanasonicDecode::HeatCoolModeDesc[1]) - { - this->set6_number_->traits.set_min_value(-5.0); - this->set6_number_->traits.set_max_value(5.0); - change_detected = true; - } - if (set7_min >= 0.0 && top76 == PanasonicDecode::HeatCoolModeDesc[1]) - { - this->set7_number_->traits.set_min_value(-5.0); - this->set7_number_->traits.set_max_value(5.0); - change_detected = true; - } - if (set8_min >= 0.0 && top81 == PanasonicDecode::HeatCoolModeDesc[1]) - { - this->set8_number_->traits.set_min_value(-5.0); - this->set8_number_->traits.set_max_value(5.0); - change_detected = true; - } - - if (set5_min <= 0.0 && top76 == PanasonicDecode::HeatCoolModeDesc[2]) - { - this->set5_number_->traits.set_min_value(20.0); - this->set5_number_->traits.set_max_value(60.0); - change_detected = true; - } - if (set6_min <= 0.0 && top81 == PanasonicDecode::HeatCoolModeDesc[2]) - { - this->set6_number_->traits.set_min_value(20.0); - this->set6_number_->traits.set_max_value(60.0); - change_detected = true; - } - if (set7_min <= 0.0 && top76 == PanasonicDecode::HeatCoolModeDesc[2]) - { - this->set7_number_->traits.set_min_value(20.0); - this->set7_number_->traits.set_max_value(60.0); - change_detected = true; - } - if (set8_min <= 0.0 && top81 == PanasonicDecode::HeatCoolModeDesc[2]) - { - this->set8_number_->traits.set_min_value(20.0); - this->set8_number_->traits.set_max_value(60.0); - change_detected = true; - } - - if (change_detected) - { - this->trait_update_counter_++; - } -#endif -#endif - } - - void PanasonicHeatpumpComponent::publish_sensor(const std::vector& data) - { -#ifdef USE_SENSOR - if (data.empty()) return; - if (this->top1_sensor_) this->top1_sensor_->publish_state(PanasonicDecode::getPumpFlow(data[169], data[170])); - if (this->top5_sensor_) this->top5_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[143]) + PanasonicDecode::getFractional(data[118], 0)); - if (this->top6_sensor_) this->top6_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[144]) + PanasonicDecode::getFractional(data[118], 3)); - if (this->top7_sensor_) this->top7_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[153])); - if (this->top8_sensor_) this->top8_sensor_->publish_state(PanasonicDecode::getByteMinus1(data[166])); - if (this->top9_sensor_) this->top9_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[42])); - if (this->top10_sensor_) this->top10_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[141])); - if (this->top11_sensor_) this->top11_sensor_->publish_state(PanasonicDecode::getWordMinus1(data[182], data[183])); - if (this->top12_sensor_) this->top12_sensor_->publish_state(PanasonicDecode::getWordMinus1(data[179], data[180])); - if (this->top14_sensor_) this->top14_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[142])); - if (this->top15_sensor_) this->top15_sensor_->publish_state(PanasonicDecode::getByteMinus1Times200(data[194])); - if (this->top16_sensor_) this->top16_sensor_->publish_state(PanasonicDecode::getByteMinus1Times200(data[193])); - if (this->top21_sensor_) this->top21_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[158])); - if (this->top22_sensor_) this->top22_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[99])); - if (this->top23_sensor_) this->top23_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[84])); - if (this->top24_sensor_) this->top24_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[94])); - if (this->top25_sensor_) this->top25_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[44])); - if (this->top27_sensor_) this->top27_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[38])); - if (this->top28_sensor_) this->top28_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[39])); - if (this->top29_sensor_) this->top29_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[75])); - if (this->top30_sensor_) this->top30_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[76])); - if (this->top31_sensor_) this->top31_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[78])); - if (this->top32_sensor_) this->top32_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[77])); - if (this->top33_sensor_) this->top33_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[156])); - if (this->top34_sensor_) this->top34_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[40])); - if (this->top35_sensor_) this->top35_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[41])); - if (this->top36_sensor_) this->top36_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[145])); - if (this->top37_sensor_) this->top37_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[146])); - if (this->top38_sensor_) this->top38_sensor_->publish_state(PanasonicDecode::getByteMinus1Times200(data[196])); - if (this->top39_sensor_) this->top39_sensor_->publish_state(PanasonicDecode::getByteMinus1Times200(data[195])); - if (this->top40_sensor_) this->top40_sensor_->publish_state(PanasonicDecode::getByteMinus1Times200(data[198])); - if (this->top41_sensor_) this->top41_sensor_->publish_state(PanasonicDecode::getByteMinus1Times200(data[197])); - if (this->top42_sensor_) this->top42_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[147])); - if (this->top43_sensor_) this->top43_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[148])); - if (this->top45_sensor_) this->top45_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[43])); - if (this->top46_sensor_) this->top46_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[149])); - if (this->top47_sensor_) this->top47_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[150])); - if (this->top48_sensor_) this->top48_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[151])); - if (this->top49_sensor_) this->top49_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[154])); - if (this->top50_sensor_) this->top50_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[155])); - if (this->top51_sensor_) this->top51_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[157])); - if (this->top52_sensor_) this->top52_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[159])); - if (this->top53_sensor_) this->top53_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[160])); - if (this->top54_sensor_) this->top54_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[161])); - if (this->top55_sensor_) this->top55_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[162])); - if (this->top56_sensor_) this->top56_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[139])); - if (this->top57_sensor_) this->top57_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[140])); - if (this->top62_sensor_) this->top62_sensor_->publish_state(PanasonicDecode::getByteMinus1Times10(data[173])); - if (this->top63_sensor_) this->top63_sensor_->publish_state(PanasonicDecode::getByteMinus1Times10(data[174])); - if (this->top64_sensor_) this->top64_sensor_->publish_state(PanasonicDecode::getByteMinus1Div5(data[163])); - if (this->top65_sensor_) this->top65_sensor_->publish_state(PanasonicDecode::getByteMinus1Times50(data[171])); - if (this->top66_sensor_) this->top66_sensor_->publish_state(PanasonicDecode::getByteMinus1Times50(data[164])); - if (this->top67_sensor_) this->top67_sensor_->publish_state(PanasonicDecode::getByteMinus1Div5(data[165])); - if (this->top70_sensor_) this->top70_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[100])); - if (this->top71_sensor_) this->top71_sensor_->publish_state(PanasonicDecode::getByteMinus1(data[101])); - if (this->top72_sensor_) this->top72_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[86])); - if (this->top73_sensor_) this->top73_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[87])); - if (this->top74_sensor_) this->top74_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[89])); - if (this->top75_sensor_) this->top75_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[88])); - if (this->top77_sensor_) this->top77_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[83])); - if (this->top78_sensor_) this->top78_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[85])); - if (this->top79_sensor_) this->top79_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[95])); - if (this->top80_sensor_) this->top80_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[96])); - if (this->top82_sensor_) this->top82_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[79])); - if (this->top83_sensor_) this->top83_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[80])); - if (this->top84_sensor_) this->top84_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[82])); - if (this->top85_sensor_) this->top85_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[81])); - if (this->top86_sensor_) this->top86_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[90])); - if (this->top87_sensor_) this->top87_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[91])); - if (this->top88_sensor_) this->top88_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[93])); - if (this->top89_sensor_) this->top89_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[92])); - if (this->top90_sensor_) this->top90_sensor_->publish_state(PanasonicDecode::getWordMinus1(data[185], data[186])); - if (this->top91_sensor_) this->top91_sensor_->publish_state(PanasonicDecode::getWordMinus1(data[188], data[189])); - if (this->top93_sensor_) this->top93_sensor_->publish_state(PanasonicDecode::getByteMinus1(data[172])); - if (this->top95_sensor_) this->top95_sensor_->publish_state(PanasonicDecode::getByteMinus1(data[45])); - if (this->top96_sensor_) this->top96_sensor_->publish_state(PanasonicDecode::getByteMinus1(data[104])); - if (this->top97_sensor_) this->top97_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[105])); - if (this->top98_sensor_) this->top98_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[106])); - if (this->top102_sensor_) this->top102_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[61])); - if (this->top103_sensor_) this->top103_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[62])); - if (this->top104_sensor_) this->top104_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[63])); - if (this->top105_sensor_) this->top105_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[64])); - if (this->top113_sensor_) this->top113_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[59])); - if (this->top115_sensor_) this->top115_sensor_->publish_state(PanasonicDecode::getByteMinus1Div50(data[125])); - if (this->top116_sensor_) this->top116_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[126])); - if (this->top117_sensor_) this->top117_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[127])); - if (this->top118_sensor_) this->top118_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[128])); - if (this->top127_sensor_) this->top127_sensor_->publish_state(PanasonicDecode::getByteMinus1Div2(data[177])); - if (this->top128_sensor_) this->top128_sensor_->publish_state(PanasonicDecode::getByteMinus1Div2(data[178])); - if (this->top131_sensor_) this->top131_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[65])); - if (this->top134_sensor_) this->top134_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[66])); - if (this->top135_sensor_) this->top135_sensor_->publish_state(PanasonicDecode::getByteMinus128(data[68])); - if (this->top136_sensor_) this->top136_sensor_->publish_state(PanasonicDecode::getByteMinus1(data[67])); - if (this->top137_sensor_) this->top137_sensor_->publish_state(PanasonicDecode::getByteMinus1(data[69])); - if (this->top138_sensor_) this->top138_sensor_->publish_state(PanasonicDecode::getByteMinus1(data[70])); -#endif - } - - void PanasonicHeatpumpComponent::publish_binary_sensor(const std::vector& data) - { -#ifdef USE_BINARY_SENSOR - if (data.empty()) return; - if (this->top0_binary_sensor_) this->top0_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[4]))); - if (this->top2_binary_sensor_) this->top2_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[4]))); - if (this->top3_binary_sensor_) this->top3_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[7]))); - if (this->top13_binary_sensor_) this->top13_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[5]))); - if (this->top26_binary_sensor_) this->top26_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[111]))); - if (this->top60_binary_sensor_) this->top60_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[112]))); - if (this->top61_binary_sensor_) this->top61_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[112]))); - if (this->top68_binary_sensor_) this->top68_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[5]))); - if (this->top69_binary_sensor_) this->top69_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[117]))); - if (this->top99_binary_sensor_) this->top99_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[24]))); - if (this->top100_binary_sensor_) this->top100_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[24]))); - if (this->top108_binary_sensor_) this->top108_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[20]))); - if (this->top109_binary_sensor_) this->top109_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[20]))); - if (this->top110_binary_sensor_) this->top110_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[20]))); - if (this->top119_binary_sensor_) this->top119_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[23]))); - if (this->top120_binary_sensor_) this->top120_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[23]))); - if (this->top121_binary_sensor_) this->top121_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[23]))); - if (this->top122_binary_sensor_) this->top122_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[23]))); - if (this->top123_binary_sensor_) this->top123_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[116]))); - if (this->top124_binary_sensor_) this->top124_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[116]))); - if (this->top129_binary_sensor_) this->top129_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[26]))); - if (this->top132_binary_sensor_) this->top132_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[26]))); - if (this->top133_binary_sensor_) this->top133_binary_sensor_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[26]))); -#endif - } - - void PanasonicHeatpumpComponent::publish_text_sensor(const std::vector& data) - { -#ifdef USE_TEXT_SENSOR - if (data.empty()) return; - if (this->top4_text_sensor_) this->top4_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::OpModeDesc, PanasonicDecode::getOpMode(data[6]))); - if (this->top17_text_sensor_) this->top17_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Powerfulmode, PanasonicDecode::getBit6and7and8(data[7]))); - if (this->top18_text_sensor_) this->top18_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Quietmode, PanasonicDecode::getBit3and4and5(data[7]))); - if (this->top19_text_sensor_) this->top19_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::HolidayState, PanasonicDecode::getBit3and4(data[5]))); - if (this->top20_text_sensor_) this->top20_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Valve, PanasonicDecode::getBit7and8(data[111]))); - if (this->top44_text_sensor_) this->top44_text_sensor_->publish_state(PanasonicDecode::getErrorInfo(data[113], data[114])); - if (this->top58_text_sensor_) this->top58_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::BlockedFree, PanasonicDecode::getBit5and6(data[9]))); - if (this->top59_text_sensor_) this->top59_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::BlockedFree, PanasonicDecode::getBit7and8(data[9]))); - if (this->top76_text_sensor_) this->top76_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::HeatCoolModeDesc, PanasonicDecode::getBit7and8(data[28]))); - if (this->top81_text_sensor_) this->top81_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::HeatCoolModeDesc, PanasonicDecode::getBit5and6(data[28]))); - if (this->top92_text_sensor_) this->top92_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::ModelNames, PanasonicDecode::getModel(data, 129))); - if (this->top94_text_sensor_) this->top94_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::ZonesState, PanasonicDecode::getBit1and2(data[6]))); - if (this->top101_text_sensor_) this->top101_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::SolarModeDesc, PanasonicDecode::getBit3and4(data[24]))); - if (this->top106_text_sensor_) this->top106_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::PumpFlowRateMode, PanasonicDecode::getBit3and4(data[29]))); - if (this->top107_text_sensor_) this->top107_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::LiquidType, PanasonicDecode::getBit1(data[20]))); - if (this->top111_text_sensor_) this->top111_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::ZonesSensorType, PanasonicDecode::getLowNibbleMinus1(data[22]))); - if (this->top112_text_sensor_) this->top112_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::ZonesSensorType, PanasonicDecode::getHighNibbleMinus1(data[22]))); - if (this->top114_text_sensor_) this->top114_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::ExtPadHeaterType, PanasonicDecode::getBit3and4(data[25]))); - if (this->top125_text_sensor_) this->top125_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Valve2, PanasonicDecode::getBit5and6(data[116]))); - if (this->top126_text_sensor_) this->top126_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Valve, PanasonicDecode::getBit7and8(data[116]))); - if (this->top130_text_sensor_) this->top130_text_sensor_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Bivalent, PanasonicDecode::getBit5and6(data[26]))); -#endif - } - - void PanasonicHeatpumpComponent::publish_number(const std::vector& data) - { -#ifdef USE_NUMBER - if (data.empty()) return; - if (this->set11_number_) this->set11_number_->publish_state(PanasonicDecode::getByteMinus128(data[42])); - if (this->set20_number_) this->set20_number_->publish_state(PanasonicDecode::getByteMinus128(data[99])); - if (this->set18_number_) this->set18_number_->publish_state(PanasonicDecode::getByteMinus128(data[84])); - if (this->set19_number_) this->set19_number_->publish_state(PanasonicDecode::getByteMinus128(data[94])); - if (this->set5_number_) this->set5_number_->publish_state(PanasonicDecode::getByteMinus128(data[38])); - if (this->set6_number_) this->set6_number_->publish_state(PanasonicDecode::getByteMinus128(data[39])); - if (this->set16_1_number_) this->set16_1_number_->publish_state(PanasonicDecode::getByteMinus128(data[75])); - if (this->set16_2_number_) this->set16_2_number_->publish_state(PanasonicDecode::getByteMinus128(data[76])); - if (this->set16_4_number_) this->set16_4_number_->publish_state(PanasonicDecode::getByteMinus128(data[78])); - if (this->set16_3_number_) this->set16_3_number_->publish_state(PanasonicDecode::getByteMinus128(data[77])); - if (this->set7_number_) this->set7_number_->publish_state(PanasonicDecode::getByteMinus128(data[40])); - if (this->set8_number_) this->set8_number_->publish_state(PanasonicDecode::getByteMinus128(data[41])); - if (this->set16_9_number_) this->set16_9_number_->publish_state(PanasonicDecode::getByteMinus128(data[86])); - if (this->set16_10_number_) this->set16_10_number_->publish_state(PanasonicDecode::getByteMinus128(data[87])); - if (this->set16_12_number_) this->set16_12_number_->publish_state(PanasonicDecode::getByteMinus128(data[89])); - if (this->set16_11_number_) this->set16_11_number_->publish_state(PanasonicDecode::getByteMinus128(data[88])); - if (this->set29_number_) this->set29_number_->publish_state(PanasonicDecode::getByteMinus128(data[83])); - if (this->set16_5_number_) this->set16_5_number_->publish_state(PanasonicDecode::getByteMinus128(data[79])); - if (this->set16_6_number_) this->set16_6_number_->publish_state(PanasonicDecode::getByteMinus128(data[80])); - if (this->set16_8_number_) this->set16_8_number_->publish_state(PanasonicDecode::getByteMinus128(data[82])); - if (this->set16_7_number_) this->set16_7_number_->publish_state(PanasonicDecode::getByteMinus128(data[81])); - if (this->set16_13_number_) this->set16_13_number_->publish_state(PanasonicDecode::getByteMinus128(data[90])); - if (this->set16_14_number_) this->set16_14_number_->publish_state(PanasonicDecode::getByteMinus128(data[91])); - if (this->set16_16_number_) this->set16_16_number_->publish_state(PanasonicDecode::getByteMinus128(data[93])); - if (this->set16_15_number_) this->set16_15_number_->publish_state(PanasonicDecode::getByteMinus128(data[92])); - if (this->set15_number_) this->set15_number_->publish_state(PanasonicDecode::getByteMinus1(data[45])); - if (this->set21_number_) this->set21_number_->publish_state(PanasonicDecode::getByteMinus1(data[104])); - if (this->set22_number_) this->set22_number_->publish_state(PanasonicDecode::getByteMinus128(data[105])); - if (this->set23_number_) this->set23_number_->publish_state(PanasonicDecode::getByteMinus128(data[106])); - if (this->set27_number_) this->set27_number_->publish_state(PanasonicDecode::getByteMinus128(data[59])); - if (this->set36_number_) this->set36_number_->publish_state(PanasonicDecode::getByteMinus128(data[65])); - if (this->set37_number_) this->set37_number_->publish_state(PanasonicDecode::getByteMinus128(data[66])); - if (this->set38_number_) this->set38_number_->publish_state(PanasonicDecode::getByteMinus128(data[68])); -#endif - } - - void PanasonicHeatpumpComponent::publish_select(const std::vector& data) - { -#ifdef USE_SELECT - if (data.empty()) return; - if (this->set9_select_) this->set9_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::OpModeDesc, PanasonicDecode::getOpMode(data[6]))); - if (this->set4_select_) this->set4_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Powerfulmode, PanasonicDecode::getBit6and7and8(data[7]))); - if (this->set3_select_) this->set3_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Quietmode, PanasonicDecode::getBit3and4and5(data[7]))); - if (this->set2_select_) this->set2_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::HolidayState, PanasonicDecode::getBit3and4(data[5]))); - if (this->set17_select_) this->set17_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::ZonesState, PanasonicDecode::getBit1and2(data[6]))); - if (this->set26_select_) this->set26_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::ExtPadHeaterType, PanasonicDecode::getBit3and4(data[25]))); - if (this->set35_select_) this->set35_select_->publish_state(PanasonicDecode::getTextState(PanasonicDecode::Bivalent, PanasonicDecode::getBit5and6(data[26]))); -#endif - } - - void PanasonicHeatpumpComponent::publish_switch(const std::vector& data) - { -#ifdef USE_SWITCH - if (data.empty()) return; - if (this->set1_switch_) this->set1_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[4]))); - if (this->set10_switch_) this->set10_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[4]))); - if (this->set24_switch_) this->set24_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[5]))); - if (this->set12_switch_) this->set12_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[111]))); - if (this->set13_switch_) this->set13_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[117]))); - if (this->set28_switch_) this->set28_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[24]))); - if (this->set30_switch_) this->set30_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[23]))); - if (this->set33_switch_) this->set33_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[23]))); - if (this->set31_switch_) this->set31_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[23]))); - if (this->set32_switch_) this->set32_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[23]))); - if (this->set34_switch_) this->set34_switch_->publish_state(PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[26]))); -#endif - } - -#ifdef USE_NUMBER - void PanasonicHeatpumpComponent::control_number(number::Number* object, float value) - { - if (object == this->set5_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 38); - else if (object == this->set6_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 39); - else if (object == this->set7_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 40); - else if (object == this->set8_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 41); - else if (object == this->set11_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 42); - else if (object == this->set15_number_) this->set_command_byte(PanasonicCommand::setPlus1(value), 45); - else if (object == this->set18_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 84); - else if (object == this->set19_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 94); - else if (object == this->set20_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 99); - else if (object == this->set21_number_) this->set_command_byte(PanasonicCommand::setPlus1(value), 104); - else if (object == this->set22_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 105); - else if (object == this->set23_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 106); - else if (object == this->set27_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 59); - else if (object == this->set29_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 83); - else if (object == this->set36_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 65); - else if (object == this->set37_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 66); - else if (object == this->set38_number_) this->set_command_byte(PanasonicCommand::setPlus128(value), 68); - // Set zone 1 curve - if (object == this->set16_1_number_ || object == this->set16_2_number_ - || object == this->set16_3_number_ || object == this->set16_4_number_ - || object == this->set16_9_number_ || object == this->set16_10_number_ - || object == this->set16_11_number_ || object == this->set16_12_number_) - { - std::vector> curve; - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_1_number_->state), 75)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_2_number_->state), 76)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_3_number_->state), 77)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_4_number_->state), 78)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_9_number_->state), 86)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_10_number_->state), 87)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_11_number_->state), 88)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_12_number_->state), 89)); - this->set_command_bytes(curve); - } - // Set zone 2 curve - if (object == this->set16_5_number_ || object == this->set16_6_number_ - || object == this->set16_7_number_ || object == this->set16_8_number_ - || object == this->set16_13_number_ || object == this->set16_14_number_ - || object == this->set16_15_number_ || object == this->set16_16_number_) - { - std::vector> curve; - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_5_number_->state), 79)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_6_number_->state), 80)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_7_number_->state), 81)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_8_number_->state), 82)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_13_number_->state), 90)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_14_number_->state), 91)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_15_number_->state), 92)); - curve.push_back(std::make_tuple(PanasonicCommand::setPlus128(this->set16_16_number_->state), 93)); - this->set_command_bytes(curve); - } - } -#endif - -#ifdef USE_SELECT - void PanasonicHeatpumpComponent::control_select(select::Select* object, size_t value) - { - if (object == this->set2_select_) this->set_command_byte(PanasonicCommand::setPlus1Multiply16(value), 5); - else if (object == this->set3_select_) this->set_command_byte(PanasonicCommand::setPlus1Multiply8(value), 7); - else if (object == this->set4_select_) this->set_command_byte(PanasonicCommand::setPlus73(value), 7); - else if (object == this->set9_select_) this->set_command_byte(PanasonicCommand::setOperationMode(value), 6); - else if (object == this->set17_select_) this->set_command_byte(PanasonicCommand::setPlus1Multiply64(value), 6); - else if (object == this->set26_select_) this->set_command_byte(PanasonicCommand::setPlus1Multiply16(value), 25); - else if (object == this->set35_select_) this->set_command_byte(PanasonicCommand::setPlus1Multiply4(value), 26); - } -#endif - -#ifdef USE_SWITCH - void PanasonicHeatpumpComponent::control_switch(switch_::Switch* object, bool state) - { - size_t value = state ? 1 : 0; - - if (object == this->set1_switch_) this->set_command_byte(PanasonicCommand::setPlus1(value), 4); - else if (object == this->set10_switch_) this->set_command_byte(PanasonicCommand::setPlus1Multiply64(value), 4); - else if (object == this->set12_switch_) this->set_command_byte(PanasonicCommand::setMultiply2(value), 8); - else if (object == this->set13_switch_) this->set_command_byte(PanasonicCommand::setMultiply4(value), 8); - else if (object == this->set14_switch_) this->set_command_byte(PanasonicCommand::setPlus1Multiply16(value), 4); - else if (object == this->set24_switch_) this->set_command_byte(PanasonicCommand::setPlus1Multiply64(value), 5); - else if (object == this->set25_switch_) this->set_command_byte(PanasonicCommand::setPlus1Multiply16(value), 20); - else if (object == this->set28_switch_) this->set_command_byte(PanasonicCommand::setPlus1Multiply4(value), 24); - else if (object == this->set30_switch_) this->set_command_byte(PanasonicCommand::setPlus1(value), 23); - else if (object == this->set31_switch_) this->set_command_byte(PanasonicCommand::setPlus1Multiply16(value), 23); - else if (object == this->set32_switch_) this->set_command_byte(PanasonicCommand::setPlus1Multiply64(value), 23); - else if (object == this->set33_switch_) this->set_command_byte(PanasonicCommand::setPlus1Multiply4(value), 23); - else if (object == this->set34_switch_) this->set_command_byte(PanasonicCommand::setPlus1(value), 26); - } -#endif } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/panasonic_heatpump.h b/components/panasonic_heatpump/panasonic_heatpump.h index d39e79f..9a08bd6 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.h +++ b/components/panasonic_heatpump/panasonic_heatpump.h @@ -1,56 +1,38 @@ #pragma once - +#include +#include +#include +#include #include "esphome/core/component.h" #include "esphome/core/defines.h" #include "esphome/core/log.h" #include "esphome/components/uart/uart.h" -#ifdef USE_SENSOR -#include "esphome/components/sensor/sensor.h" -#endif -#ifdef USE_BINARY_SENSOR -#include "esphome/components/binary_sensor/binary_sensor.h" -#endif -#ifdef USE_TEXT_SENSOR -#include "esphome/components/text_sensor/text_sensor.h" -#endif -#ifdef USE_NUMBER -#include "esphome/components/number/number.h" -#endif -#ifdef USE_SELECT -#include "esphome/components/select/select.h" -#endif -#ifdef USE_SWITCH -#include "esphome/components/switch/switch.h" -#endif +#include "helpers.h" #include "decode.h" #include "commands.h" -#include "helpers.h" -#include -#include -#include namespace esphome { namespace panasonic_heatpump { - enum LoopState + enum LoopState : uint8_t { READ_RESPONSE, CHECK_RESPONSE, - SET_NUMBER_TRAITS, PUBLISH_SENSOR, PUBLISH_BINARY_SENSOR, PUBLISH_TEXT_SENSOR, PUBLISH_NUMBER, PUBLISH_SELECT, PUBLISH_SWITCH, + PUBLISH_CLIMATE, SEND_REQUEST, READ_REQUEST, RESTART_LOOP }; - enum RequestType + enum RequestType : uint8_t { INITIAL, POLLING, @@ -58,221 +40,20 @@ namespace esphome NONE }; + class PanasonicHeatpumpEntity + { + public: + virtual void set_id(const int id) { id_ = id; } + virtual void publish_new_state(const std::vector& data) = 0; + + protected: + int id_ { -1 }; + int keep_state_ { 0 }; + }; + class PanasonicHeatpumpComponent : public PollingComponent, public uart::UARTDevice { public: - // ToDo: Add template for custom sensor classes similar to SUB_SENSOR (see Pipsolar) -#ifdef USE_SENSOR - SUB_SENSOR(top1); - SUB_SENSOR(top5); - SUB_SENSOR(top6); - SUB_SENSOR(top7); - SUB_SENSOR(top8); - SUB_SENSOR(top9); - SUB_SENSOR(top10); - SUB_SENSOR(top11); - SUB_SENSOR(top12); - SUB_SENSOR(top14); - SUB_SENSOR(top15); - SUB_SENSOR(top16); - SUB_SENSOR(top21); - SUB_SENSOR(top22); - SUB_SENSOR(top23); - SUB_SENSOR(top24); - SUB_SENSOR(top25); - SUB_SENSOR(top27); - SUB_SENSOR(top28); - SUB_SENSOR(top29); - SUB_SENSOR(top30); - SUB_SENSOR(top31); - SUB_SENSOR(top32); - SUB_SENSOR(top33); - SUB_SENSOR(top34); - SUB_SENSOR(top35); - SUB_SENSOR(top36); - SUB_SENSOR(top37); - SUB_SENSOR(top38); - SUB_SENSOR(top39); - SUB_SENSOR(top40); - SUB_SENSOR(top41); - SUB_SENSOR(top42); - SUB_SENSOR(top43); - SUB_SENSOR(top45); - SUB_SENSOR(top46); - SUB_SENSOR(top47); - SUB_SENSOR(top48); - SUB_SENSOR(top49); - SUB_SENSOR(top50); - SUB_SENSOR(top51); - SUB_SENSOR(top52); - SUB_SENSOR(top53); - SUB_SENSOR(top54); - SUB_SENSOR(top55); - SUB_SENSOR(top56); - SUB_SENSOR(top57); - SUB_SENSOR(top62); - SUB_SENSOR(top63); - SUB_SENSOR(top64); - SUB_SENSOR(top65); - SUB_SENSOR(top66); - SUB_SENSOR(top67); - SUB_SENSOR(top70); - SUB_SENSOR(top71); - SUB_SENSOR(top72); - SUB_SENSOR(top73); - SUB_SENSOR(top74); - SUB_SENSOR(top75); - SUB_SENSOR(top77); - SUB_SENSOR(top78); - SUB_SENSOR(top79); - SUB_SENSOR(top80); - SUB_SENSOR(top82); - SUB_SENSOR(top83); - SUB_SENSOR(top84); - SUB_SENSOR(top85); - SUB_SENSOR(top86); - SUB_SENSOR(top87); - SUB_SENSOR(top88); - SUB_SENSOR(top89); - SUB_SENSOR(top90); - SUB_SENSOR(top91); - SUB_SENSOR(top93); - SUB_SENSOR(top95); - SUB_SENSOR(top96); - SUB_SENSOR(top97); - SUB_SENSOR(top98); - SUB_SENSOR(top102); - SUB_SENSOR(top103); - SUB_SENSOR(top104); - SUB_SENSOR(top105); - SUB_SENSOR(top113); - SUB_SENSOR(top115); - SUB_SENSOR(top116); - SUB_SENSOR(top117); - SUB_SENSOR(top118); - SUB_SENSOR(top127); - SUB_SENSOR(top128); - SUB_SENSOR(top131); - SUB_SENSOR(top134); - SUB_SENSOR(top135); - SUB_SENSOR(top136); - SUB_SENSOR(top137); - SUB_SENSOR(top138); -#endif -#ifdef USE_BINARY_SENSOR - SUB_BINARY_SENSOR(top0); - SUB_BINARY_SENSOR(top2); - SUB_BINARY_SENSOR(top3); - SUB_BINARY_SENSOR(top13); - SUB_BINARY_SENSOR(top26); - SUB_BINARY_SENSOR(top60); - SUB_BINARY_SENSOR(top61); - SUB_BINARY_SENSOR(top68); - SUB_BINARY_SENSOR(top69); - SUB_BINARY_SENSOR(top99); - SUB_BINARY_SENSOR(top100); - SUB_BINARY_SENSOR(top108); - SUB_BINARY_SENSOR(top109); - SUB_BINARY_SENSOR(top110); - SUB_BINARY_SENSOR(top119); - SUB_BINARY_SENSOR(top120); - SUB_BINARY_SENSOR(top121); - SUB_BINARY_SENSOR(top122); - SUB_BINARY_SENSOR(top123); - SUB_BINARY_SENSOR(top124); - SUB_BINARY_SENSOR(top129); - SUB_BINARY_SENSOR(top132); - SUB_BINARY_SENSOR(top133); -#endif -#ifdef USE_TEXT_SENSOR - SUB_TEXT_SENSOR(top4); - SUB_TEXT_SENSOR(top17); - SUB_TEXT_SENSOR(top18); - SUB_TEXT_SENSOR(top19); - SUB_TEXT_SENSOR(top20); - SUB_TEXT_SENSOR(top44); - SUB_TEXT_SENSOR(top58); - SUB_TEXT_SENSOR(top59); - SUB_TEXT_SENSOR(top76); - SUB_TEXT_SENSOR(top81); - SUB_TEXT_SENSOR(top92); - SUB_TEXT_SENSOR(top94); - SUB_TEXT_SENSOR(top101); - SUB_TEXT_SENSOR(top106); - SUB_TEXT_SENSOR(top107); - SUB_TEXT_SENSOR(top111); - SUB_TEXT_SENSOR(top112); - SUB_TEXT_SENSOR(top114); - SUB_TEXT_SENSOR(top125); - SUB_TEXT_SENSOR(top126); - SUB_TEXT_SENSOR(top130); -#endif -#ifdef USE_NUMBER - SUB_NUMBER(set5); - SUB_NUMBER(set6); - SUB_NUMBER(set7); - SUB_NUMBER(set8); - SUB_NUMBER(set11); - SUB_NUMBER(set15); - SUB_NUMBER(set16_1); - SUB_NUMBER(set16_2); - SUB_NUMBER(set16_3); - SUB_NUMBER(set16_4); - SUB_NUMBER(set16_5); - SUB_NUMBER(set16_6); - SUB_NUMBER(set16_7); - SUB_NUMBER(set16_8); - SUB_NUMBER(set16_9); - SUB_NUMBER(set16_10); - SUB_NUMBER(set16_11); - SUB_NUMBER(set16_12); - SUB_NUMBER(set16_13); - SUB_NUMBER(set16_14); - SUB_NUMBER(set16_15); - SUB_NUMBER(set16_16); - SUB_NUMBER(set18); - SUB_NUMBER(set19); - SUB_NUMBER(set20); - SUB_NUMBER(set21); - SUB_NUMBER(set22); - SUB_NUMBER(set23); - SUB_NUMBER(set27); - SUB_NUMBER(set29); - SUB_NUMBER(set36); - SUB_NUMBER(set37); - SUB_NUMBER(set38); - - void control_number(number::Number* object, float value); -#endif -#ifdef USE_SELECT - SUB_SELECT(set2); - SUB_SELECT(set3); - SUB_SELECT(set4); - SUB_SELECT(set9); - SUB_SELECT(set17); - SUB_SELECT(set26); - SUB_SELECT(set35); - - void control_select(select::Select* object, size_t value); -#endif -#ifdef USE_SWITCH - SUB_SWITCH(set1); - SUB_SWITCH(set10); - SUB_SWITCH(set12); - SUB_SWITCH(set13); - SUB_SWITCH(set14); - SUB_SWITCH(set24); - SUB_SWITCH(set25); - SUB_SWITCH(set28); - SUB_SWITCH(set30); - SUB_SWITCH(set31); - SUB_SWITCH(set32); - SUB_SWITCH(set33); - SUB_SWITCH(set34); - - void control_switch(switch_::Switch* object, bool state); -#endif - PanasonicHeatpumpComponent() = default; // base class functions float get_setup_priority() const override { return setup_priority::DATA; } @@ -282,9 +63,22 @@ namespace esphome void loop() override; // option functions void set_uart_client(uart::UARTComponent* uart) { this->uart_client_ = uart; } - void set_log_uart_msg(bool enable) { this->log_uart_msg_ = enable; } + void set_log_uart_msg(bool active) { this->log_uart_msg_ = active; } // uart message variables to use in lambda functions int getResponseByte(const int index); + // command functions + void set_command_high_nibble(const uint8_t value, const uint8_t index); + void set_command_low_nibble(const uint8_t value, const uint8_t index); + void set_command_byte(const uint8_t value, const uint8_t index); + void set_command_curve(const uint8_t value, const uint8_t index); + // entity functions + void add_binary_sensor(PanasonicHeatpumpEntity *binary_sensor) { binary_sensors_.push_back(binary_sensor); } + void add_climate(PanasonicHeatpumpEntity *climate) { climates_.push_back(climate); } + void add_number(PanasonicHeatpumpEntity *number) { numbers_.push_back(number); } + void add_select(PanasonicHeatpumpEntity *select) { selects_.push_back(select); } + void add_sensor(PanasonicHeatpumpEntity *sensor) { sensors_.push_back(sensor); } + void add_switch(PanasonicHeatpumpEntity *switch_) { switches_.push_back(switch_); } + void add_text_sensor(PanasonicHeatpumpEntity *text_sensor) { text_sensors_.push_back(text_sensor); } protected: // options variables @@ -303,23 +97,20 @@ namespace esphome bool request_receiving_ { false }; RequestType next_request_ { RequestType::INITIAL }; LoopState loop_state_ { LoopState::RESTART_LOOP }; - uint16_t trait_update_counter_ { 0 }; + // entity vectors + std::vector binary_sensors_; + std::vector climates_; + std::vector numbers_; + std::vector selects_; + std::vector sensors_; + std::vector switches_; + std::vector text_sensors_; // uart message functions void read_response(); void send_request(RequestType requestType); void read_request(); bool check_response(const std::vector& data); - void set_command_byte(const uint8_t value, const uint8_t index); - void set_command_bytes(const std::vector>& data); - // sensor and control publish functions - void set_number_traits(const std::vector& data); - void publish_sensor(const std::vector& data); - void publish_binary_sensor(const std::vector& data); - void publish_text_sensor(const std::vector& data); - void publish_number(const std::vector& data); - void publish_select(const std::vector& data); - void publish_switch(const std::vector& data); }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/select/__init__.py b/components/panasonic_heatpump/select/__init__.py index b6e6b15..c635cab 100644 --- a/components/panasonic_heatpump/select/__init__.py +++ b/components/panasonic_heatpump/select/__init__.py @@ -7,6 +7,7 @@ from esphome.const import ( from .. import CONF_PANASONIC_HEATPUMP_ID, PanasonicHeatpumpComponent, panasonic_heatpump_ns +CONF_COOL_MODE = "cool_mode" CONF_SET2 = "set2" # Set Holiday Mode CONF_SET3 = "set3" # Set Quiet Mode CONF_SET4 = "set4" # Set Powerful Mode @@ -30,17 +31,21 @@ CONF_SELECTS = [ [ "Off", "Scheduled", "Active", ], [ "Off", "Level 1", "Level 2", "Level 3", ], [ "Off", "30min", "60min", "90min", ], - [ "Heat only", "Cool only", "Auto", "Auto(heat)", "Auto(cool)", "DHW only", "Heat+DHW", "Cool+DHW", "Auto+DHW", "Auto(heat)+DHW", "Auto(cool)+DHW", ], + [ "TANK", "HEAT", "HEAT+TANK", ], [ "Zone 1", "Zone 2", "Zone 1 & 2", ], [ "Disabled", "Type-A", "Type-B" ], [ "Alternative", "Parallel", "Advanced Parallel" ], ] +CONF_SELECT_COOL_MODE = [ "TANK", "HEAT", "HEAT+TANK", "COOL", "COOL+TANK", "AUTO", "AUTO+TANK", ] PanasonicHeatpumpSelect = panasonic_heatpump_ns.class_("PanasonicHeatpumpSelect", select.Select, cg.Component) CONFIG_SCHEMA = cv.Schema( { - cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id(PanasonicHeatpumpComponent), + cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id( + PanasonicHeatpumpComponent + ), + cv.Optional(CONF_COOL_MODE, default=False): cv.boolean, cv.Optional(CONF_SET2): select.select_schema( PanasonicHeatpumpSelect, @@ -67,11 +72,13 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) async def to_code(config): - hub = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) + parent = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) for index, key in enumerate(TYPES): if child_config := config.get(key): - var = await select.new_select(child_config, options=CONF_SELECTS[index]) + child_options = CONF_SELECT_COOL_MODE if config[CONF_COOL_MODE] and key == CONF_SET9 else CONF_SELECTS[index] + + var = await select.new_select(child_config, options=child_options) await cg.register_component(var, child_config) - await cg.register_parented(var, config[CONF_PANASONIC_HEATPUMP_ID]) - cg.add(getattr(hub, f"set_{key}_select")(var)) + cg.add(var.set_parent(parent)) cg.add(var.set_id(index)) + cg.add(parent.add_select(var)) diff --git a/components/panasonic_heatpump/select/panasonic_heatpump_select.cpp b/components/panasonic_heatpump/select/panasonic_heatpump_select.cpp index 062abf2..7dacc18 100644 --- a/components/panasonic_heatpump/select/panasonic_heatpump_select.cpp +++ b/components/panasonic_heatpump/select/panasonic_heatpump_select.cpp @@ -1,5 +1,4 @@ #include "panasonic_heatpump_select.h" -#include "esphome/core/log.h" namespace esphome @@ -16,10 +15,111 @@ namespace esphome void PanasonicHeatpumpSelect::control(const std::string &value) { + auto optIndex = this->index_of(value); + if (!optIndex.has_value()) return; + size_t index = optIndex.value(); + + switch (this->id_) + { + case SelectIds::CONF_SET2: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply16(index), 5); + break; + } + case SelectIds::CONF_SET3: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply8(index), 7); + break; + } + case SelectIds::CONF_SET4: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1(index), 7); + break; + } + case SelectIds::CONF_SET9: + { + this->parent_->set_command_byte(PanasonicCommand::setOperationMode(index), 6); + break; + } + case SelectIds::CONF_SET17: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply64(index), 6); + break; + } + case SelectIds::CONF_SET26: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply16(index), 25); + break; + } + case SelectIds::CONF_SET35: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply4(index), 26); + break; + } + default: return; + }; this->publish_state(value); - auto index = this->active_index(); - if (index.has_value()) - this->parent_->control_select(this, index.value()); + this->keep_state_ = 2; + } + + void PanasonicHeatpumpSelect::publish_new_state(const std::vector& data) + { + if (this->keep_state_ > 0) + { + this->keep_state_--; + return; + } + if (data.empty()) return; + + std::string new_state; + switch (this->id_) + { + case SelectIds::CONF_SET9: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::OperationMode, PanasonicDecode::getOperationMode(data[6])); + if (this->has_state() && this->state == new_state) return; + break; + } + case SelectIds::CONF_SET4: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::PowerfulMode, PanasonicDecode::getBit6and7and8(data[7])); + if (this->has_state() && this->state == new_state) return; + break; + } + case SelectIds::CONF_SET3: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::QuietMode, PanasonicDecode::getBit3and4and5(data[7])); + if (this->has_state() && this->state == new_state) return; + break; + } + case SelectIds::CONF_SET2: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::HolidayState, PanasonicDecode::getBit3and4(data[5])); + if (this->has_state() && this->state == new_state) return; + break; + } + case SelectIds::CONF_SET17: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ZoneState, PanasonicDecode::getBit1and2(data[6])); + if (this->has_state() && this->state == new_state) return; + break; + } + case SelectIds::CONF_SET26: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ExtPadHeaterType, PanasonicDecode::getBit3and4(data[25])); + if (this->has_state() && this->state == new_state) return; + break; + } + case SelectIds::CONF_SET35: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::BivalentMode, PanasonicDecode::getBit5and6(data[26])); + if (this->has_state() && this->state == new_state) return; + break; + } + default: return; + }; + + this->publish_state(new_state); } } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/select/panasonic_heatpump_select.h b/components/panasonic_heatpump/select/panasonic_heatpump_select.h index 8f7ebe5..1bbfc03 100644 --- a/components/panasonic_heatpump/select/panasonic_heatpump_select.h +++ b/components/panasonic_heatpump/select/panasonic_heatpump_select.h @@ -1,23 +1,36 @@ #pragma once -#include "esphome/components/select/select.h" #include "esphome/core/component.h" +#include "esphome/components/select/select.h" #include "../panasonic_heatpump.h" +#include "../decode.h" +#include "../commands.h" namespace esphome { namespace panasonic_heatpump { - class PanasonicHeatpumpSelect : public select::Select, public Component, public Parented + enum SelectIds : uint8_t + { + CONF_SET2, + CONF_SET3, + CONF_SET4, + CONF_SET9, + CONF_SET17, + CONF_SET26, + CONF_SET35, + }; + + class PanasonicHeatpumpSelect : public select::Select, public Component, + public Parented, public PanasonicHeatpumpEntity { public: PanasonicHeatpumpSelect() = default; void dump_config() override; - void set_id(int id) { this->id_ = id; } + void publish_new_state(const std::vector& data) override; protected: void control(const std::string &value) override; - int id_; }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/sensor/__init__.py b/components/panasonic_heatpump/sensor/__init__.py index 0e16ea7..72c4bfa 100644 --- a/components/panasonic_heatpump/sensor/__init__.py +++ b/components/panasonic_heatpump/sensor/__init__.py @@ -230,7 +230,9 @@ PanasonicHeatpumpSensor = panasonic_heatpump_ns.class_("PanasonicHeatpumpSensor" CONFIG_SCHEMA = cv.Schema( { - cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id(PanasonicHeatpumpComponent), + cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id( + PanasonicHeatpumpComponent + ), cv.Optional(CONF_TOP1): sensor.sensor_schema( PanasonicHeatpumpSensor, @@ -896,10 +898,11 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) async def to_code(config): - hub = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) - for key in TYPES: + parent = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) + for index, key in enumerate(TYPES): if child_config := config.get(key): var = await sensor.new_sensor(child_config) await cg.register_component(var, child_config) - await cg.register_parented(var, config[CONF_PANASONIC_HEATPUMP_ID]) - cg.add(getattr(hub, f"set_{key}_sensor")(var)) + cg.add(var.set_parent(parent)) + cg.add(var.set_id(index)) + cg.add(parent.add_sensor(var)) diff --git a/components/panasonic_heatpump/sensor/panasonic_heatpump_sensor.cpp b/components/panasonic_heatpump/sensor/panasonic_heatpump_sensor.cpp index 58c558c..b133a8e 100644 --- a/components/panasonic_heatpump/sensor/panasonic_heatpump_sensor.cpp +++ b/components/panasonic_heatpump/sensor/panasonic_heatpump_sensor.cpp @@ -1,5 +1,4 @@ #include "panasonic_heatpump_sensor.h" -#include "esphome/core/log.h" namespace esphome @@ -13,5 +12,588 @@ namespace esphome LOG_SENSOR("", "Panasonic Heatpump Sensor", this); delay(10); } + + void PanasonicHeatpumpSensor::publish_new_state(const std::vector& data) + { + if (data.empty()) return; + + float new_state; + switch (this->id_) + { + case SensorIds::CONF_TOP1: + { + new_state = PanasonicDecode::getPumpFlow(data, 169); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP5: + { + new_state = PanasonicDecode::getByteMinus128(data[143]) + PanasonicDecode::getFractional(data[118], 0); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP6: + { + new_state = PanasonicDecode::getByteMinus128(data[144]) + PanasonicDecode::getFractional(data[118], 3); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP7: + { + new_state = PanasonicDecode::getByteMinus128(data[153]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP8: + { + new_state = PanasonicDecode::getByteMinus1(data[166]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP9: + { + new_state = PanasonicDecode::getByteMinus128(data[42]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP10: + { + new_state = PanasonicDecode::getByteMinus128(data[141]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP11: + { + new_state = PanasonicDecode::getWordMinus1(data, 182); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP12: + { + new_state = PanasonicDecode::getWordMinus1(data, 179); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP14: + { + new_state = PanasonicDecode::getByteMinus128(data[142]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP15: + { + new_state = PanasonicDecode::getByteMinus1Times200(data[194]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP16: + { + new_state = PanasonicDecode::getByteMinus1Times200(data[193]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP21: + { + new_state = PanasonicDecode::getByteMinus128(data[158]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP22: + { + new_state = PanasonicDecode::getByteMinus128(data[99]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP23: + { + new_state = PanasonicDecode::getByteMinus128(data[84]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP24: + { + new_state = PanasonicDecode::getByteMinus128(data[94]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP25: + { + new_state = PanasonicDecode::getByteMinus128(data[44]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP27: + { + new_state = PanasonicDecode::getByteMinus128(data[38]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP28: + { + new_state = PanasonicDecode::getByteMinus128(data[39]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP29: + { + new_state = PanasonicDecode::getByteMinus128(data[75]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP30: + { + new_state = PanasonicDecode::getByteMinus128(data[76]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP31: + { + new_state = PanasonicDecode::getByteMinus128(data[78]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP32: + { + new_state = PanasonicDecode::getByteMinus128(data[77]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP33: + { + new_state = PanasonicDecode::getByteMinus128(data[156]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP34: + { + new_state = PanasonicDecode::getByteMinus128(data[40]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP35: + { + new_state = PanasonicDecode::getByteMinus128(data[41]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP36: + { + new_state = PanasonicDecode::getByteMinus128(data[145]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP37: + { + new_state = PanasonicDecode::getByteMinus128(data[146]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP38: + { + new_state = PanasonicDecode::getByteMinus1Times200(data[196]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP39: + { + new_state = PanasonicDecode::getByteMinus1Times200(data[195]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP40: + { + new_state = PanasonicDecode::getByteMinus1Times200(data[198]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP41: + { + new_state = PanasonicDecode::getByteMinus1Times200(data[197]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP42: + { + new_state = PanasonicDecode::getByteMinus128(data[147]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP43: + { + new_state = PanasonicDecode::getByteMinus128(data[148]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP45: + { + new_state = PanasonicDecode::getByteMinus128(data[43]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP46: + { + new_state = PanasonicDecode::getByteMinus128(data[149]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP47: + { + new_state = PanasonicDecode::getByteMinus128(data[150]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP48: + { + new_state = PanasonicDecode::getByteMinus128(data[151]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP49: + { + new_state = PanasonicDecode::getByteMinus128(data[154]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP50: + { + new_state = PanasonicDecode::getByteMinus128(data[155]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP51: + { + new_state = PanasonicDecode::getByteMinus128(data[157]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP52: + { + new_state = PanasonicDecode::getByteMinus128(data[159]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP53: + { + new_state = PanasonicDecode::getByteMinus128(data[160]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP54: + { + new_state = PanasonicDecode::getByteMinus128(data[161]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP55: + { + new_state = PanasonicDecode::getByteMinus128(data[162]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP56: + { + new_state = PanasonicDecode::getByteMinus128(data[139]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP57: + { + new_state = PanasonicDecode::getByteMinus128(data[140]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP62: + { + new_state = PanasonicDecode::getByteMinus1Times10(data[173]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP63: + { + new_state = PanasonicDecode::getByteMinus1Times10(data[174]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP64: + { + new_state = PanasonicDecode::getByteMinus1Div5(data[163]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP65: + { + new_state = PanasonicDecode::getByteMinus1Times50(data[171]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP66: + { + new_state = PanasonicDecode::getByteMinus1Times50(data[164]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP67: + { + new_state = PanasonicDecode::getByteMinus1Div5(data[165]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP70: + { + new_state = PanasonicDecode::getByteMinus128(data[100]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP71: + { + new_state = PanasonicDecode::getByteMinus1(data[101]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP72: + { + new_state = PanasonicDecode::getByteMinus128(data[86]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP73: + { + new_state = PanasonicDecode::getByteMinus128(data[87]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP74: + { + new_state = PanasonicDecode::getByteMinus128(data[89]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP75: + { + new_state = PanasonicDecode::getByteMinus128(data[88]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP77: + { + new_state = PanasonicDecode::getByteMinus128(data[83]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP78: + { + new_state = PanasonicDecode::getByteMinus128(data[85]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP79: + { + new_state = PanasonicDecode::getByteMinus128(data[95]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP80: + { + new_state = PanasonicDecode::getByteMinus128(data[96]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP82: + { + new_state = PanasonicDecode::getByteMinus128(data[79]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP83: + { + new_state = PanasonicDecode::getByteMinus128(data[80]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP84: + { + new_state = PanasonicDecode::getByteMinus128(data[82]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP85: + { + new_state = PanasonicDecode::getByteMinus128(data[81]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP86: + { + new_state = PanasonicDecode::getByteMinus128(data[90]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP87: + { + new_state = PanasonicDecode::getByteMinus128(data[91]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP88: + { + new_state = PanasonicDecode::getByteMinus128(data[93]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP89: + { + new_state = PanasonicDecode::getByteMinus128(data[92]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP90: + { + new_state = PanasonicDecode::getWordMinus1(data, 185); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP91: + { + new_state = PanasonicDecode::getWordMinus1(data, 188); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP93: + { + new_state = PanasonicDecode::getByteMinus1(data[172]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP95: + { + new_state = PanasonicDecode::getByteMinus1(data[45]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP96: + { + new_state = PanasonicDecode::getByteMinus1(data[104]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP97: + { + new_state = PanasonicDecode::getByteMinus128(data[105]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP98: + { + new_state = PanasonicDecode::getByteMinus128(data[106]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP102: + { + new_state = PanasonicDecode::getByteMinus128(data[61]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP103: + { + new_state = PanasonicDecode::getByteMinus128(data[62]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP104: + { + new_state = PanasonicDecode::getByteMinus128(data[63]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP105: + { + new_state = PanasonicDecode::getByteMinus128(data[64]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP113: + { + new_state = PanasonicDecode::getByteMinus128(data[59]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP115: + { + new_state = PanasonicDecode::getByteMinus1Div50(data[125]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP116: + { + new_state = PanasonicDecode::getByteMinus128(data[126]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP117: + { + new_state = PanasonicDecode::getByteMinus128(data[127]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP118: + { + new_state = PanasonicDecode::getByteMinus128(data[128]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP127: + { + new_state = PanasonicDecode::getByteMinus1Div2(data[177]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP128: + { + new_state = PanasonicDecode::getByteMinus1Div2(data[178]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP131: + { + new_state = PanasonicDecode::getByteMinus128(data[65]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP134: + { + new_state = PanasonicDecode::getByteMinus128(data[66]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP135: + { + new_state = PanasonicDecode::getByteMinus128(data[68]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP136: + { + new_state = PanasonicDecode::getByteMinus1(data[67]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP137: + { + new_state = PanasonicDecode::getByteMinus1(data[69]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case SensorIds::CONF_TOP138: + { + new_state = PanasonicDecode::getByteMinus1(data[70]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + default: return; + }; + + this->publish_state(new_state); + } } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/sensor/panasonic_heatpump_sensor.h b/components/panasonic_heatpump/sensor/panasonic_heatpump_sensor.h index 82072b9..637bcfe 100644 --- a/components/panasonic_heatpump/sensor/panasonic_heatpump_sensor.h +++ b/components/panasonic_heatpump/sensor/panasonic_heatpump_sensor.h @@ -1,18 +1,120 @@ #pragma once -#include "esphome/components/sensor/sensor.h" #include "esphome/core/component.h" +#include "esphome/components/sensor/sensor.h" #include "../panasonic_heatpump.h" +#include "../decode.h" namespace esphome { namespace panasonic_heatpump { - class PanasonicHeatpumpSensor : public sensor::Sensor, public Component, public Parented + enum SensorIds : uint8_t + { + CONF_TOP1, + CONF_TOP5, + CONF_TOP6, + CONF_TOP7, + CONF_TOP8, + CONF_TOP9, + CONF_TOP10, + CONF_TOP11, + CONF_TOP12, + CONF_TOP14, + CONF_TOP15, + CONF_TOP16, + CONF_TOP21, + CONF_TOP22, + CONF_TOP23, + CONF_TOP24, + CONF_TOP25, + CONF_TOP27, + CONF_TOP28, + CONF_TOP29, + CONF_TOP30, + CONF_TOP31, + CONF_TOP32, + CONF_TOP33, + CONF_TOP34, + CONF_TOP35, + CONF_TOP36, + CONF_TOP37, + CONF_TOP38, + CONF_TOP39, + CONF_TOP40, + CONF_TOP41, + CONF_TOP42, + CONF_TOP43, + CONF_TOP45, + CONF_TOP46, + CONF_TOP47, + CONF_TOP48, + CONF_TOP49, + CONF_TOP50, + CONF_TOP51, + CONF_TOP52, + CONF_TOP53, + CONF_TOP54, + CONF_TOP55, + CONF_TOP56, + CONF_TOP57, + CONF_TOP62, + CONF_TOP63, + CONF_TOP64, + CONF_TOP65, + CONF_TOP66, + CONF_TOP67, + CONF_TOP70, + CONF_TOP71, + CONF_TOP72, + CONF_TOP73, + CONF_TOP74, + CONF_TOP75, + CONF_TOP77, + CONF_TOP78, + CONF_TOP79, + CONF_TOP80, + CONF_TOP82, + CONF_TOP83, + CONF_TOP84, + CONF_TOP85, + CONF_TOP86, + CONF_TOP87, + CONF_TOP88, + CONF_TOP89, + CONF_TOP90, + CONF_TOP91, + CONF_TOP93, + CONF_TOP95, + CONF_TOP96, + CONF_TOP97, + CONF_TOP98, + CONF_TOP102, + CONF_TOP103, + CONF_TOP104, + CONF_TOP105, + CONF_TOP113, + CONF_TOP115, + CONF_TOP116, + CONF_TOP117, + CONF_TOP118, + CONF_TOP127, + CONF_TOP128, + CONF_TOP131, + CONF_TOP134, + CONF_TOP135, + CONF_TOP136, + CONF_TOP137, + CONF_TOP138, + }; + + class PanasonicHeatpumpSensor : public sensor::Sensor, public Component, + public Parented, public PanasonicHeatpumpEntity { public: PanasonicHeatpumpSensor() = default; void dump_config() override; + void publish_new_state(const std::vector& data) override; }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/switch/__init__.py b/components/panasonic_heatpump/switch/__init__.py index b718eab..c96d79d 100644 --- a/components/panasonic_heatpump/switch/__init__.py +++ b/components/panasonic_heatpump/switch/__init__.py @@ -40,7 +40,9 @@ PanasonicHeatpumpSwitch = panasonic_heatpump_ns.class_("PanasonicHeatpumpSwitch" CONFIG_SCHEMA = cv.Schema( { - cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id(PanasonicHeatpumpComponent), + cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id( + PanasonicHeatpumpComponent + ), cv.Optional(CONF_SET1): switch.switch_schema( PanasonicHeatpumpSwitch, @@ -85,11 +87,11 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) async def to_code(config): - hub = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) + parent = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) for index, key in enumerate(TYPES): if child_config := config.get(key): var = await switch.new_switch(child_config) await cg.register_component(var, child_config) - await cg.register_parented(var, config[CONF_PANASONIC_HEATPUMP_ID]) - cg.add(getattr(hub, f"set_{key}_switch")(var)) + cg.add(var.set_parent(parent)) cg.add(var.set_id(index)) + cg.add(parent.add_switch(var)) diff --git a/components/panasonic_heatpump/switch/panasonic_heatpump_switch.cpp b/components/panasonic_heatpump/switch/panasonic_heatpump_switch.cpp index 2716d43..6b2ef19 100644 --- a/components/panasonic_heatpump/switch/panasonic_heatpump_switch.cpp +++ b/components/panasonic_heatpump/switch/panasonic_heatpump_switch.cpp @@ -1,5 +1,4 @@ #include "panasonic_heatpump_switch.h" -#include "esphome/core/log.h" namespace esphome @@ -16,8 +15,169 @@ namespace esphome void PanasonicHeatpumpSwitch::write_state(bool state) { + size_t value = state ? 1 : 0; + + switch (this->id_) + { + case SwitchIds::CONF_SET1: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1(value), 4); + break; + } + case SwitchIds::CONF_SET10: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply64(value), 4); + break; + } + case SwitchIds::CONF_SET12: + { + this->parent_->set_command_byte(PanasonicCommand::setMultiply2(value), 8); + break; + } + case SwitchIds::CONF_SET13: + { + this->parent_->set_command_byte(PanasonicCommand::setMultiply4(value), 8); + break; + } + case SwitchIds::CONF_SET14: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply16(value), 4); + break; + } + case SwitchIds::CONF_SET24: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply64(value), 5); + break; + } + case SwitchIds::CONF_SET25: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply16(value), 20); + break; + } + case SwitchIds::CONF_SET28: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply4(value), 24); + break; + } + case SwitchIds::CONF_SET30: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1(value), 23); + break; + } + case SwitchIds::CONF_SET31: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply16(value), 23); + break; + } + case SwitchIds::CONF_SET32: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply64(value), 23); + break; + } + case SwitchIds::CONF_SET33: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1Multiply4(value), 23); + break; + } + case SwitchIds::CONF_SET34: + { + this->parent_->set_command_byte(PanasonicCommand::setPlus1(value), 26); + break; + } + default: return; + }; this->publish_state(state); - this->parent_->control_switch(this, state); + this->keep_state_ = 2; + } + + void PanasonicHeatpumpSwitch::publish_new_state(const std::vector& data) + { + if (this->keep_state_ > 0) + { + this->keep_state_--; + return; + } + if (data.empty()) return; + + bool new_state; + switch (this->id_) + { + case SwitchIds::CONF_SET1: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[4])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET10: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[4])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET24: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[5])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET12: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[111])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET13: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[117])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET28: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[24])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET25: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[20])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET30: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[23])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET33: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit5and6(data[23])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET31: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit3and4(data[23])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET32: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit1and2(data[23])); + if (this->state == new_state) return; + break; + } + case SwitchIds::CONF_SET34: + { + new_state = PanasonicDecode::getBinaryState(PanasonicDecode::getBit7and8(data[26])); + if (this->state == new_state) return; + break; + } + default: return; + }; + + this->publish_state(new_state); } } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/switch/panasonic_heatpump_switch.h b/components/panasonic_heatpump/switch/panasonic_heatpump_switch.h index de9f4f7..75addb9 100644 --- a/components/panasonic_heatpump/switch/panasonic_heatpump_switch.h +++ b/components/panasonic_heatpump/switch/panasonic_heatpump_switch.h @@ -1,23 +1,42 @@ #pragma once -#include "esphome/components/switch/switch.h" #include "esphome/core/component.h" +#include "esphome/components/switch/switch.h" #include "../panasonic_heatpump.h" +#include "../decode.h" +#include "../commands.h" namespace esphome { namespace panasonic_heatpump { - class PanasonicHeatpumpSwitch : public switch_::Switch, public Component, public Parented + enum SwitchIds : uint8_t + { + CONF_SET1, + CONF_SET10, + CONF_SET12, + CONF_SET13, + CONF_SET14, + CONF_SET24, + CONF_SET25, + CONF_SET28, + CONF_SET30, + CONF_SET31, + CONF_SET32, + CONF_SET33, + CONF_SET34, + }; + + class PanasonicHeatpumpSwitch : public switch_::Switch, public Component, + public Parented, public PanasonicHeatpumpEntity { public: PanasonicHeatpumpSwitch() = default; void dump_config() override; - void set_id(int id) { this->id_ = id; } + void publish_new_state(const std::vector& data) override; protected: void write_state(bool state) override; - int id_; }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/text_sensor/__init__.py b/components/panasonic_heatpump/text_sensor/__init__.py index ad00a96..e483aee 100644 --- a/components/panasonic_heatpump/text_sensor/__init__.py +++ b/components/panasonic_heatpump/text_sensor/__init__.py @@ -7,7 +7,7 @@ from esphome.const import ( from .. import CONF_PANASONIC_HEATPUMP_ID, PanasonicHeatpumpComponent, panasonic_heatpump_ns -ICON_OPERATING_MODE = "mdi:thermostat" +ICON_OPERATION_MODE = "mdi:thermostat" ICON_POWERFUL_MODE = "mdi:arm-flex" ICON_QUIET_MODE = "mdi:sleep" ICON_HOLIDAY_MODE = "mdi:palm-tree" @@ -24,7 +24,7 @@ ICON_PUMP = "mdi:pump" ICON_EXTERNAL_PAD_HEATER = "mdi:radiator" -CONF_TOP4 = "top4" # Operating Mode State +CONF_TOP4 = "top4" # Operation Mode # ToDo: Split up top4 into top4_1 (Heating Mode State) and top4_2 (DHW Mode State) CONF_TOP17 = "top17" # Powerful Mode Time CONF_TOP18 = "top18" # Quiet Mode Level @@ -75,11 +75,13 @@ PanasonicHeatpumpTextSensor = panasonic_heatpump_ns.class_("PanasonicHeatpumpTex CONFIG_SCHEMA = cv.Schema( { - cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id(PanasonicHeatpumpComponent), + cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id( + PanasonicHeatpumpComponent + ), cv.Optional(CONF_TOP4): text_sensor.text_sensor_schema( PanasonicHeatpumpTextSensor, - icon=ICON_OPERATING_MODE, + icon=ICON_OPERATION_MODE, ), cv.Optional(CONF_TOP17): text_sensor.text_sensor_schema( PanasonicHeatpumpTextSensor, @@ -161,10 +163,11 @@ CONFIG_SCHEMA = cv.Schema( ).extend(cv.COMPONENT_SCHEMA) async def to_code(config): - hub = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) - for key in TYPES: + parent = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) + for index, key in enumerate(TYPES): if child_config := config.get(key): var = await text_sensor.new_text_sensor(child_config) await cg.register_component(var, child_config) - await cg.register_parented(var, config[CONF_PANASONIC_HEATPUMP_ID]) - cg.add(getattr(hub, f"set_{key}_text_sensor")(var)) + cg.add(var.set_parent(parent)) + cg.add(var.set_id(index)) + cg.add(parent.add_text_sensor(var)) diff --git a/components/panasonic_heatpump/text_sensor/panasonic_heatpump_text_sensor.cpp b/components/panasonic_heatpump/text_sensor/panasonic_heatpump_text_sensor.cpp index 016838b..18dcd0d 100644 --- a/components/panasonic_heatpump/text_sensor/panasonic_heatpump_text_sensor.cpp +++ b/components/panasonic_heatpump/text_sensor/panasonic_heatpump_text_sensor.cpp @@ -1,5 +1,4 @@ #include "panasonic_heatpump_text_sensor.h" -#include "esphome/core/log.h" namespace esphome @@ -13,5 +12,144 @@ namespace esphome LOG_TEXT_SENSOR("", "Panasonic Heatpump Text Sensor", this); delay(10); } + + void PanasonicHeatpumpTextSensor::publish_new_state(const std::vector& data) + { + if (data.empty()) return; + + std::string new_state; + switch (this->id_) + { + case TextSensorIds::CONF_TOP4: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::OperationMode, PanasonicDecode::getOperationMode(data[6])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP17: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::PowerfulMode, PanasonicDecode::getBit6and7and8(data[7])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP18: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::QuietMode, PanasonicDecode::getBit3and4and5(data[7])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP19: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::HolidayState, PanasonicDecode::getBit3and4(data[5])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP20: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ThreeWayValve, PanasonicDecode::getBit7and8(data[111])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP44: + { + new_state = PanasonicDecode::getErrorInfo(data[113], data[114]); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP58: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::BlockedFree, PanasonicDecode::getBit5and6(data[9])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP59: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::BlockedFree, PanasonicDecode::getBit7and8(data[9])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP76: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::WaterTempControl, PanasonicDecode::getBit7and8(data[28])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP81: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::WaterTempControl, PanasonicDecode::getBit5and6(data[28])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP92: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ModelNames, PanasonicDecode::getModel(data, 129)); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP94: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ZoneState, PanasonicDecode::getBit1and2(data[6])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP101: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::SolarMode, PanasonicDecode::getBit3and4(data[24])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP106: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::PumpFlowRateMode, PanasonicDecode::getBit3and4(data[29])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP107: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::LiquidType, PanasonicDecode::getBit1(data[20])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP111: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ZoneSensorType, PanasonicDecode::getLowNibbleMinus1(data[22])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP112: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ZoneSensorType, PanasonicDecode::getHighNibbleMinus1(data[22])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP114: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ExtPadHeaterType, PanasonicDecode::getBit3and4(data[25])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP125: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::TwoWayValve, PanasonicDecode::getBit5and6(data[116])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP126: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::ThreeWayValve, PanasonicDecode::getBit7and8(data[116])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + case TextSensorIds::CONF_TOP130: + { + new_state = PanasonicDecode::getTextState(PanasonicDecode::BivalentMode, PanasonicDecode::getBit5and6(data[26])); + if (this->has_state() && this->get_state() == new_state) return; + break; + } + default: return; + }; + + this->publish_state(new_state); + } } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/text_sensor/panasonic_heatpump_text_sensor.h b/components/panasonic_heatpump/text_sensor/panasonic_heatpump_text_sensor.h index 164d7eb..4f595b3 100644 --- a/components/panasonic_heatpump/text_sensor/panasonic_heatpump_text_sensor.h +++ b/components/panasonic_heatpump/text_sensor/panasonic_heatpump_text_sensor.h @@ -1,18 +1,46 @@ #pragma once -#include "esphome/components/text_sensor/text_sensor.h" #include "esphome/core/component.h" +#include "esphome/components/text_sensor/text_sensor.h" #include "../panasonic_heatpump.h" +#include "../decode.h" namespace esphome { namespace panasonic_heatpump { - class PanasonicHeatpumpTextSensor : public text_sensor::TextSensor, public Component, public Parented + enum TextSensorIds : uint8_t + { + CONF_TOP4, + CONF_TOP17, + CONF_TOP18, + CONF_TOP19, + CONF_TOP20, + CONF_TOP44, + CONF_TOP58, + CONF_TOP59, + CONF_TOP76, + CONF_TOP81, + CONF_TOP92, + CONF_TOP94, + CONF_TOP101, + CONF_TOP106, + CONF_TOP107, + CONF_TOP111, + CONF_TOP112, + CONF_TOP114, + CONF_TOP125, + CONF_TOP126, + CONF_TOP130, + }; + + class PanasonicHeatpumpTextSensor : public text_sensor::TextSensor, public Component, + public Parented, public PanasonicHeatpumpEntity { public: PanasonicHeatpumpTextSensor() = default; void dump_config() override; + void publish_new_state(const std::vector& data) override; }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/prototypes/panasonic_heatpump/decode.cpp b/prototypes/panasonic_heatpump/decode_proto.cpp similarity index 99% rename from prototypes/panasonic_heatpump/decode.cpp rename to prototypes/panasonic_heatpump/decode_proto.cpp index 4c4436c..e13775d 100644 --- a/prototypes/panasonic_heatpump/decode.cpp +++ b/prototypes/panasonic_heatpump/decode_proto.cpp @@ -1,4 +1,4 @@ -#include "decode.h" +#include "decode_proto.h" int getBit1(uint8_t input) { @@ -179,7 +179,7 @@ float getPumpFlow(uint8_t input1, uint8_t input2) int PumpFlow2 = (int)input2; float PumpFlow1 = (((float)input1 - 1) / 256); float PumpFlow = PumpFlow2 + PumpFlow1; - + return PumpFlow; } @@ -189,7 +189,7 @@ float getFractional(uint8_t input, uint8_t shift) float result; int fractional = (int)((input >> shift) & 0b111) - 1; result = fractional * 0.25; - + return result; } diff --git a/prototypes/panasonic_heatpump/decode.h b/prototypes/panasonic_heatpump/decode_proto.h similarity index 97% rename from prototypes/panasonic_heatpump/decode.h rename to prototypes/panasonic_heatpump/decode_proto.h index 750d5eb..6eb48da 100644 --- a/prototypes/panasonic_heatpump/decode.h +++ b/prototypes/panasonic_heatpump/decode_proto.h @@ -5,11 +5,11 @@ #include #include -#define NUMBER_OF_MODELS 51 -#define NUMBER_OF_TOPICS 127 -#define NUMBER_OF_TOPICS_EXTRA 6 -#define NUMBER_OF_OPT_TOPICS 7 -#define MAX_TOPIC_LEN 42 +#define NUMBER_OF_MODELS_PROTO 51 +#define NUMBER_OF_TOPICS_PROTO 127 +#define NUMBER_OF_TOPICS_EXTRA_PROTO 6 +#define NUMBER_OF_OPT_TOPICS_PROTO 7 +#define MAX_TOPIC_LEN_PROTO 42 int getBit1(uint8_t input); int getBit1and2(uint8_t input); @@ -117,7 +117,7 @@ static const char *ModelNames[] = }; // stores the bytes #129 to #138 of known models in the same order as the ModelNames above -static const uint8_t KnownModels[NUMBER_OF_MODELS][10] = +static const uint8_t KnownModels[NUMBER_OF_MODELS_PROTO][10] = { 0xE2, 0xCF, 0x0B, 0x13, 0x33, 0x32, 0xD1, 0x0C, 0x16, 0x33, //0 0xE2, 0xCF, 0x0B, 0x14, 0x33, 0x42, 0xD1, 0x0B, 0x17, 0x33, //1 diff --git a/prototypes/panasonic_heatpump/heishamon_decode.xlsx b/prototypes/panasonic_heatpump/heishamon_decode.xlsx index afba72f..359ddba 100644 Binary files a/prototypes/panasonic_heatpump/heishamon_decode.xlsx and b/prototypes/panasonic_heatpump/heishamon_decode.xlsx differ