1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-31 15:12:06 +00:00

Refactor fan platform to resemble climate/cover platforms (#2848)

Co-authored-by: Oxan van Leeuwen <oxan@oxanvanleeuwen.nl>
Co-authored-by: rob-deutsch <robzyb+altgithub@gmail.com>
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
Oxan van Leeuwen
2022-01-23 10:21:54 +01:00
committed by GitHub
parent 8187a4bce9
commit 2a84db7f85
41 changed files with 593 additions and 506 deletions

View File

@@ -27,23 +27,24 @@ from esphome.cpp_helpers import setup_entity
IS_PLATFORM_COMPONENT = True
fan_ns = cg.esphome_ns.namespace("fan")
FanState = fan_ns.class_("FanState", cg.EntityBase, cg.Component)
MakeFan = cg.Application.struct("MakeFan")
Fan = fan_ns.class_("Fan", cg.EntityBase)
FanState = fan_ns.class_("Fan", Fan, cg.Component)
FanDirection = fan_ns.enum("FanDirection")
FanDirection = fan_ns.enum("FanDirection", is_class=True)
FAN_DIRECTION_ENUM = {
"FORWARD": FanDirection.FAN_DIRECTION_FORWARD,
"REVERSE": FanDirection.FAN_DIRECTION_REVERSE,
"FORWARD": FanDirection.FORWARD,
"REVERSE": FanDirection.REVERSE,
}
FanRestoreMode = fan_ns.enum("FanRestoreMode")
FanRestoreMode = fan_ns.enum("FanRestoreMode", is_class=True)
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,
"NO_RESTORE": FanRestoreMode.NO_RESTORE,
"ALWAYS_OFF": FanRestoreMode.ALWAYS_OFF,
"ALWAYS_ON": FanRestoreMode.ALWAYS_ON,
"RESTORE_DEFAULT_OFF": FanRestoreMode.RESTORE_DEFAULT_OFF,
"RESTORE_DEFAULT_ON": FanRestoreMode.RESTORE_DEFAULT_ON,
"RESTORE_INVERTED_DEFAULT_OFF": FanRestoreMode.RESTORE_INVERTED_DEFAULT_OFF,
"RESTORE_INVERTED_DEFAULT_ON": FanRestoreMode.RESTORE_INVERTED_DEFAULT_ON,
}
# Actions
@@ -61,8 +62,8 @@ 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(
cv.GenerateID(): cv.declare_id(Fan),
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),
@@ -158,19 +159,19 @@ async def register_fan(var, config):
if not CORE.has_id(config[CONF_ID]):
var = cg.Pvariable(config[CONF_ID], var)
cg.add(cg.App.register_fan(var))
await cg.register_component(var, config)
await setup_fan_core_(var, config)
async def create_fan_state(config):
var = cg.new_Pvariable(config[CONF_ID])
await register_fan(var, config)
await cg.register_component(var, config)
return var
FAN_ACTION_SCHEMA = maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(FanState),
cv.Required(CONF_ID): cv.use_id(Fan),
}
)
@@ -192,7 +193,7 @@ async def fan_turn_off_to_code(config, action_id, template_arg, args):
TurnOnAction,
maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(FanState),
cv.Required(CONF_ID): cv.use_id(Fan),
cv.Optional(CONF_OSCILLATING): cv.templatable(cv.boolean),
cv.Optional(CONF_SPEED): cv.templatable(cv.int_range(1)),
cv.Optional(CONF_DIRECTION): cv.templatable(
@@ -227,7 +228,7 @@ async def fan_cycle_speed_to_code(config, action_id, template_arg, args):
FanIsOnCondition,
automation.maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(FanState),
cv.Required(CONF_ID): cv.use_id(Fan),
}
),
)
@@ -236,7 +237,7 @@ async def fan_cycle_speed_to_code(config, action_id, template_arg, args):
FanIsOffCondition,
automation.maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(FanState),
cv.Required(CONF_ID): cv.use_id(Fan),
}
),
)

View File

@@ -1,10 +0,0 @@
#include "automation.h"
#include "esphome/core/log.h"
namespace esphome {
namespace fan {
static const char *const TAG = "fan.automation";
} // namespace fan
} // namespace esphome

View File

