diff --git a/.gitignore b/.gitignore index 078bf90..561654a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ venv/ builds/ *.py[cod] +.DS_Store \ No newline at end of file diff --git a/ac.yaml.example b/ac.yaml.example index 454dcf2..7ccfc72 100644 --- a/ac.yaml.example +++ b/ac.yaml.example @@ -46,6 +46,8 @@ climate: # Enable as needed # eco_switch: # name: Panasonic AC Eco Switch + # econavi_switch: + # name: Panasonic AC Econavi Switch # nanoex_switch: # name: Panasonic AC NanoeX Switch # mild_dry_switch: diff --git a/components/panasonic_ac/climate.py b/components/panasonic_ac/climate.py index 3906a2d..d6a0b09 100644 --- a/components/panasonic_ac/climate.py +++ b/components/panasonic_ac/climate.py @@ -34,6 +34,7 @@ CONF_CURRENT_TEMPERATURE_SENSOR = "current_temperature_sensor" CONF_NANOEX_SWITCH = "nanoex_switch" CONF_ECO_SWITCH = "eco_switch" +CONF_ECONAVI_SWITCH = "econavi_switch" CONF_MILD_DRY_SWITCH = "mild_dry_switch" CONF_WLAN = "wlan" CONF_CNT = "cnt" @@ -82,6 +83,7 @@ { cv.GenerateID(): cv.declare_id(PanasonicACCNT), cv.Optional(CONF_ECO_SWITCH): SWITCH_SCHEMA, + cv.Optional(CONF_ECONAVI_SWITCH): SWITCH_SCHEMA, cv.Optional(CONF_MILD_DRY_SWITCH): SWITCH_SCHEMA, cv.Optional(CONF_CURRENT_TEMPERATURE_SENSOR): cv.use_id(sensor.Sensor), } @@ -112,7 +114,7 @@ async def to_code(config): sens = await sensor.new_sensor(config[CONF_OUTSIDE_TEMPERATURE]) cg.add(var.set_outside_temperature_sensor(sens)) - for s in [CONF_ECO_SWITCH, CONF_NANOEX_SWITCH, CONF_MILD_DRY_SWITCH]: + for s in [CONF_ECO_SWITCH, CONF_NANOEX_SWITCH, CONF_MILD_DRY_SWITCH, CONF_ECONAVI_SWITCH]: if s in config: conf = config[s] a_switch = cg.new_Pvariable(conf[CONF_ID]) diff --git a/components/panasonic_ac/esppac.cpp b/components/panasonic_ac/esppac.cpp index 4530fda..35e1b27 100644 --- a/components/panasonic_ac/esppac.cpp +++ b/components/panasonic_ac/esppac.cpp @@ -121,6 +121,13 @@ void PanasonicAC::update_eco(bool eco) { } } +void PanasonicAC::update_econavi(bool econavi) { + if (this->econavi_switch_ != nullptr) { + this->econavi_state_ = econavi; + this->econavi_switch_->publish_state(this->econavi_state_); + } +} + void PanasonicAC::update_mild_dry(bool mild_dry) { if (this->mild_dry_switch_ != nullptr) { this->mild_dry_state_ = mild_dry; @@ -200,6 +207,15 @@ void PanasonicAC::set_eco_switch(switch_::Switch *eco_switch) { }); } +void PanasonicAC::set_econavi_switch(switch_::Switch *econavi_switch) { + this->econavi_switch_ = econavi_switch; + this->econavi_switch_->add_on_state_callback([this](bool state) { + if (state == this->econavi_state_) + return; + this->on_econavi_change(state); + }); +} + void PanasonicAC::set_mild_dry_switch(switch_::Switch *mild_dry_switch) { this->mild_dry_switch_ = mild_dry_switch; this->mild_dry_switch_->add_on_state_callback([this](bool state) { diff --git a/components/panasonic_ac/esppac.h b/components/panasonic_ac/esppac.h index 3cb5a42..bc25850 100644 --- a/components/panasonic_ac/esppac.h +++ b/components/panasonic_ac/esppac.h @@ -11,7 +11,7 @@ namespace esphome { namespace panasonic_ac { -static const char *const VERSION = "2.0.0"; +static const char *const VERSION = "2.1.0"; static const uint8_t BUFFER_SIZE = 128; // The maximum size of a single packet (both receive and transmit) static const uint8_t READ_TIMEOUT = 20; // The maximum time to wait before considering a packet complete @@ -37,6 +37,7 @@ class PanasonicAC : public Component, public uart::UARTDevice, public climate::C void set_horizontal_swing_select(select::Select *horizontal_swing_select); void set_nanoex_switch(switch_::Switch *nanoex_switch); void set_eco_switch(switch_::Switch *eco_switch); + void set_econavi_switch(switch_::Switch *econavi_switch); void set_mild_dry_switch(switch_::Switch *mild_dry_switch); void set_current_temperature_sensor(sensor::Sensor *current_temperature_sensor); @@ -50,6 +51,7 @@ class PanasonicAC : public Component, public uart::UARTDevice, public climate::C select::Select *horizontal_swing_select_ = nullptr; // Select to store manual position of horizontal swing switch_::Switch *nanoex_switch_ = nullptr; // Switch to toggle nanoeX on/off switch_::Switch *eco_switch_ = nullptr; // Switch to toggle eco mode on/off + switch_::Switch *econavi_switch_ = nullptr; // Switch to toggle econavi mode on/off switch_::Switch *mild_dry_switch_ = nullptr; // Switch to toggle mild dry mode on/off sensor::Sensor *current_temperature_sensor_ = nullptr; // Sensor to use for current temperature where AC does not report @@ -58,6 +60,7 @@ class PanasonicAC : public Component, public uart::UARTDevice, public climate::C bool nanoex_state_ = false; // Stores the state of nanoex to prevent duplicate packets bool eco_state_ = false; // Stores the state of eco to prevent duplicate packets + bool econavi_state_ = false; // Stores the state of econavi to prevent duplicate packets bool mild_dry_state_ = false; // Stores the state of mild dry to prevent duplicate packets bool waiting_for_response_ = false; // Set to true if we are waiting for a response @@ -83,12 +86,14 @@ class PanasonicAC : public Component, public uart::UARTDevice, public climate::C void update_swing_vertical(const std::string &swing); void update_nanoex(bool nanoex); void update_eco(bool eco); + void update_econavi(bool econavi); void update_mild_dry(bool mild_dry); virtual void on_horizontal_swing_change(const std::string &swing) = 0; virtual void on_vertical_swing_change(const std::string &swing) = 0; virtual void on_nanoex_change(bool nanoex) = 0; virtual void on_eco_change(bool eco) = 0; + virtual void on_econavi_change(bool econavi) = 0; virtual void on_mild_dry_change(bool mild_dry) = 0; climate::ClimateAction determine_action(); diff --git a/components/panasonic_ac/esppac_cnt.cpp b/components/panasonic_ac/esppac_cnt.cpp index c187d02..c68e0e7 100644 --- a/components/panasonic_ac/esppac_cnt.cpp +++ b/components/panasonic_ac/esppac_cnt.cpp @@ -155,6 +155,7 @@ void PanasonicACCNT::set_data(bool set) { std::string preset = determine_preset(this->data[5]); bool nanoex = determine_preset_nanoex(this->data[5]); bool eco = determine_eco(this->data[8]); + bool econavi = determine_econavi(this->data[5]); bool mildDry = determine_mild_dry(this->data[2]); this->update_target_temperature((int8_t) this->data[1]); @@ -198,6 +199,7 @@ void PanasonicACCNT::set_data(bool set) { this->update_nanoex(nanoex); this->update_eco(eco); + this->update_econavi(econavi); this->update_mild_dry(mildDry); } @@ -398,17 +400,13 @@ std::string PanasonicACCNT::determine_preset(uint8_t preset) { switch (nib) { case 0x02: - // return climate::CLIMATE_PRESET_BOOST; return "Powerful"; case 0x04: - // return climate::CLIMATE_PRESET_ECO; return "Quiet"; case 0x00: - // return climate::CLIMATE_PRESET_NONE; return "Normal"; default: ESP_LOGW(TAG, "Received unknown preset"); - // return climate::CLIMATE_PRESET_NONE; return "Normal"; } } @@ -437,6 +435,17 @@ bool PanasonicACCNT::determine_eco(uint8_t value) { } } +bool PanasonicACCNT::determine_econavi(uint8_t value) { + if (value == 0x10) + return true; + else if (value == 0x00) + return false; + else { + ESP_LOGW(TAG, "Received unknown econavi value"); + return false; + } +} + bool PanasonicACCNT::determine_mild_dry(uint8_t value) { if (value == 0x7F) return true; @@ -538,6 +547,23 @@ void PanasonicACCNT::on_eco_change(bool state) { send_command(this->data, CommandType::Normal, CTRL_HEADER); } +void PanasonicACCNT::on_econavi_change(bool state) { + if (this->state_ != ACState::Ready) + return; + + this->econavi_state_ = state; + + if (state) { + ESP_LOGV(TAG, "Turning econavi mode on"); + this->data[5] = 0x10; + } else { + ESP_LOGV(TAG, "Turning econavi mode off"); + this->data[5] = 0x00; + } + + send_command(this->data, CommandType::Normal, CTRL_HEADER); +} + void PanasonicACCNT::on_mild_dry_change(bool state) { if (this->state_ != ACState::Ready) return; diff --git a/components/panasonic_ac/esppac_cnt.h b/components/panasonic_ac/esppac_cnt.h index 783b0d6..f90ea7d 100644 --- a/components/panasonic_ac/esppac_cnt.h +++ b/components/panasonic_ac/esppac_cnt.h @@ -24,6 +24,7 @@ class PanasonicACCNT : public PanasonicAC { void on_vertical_swing_change(const std::string &swing) override; void on_nanoex_change(bool nanoex) override; void on_eco_change(bool eco) override; + void on_econavi_change(bool eco) override; void on_mild_dry_change(bool mild_dry) override; void setup() override; @@ -53,6 +54,7 @@ class PanasonicACCNT : public PanasonicAC { std::string determine_preset(uint8_t preset); bool determine_preset_nanoex(uint8_t preset); bool determine_eco(uint8_t value); + bool determine_econavi(uint8_t value); bool determine_mild_dry(uint8_t value); }; diff --git a/components/panasonic_ac/esppac_wlan.cpp b/components/panasonic_ac/esppac_wlan.cpp index 0d8b322..77aa6e6 100644 --- a/components/panasonic_ac/esppac_wlan.cpp +++ b/components/panasonic_ac/esppac_wlan.cpp @@ -813,6 +813,25 @@ void PanasonicACWLAN::on_eco_change(bool state) { // send_set_command(); } +void PanasonicACWLAN::on_econavi_change(bool state) { + if (this->state_ != ACState::Ready) + return; + + return; + + // TODO: implement econavi + + // if (state) { + // ESP_LOGV(TAG, "Turning econavi on"); + // set_value(..., ...); // econavi on + // } else { + // ESP_LOGV(TAG, "Turning econavi off"); + // set_value(..., ...); // econavi off + // } + + // send_set_command(); +} + void PanasonicACWLAN::on_mild_dry_change(bool state) { if (this->state_ != ACState::Ready) return; diff --git a/components/panasonic_ac/esppac_wlan.h b/components/panasonic_ac/esppac_wlan.h index ae2e267..7e86630 100644 --- a/components/panasonic_ac/esppac_wlan.h +++ b/components/panasonic_ac/esppac_wlan.h @@ -32,6 +32,7 @@ class PanasonicACWLAN : public PanasonicAC { void on_vertical_swing_change(const std::string &swing) override; void on_nanoex_change(bool nanoex) override; void on_eco_change(bool eco) override; + void on_econavi_change(bool eco) override; void on_mild_dry_change(bool mild_dry) override; void setup() override; diff --git a/protocol/cztacg1/protocol_description_query.ods b/protocol/cztacg1/protocol_description_query.ods index bff3cda..8f7cdb2 100644 Binary files a/protocol/cztacg1/protocol_description_query.ods and b/protocol/cztacg1/protocol_description_query.ods differ