diff --git a/components/panasonic_heatpump/button/__init__.py b/components/panasonic_heatpump/button/__init__.py new file mode 100644 index 0000000..f723e77 --- /dev/null +++ b/components/panasonic_heatpump/button/__init__.py @@ -0,0 +1,37 @@ +import esphome.codegen as cg +import esphome.config_validation as cv +from esphome.components import button +from esphome.const import ( + ENTITY_CATEGORY_CONFIG, +) +from .. import CONF_PANASONIC_HEATPUMP_ID, PanasonicHeatpumpComponent, panasonic_heatpump_ns + + +CONF_RESET = "reset" + +TYPES = [ + CONF_RESET, +] + +PanasonicHeatpumpButton = panasonic_heatpump_ns.class_("PanasonicHeatpumpButton", button.Button) + +CONFIG_SCHEMA = cv.Schema( + { + cv.GenerateID(CONF_PANASONIC_HEATPUMP_ID): cv.use_id(PanasonicHeatpumpComponent), + + cv.Optional(CONF_RESET): button.button_schema( + PanasonicHeatpumpButton, + ), + } +) + +async def to_code(config): + hub = await cg.get_variable(config[CONF_PANASONIC_HEATPUMP_ID]) + for key in TYPES: + await setup_conf(config, key, hub) + +async def setup_conf(parent_config, key, hub): + if child_config := parent_config.get(key): + var = await button.new_button(child_config) + await cg.register_parented(var, parent_config[CONF_PANASONIC_HEATPUMP_ID]) + cg.add(getattr(hub, f"set_{key}_button")(var)) diff --git a/components/panasonic_heatpump/button/panasonic_heatpump_button.cpp b/components/panasonic_heatpump/button/panasonic_heatpump_button.cpp new file mode 100644 index 0000000..b3c429b --- /dev/null +++ b/components/panasonic_heatpump/button/panasonic_heatpump_button.cpp @@ -0,0 +1,13 @@ +#include "panasonic_heatpump_button.h" + + +namespace esphome +{ + namespace panasonic_heatpump + { + void PanasonicHeatpumpButton::press_action() + { + this->parent_->button_press_action(this); + } + } // namespace panasonic_heatpump +} // namespace esphome diff --git a/components/panasonic_heatpump/button/panasonic_heatpump_button.h b/components/panasonic_heatpump/button/panasonic_heatpump_button.h new file mode 100644 index 0000000..4f3128b --- /dev/null +++ b/components/panasonic_heatpump/button/panasonic_heatpump_button.h @@ -0,0 +1,19 @@ +#pragma once +#include "esphome/components/button/button.h" +#include "../panasonic_heatpump.h" + + +namespace esphome +{ + namespace panasonic_heatpump + { + class PanasonicHeatpumpButton : public button::Button, public Parented + { + public: + PanasonicHeatpumpButton() = default; + + protected: + void press_action() override; + }; + } // namespace panasonic_heatpump +} // namespace esphome diff --git a/components/panasonic_heatpump/commands.cpp b/components/panasonic_heatpump/commands.cpp index 90a0894..d6e9d49 100644 --- a/components/panasonic_heatpump/commands.cpp +++ b/components/panasonic_heatpump/commands.cpp @@ -1,85 +1,21 @@ #include "commands.h" -#define REQUEST_DATA_SIZE 111 -#define REQUEST_INITIAL_SIZE 8 -#define REQUEST_OPTIONAL_SIZE 20 - -#define OPTIONALPCBQUERYTIME 1000 // send optional pcb query each second -#define OPTIONALPCBSAVETIME 300 // save each 5 minutes the current optional pcb state into flash to have valid values during reboot - namespace esphome { namespace panasonic_heatpump { - // ToDo: Use vector instead of byte[] - static uint8_t temp_command[REQUEST_DATA_SIZE] = { 0 }; - static uint8_t temp_command_optional[REQUEST_OPTIONAL_SIZE] = { - 0xF1, 0x11, 0x01, 0x50, 0x00, 0x00, 0x40, 0xFF, 0xFF, 0xE5, 0xFF, 0xFF, 0x00, 0xFF, 0xEB, - 0xFF, 0xFF, 0x00, 0x00, 0x00 - }; - - static const uint8_t InitialRequest[REQUEST_INITIAL_SIZE] = { - 0x31, 0x05, 0x10, 0x01, 0x00, 0x00, 0x00, 0xB9 - }; - static const uint8_t PeriodicalRequest[REQUEST_DATA_SIZE] = { - 0x71, 0x6C, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x12 - }; - static const uint8_t CommandRequest[REQUEST_DATA_SIZE] = { - 0xF1, 0x6C, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x92 - }; - - - std::vector PanasonicCommand::setCommand(uint8_t index, uint8_t newValue) + uint8_t PanasonicCommand::calcChecksum(std::vector& data, int length) { - // initialize the command - memcpy(temp_command, CommandRequest, sizeof(CommandRequest)); - // set command byte - temp_command[index] = newValue; - // calculate and set set checksum - temp_command[REQUEST_DATA_SIZE - 1] = calcChecksum(temp_command, REQUEST_DATA_SIZE - 1); - - // convert to vector and return - return std::vector(temp_command, temp_command + REQUEST_DATA_SIZE); - } - - std::vector PanasonicCommand::setOptionalCommand(uint8_t index, uint8_t newValue) - { - // set command byte - temp_command_optional[index] = newValue; - // calculate and set set checksum - temp_command_optional[REQUEST_OPTIONAL_SIZE - 1] = calcChecksum(temp_command_optional, REQUEST_OPTIONAL_SIZE - 1); - - // convert to vector and return - return std::vector(temp_command_optional, temp_command_optional + REQUEST_OPTIONAL_SIZE); - } - - uint8_t PanasonicCommand::calcChecksum(uint8_t *command, int length) - { - uint8_t chk = 0; + uint8_t checksum = 0; for (int i = 0; i < length; i++) { - chk += command[i]; + checksum += data[i]; } - chk = (chk ^ 0xFF) + 01; - return chk; + checksum = (checksum ^ 0xFF) + 01; + return checksum; } - uint8_t PanasonicCommand::setMultiply2(unsigned int input) { return input * 2; @@ -182,9 +118,9 @@ namespace esphome return hextemp; } - uint8_t PanasonicCommand::setByte6(int val, int base, int bit) + uint8_t PanasonicCommand::setByte6(uint8_t byte6, int val, int base, int bit) { - return (temp_command_optional[6] & ~(base << bit)) | (val << bit); + return (byte6 & ~(base << bit)) | (val << bit); } uint8_t PanasonicCommand::setDemandControl(unsigned int input) @@ -199,20 +135,5 @@ namespace esphome } return 0; } - - std::string PanasonicCommand::toHexString(std::vector &data) - { - char cmdArr[400]; - - //ESP_LOGD("custom", "############ CMD: %s", to_hex_string(vec, REQUEST_DATA_SIZE)); - for (int i = 0; i < 10; i++) - { - if (i == 0) sprintf(cmdArr, "0x"); - if (i > 0) sprintf(cmdArr, "%s-", cmdArr); - sprintf(cmdArr, "%s-%02X", cmdArr, data[i]); - } - std::string cmdStr = cmdArr; - return cmdStr; - } } // namespace panasonic_heatpump } // namespace esphome \ No newline at end of file diff --git a/components/panasonic_heatpump/commands.h b/components/panasonic_heatpump/commands.h index 5ddf30f..5b07971 100644 --- a/components/panasonic_heatpump/commands.h +++ b/components/panasonic_heatpump/commands.h @@ -1,13 +1,10 @@ #pragma once -#include -#include -#include #include -#include -#include #include -#include -#include + +#define REQUEST_INITIAL_SIZE 8 +#define REQUEST_DATA_SIZE 111 +#define REQUEST_OPTIONAL_SIZE 20 namespace esphome @@ -19,9 +16,7 @@ namespace esphome public: PanasonicCommand() = delete; - static std::vector setCommand(uint8_t index, uint8_t newValue); - static std::vector setOptionalCommand(uint8_t index, uint8_t newValue); - static uint8_t calcChecksum(uint8_t *command, int length); + static uint8_t calcChecksum(std::vector& data, int length); static uint8_t setMultiply2(unsigned int input); static uint8_t setMultiply4(unsigned int input); static uint8_t setPlus1Multiply4(unsigned int input); @@ -34,9 +29,32 @@ namespace esphome static uint8_t setOperationMode(unsigned int input); static uint8_t setBivalentMode(unsigned int input); static uint8_t temp2hex(float temp); - static uint8_t setByte6(int val, int base, int bit); + static uint8_t setByte6(uint8_t byte6, int val, int base, int bit); static uint8_t setDemandControl(unsigned int input); - static std::string toHexString(std::vector &data); + + static constexpr uint8_t InitialMessage[REQUEST_INITIAL_SIZE] = { + 0x31, 0x05, 0x10, 0x01, 0x00, 0x00, 0x00, 0xB9 + }; + static constexpr uint8_t PeriodicalMessage[REQUEST_DATA_SIZE] = { + 0x71, 0x6C, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x12 + }; + static constexpr uint8_t CommandMessage[REQUEST_DATA_SIZE] = { + 0xF1, 0x6C, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x92 + }; }; } // namespace panasonic_heatpump } // namespace esphome diff --git a/components/panasonic_heatpump/decode.h b/components/panasonic_heatpump/decode.h index 80131da..d9d7887 100644 --- a/components/panasonic_heatpump/decode.h +++ b/components/panasonic_heatpump/decode.h @@ -1,6 +1,4 @@ #pragma once -#include -#include #include #include #include diff --git a/components/panasonic_heatpump/number/__init__.py b/components/panasonic_heatpump/number/__init__.py index d6139c0..e1eca6b 100644 --- a/components/panasonic_heatpump/number/__init__.py +++ b/components/panasonic_heatpump/number/__init__.py @@ -8,38 +8,38 @@ from esphome.const import ( from .. import CONF_PANASONIC_HEATPUMP_ID, PanasonicHeatpumpComponent, panasonic_heatpump_ns -CONF_SET_Z1_HEAT_REQUEST_TEMPERATURE = "set_z1_heat_request_temperature" -CONF_SET_Z1_COOL_REQUEST_TEMPERATURE = "set_z1_cool_request_temperature" -CONF_SET_Z2_HEAT_REQUEST_TEMPERATURE = "set_z2_heat_request_temperature" -CONF_SET_Z2_COOL_REQUEST_TEMPERATURE = "set_z2_cool_request_temperature" -CONF_SET_DHW_TEMP = "set_DHW_temp" -CONF_SET_MAX_PUMP_DUTY = "set_max_pump_duty" -CONF_SET_ZONE1_HEAT_TARGET_HIGH = "set_zone1_heat_target_high" -CONF_SET_ZONE1_HEAT_TARGET_LOW = "set_zone1_heat_target_low" -CONF_SET_ZONE1_HEAT_OUTSIDE_LOW = "set_zone1_heat_outside_low" -CONF_SET_ZONE1_HEAT_OUTSIDE_HIGH = "set_zone1_heat_outside_high" -CONF_SET_ZONE2_HEAT_TARGET_HIGH = "set_zone2_heat_target_high" -CONF_SET_ZONE2_HEAT_TARGET_LOW = "set_zone2_heat_target_low" -CONF_SET_ZONE2_HEAT_OUTSIDE_LOW = "set_zone2_heat_outside_low" -CONF_SET_ZONE2_HEAT_OUTSIDE_HIGH = "set_zone2_heat_outside_high" -CONF_SET_ZONE1_COOL_TARGET_HIGH = "set_zone1_cool_target_high" -CONF_SET_ZONE1_COOL_TARGET_LOW = "set_zone1_cool_target_low" -CONF_SET_ZONE1_COOL_OUTSIDE_LOW = "set_zone1_cool_outside_low" -CONF_SET_ZONE1_COOL_OUTSIDE_HIGH = "set_zone1_cool_outside_high" -CONF_SET_ZONE2_COOL_TARGET_HIGH = "set_zone2_cool_target_high" -CONF_SET_ZONE2_COOL_TARGET_LOW = "set_zone2_cool_target_low" -CONF_SET_ZONE2_COOL_OUTSIDE_LOW = "set_zone2_cool_outside_low" -CONF_SET_ZONE2_COOL_OUTSIDE_HIGH = "set_zone2_cool_outside_high" -CONF_SET_FLOOR_HEAT_DELTA = "set_floor_heat_delta" -CONF_SET_FLOOR_COOL_DELTA = "set_floor_cool_delta" -CONF_SET_DHW_HEAT_DELTA = "set_dhw_heat_delta" -CONF_SET_HEATER_DELAY_TIME = "set_heater_delay_time" -CONF_SET_HEATER_START_DELTA = "set_heater_start_delta" -CONF_SET_HEATER_STOP_DELTA = "set_heater_stop_delta" -CONF_SET_BUFFER_DELTA = "set_buffer_delta" -CONF_SET_HEATINGOFFOUTDOORTEMP = "set_heatingoffoutdoortemp" -CONF_SET_BIVALENT_START_TEMPERATURE = "set_bivalent_start_temperature" -CONF_SET_BIVALENT_STOP_TEMPERATURE = "set_bivalent_stop_temperature" +CONF_SET_Z1_HEAT_REQUEST_TEMPERATURE = "z1_heat_request_temperature" +CONF_SET_Z1_COOL_REQUEST_TEMPERATURE = "z1_cool_request_temperature" +CONF_SET_Z2_HEAT_REQUEST_TEMPERATURE = "z2_heat_request_temperature" +CONF_SET_Z2_COOL_REQUEST_TEMPERATURE = "z2_cool_request_temperature" +CONF_SET_DHW_TEMP = "dhw_temp" +CONF_SET_MAX_PUMP_DUTY = "max_pump_duty" +CONF_SET_ZONE1_HEAT_TARGET_HIGH = "zone1_heat_target_high" +CONF_SET_ZONE1_HEAT_TARGET_LOW = "zone1_heat_target_low" +CONF_SET_ZONE1_HEAT_OUTSIDE_LOW = "zone1_heat_outside_low" +CONF_SET_ZONE1_HEAT_OUTSIDE_HIGH = "zone1_heat_outside_high" +CONF_SET_ZONE2_HEAT_TARGET_HIGH = "zone2_heat_target_high" +CONF_SET_ZONE2_HEAT_TARGET_LOW = "zone2_heat_target_low" +CONF_SET_ZONE2_HEAT_OUTSIDE_LOW = "zone2_heat_outside_low" +CONF_SET_ZONE2_HEAT_OUTSIDE_HIGH = "zone2_heat_outside_high" +CONF_SET_ZONE1_COOL_TARGET_HIGH = "zone1_cool_target_high" +CONF_SET_ZONE1_COOL_TARGET_LOW = "zone1_cool_target_low" +CONF_SET_ZONE1_COOL_OUTSIDE_LOW = "zone1_cool_outside_low" +CONF_SET_ZONE1_COOL_OUTSIDE_HIGH = "zone1_cool_outside_high" +CONF_SET_ZONE2_COOL_TARGET_HIGH = "zone2_cool_target_high" +CONF_SET_ZONE2_COOL_TARGET_LOW = "zone2_cool_target_low" +CONF_SET_ZONE2_COOL_OUTSIDE_LOW = "zone2_cool_outside_low" +CONF_SET_ZONE2_COOL_OUTSIDE_HIGH = "zone2_cool_outside_high" +CONF_SET_FLOOR_HEAT_DELTA = "floor_heat_delta" +CONF_SET_FLOOR_COOL_DELTA = "floor_cool_delta" +CONF_SET_DHW_HEAT_DELTA = "dhw_heat_delta" +CONF_SET_HEATER_DELAY_TIME = "heater_delay_time" +CONF_SET_HEATER_START_DELTA = "heater_start_delta" +CONF_SET_HEATER_STOP_DELTA = "heater_stop_delta" +CONF_SET_BUFFER_DELTA = "buffer_delta" +CONF_SET_HEATINGOFFOUTDOORTEMP = "heatingoffoutdoortemp" +CONF_SET_BIVALENT_START_TEMPERATURE = "bivalent_start_temperature" +CONF_SET_BIVALENT_STOP_TEMPERATURE = "bivalent_stop_temperature" TYPES = [ CONF_SET_Z1_HEAT_REQUEST_TEMPERATURE, diff --git a/components/panasonic_heatpump/panasonic_heatpump.cpp b/components/panasonic_heatpump/panasonic_heatpump.cpp index 78adb55..08f75a2 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.cpp +++ b/components/panasonic_heatpump/panasonic_heatpump.cpp @@ -1,7 +1,7 @@ #include "panasonic_heatpump.h" -#define RESPONSE_DATA_SIZE 203 -#define REQUEST_DATA_SIZE 111 +#define response_message_SIZE 203 +#define request_message_SIZE 111 namespace esphome @@ -145,6 +145,63 @@ namespace esphome LOG_TEXT_SENSOR("", "Panasonic Heatpump TextSensor", this->top112_text_sensor_); LOG_TEXT_SENSOR("", "Panasonic Heatpump TextSensor", this->top114_text_sensor_); LOG_TEXT_SENSOR("", "Panasonic Heatpump TextSensor", this->top124_text_sensor_); +#endif +#ifdef USE_BUTTON + LOG_BUTTON("", "Panasonic Heatpump Button", this->reset_button_); +#endif +#ifdef USE_NUMBER + LOG_NUMBER("", "Panasonic Heatpump Number", this->z1_heat_request_temperature_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->z1_cool_request_temperature_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->z2_heat_request_temperature_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->z2_cool_request_temperature_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->dhw_temp_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->max_pump_duty_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone1_heat_target_high_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone1_heat_target_low_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone1_heat_outside_low_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone1_heat_outside_high_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone2_heat_target_high_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone2_heat_target_low_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone2_heat_outside_low_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone2_heat_outside_high_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone1_cool_target_high_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone1_cool_target_low_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone1_cool_outside_low_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone1_cool_outside_high_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone2_cool_target_high_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone2_cool_target_low_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone2_cool_outside_low_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->zone2_cool_outside_high_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->floor_heat_delta_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->floor_cool_delta_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->dhw_heat_delta_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->heater_delay_time_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->heater_start_delta_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->heater_stop_delta_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->buffer_delta_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->heatingoffoutdoortemp_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->bivalent_start_temperature_number_); + LOG_NUMBER("", "Panasonic Heatpump Number", this->bivalent_stop_temperature_number_); +#endif +#ifdef USE_SELECT + LOG_SELECT("", "Panasonic Heatpump Select", this->quiet_mode_select_); + LOG_SELECT("", "Panasonic Heatpump Select", this->powerful_mode_select_); + LOG_SELECT("", "Panasonic Heatpump Select", this->operation_mode_select_); + LOG_SELECT("", "Panasonic Heatpump Select", this->zones_select_); + LOG_SELECT("", "Panasonic Heatpump Select", this->external_pad_heater_select_); + LOG_SELECT("", "Panasonic Heatpump Select", this->powerful_mode2_select_); + LOG_SELECT("", "Panasonic Heatpump Select", this->bivalent_mode_select_); +#endif +#ifdef USE_SWITCH + LOG_SWITCH("", "Panasonic Heatpump Switch", this->heatpump_state_switch_); + LOG_SWITCH("", "Panasonic Heatpump Switch", this->holiday_mode_switch_); + LOG_SWITCH("", "Panasonic Heatpump Switch", this->force_dhw_switch_); + LOG_SWITCH("", "Panasonic Heatpump Switch", this->force_defrost_switch_); + LOG_SWITCH("", "Panasonic Heatpump Switch", this->force_sterilization_switch_); + LOG_SWITCH("", "Panasonic Heatpump Switch", this->pump_switch_); + LOG_SWITCH("", "Panasonic Heatpump Switch", this->main_schedule_switch_); + LOG_SWITCH("", "Panasonic Heatpump Switch", this->alt_external_sensor_switch_); + LOG_SWITCH("", "Panasonic Heatpump Switch", this->buffer_switch_); #endif } @@ -166,35 +223,39 @@ namespace esphome this->response_receiving_ = true; } // Add current byte to message buffer - this->response_data_.push_back(byte_hp); + this->response_message_.push_back(byte_hp); // 2. bytes contains the payload size - if (this->response_data_.size() == 2) + if (this->response_message_.size() == 2) this->response_payload_length_ = byte_hp; // Discard message if 3. and 4. byte are not as expected - if (this->response_data_.size() == 3 && byte_hp != 0x01 || - this->response_data_.size() == 4 && byte_hp != 0x10) + if (this->response_message_.size() == 3 && byte_hp != 0x01 || + this->response_message_.size() == 4 && byte_hp != 0x10) { ESP_LOGW(TAG, "Invalid response message: %d. byte is 0x%02X but expexted is 0x%02X", - response_data_.size(), byte_hp, response_data_.size() == 3 ? "01" : "10"); + response_message_.size(), byte_hp, response_message_.size() == 3 ? "01" : "10"); delay(10); - this->response_data_.clear(); + this->response_message_.clear(); this->response_receiving_ = false; continue; } // Decode message if message is complete - if (this->response_data_.size() > 2 && this->response_data_.size() == this->response_payload_length_ + 3) + if (this->response_message_.size() > 2 && this->response_message_.size() == this->response_payload_length_ + 3) { - this->log_uart_hex("<<<", this->response_data_, ','); - this->decode_response(this->response_data_); - this->response_data_.clear(); + this->log_uart_hex("<<<", this->response_message_, ','); + this->decode_response(this->response_message_); + this->response_message_.clear(); this->response_receiving_ = false; } } while (this->uart_wm_->available()) { + // stop forwording messages if no message is currently processing + if (!this->forward_requests_ && !this->request_receiving_) + continue; + this->uart_wm_->read_byte(&byte_wm); this->uart_hp_->write_byte(byte_wm); @@ -206,28 +267,28 @@ namespace esphome this->request_receiving_ = true; } // Add current byte to message buffer - this->request_data_.push_back(byte_wm); + this->request_message_.push_back(byte_wm); // 2. bytes contains the payload size - if (this->request_data_.size() == 2) + if (this->request_message_.size() == 2) this->request_payload_length_ = byte_wm; // Discard message if 3. and 4. byte are not as expected - if (this->request_data_.size() == 3 && byte_wm != 0x01 || - this->request_data_.size() == 4 && byte_wm != 0x10) + if (this->request_message_.size() == 3 && byte_wm != 0x01 || + this->request_message_.size() == 4 && byte_wm != 0x10) { ESP_LOGW(TAG, "Invalid request message: %d. byte is 0x%02X but expexted is 0x%02X", - request_data_.size(), byte_wm, request_data_.size() == 3 ? "01" : "10"); + request_message_.size(), byte_wm, request_message_.size() == 3 ? "01" : "10"); delay(10); - this->request_data_.clear(); + this->request_message_.clear(); this->request_receiving_ = false; continue; } // Decode message if message is complete - if (this->request_data_.size() > 2 && this->request_data_.size() == this->request_payload_length_ + 3) + if (this->request_message_.size() > 2 && this->request_message_.size() == this->request_payload_length_ + 3) { - this->log_uart_hex(">>>", this->request_data_, ','); - this->request_data_.clear(); + this->log_uart_hex(">>>", this->request_message_, ','); + this->request_message_.clear(); this->request_receiving_ = false; } } @@ -240,9 +301,9 @@ namespace esphome // payload_length: payload_length + 3 = packet_length // checksum: if (sum(all bytes) & 0xFF == 0) ==> valid packet - if (bytes.size() != RESPONSE_DATA_SIZE) + if (bytes.size() != response_message_SIZE) { - ESP_LOGW(TAG, "Invalid response message length: recieved %d - expected %d", bytes.size(), RESPONSE_DATA_SIZE); + ESP_LOGW(TAG, "Invalid response message length: recieved %d - expected %d", bytes.size(), response_message_SIZE); delay(10); return; } @@ -395,9 +456,36 @@ namespace esphome #endif } - void PanasonicHeatpumpComponent::send_request() + void PanasonicHeatpumpComponent::send_initial_message() { + // send command + this->uart_hp_->write_array(PanasonicCommand::InitialMessage, REQUEST_INITIAL_SIZE); + this->log_uart_hex(">>>", this->command_message_, ','); + delay(100); // NOLINT + } + void PanasonicHeatpumpComponent::send_periodical_message() + { + // send command + this->uart_hp_->write_array(PanasonicCommand::PeriodicalMessage, REQUEST_DATA_SIZE); + this->log_uart_hex(">>>", this->command_message_, ','); + delay(100); // NOLINT + } + + void PanasonicHeatpumpComponent::send_command_message(uint8_t value, uint8_t index) + { + // initialize the command + command_message_.clear(); + command_message_.insert(this->command_message_.end(), PanasonicCommand::CommandMessage, + PanasonicCommand::CommandMessage + REQUEST_DATA_SIZE); + // set command byte + command_message_[index] = value; + // calculate and set set checksum (last element) + command_message_.back() = PanasonicCommand::calcChecksum(command_message_, command_message_.size() - 1); + // send command + this->uart_hp_->write_array(this->command_message_); + this->log_uart_hex(">>>", this->command_message_, ','); + delay(100); // NOLINT } void PanasonicHeatpumpComponent::log_uart_hex(std::string prefix, std::vector bytes, uint8_t separator) @@ -424,25 +512,77 @@ namespace esphome } } +#ifdef USE_BUTTON + void PanasonicHeatpumpComponent::button_press_action(button::Button* object) + { + // if (object == this->reset_button_) + // this->send_request(value, index); + } +#endif #ifdef USE_NUMBER void PanasonicHeatpumpComponent::number_control(number::Number* object, float value) { - // if (object == top0_number_) - // this->send_request(value); + // if (object == this->z1_heat_request_temperature_number_) + // this->send_request(value, index); + // else if (object == this->z1_cool_request_temperature_number_) + // else if (object == this->z2_heat_request_temperature_number_) + // else if (object == this->z2_cool_request_temperature_number_) + // else if (object == this->dhw_temp_number_) + // else if (object == this->max_pump_duty_number_) + // else if (object == this->zone1_heat_target_high_number_) + // else if (object == this->zone1_heat_target_low_number_) + // else if (object == this->zone1_heat_outside_low_number_) + // else if (object == this->zone1_heat_outside_high_number_) + // else if (object == this->zone2_heat_target_high_number_) + // else if (object == this->zone2_heat_target_low_number_) + // else if (object == this->zone2_heat_outside_low_number_) + // else if (object == this->zone2_heat_outside_high_number_) + // else if (object == this->zone1_cool_target_high_number_) + // else if (object == this->zone1_cool_target_low_number_) + // else if (object == this->zone1_cool_outside_low_number_) + // else if (object == this->zone1_cool_outside_high_number_) + // else if (object == this->zone2_cool_target_high_number_) + // else if (object == this->zone2_cool_target_low_number_) + // else if (object == this->zone2_cool_outside_low_number_) + // else if (object == this->zone2_cool_outside_high_number_) + // else if (object == this->floor_heat_delta_number_) + // else if (object == this->floor_cool_delta_number_) + // else if (object == this->dhw_heat_delta_number_) + // else if (object == this->heater_delay_time_number_) + // else if (object == this->heater_start_delta_number_) + // else if (object == this->heater_stop_delta_number_) + // else if (object == this->buffer_delta_number_) + // else if (object == this->heatingoffoutdoortemp_number_) + // else if (object == this->bivalent_start_temperature_number_) + // else if (object == this->bivalent_stop_temperature_number_) } #endif #ifdef USE_SELECT void PanasonicHeatpumpComponent::select_control(select::Select* object, const std::string &value) { - // if (object == top1_select_) - // this->send_request(value); + // if (object == this->quiet_mode_select_) + // this->send_request(value, index); + // else if (object == this->powerful_mode_select_) + // else if (object == this->operation_mode_select_) + // else if (object == this->zones_select_) + // else if (object == this->external_pad_heater_select_) + // else if (object == this->powerful_mode2_select_) + // else if (object == this->bivalent_mode_select_) } #endif #ifdef USE_SWITCH void PanasonicHeatpumpComponent::switch_control(switch::Switch* object, bool state) { - // if (object == top2_switch_) - // this->send_request(value); + // if (object == this->heatpump_state_switch_) + // this->send_request(value, index); + // else if (object == this->holiday_mode_switch_) + // else if (object == this->force_dhw_switch_) + // else if (object == this->force_defrost_switch_) + // else if (object == this->force_sterilization_switch_) + // else if (object == this->pump_switch_) + // else if (object == this->main_schedule_switch_) + // else if (object == this->alt_external_sensor_switch_) + // else if (object == this->buffer_switch_) } #endif } // namespace panasonic_heatpump diff --git a/components/panasonic_heatpump/panasonic_heatpump.h b/components/panasonic_heatpump/panasonic_heatpump.h index ca95b58..63e86df 100644 --- a/components/panasonic_heatpump/panasonic_heatpump.h +++ b/components/panasonic_heatpump/panasonic_heatpump.h @@ -13,6 +13,9 @@ #ifdef USE_TEXT_SENSOR #include "esphome/components/text_sensor/text_sensor.h" #endif +#ifdef USE_BUTTON +#include "esphome/components/button/button.h" +#endif #ifdef USE_NUMBER #include "esphome/components/number/number.h" #endif @@ -23,6 +26,7 @@ #include "esphome/components/switch/switch.h" #endif #include "decode.h" +#include "commands.h" #include #include @@ -167,14 +171,62 @@ namespace esphome SUB_TEXT_SENSOR(top114); SUB_TEXT_SENSOR(top124); #endif +#ifdef USE_BUTTON + SUB_BUTTON(reset); +#endif #ifdef USE_NUMBER - // SUB_NUMBER(top0); + SUB_NUMBER(z1_heat_request_temperature); + SUB_NUMBER(z1_cool_request_temperature); + SUB_NUMBER(z2_heat_request_temperature); + SUB_NUMBER(z2_cool_request_temperature); + SUB_NUMBER(dhw_temp); + SUB_NUMBER(max_pump_duty); + SUB_NUMBER(zone1_heat_target_high); + SUB_NUMBER(zone1_heat_target_low); + SUB_NUMBER(zone1_heat_outside_low); + SUB_NUMBER(zone1_heat_outside_high); + SUB_NUMBER(zone2_heat_target_high); + SUB_NUMBER(zone2_heat_target_low); + SUB_NUMBER(zone2_heat_outside_low); + SUB_NUMBER(zone2_heat_outside_high); + SUB_NUMBER(zone1_cool_target_high); + SUB_NUMBER(zone1_cool_target_low); + SUB_NUMBER(zone1_cool_outside_low); + SUB_NUMBER(zone1_cool_outside_high); + SUB_NUMBER(zone2_cool_target_high); + SUB_NUMBER(zone2_cool_target_low); + SUB_NUMBER(zone2_cool_outside_low); + SUB_NUMBER(zone2_cool_outside_high); + SUB_NUMBER(floor_heat_delta); + SUB_NUMBER(floor_cool_delta); + SUB_NUMBER(dhw_heat_delta); + SUB_NUMBER(heater_delay_time); + SUB_NUMBER(heater_start_delta); + SUB_NUMBER(heater_stop_delta); + SUB_NUMBER(buffer_delta); + SUB_NUMBER(heatingoffoutdoortemp); + SUB_NUMBER(bivalent_start_temperature); + SUB_NUMBER(bivalent_stop_temperature); #endif #ifdef USE_SELECT - // SUB_SELECT(top1); + SUB_SELECT(quiet_mode); + SUB_SELECT(powerful_mode); + SUB_SELECT(operation_mode); + SUB_SELECT(zones); + SUB_SELECT(external_pad_heater); + SUB_SELECT(powerful_mode2); + SUB_SELECT(bivalent_mode); #endif #ifdef USE_SWITCH - // SUB_SWITCH(top2); + SUB_SWITCH(heatpump_state); + SUB_SWITCH(holiday_mode); + SUB_SWITCH(force_dhw); + SUB_SWITCH(force_defrost); + SUB_SWITCH(force_sterilization); + SUB_SWITCH(pump); + SUB_SWITCH(main_schedule); + SUB_SWITCH(alt_external_sensor); + SUB_SWITCH(buffer); #endif PanasonicHeatpumpComponent() = default; @@ -184,6 +236,10 @@ namespace esphome void set_uart_hp(uart::UARTComponent *uart) { this->uart_hp_ = uart; } void set_uart_wm(uart::UARTComponent *uart) { this->uart_wm_ = uart; } + +#ifdef USE_BUTTON + void button_press_action(button::Button* object); +#endif #ifdef USE_NUMBER void number_control(number::Number* object, float value); #endif @@ -198,15 +254,19 @@ namespace esphome uart::UARTComponent *uart_hp_; uart::UARTComponent *uart_wm_; - std::vector response_data_; - std::vector request_data_; + std::vector response_message_; + std::vector request_message_; + std::vector command_message_; uint8_t response_payload_length_; uint8_t request_payload_length_; bool response_receiving_{false}; bool request_receiving_{false}; + bool forward_requests_{true}; void decode_response(std::vector data); - void send_request(); + void send_initial_message(); + void send_periodical_message(); + void send_command_message(uint8_t value, uint8_t index); void log_uart_hex(std::string prefix, std::vector bytes, uint8_t separator); }; } // namespace panasonic_heatpump diff --git a/components/panasonic_heatpump/select/__init__.py b/components/panasonic_heatpump/select/__init__.py index 3b641f4..37686d8 100644 --- a/components/panasonic_heatpump/select/__init__.py +++ b/components/panasonic_heatpump/select/__init__.py @@ -7,13 +7,13 @@ from esphome.const import ( from .. import CONF_PANASONIC_HEATPUMP_ID, PanasonicHeatpumpComponent, panasonic_heatpump_ns -CONF_SET_QUIET_MODE = "set_quiet_mode" -CONF_SET_POWERFUL_MODE = "set_powerful_mode" -CONF_SET_OPERATION_MODE = "set_operation_mode" -CONF_SET_ZONES = "set_zones" -CONF_SET_EXTERNAL_PAD_HEATER = "set_external_pad_heater" -CONF_SET_POWERFUL_MODE = "set_powerful_mode" -CONF_SET_BIVALENT_MODE = "set_bivalent_mode" +CONF_SET_QUIET_MODE = "quiet_mode" +CONF_SET_POWERFUL_MODE = "powerful_mode" +CONF_SET_OPERATION_MODE = "operation_mode" +CONF_SET_ZONES = "zones" +CONF_SET_EXTERNAL_PAD_HEATER = "external_pad_heater" +CONF_SET_POWERFUL_MODE2 = "powerful_mode2" +CONF_SET_BIVALENT_MODE = "bivalent_mode" TYPES = [ CONF_SET_QUIET_MODE, @@ -21,7 +21,7 @@ TYPES = [ CONF_SET_OPERATION_MODE, CONF_SET_ZONES, CONF_SET_EXTERNAL_PAD_HEATER, - CONF_SET_POWERFUL_MODE, + CONF_SET_POWERFUL_MODE2, CONF_SET_BIVALENT_MODE, ] @@ -46,7 +46,7 @@ CONFIG_SCHEMA = cv.Schema( cv.Optional(CONF_SET_EXTERNAL_PAD_HEATER): select.select_schema( PanasonicHeatpumpSelect, ), - cv.Optional(CONF_SET_POWERFUL_MODE): select.select_schema( + cv.Optional(CONF_SET_POWERFUL_MODE2): select.select_schema( PanasonicHeatpumpSelect, ), cv.Optional(CONF_SET_BIVALENT_MODE): select.select_schema( diff --git a/components/panasonic_heatpump/switch/__init__.py b/components/panasonic_heatpump/switch/__init__.py index 8d1b9dc..29136c8 100644 --- a/components/panasonic_heatpump/switch/__init__.py +++ b/components/panasonic_heatpump/switch/__init__.py @@ -7,15 +7,15 @@ from esphome.const import ( from .. import CONF_PANASONIC_HEATPUMP_ID, PanasonicHeatpumpComponent, panasonic_heatpump_ns -CONF_SET_HEATPUMP_STATE = "set_heatpump_state" -CONF_SET_HOLIDAY_MODE = "set_holiday_mode" -CONF_SET_FORCE_DHW = "set_force_DHW" -CONF_SET_FORCE_DEFROST = "set_force_defrost" -CONF_SET_FORCE_STERILIZATION = "set_force_sterilization" -CONF_SET_PUMP = "set_pump" -CONF_SET_MAIN_SCHEDULE = "set_main_schedule" -CONF_SET_ALT_EXTERNAL_SENSOR = "set_alt_external_sensor" -CONF_SET_BUFFER = "set_buffer" +CONF_SET_HEATPUMP_STATE = "heatpump_state" +CONF_SET_HOLIDAY_MODE = "holiday_mode" +CONF_SET_FORCE_DHW = "force_dhw" +CONF_SET_FORCE_DEFROST = "force_defrost" +CONF_SET_FORCE_STERILIZATION = "force_sterilization" +CONF_SET_PUMP = "pump" +CONF_SET_MAIN_SCHEDULE = "main_schedule" +CONF_SET_ALT_EXTERNAL_SENSOR = "alt_external_sensor" +CONF_SET_BUFFER = "buffer" TYPES = [ CONF_SET_HEATPUMP_STATE,