@@ -9,7 +9,7 @@ namespace fan {
template<typename... Ts> class TurnOnAction : public Action<Ts...> {
public:
explicit TurnOnAction(FanState *state) : state_(state) {}
explicit TurnOnAction(Fan *state) : state_(state) {}
TEMPLATABLE_VALUE(bool, oscillating)
TEMPLATABLE_VALUE(int, speed)
@@ -29,30 +29,30 @@ template<typename... Ts> class TurnOnAction : public Action<Ts...> {
call.perform();
}
FanState *state_;
Fan *state_;
};
template<typename... Ts> class TurnOffAction : public Action<Ts...> {
public:
explicit TurnOffAction(FanState *state) : state_(state) {}
explicit TurnOffAction(Fan *state) : state_(state) {}
void play(Ts... x) override { this->state_->turn_off().perform(); }
FanState *state_;
Fan *state_;
};
template<typename... Ts> class ToggleAction : public Action<Ts...> {
public:
explicit ToggleAction(FanState *state) : state_(state) {}
explicit ToggleAction(Fan *state) : state_(state) {}
void play(Ts... x) override { this->state_->toggle().perform(); }
FanState *state_;
Fan *state_;
};
template<typename... Ts> class CycleSpeedAction : public Action<Ts...> {
public:
explicit CycleSpeedAction(FanState *state) : state_(state) {}
explicit CycleSpeedAction(Fan *state) : state_(state) {}
void play(Ts... x) override {
// check to see if fan supports speeds and is on
@@ -83,29 +83,29 @@ template<typename... Ts> class CycleSpeedAction : public Action<Ts...> {
}
}
FanState *state_;
Fan *state_;
};
template<typename... Ts> class FanIsOnCondition : public Condition<Ts...> {
public:
explicit FanIsOnCondition(FanState *state) : state_(state) {}
explicit FanIsOnCondition(Fan *state) : state_(state) {}
bool check(Ts... x) override { return this->state_->state; }
protected:
FanState *state_;
Fan *state_;
};
template<typename... Ts> class FanIsOffCondition : public Condition<Ts...> {
public:
explicit FanIsOffCondition(FanState *state) : state_(state) {}
explicit FanIsOffCondition(Fan *state) : state_(state) {}
bool check(Ts... x) override { return !this->state_->state; }
protected:
FanState *state_;
Fan *state_;
};
class FanTurnOnTrigger : public Trigger<> {
public:
FanTurnOnTrigger(FanState *state) {
FanTurnOnTrigger(Fan *state) {
state->add_on_state_callback([this, state]() {
auto is_on = state->state;
auto should_trigger = is_on && !this->last_on_;
@@ -123,7 +123,7 @@ class FanTurnOnTrigger : public Trigger<> {
class FanTurnOffTrigger : public Trigger<> {
public:
FanTurnOffTrigger(FanState *state) {
FanTurnOffTrigger(Fan *state) {
state->add_on_state_callback([this, state]() {
auto is_on = state->state;
auto should_trigger = !is_on && this->last_on_;
@@ -141,7 +141,7 @@ class FanTurnOffTrigger : public Trigger<> {
class FanSpeedSetTrigger : public Trigger<> {
public:
FanSpeedSetTrigger(FanState *state) {
FanSpeedSetTrigger(Fan *state) {
state->add_on_state_callback([this, state]() {
auto speed = state->speed;
auto should_trigger = speed != !this->last_speed_;

View File

@@ -0,0 +1,175 @@
#include "fan.h"
#include "fan_helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace fan {
static const char *const TAG = "fan";
const LogString *fan_direction_to_string(FanDirection direction) {
switch (direction) {
case FanDirection::FORWARD:
return LOG_STR("FORWARD");
case FanDirection::REVERSE:
return LOG_STR("REVERSE");
default:
return LOG_STR("UNKNOWN");
}
}
void FanCall::perform() {
ESP_LOGD(TAG, "'%s' - Setting:", this->parent_.get_name().c_str());
this->validate_();
if (this->binary_state_.has_value())
ESP_LOGD(TAG, " State: %s", ONOFF(*this->binary_state_));
if (this->oscillating_.has_value())
ESP_LOGD(TAG, " Oscillating: %s", YESNO(*this->oscillating_));
if (this->speed_.has_value())
ESP_LOGD(TAG, " Speed: %d", *this->speed_);
if (this->direction_.has_value())
ESP_LOGD(TAG, " Direction: %s", LOG_STR_ARG(fan_direction_to_string(*this->direction_)));
this->parent_.control(*this);
}
void FanCall::validate_() {
auto traits = this->parent_.get_traits();
if (this->speed_.has_value())
this->speed_ = clamp(*this->speed_, 1, traits.supported_speed_count());
if (this->binary_state_.has_value() && *this->binary_state_) {
// when turning on, if current speed is zero, set speed to 100%
if (traits.supports_speed() && !this->parent_.state && this->parent_.speed == 0) {
this->speed_ = traits.supported_speed_count();
}
}
if (this->oscillating_.has_value() && !traits.supports_oscillation()) {
ESP_LOGW(TAG, "'%s' - This fan does not support oscillation!", this->parent_.get_name().c_str());
this->oscillating_.reset();
}
if (this->speed_.has_value() && !traits.supports_speed()) {
ESP_LOGW(TAG, "'%s' - This fan does not support speeds!", this->parent_.get_name().c_str());
this->speed_.reset();
}
if (this->direction_.has_value() && !traits.supports_direction()) {
ESP_LOGW(TAG, "'%s' - This fan does not support directions!", this->parent_.get_name().c_str());
this->direction_.reset();
}
}
// This whole method is deprecated, don't warn about usage of deprecated methods inside of it.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
FanCall &FanCall::set_speed(const char *legacy_speed) {
const auto supported_speed_count = this->parent_.get_traits().supported_speed_count();
if (strcasecmp(legacy_speed, "low") == 0) {
this->set_speed(fan::speed_enum_to_level(FAN_SPEED_LOW, supported_speed_count));
} else if (strcasecmp(legacy_speed, "medium") == 0) {
this->set_speed(fan::speed_enum_to_level(FAN_SPEED_MEDIUM, supported_speed_count));
} else if (strcasecmp(legacy_speed, "high") == 0) {
this->set_speed(fan::speed_enum_to_level(FAN_SPEED_HIGH, supported_speed_count));
}
return *this;
}
#pragma GCC diagnostic pop
FanCall FanRestoreState::to_call(Fan &fan) {
auto call = fan.make_call();
call.set_state(this->state);
call.set_oscillating(this->oscillating);
call.set_speed(this->speed);
call.set_direction(this->direction);
return call;
}
void FanRestoreState::apply(Fan &fan) {
fan.state = this->state;
fan.oscillating = this->oscillating;
fan.speed = this->speed;
fan.direction = this->direction;
fan.publish_state();
}
Fan::Fan() : EntityBase("") {}
Fan::Fan(const std::string &name) : EntityBase(name) {}
FanCall Fan::turn_on() { return this->make_call().set_state(true); }
FanCall Fan::turn_off() { return this->make_call().set_state(false); }
FanCall Fan::toggle() { return this->make_call().set_state(!this->state); }
FanCall Fan::make_call() { return FanCall(*this); }
void Fan::add_on_state_callback(std::function<void()> &&callback) { this->state_callback_.add(std::move(callback)); }
void Fan::publish_state() {
auto traits = this->get_traits();
ESP_LOGD(TAG, "'%s' - Sending state:", this->name_.c_str());
ESP_LOGD(TAG, " State: %s", ONOFF(this->state));
if (traits.supports_speed())
ESP_LOGD(TAG, " Speed: %d", this->speed);
if (traits.supports_oscillation())
ESP_LOGD(TAG, " Oscillating: %s", YESNO(this->oscillating));
if (traits.supports_direction())
ESP_LOGD(TAG, " Direction: %s", LOG_STR_ARG(fan_direction_to_string(this->direction)));
this->state_callback_.call();
this->save_state_();
}
// Random 32-bit value, change this every time the layout of the FanRestoreState struct changes.
constexpr uint32_t RESTORE_STATE_VERSION = 0x71700ABA;
optional<FanRestoreState> Fan::restore_state_() {
FanRestoreState recovered{};
this->rtc_ = global_preferences->make_preference<FanRestoreState>(this->get_object_id_hash() ^ RESTORE_STATE_VERSION);
bool restored = this->rtc_.load(&recovered);
switch (this->restore_mode_) {
case FanRestoreMode::NO_RESTORE:
return {};
case FanRestoreMode::ALWAYS_OFF:
recovered.state = false;
return recovered;
case FanRestoreMode::ALWAYS_ON:
recovered.state = true;
return recovered;
case FanRestoreMode::RESTORE_DEFAULT_OFF:
recovered.state = restored ? recovered.state : false;
return recovered;
case FanRestoreMode::RESTORE_DEFAULT_ON:
recovered.state = restored ? recovered.state : true;
return recovered;
case FanRestoreMode::RESTORE_INVERTED_DEFAULT_OFF:
recovered.state = restored ? !recovered.state : false;
return recovered;
case FanRestoreMode::RESTORE_INVERTED_DEFAULT_ON:
recovered.state = restored ? !recovered.state : true;
return recovered;
}
return {};
}
void Fan::save_state_() {
FanRestoreState state{};
state.state = this->state;
state.oscillating = this->oscillating;
state.speed = this->speed;
state.direction = this->direction;
this->rtc_.save(&state);
}
void Fan::dump_traits_(const char *tag, const char *prefix) {
if (this->get_traits().supports_speed()) {
ESP_LOGCONFIG(tag, "%s Speed: YES", prefix);
ESP_LOGCONFIG(tag, "%s Speed count: %d", prefix, this->get_traits().supported_speed_count());
}
if (this->get_traits().supports_oscillation())
ESP_LOGCONFIG(tag, "%s Oscillation: YES", prefix);
if (this->get_traits().supports_direction())
ESP_LOGCONFIG(tag, "%s Direction: YES", prefix);
}
uint32_t Fan::hash_base() { return 418001110UL; }
} // namespace fan
} // namespace esphome

View File

@@ -0,0 +1,154 @@
#pragma once
#include "esphome/core/entity_base.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#include "esphome/core/optional.h"
#include "esphome/core/preferences.h"
#include "fan_traits.h"
namespace esphome {
namespace fan {
#define LOG_FAN(prefix, type, obj) \
if ((obj) != nullptr) { \
ESP_LOGCONFIG(TAG, "%s%s '%s'", prefix, LOG_STR_LITERAL(type), (obj)->get_name().c_str()); \
(obj)->dump_traits_(TAG, prefix); \
}
/// Simple enum to represent the speed of a fan. - DEPRECATED - Will be deleted soon
enum ESPDEPRECATED("FanSpeed is deprecated.", "2021.9") FanSpeed {
FAN_SPEED_LOW = 0, ///< The fan is running on low speed.
FAN_SPEED_MEDIUM = 1, ///< The fan is running on medium speed.
FAN_SPEED_HIGH = 2 ///< The fan is running on high/full speed.
};
/// Simple enum to represent the direction of a fan.
enum class FanDirection { FORWARD = 0, REVERSE = 1 };
/// Restore mode of a fan.
enum class FanRestoreMode {
NO_RESTORE,
ALWAYS_OFF,
ALWAYS_ON,
RESTORE_DEFAULT_OFF,
RESTORE_DEFAULT_ON,
RESTORE_INVERTED_DEFAULT_OFF,
RESTORE_INVERTED_DEFAULT_ON,
};
const LogString *fan_direction_to_string(FanDirection direction);
class Fan;
class FanCall {
public:
explicit FanCall(Fan &parent) : parent_(parent) {}
FanCall &set_state(bool binary_state) {
this->binary_state_ = binary_state;
return *this;
}
FanCall &set_state(optional<bool> binary_state) {
this->binary_state_ = binary_state;
return *this;
}
optional<bool> get_state() const { return this->binary_state_; }
FanCall &set_oscillating(bool oscillating) {
this->oscillating_ = oscillating;
return *this;
}
FanCall &set_oscillating(optional<bool> oscillating) {
this->oscillating_ = oscillating;
return *this;
}
optional<bool> get_oscillating() const { return this->oscillating_; }
FanCall &set_speed(int speed) {
this->speed_ = speed;
return *this;
}
ESPDEPRECATED("set_speed() with string argument is deprecated, use integer argument instead.", "2021.9")
FanCall &set_speed(const char *legacy_speed);
optional<int> get_speed() const { return this->speed_; }
FanCall &set_direction(FanDirection direction) {
this->direction_ = direction;
return *this;
}
FanCall &set_direction(optional<FanDirection> direction) {
this->direction_ = direction;
return *this;
}
optional<FanDirection> get_direction() const { return this->direction_; }
void perform();
protected:
void validate_();
Fan &parent_;
optional<bool> binary_state_;
optional<bool> oscillating_;
optional<int> speed_;
optional<FanDirection> direction_{};
};
struct FanRestoreState {
bool state;
int speed;
bool oscillating;
FanDirection direction;
/// Convert this struct to a fan call that can be performed.
FanCall to_call(Fan &fan);
/// Apply these settings to the fan.
void apply(Fan &fan);
} __attribute__((packed));
class Fan : public EntityBase {
public:
Fan();
/// Construct the fan with name.
explicit Fan(const std::string &name);
/// The current on/off state of the fan.
bool state{false};
/// The current oscillation state of the fan.
bool oscillating{false};
/// The current fan speed level
int speed{0};
/// The current direction of the fan
FanDirection direction{FanDirection::FORWARD};
FanCall turn_on();
FanCall turn_off();
FanCall toggle();
FanCall make_call();
/// Register a callback that will be called each time the state changes.
void add_on_state_callback(std::function<void()> &&callback);
void publish_state();
virtual FanTraits get_traits() = 0;
/// Set the restore mode of this fan.
void set_restore_mode(FanRestoreMode restore_mode) { this->restore_mode_ = restore_mode; }
protected:
friend FanCall;
virtual void control(const FanCall &call) = 0;
optional<FanRestoreState> restore_state_();
void save_state_();
void dump_traits_(const char *tag, const char *prefix);
uint32_t hash_base() override;
CallbackManager<void()> state_callback_{};
ESPPreferenceObject rtc_;
FanRestoreMode restore_mode_;
};
} // namespace fan
} // namespace esphome

View File

@@ -1,5 +1,6 @@
#pragma once
#include "fan_state.h"
#include "fan.h"
namespace esphome {
namespace fan {

View File

@@ -1,121 +1,16 @@
#include "fan_state.h"
#include "fan_helpers.h"
#include "esphome/core/log.h"
namespace esphome {
namespace fan {
static const char *const TAG = "fan";
const FanTraits &FanState::get_traits() const { return this->traits_; }
void FanState::set_traits(const FanTraits &traits) { this->traits_ = traits; }
void FanState::add_on_state_callback(std::function<void()> &&callback) {
this->state_callback_.add(std::move(callback));
}
FanState::FanState(const std::string &name) : EntityBase(name) {}
FanStateCall FanState::turn_on() { return this->make_call().set_state(true); }
FanStateCall FanState::turn_off() { return this->make_call().set_state(false); }
FanStateCall FanState::toggle() { return this->make_call().set_state(!this->state); }
FanStateCall FanState::make_call() { return FanStateCall(this); }
struct FanStateRTCState {
bool state;
int speed;
bool oscillating;
FanDirection direction;
};
void FanState::setup() {
auto call = this->make_call();
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<FanStateRTCState>(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<FanStateRTCState>(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();
auto restore = this->restore_state_();
if (restore)
restore->to_call(*this).perform();
}
float FanState::get_setup_priority() const { return setup_priority::DATA - 1.0f; }
uint32_t FanState::hash_base() { return 418001110UL; }
void FanStateCall::perform() const {
if (this->binary_state_.has_value()) {
this->state_->state = *this->binary_state_;
}
if (this->oscillating_.has_value()) {
this->state_->oscillating = *this->oscillating_;
}
if (this->direction_.has_value()) {
this->state_->direction = *this->direction_;
}
if (this->speed_.has_value()) {
const int speed_count = this->state_->get_traits().supported_speed_count();
this->state_->speed = clamp(*this->speed_, 1, speed_count);
}
FanStateRTCState saved{};
saved.state = this->state_->state;
saved.speed = this->state_->speed;
saved.oscillating = this->state_->oscillating;
saved.direction = this->state_->direction;
this->state_->rtc_.save(&saved);
this->state_->state_callback_.call();
}
// This whole method is deprecated, don't warn about usage of deprecated methods inside of it.
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
FanStateCall &FanStateCall::set_speed(const char *legacy_speed) {
const auto supported_speed_count = this->state_->get_traits().supported_speed_count();
if (strcasecmp(legacy_speed, "low") == 0) {
this->set_speed(fan::speed_enum_to_level(FAN_SPEED_LOW, supported_speed_count));
} else if (strcasecmp(legacy_speed, "medium") == 0) {
this->set_speed(fan::speed_enum_to_level(FAN_SPEED_MEDIUM, supported_speed_count));
} else if (strcasecmp(legacy_speed, "high") == 0) {
this->set_speed(fan::speed_enum_to_level(FAN_SPEED_HIGH, supported_speed_count));
}
return *this;
}
} // namespace fan
} // namespace esphome

View File

@@ -1,126 +1,34 @@
#pragma once
#include "esphome/core/component.h"
#include "esphome/core/entity_base.h"
#include "esphome/core/helpers.h"
#include "esphome/core/preferences.h"
#include "esphome/core/log.h"
#include "fan_traits.h"
#include "fan.h"
namespace esphome {
namespace fan {
/// Simple enum to represent the speed of a fan. - DEPRECATED - Will be deleted soon
enum ESPDEPRECATED("FanSpeed is deprecated.", "2021.9") FanSpeed {
FAN_SPEED_LOW = 0, ///< The fan is running on low speed.
FAN_SPEED_MEDIUM = 1, ///< The fan is running on medium speed.
FAN_SPEED_HIGH = 2 ///< The fan is running on high/full speed.
enum ESPDEPRECATED("LegacyFanDirection members are deprecated, use FanDirection instead.",
"2022.2") LegacyFanDirection {
FAN_DIRECTION_FORWARD = 0,
FAN_DIRECTION_REVERSE = 1
};
/// 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 {
public:
explicit FanStateCall(FanState *state) : state_(state) {}
FanStateCall &set_state(bool binary_state) {
this->binary_state_ = binary_state;
return *this;
}
FanStateCall &set_state(optional<bool> binary_state) {
this->binary_state_ = binary_state;
return *this;
}
FanStateCall &set_oscillating(bool oscillating) {
this->oscillating_ = oscillating;
return *this;
}
FanStateCall &set_oscillating(optional<bool> oscillating) {
this->oscillating_ = oscillating;
return *this;
}
FanStateCall &set_speed(int speed) {
this->speed_ = speed;
return *this;
}
ESPDEPRECATED("set_speed() with string argument is deprecated, use integer argument instead.", "2021.9")
FanStateCall &set_speed(const char *legacy_speed);
FanStateCall &set_direction(FanDirection direction) {
this->direction_ = direction;
return *this;
}
FanStateCall &set_direction(optional<FanDirection> direction) {
this->direction_ = direction;
return *this;
}
void perform() const;
protected:
FanState *const state_;
optional<bool> binary_state_;
optional<bool> oscillating_;
optional<int> speed_;
optional<FanDirection> direction_{};
};
class FanState : public EntityBase, public Component {
class ESPDEPRECATED("FanState is deprecated, use Fan instead.", "2022.2") FanState : public Fan, public Component {
public:
FanState() = default;
/// Construct the fan state with name.
explicit FanState(const std::string &name);
explicit FanState(const std::string &name) : Fan(name) {}
/// Register a callback that will be called each time the state changes.
void add_on_state_callback(std::function<void()> &&callback);
/// Get the traits of this fan (i.e. what features it supports).
const FanTraits &get_traits() const;
/// Get the traits of this fan.
FanTraits get_traits() override { return this->traits_; }
/// 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.
bool oscillating{false};
/// The current fan speed level
int speed{};
/// The current direction of the fan
FanDirection direction{FAN_DIRECTION_FORWARD};
FanStateCall turn_on();
FanStateCall turn_off();
FanStateCall toggle();
FanStateCall make_call();
void set_traits(const FanTraits &traits) { this->traits_ = traits; }
void setup() override;
float get_setup_priority() const override;
protected:
friend FanStateCall;
uint32_t hash_base() override;
void control(const FanCall &call) override { this->publish_state(); }
FanTraits traits_{};
CallbackManager<void()> state_callback_{};
ESPPreferenceObject rtc_;
/// Restore mode of the fan.
FanRestoreMode restore_mode_;
};
} // namespace fan