diff --git a/esphome/components/fan/__init__.py b/esphome/components/fan/__init__.py index f8772948fc..15895976d1 100644 --- a/esphome/components/fan/__init__.py +++ b/esphome/components/fan/__init__.py @@ -41,6 +41,7 @@ FAN_DIRECTION_ENUM = { TurnOnAction = fan_ns.class_("TurnOnAction", automation.Action) TurnOffAction = fan_ns.class_("TurnOffAction", automation.Action) ToggleAction = fan_ns.class_("ToggleAction", automation.Action) +CycleSpeedAction = fan_ns.class_("CycleSpeedAction", automation.Action) FanTurnOnTrigger = fan_ns.class_("FanTurnOnTrigger", automation.Trigger.template()) FanTurnOffTrigger = fan_ns.class_("FanTurnOffTrigger", automation.Trigger.template()) @@ -204,6 +205,12 @@ async def fan_turn_on_to_code(config, action_id, template_arg, args): return var +@automation.register_action("fan.cycle_speed", CycleSpeedAction, FAN_ACTION_SCHEMA) +async def fan_cycle_speed_to_code(config, action_id, template_arg, args): + paren = await cg.get_variable(config[CONF_ID]) + return cg.new_Pvariable(action_id, template_arg, paren) + + @automation.register_condition( "fan.is_on", FanIsOnCondition, diff --git a/esphome/components/fan/automation.h b/esphome/components/fan/automation.h index 7ff7c720df..608f772b75 100644 --- a/esphome/components/fan/automation.h +++ b/esphome/components/fan/automation.h @@ -50,6 +50,42 @@ template class ToggleAction : public Action { FanState *state_; }; +template class CycleSpeedAction : public Action { + public: + explicit CycleSpeedAction(FanState *state) : state_(state) {} + + void play(Ts... x) override { + // check to see if fan supports speeds and is on + if (this->state_->get_traits().supported_speed_count()) { + if (this->state_->state) { + int speed = this->state_->speed + 1; + int supported_speed_count = this->state_->get_traits().supported_speed_count(); + if (speed > supported_speed_count) { + // was running at max speed, so turn off + speed = 1; + auto call = this->state_->turn_off(); + call.set_speed(speed); + call.perform(); + } else { + auto call = this->state_->turn_on(); + call.set_speed(speed); + call.perform(); + } + } else { + // fan was off, so set speed to 1 + auto call = this->state_->turn_on(); + call.set_speed(1); + call.perform(); + } + } else { + // fan doesn't support speed counts, so toggle + this->state_->toggle().perform(); + } + } + + FanState *state_; +}; + template class FanIsOnCondition : public Condition { public: explicit FanIsOnCondition(FanState *state) : state_(state) {}