From 606525ed18e50586caef7bd9cc84fcf7b3a863d5 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 23 Sep 2026 23:21:21 +0100 Subject: [PATCH] [output] Use register_apply_action for the output actions (#19512) --- esphome/components/output/__init__.py | 113 ++++++++++--------------- esphome/components/output/automation.h | 69 --------------- tests/components/output/common.yaml | 3 + 3 files changed, 48 insertions(+), 137 deletions(-) delete mode 100644 esphome/components/output/automation.h diff --git a/esphome/components/output/__init__.py b/esphome/components/output/__init__.py index 10d5e5eb59..1b79403784 100644 --- a/esphome/components/output/__init__.py +++ b/esphome/components/output/__init__.py @@ -1,3 +1,5 @@ +from dataclasses import dataclass + from esphome import automation from esphome.automation import maybe_simple_id import esphome.codegen as cg @@ -12,12 +14,26 @@ from esphome.const import ( CONF_POWER_SUPPLY, ) from esphome.core import CORE +from esphome.types import ConfigType CODEOWNERS = ["@esphome/core"] IS_PLATFORM_COMPONENT = True +DOMAIN = "output" CONF_ZERO_MEANS_ZERO = "zero_means_zero" + +@dataclass +class OutputData: + power_scaling: bool = False + + +def _get_data() -> OutputData: + if DOMAIN not in CORE.data: + CORE.data[DOMAIN] = OutputData() + return CORE.data[DOMAIN] + + BINARY_OUTPUT_SCHEMA = cv.Schema( { cv.Optional(CONF_POWER_SUPPLY): cv.use_id(power_supply.PowerSupply), @@ -39,13 +55,6 @@ BinaryOutputPtr = BinaryOutput.operator("ptr") FloatOutput = output_ns.class_("FloatOutput", BinaryOutput) FloatOutputPtr = FloatOutput.operator("ptr") -# Actions -TurnOffAction = output_ns.class_("TurnOffAction", automation.Action) -TurnOnAction = output_ns.class_("TurnOnAction", automation.Action) -SetLevelAction = output_ns.class_("SetLevelAction", automation.Action) -SetMinPowerAction = output_ns.class_("SetMinPowerAction", automation.Action) -SetMaxPowerAction = output_ns.class_("SetMaxPowerAction", automation.Action) - async def setup_output_platform_(obj, config): if CONF_INVERTED in config: @@ -85,81 +94,49 @@ BINARY_OUTPUT_ACTION_SCHEMA = maybe_simple_id( ) -@automation.register_action( - "output.turn_on", TurnOnAction, BINARY_OUTPUT_ACTION_SCHEMA, synchronous=True -) -async def output_turn_on_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) +def _enable_power_scaling(config: ConfigType) -> ConfigType: + # set_min_power/set_max_power only exist with the define; to_code emits it from this fact. + _get_data().power_scaling = True + return config -@automation.register_action( - "output.turn_off", TurnOffAction, BINARY_OUTPUT_ACTION_SCHEMA, synchronous=True -) -async def output_turn_off_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) +for _name, _call in ( + ("output.turn_on", "turn_on()"), + ("output.turn_off", "turn_off()"), +): + automation.register_apply_action( + _name, BINARY_OUTPUT_ACTION_SCHEMA, automation.ApplyCall(_call) + ) - -@automation.register_action( +automation.register_apply_action( "output.set_level", - SetLevelAction, cv.Schema( { cv.Required(CONF_ID): cv.use_id(FloatOutput), cv.Required(CONF_LEVEL): cv.templatable(cv.percentage), } ), - synchronous=True, + automation.ApplyField(CONF_LEVEL, "set_level", cg.float_), ) -async def output_set_level_to_code(config, action_id, template_arg, args): - paren = await cg.get_variable(config[CONF_ID]) - var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = await cg.templatable(config[CONF_LEVEL], args, cg.float_) - cg.add(var.set_level(template_)) - return var - -@automation.register_action( - "output.set_min_power", - SetMinPowerAction, - cv.Schema( - { - cv.Required(CONF_ID): cv.use_id(FloatOutput), - cv.Required(CONF_MIN_POWER): cv.templatable(cv.percentage), - } - ), - synchronous=True, -) -async def output_set_min_power_to_code(config, action_id, template_arg, args): - cg.add_define("USE_OUTPUT_FLOAT_POWER_SCALING") - paren = await cg.get_variable(config[CONF_ID]) - var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = await cg.templatable(config[CONF_MIN_POWER], args, cg.float_) - cg.add(var.set_min_power(template_)) - return var - - -@automation.register_action( - "output.set_max_power", - SetMaxPowerAction, - cv.Schema( - { - cv.Required(CONF_ID): cv.use_id(FloatOutput), - cv.Required(CONF_MAX_POWER): cv.templatable(cv.percentage), - } - ), - synchronous=True, -) -async def output_set_max_power_to_code(config, action_id, template_arg, args): - cg.add_define("USE_OUTPUT_FLOAT_POWER_SCALING") - paren = await cg.get_variable(config[CONF_ID]) - var = cg.new_Pvariable(action_id, template_arg, paren) - template_ = await cg.templatable(config[CONF_MAX_POWER], args, cg.float_) - cg.add(var.set_max_power(template_)) - return var +for _name, _key, _target in ( + ("output.set_min_power", CONF_MIN_POWER, "set_min_power"), + ("output.set_max_power", CONF_MAX_POWER, "set_max_power"), +): + automation.register_apply_action( + _name, + cv.Schema( + { + cv.Required(CONF_ID): cv.use_id(FloatOutput), + cv.Required(_key): cv.templatable(cv.percentage), + } + ).add_extra(_enable_power_scaling), + automation.ApplyField(_key, _target, cg.float_), + ) async def to_code(config): cg.add_define("USE_OUTPUT") + if _get_data().power_scaling: + cg.add_define("USE_OUTPUT_FLOAT_POWER_SCALING") cg.add_global(output_ns.using) diff --git a/esphome/components/output/automation.h b/esphome/components/output/automation.h deleted file mode 100644 index efe775ba57..0000000000 --- a/esphome/components/output/automation.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include "esphome/core/component.h" -#include "esphome/core/automation.h" -#include "esphome/core/defines.h" -#include "esphome/components/output/binary_output.h" -#include "esphome/components/output/float_output.h" - -namespace esphome::output { - -template class TurnOffAction final : public Action { - public: - TurnOffAction(BinaryOutput *output) : output_(output) {} - - void play(const Ts &...x) override { this->output_->turn_off(); } - - protected: - BinaryOutput *output_; -}; - -template class TurnOnAction final : public Action { - public: - TurnOnAction(BinaryOutput *output) : output_(output) {} - - void play(const Ts &...x) override { this->output_->turn_on(); } - - protected: - BinaryOutput *output_; -}; - -template class SetLevelAction final : public Action { - public: - SetLevelAction(FloatOutput *output) : output_(output) {} - - TEMPLATABLE_VALUE(float, level) - - void play(const Ts &...x) override { this->output_->set_level(this->level_.value(x...)); } - - protected: - FloatOutput *output_; -}; - -#ifdef USE_OUTPUT_FLOAT_POWER_SCALING -template class SetMinPowerAction final : public Action { - public: - SetMinPowerAction(FloatOutput *output) : output_(output) {} - - TEMPLATABLE_VALUE(float, min_power) - - void play(const Ts &...x) override { this->output_->set_min_power(this->min_power_.value(x...)); } - - protected: - FloatOutput *output_; -}; - -template class SetMaxPowerAction final : public Action { - public: - SetMaxPowerAction(FloatOutput *output) : output_(output) {} - - TEMPLATABLE_VALUE(float, max_power) - - void play(const Ts &...x) override { this->output_->set_max_power(this->max_power_.value(x...)); } - - protected: - FloatOutput *output_; -}; -#endif // USE_OUTPUT_FLOAT_POWER_SCALING - -} // namespace esphome::output diff --git a/tests/components/output/common.yaml b/tests/components/output/common.yaml index df20dcde2b..6448b3cfe6 100644 --- a/tests/components/output/common.yaml +++ b/tests/components/output/common.yaml @@ -6,6 +6,9 @@ esphome: - output.set_level: id: output_light_output_1 level: 50% + - output.set_level: + id: output_light_output_1 + level: !lambda return 0.25f; - output.set_min_power: id: output_light_output_1 min_power: 20%