diff --git a/README.rst b/README.rst index 8d277e8..8f8f2b6 100644 --- a/README.rst +++ b/README.rst @@ -63,7 +63,6 @@ This component requires a `UART Bus `_ name: Haier AC uart_id: ac_port wifi_signal: true - beeper: true display: true visual: min_temperature: 16 °C diff --git a/components/haier/climate.py b/components/haier/climate.py index f7423a1..3bdc307 100644 --- a/components/haier/climate.py +++ b/components/haier/climate.py @@ -240,7 +240,9 @@ def validate_visual(config): ): cv.ensure_list( cv.enum(SUPPORTED_HON_CONTROL_METHODS, upper=True) ), - cv.Optional(CONF_BEEPER, default=True): cv.boolean, + cv.Optional(CONF_BEEPER): cv.invalid( + f"The {CONF_BEEPER} option is deprecated, use beeper_on/beeper_off actions or beeper switch for a haier platform instead" + ), cv.Optional( CONF_CONTROL_PACKET_SIZE, default=PROTOCOL_CONTROL_PACKET_SIZE ): cv.int_range(min=PROTOCOL_CONTROL_PACKET_SIZE, max=50), diff --git a/components/haier/hon_climate.cpp b/components/haier/hon_climate.cpp index a1c5098..f798aa5 100644 --- a/components/haier/hon_climate.cpp +++ b/components/haier/hon_climate.cpp @@ -31,9 +31,15 @@ HonClimate::HonClimate() HonClimate::~HonClimate() {} -void HonClimate::set_beeper_state(bool state) { this->beeper_status_ = state; } +void HonClimate::set_beeper_state(bool state) { + if (state != this->settings_.beeper_state) { + this->settings_.beeper_state = state; + this->beeper_switch_->publish_state(state); + this->rtc_.save(&this->settings_); + } +} -bool HonClimate::get_beeper_state() const { return this->beeper_status_; } +bool HonClimate::get_beeper_state() const { return this->settings_.beeper_state; } esphome::optional HonClimate::get_vertical_airflow() const { return this->current_vertical_swing_; @@ -474,13 +480,13 @@ haier_protocol::HaierMessage HonClimate::get_power_message(bool state) { } void HonClimate::initialization() { - constexpr uint32_t restore_settings_version = 0xE834D8DCUL; + constexpr uint32_t restore_settings_version = 0x2A3613DCUL; this->rtc_ = global_preferences->make_preference(this->get_object_id_hash() ^ restore_settings_version); HonSettings recovered; if (this->rtc_.load(&recovered)) { this->settings_ = recovered; } else { - this->settings_ = {hon_protocol::VerticalSwingMode::CENTER, hon_protocol::HorizontalSwingMode::CENTER}; + this->settings_ = {hon_protocol::VerticalSwingMode::CENTER, hon_protocol::HorizontalSwingMode::CENTER, true}; } this->current_vertical_swing_ = this->settings_.last_vertiacal_swing; this->current_horizontal_swing_ = this->settings_.last_horizontal_swing; @@ -638,7 +644,7 @@ haier_protocol::HaierMessage HonClimate::get_control_message() { out_data->horizontal_swing_mode = (uint8_t) this->pending_horizontal_direction_.value(); this->pending_horizontal_direction_.reset(); } - out_data->beeper_status = ((!this->beeper_status_) || (!has_hvac_settings)) ? 1 : 0; + out_data->beeper_status = ((!this->settings_.beeper_state) || (!has_hvac_settings)) ? 1 : 0; control_out_buffer[4] = 0; // This byte should be cleared before setting values out_data->display_status = this->display_status_ ? 1 : 0; out_data->health_mode = this->health_mode_ ? 1 : 0; @@ -765,6 +771,15 @@ void HonClimate::update_sub_text_sensor_(SubTextSensorType type, const std::stri } #endif // USE_TEXT_SENSOR +#ifdef USE_SWITCH +void HonClimate::set_beeper_switch(switch_::Switch *sw) { + this->beeper_switch_ = sw; + if (this->beeper_switch_ != nullptr) { + this->beeper_switch_->publish_state(this->settings_.beeper_state); + } +} +#endif // USE_SWITCH + haier_protocol::HandlerError HonClimate::process_status_message_(const uint8_t *packet_buffer, uint8_t size) { size_t expected_size = 2 + this->status_message_header_size_ + this->real_control_packet_size_ + this->real_sensors_packet_size_; @@ -1017,7 +1032,7 @@ void HonClimate::fill_control_messages_queue_() { haier_protocol::HaierMessage(haier_protocol::FrameType::CONTROL, (uint16_t) hon_protocol::SubcommandsControl::SET_SINGLE_PARAMETER + (uint8_t) hon_protocol::DataParameters::BEEPER_STATUS, - this->beeper_status_ ? ZERO_BUF : ONE_BUF, 2)); + this->settings_.beeper_state ? ZERO_BUF : ONE_BUF, 2)); } // Health mode { diff --git a/components/haier/hon_climate.h b/components/haier/hon_climate.h index 64c5418..ac87903 100644 --- a/components/haier/hon_climate.h +++ b/components/haier/hon_climate.h @@ -10,6 +10,9 @@ #ifdef USE_TEXT_SENSOR #include "esphome/components/text_sensor/text_sensor.h" #endif +#ifdef USE_SWITCH +#include "esphome/components/switch/switch.h" +#endif #include "esphome/core/automation.h" #include "haier_base.h" #include "hon_packet.h" @@ -28,6 +31,7 @@ enum class HonControlMethod { MONITOR_ONLY = 0, SET_GROUP_PARAMETERS, SET_SINGLE struct HonSettings { hon_protocol::VerticalSwingMode last_vertiacal_swing; hon_protocol::HorizontalSwingMode last_horizontal_swing; + bool beeper_state; }; class HonClimate : public HaierClimateBase { @@ -86,6 +90,13 @@ class HonClimate : public HaierClimateBase { protected: void update_sub_text_sensor_(SubTextSensorType type, const std::string &value); text_sensor::TextSensor *sub_text_sensors_[(size_t) SubTextSensorType::SUB_TEXT_SENSOR_TYPE_COUNT]{nullptr}; +#endif +#ifdef USE_SWITCH + public: + void set_beeper_switch(switch_::Switch *sw); + + protected: + switch_::Switch *beeper_switch_{nullptr}; #endif public: HonClimate(); @@ -153,7 +164,6 @@ class HonClimate : public HaierClimateBase { bool functions_[5]; }; - bool beeper_status_; CleaningState cleaning_status_; bool got_valid_outdoor_temp_; esphome::optional pending_vertical_direction_{}; diff --git a/components/haier/switch/__init__.py b/components/haier/switch/__init__.py index 7bca6e8..979442e 100644 --- a/components/haier/switch/__init__.py +++ b/components/haier/switch/__init__.py @@ -33,15 +33,19 @@ DisplaySwitch, icon=ICON_LED_ON, entity_category=ENTITY_CATEGORY_CONFIG, + default_restore_mode="DISABLED", ), cv.Optional(CONF_HEALTH_MODE): switch.switch_schema( HealthModeSwitch, icon=ICON_LEAF, + default_restore_mode="DISABLED", ), + # Beeper switch is only supported for HonClimate cv.Optional(CONF_BEEPER): switch.switch_schema( BeeperSwitch, icon=ICON_VOLUME_HIGH, entity_category=ENTITY_CATEGORY_CONFIG, + default_restore_mode="DISABLED", ), } ) @@ -52,14 +56,15 @@ async def to_code(config): full_id, parent = await cg.get_variable_with_full_id(config[CONF_HAIER_ID]) - for switch_type in [CONF_DISPLAY, CONF_HEALTH_MODE]: - if conf := config.get(switch_type): - swtch = await switch.new_switch(conf) - await cg.register_parented(swtch, parent) +# for switch_type in [CONF_DISPLAY, CONF_HEALTH_MODE]: +# if conf := config.get(switch_type): +# sw_var = await switch.new_switch(conf) +# await cg.register_parented(sw_var, parent) if conf := config.get(CONF_BEEPER): if full_id.type is HonClimate: - swtch = await switch.new_switch(conf) - await cg.register_parented(swtch, parent) + sw_var = await switch.new_switch(conf) + await cg.register_parented(sw_var, parent) + cg.add(getattr(parent, f"set_beeper_switch")(sw_var)) else: raise ValueError("Beeper switch is only supported for hon climate") diff --git a/components/haier/switch/beeper.cpp b/components/haier/switch/beeper.cpp new file mode 100644 index 0000000..1ce64d0 --- /dev/null +++ b/components/haier/switch/beeper.cpp @@ -0,0 +1,14 @@ +#include "beeper.h" + +namespace esphome { +namespace haier { + +void BeeperSwitch::write_state(bool state) { + if (this->parent_->get_beeper_state() != state) { + this->parent_->set_beeper_state(state); + } + this->publish_state(state); +} + +} // namespace haier +} // namespace esphome diff --git a/components/haier/switch/beeper.h b/components/haier/switch/beeper.h new file mode 100644 index 0000000..7396a7a --- /dev/null +++ b/components/haier/switch/beeper.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/components/switch/switch.h" +#include "../hon_climate.h" + +namespace esphome { +namespace haier { + +class BeeperSwitch : public switch_::Switch, public Parented { + public: + BeeperSwitch() = default; + + protected: + void write_state(bool state) override; +}; + +} // namespace haier +} // namespace esphome diff --git a/configs/climate/haier_hon.yaml b/configs/climate/haier_hon.yaml index 9b704df..bb3980a 100644 --- a/configs/climate/haier_hon.yaml +++ b/configs/climate/haier_hon.yaml @@ -5,7 +5,6 @@ name: ${device_name} uart_id: ${uart_id} wifi_signal: ${send_wifi} # Optional, default true, enables WiFI signal transmission from ESP to AC - beeper: true # Optional, default true, disables beep on commands from ESP visual: # Optional, you can use it to limit min and max temperatures in UI (not working for remote!) min_temperature: 16 °C max_temperature: 30 °C diff --git a/docs/esphome-docs/climate/haier.rst b/docs/esphome-docs/climate/haier.rst index c14b14c..5f740d6 100644 --- a/docs/esphome-docs/climate/haier.rst +++ b/docs/esphome-docs/climate/haier.rst @@ -65,7 +65,6 @@ This component requires a :ref:`uart` to be setup. name: Haier AC uart_id: ac_port wifi_signal: true - beeper: true display: true visual: min_temperature: 16 °C diff --git a/docs/examples/max-hon.yaml b/docs/examples/max-hon.yaml index 4279ad8..bdbadb5 100644 --- a/docs/examples/max-hon.yaml +++ b/docs/examples/max-hon.yaml @@ -20,7 +20,6 @@ climate: name: Haier hOn Climate uart_id: haier_uart wifi_signal: true - beeper: true visual: min_temperature: 16 °C max_temperature: 30 °C diff --git a/docs/hon_example.rst b/docs/hon_example.rst index c6502a9..8719d94 100644 --- a/docs/hon_example.rst +++ b/docs/hon_example.rst @@ -48,7 +48,6 @@ Maximum configuration witch will use all possible options will look like this: name: Haier hOn Climate uart_id: haier_uart wifi_signal: true - beeper: true visual: min_temperature: 16 °C max_temperature: 30 °C