From f9a7f008436455c8c771426433af296ac27321a9 Mon Sep 17 00:00:00 2001 From: Joshua Spence Date: Sun, 23 Jan 2022 06:41:58 +1100 Subject: [PATCH] Add restore_mode to fan component (#3051) --- esphome/components/fan/__init__.py | 16 +++++++++ esphome/components/fan/fan_state.cpp | 54 +++++++++++++++++++++++----- esphome/components/fan/fan_state.h | 15 ++++++++ 3 files changed, 76 insertions(+), 9 deletions(-) diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index 52bec3b5b6..8dec2dee51 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -19,6 +19,7 @@ from esphome.const import ( CONF_ON_TURN_ON, CONF_TRIGGER_ID, CONF_DIRECTION, + CONF_RESTORE_MODE, ) from esphome.core import CORE, coroutine_with_priority from esphome.cpp_helpers import setup_entity @@ -35,6 +36,16 @@ FAN_DIRECTION_ENUM = { "REVERSE": FanDirection.FAN_DIRECTION_REVERSE, } +FanRestoreMode = fan_ns.enum("FanRestoreMode") +RESTORE_MODES = { + "RESTORE_DEFAULT_OFF": FanRestoreMode.FAN_RESTORE_DEFAULT_OFF, + "RESTORE_DEFAULT_ON": FanRestoreMode.FAN_RESTORE_DEFAULT_ON, + "ALWAYS_OFF": FanRestoreMode.FAN_ALWAYS_OFF, + "ALWAYS_ON": FanRestoreMode.FAN_ALWAYS_ON, + "RESTORE_INVERTED_DEFAULT_OFF": FanRestoreMode.FAN_RESTORE_INVERTED_DEFAULT_OFF, + "RESTORE_INVERTED_DEFAULT_ON": FanRestoreMode.FAN_RESTORE_INVERTED_DEFAULT_ON, +} + # Actions TurnOnAction = fan_ns.class_("TurnOnAction", automation.Action) TurnOffAction = fan_ns.class_("TurnOffAction", automation.Action) @@ -51,6 +62,9 @@ FanIsOffCondition = fan_ns.class_("FanIsOffCondition", automation.Condition.temp FAN_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).extend( { cv.GenerateID(): cv.declare_id(FanState), + cv.Optional(CONF_RESTORE_MODE, default="restore_default_off"): cv.enum( + RESTORE_MODES, upper=True, space="_" + ), cv.OnlyWith(CONF_MQTT_ID, "mqtt"): cv.declare_id(mqtt.MQTTFanComponent), cv.Optional(CONF_OSCILLATION_STATE_TOPIC): cv.All( cv.requires_component("mqtt"), cv.publish_topic @@ -92,6 +106,8 @@ FAN_SCHEMA = cv.ENTITY_BASE_SCHEMA.extend(cv.MQTT_COMMAND_COMPONENT_SCHEMA).exte async def setup_fan_core_(var, config): await setup_entity(var, config) + cg.add(var.set_restore_mode(config[CONF_RESTORE_MODE])) + if CONF_MQTT_ID in config: mqtt_ = cg.new_Pvariable(config[CONF_MQTT_ID], var) await mqtt.register_mqtt_component(mqtt_, config) diff --git a/esphome/components/fan/fan_state.cpp b/esphome/components/fan/fan_state.cpp index 6ff4d3a833..7f9023f881 100644 --- a/esphome/components/fan/fan_state.cpp +++ b/esphome/components/fan/fan_state.cpp @@ -27,16 +27,52 @@ struct FanStateRTCState { }; void FanState::setup() { - this->rtc_ = global_preferences->make_preference(this->get_object_id_hash()); - FanStateRTCState recovered{}; - if (!this->rtc_.load(&recovered)) - return; - auto call = this->make_call(); - call.set_state(recovered.state); - call.set_speed(recovered.speed); - call.set_oscillating(recovered.oscillating); - call.set_direction(recovered.direction); + FanStateRTCState recovered{}; + + switch (this->restore_mode_) { + case FAN_RESTORE_DEFAULT_OFF: + case FAN_RESTORE_DEFAULT_ON: + case FAN_RESTORE_INVERTED_DEFAULT_OFF: + case FAN_RESTORE_INVERTED_DEFAULT_ON: + this->rtc_ = global_preferences->make_preference(this->get_object_id_hash()); + if (!this->rtc_.load(&recovered)) { + if (this->restore_mode_ == FAN_RESTORE_DEFAULT_ON || this->restore_mode_ == FAN_RESTORE_INVERTED_DEFAULT_ON) { + call.set_state(true); + } else { + call.set_state(false); + } + } else { + if (this->restore_mode_ == FAN_RESTORE_INVERTED_DEFAULT_OFF || + this->restore_mode_ == FAN_RESTORE_INVERTED_DEFAULT_ON) { + call.set_state(!recovered.state); + } else { + call.set_state(recovered.state); + } + + call.set_speed(recovered.speed); + call.set_oscillating(recovered.oscillating); + call.set_direction(recovered.direction); + } + break; + case FAN_ALWAYS_OFF: + case FAN_ALWAYS_ON: + if (this->restore_mode_ == FAN_ALWAYS_OFF) { + call.set_state(false); + } else if (this->restore_mode_ == FAN_ALWAYS_ON) { + call.set_state(true); + } + + this->rtc_ = global_preferences->make_preference(this->get_object_id_hash()); + if (this->rtc_.load(&recovered)) { + call.set_speed(recovered.speed); + call.set_oscillating(recovered.oscillating); + call.set_direction(recovered.direction); + } + + break; + } + call.perform(); } float FanState::get_setup_priority() const { return setup_priority::DATA - 1.0f; } diff --git a/esphome/components/fan/fan_state.h b/esphome/components/fan/fan_state.h index c5a6f59ac4..c0d9d64d2c 100644 --- a/esphome/components/fan/fan_state.h +++ b/esphome/components/fan/fan_state.h @@ -20,6 +20,15 @@ enum ESPDEPRECATED("FanSpeed is deprecated.", "2021.9") FanSpeed { /// Simple enum to represent the direction of a fan enum FanDirection { FAN_DIRECTION_FORWARD = 0, FAN_DIRECTION_REVERSE = 1 }; +enum FanRestoreMode { + FAN_RESTORE_DEFAULT_OFF, + FAN_RESTORE_DEFAULT_ON, + FAN_ALWAYS_OFF, + FAN_ALWAYS_ON, + FAN_RESTORE_INVERTED_DEFAULT_OFF, + FAN_RESTORE_INVERTED_DEFAULT_ON, +}; + class FanState; class FanStateCall { @@ -81,6 +90,9 @@ class FanState : public EntityBase, public Component { /// Set the traits of this fan (i.e. what features it supports). void set_traits(const FanTraits &traits); + /// Set the restore mode of this fan + void set_restore_mode(FanRestoreMode restore_mode) { this->restore_mode_ = restore_mode; } + /// The current ON/OFF state of the fan. bool state{false}; /// The current oscillation state of the fan. @@ -106,6 +118,9 @@ class FanState : public EntityBase, public Component { FanTraits traits_{}; CallbackManager state_callback_{}; ESPPreferenceObject rtc_; + + /// Restore mode of the fan. + FanRestoreMode restore_mode_; }; } // namespace fan