[datetime] Use register_apply_action for date.set, time.set and datetime.set (#19513)

This commit is contained in:
J. Nick Koston
2026-09-23 23:21:39 +01:00
committed by GitHub
parent 606525ed18
commit 62b501049f
5 changed files with 100 additions and 159 deletions
+60 -117
View File
@@ -1,3 +1,5 @@
from collections.abc import Callable
from esphome import automation
import esphome.codegen as cg
from esphome.components import mqtt, time, web_server
@@ -21,13 +23,13 @@ from esphome.const import (
CONF_WEB_SERVER,
CONF_YEAR,
)
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import (
entity_duplicate_validator,
queue_entity_register,
setup_entity,
)
from esphome.cpp_generator import MockObj, MockObjClass, TemplateArgsType
from esphome.cpp_generator import MockObj, MockObjClass
from esphome.types import ConfigType, SafeExpType
CODEOWNERS = ["@rfdarter", "@jesserockz"]
@@ -40,11 +42,6 @@ DateEntity = datetime_ns.class_("DateEntity", DateTimeBase)
TimeEntity = datetime_ns.class_("TimeEntity", DateTimeBase)
DateTimeEntity = datetime_ns.class_("DateTimeEntity", DateTimeBase)
# Actions
DateSetAction = datetime_ns.class_("DateSetAction", automation.Action)
TimeSetAction = datetime_ns.class_("TimeSetAction", automation.Action)
DateTimeSetAction = datetime_ns.class_("DateTimeSetAction", automation.Action)
DateTimeStateTrigger = datetime_ns.class_(
"DateTimeStateTrigger", automation.Trigger.template(cg.ESPTime)
)
@@ -181,118 +178,64 @@ async def to_code(config: ConfigType) -> None:
cg.add_global(datetime_ns.using)
@automation.register_action(
"datetime.date.set",
DateSetAction,
cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(DateEntity),
cv.Required(CONF_DATE): cv.Any(
cv.returning_lambda, cv.date_time(date=True, time=False)
),
}
),
synchronous=True,
)
async def datetime_date_set_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
action_var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(action_var, config[CONF_ID])
date_config = config[CONF_DATE]
if cg.is_template(date_config):
template_ = await cg.templatable(date_config, args, cg.ESPTime)
cg.add(action_var.set_date(template_))
else:
date_struct = cg.StructInitializer(
cg.ESPTime,
("day_of_month", date_config[CONF_DAY]),
("month", date_config[CONF_MONTH]),
("year", date_config[CONF_YEAR]),
def _esptime_initializer(
members: tuple[tuple[str, str], ...],
) -> Callable[[ConfigType, ConfigType], str]:
def const_fn(config: ConfigType, value: ConfigType) -> str:
return str(
cg.StructInitializer(
cg.ESPTime, *((member, value[key]) for member, key in members)
)
)
template_ = await cg.templatable(date_struct, args, cg.ESPTime)
cg.add(action_var.set_date(template_))
return action_var
return const_fn
@automation.register_action(
"datetime.time.set",
TimeSetAction,
cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(TimeEntity),
cv.Required(CONF_TIME): cv.Any(
cv.returning_lambda, cv.date_time(date=False, time=True)
),
}
# ESPTime member order, so the designated initializer compiles.
_TIME_MEMBERS = (("second", CONF_SECOND), ("minute", CONF_MINUTE), ("hour", CONF_HOUR))
_DATE_MEMBERS = (("day_of_month", CONF_DAY), ("month", CONF_MONTH), ("year", CONF_YEAR))
for _name, _entity, _key, _target, _date, _time, _members in (
(
"datetime.date.set",
DateEntity,
CONF_DATE,
"set_date",
True,
False,
_DATE_MEMBERS,
),
synchronous=True,
)
async def datetime_time_set_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
action_var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(action_var, config[CONF_ID])
time_config = config[CONF_TIME]
if cg.is_template(time_config):
template_ = await cg.templatable(time_config, args, cg.ESPTime)
cg.add(action_var.set_time(template_))
else:
time_struct = cg.StructInitializer(
cg.ESPTime,
("second", time_config[CONF_SECOND]),
("minute", time_config[CONF_MINUTE]),
("hour", time_config[CONF_HOUR]),
)
template_ = await cg.templatable(time_struct, args, cg.ESPTime)
cg.add(action_var.set_time(template_))
return action_var
@automation.register_action(
"datetime.datetime.set",
DateTimeSetAction,
cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(DateTimeEntity),
cv.Required(CONF_DATETIME): cv.Any(
cv.returning_lambda, cv.date_time(date=True, time=True)
),
},
(
"datetime.time.set",
TimeEntity,
CONF_TIME,
"set_time",
False,
True,
_TIME_MEMBERS,
),
synchronous=True,
)
async def datetime_datetime_set_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
action_var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(action_var, config[CONF_ID])
datetime_config = config[CONF_DATETIME]
if cg.is_template(datetime_config):
template_ = await cg.templatable(datetime_config, args, cg.ESPTime)
cg.add(action_var.set_datetime(template_))
else:
datetime_struct = cg.StructInitializer(
cg.ESPTime,
("second", datetime_config[CONF_SECOND]),
("minute", datetime_config[CONF_MINUTE]),
("hour", datetime_config[CONF_HOUR]),
("day_of_month", datetime_config[CONF_DAY]),
("month", datetime_config[CONF_MONTH]),
("year", datetime_config[CONF_YEAR]),
)
template_ = await cg.templatable(datetime_struct, args, cg.ESPTime)
cg.add(action_var.set_datetime(template_))
return action_var
(
"datetime.datetime.set",
DateTimeEntity,
CONF_DATETIME,
"set_datetime",
True,
True,
_TIME_MEMBERS + _DATE_MEMBERS,
),
):
automation.register_apply_action(
_name,
cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(_entity),
cv.Required(_key): cv.Any(
cv.returning_lambda, cv.date_time(date=_date, time=_time)
),
}
),
automation.ApplyField(
_key, _target, cg.ESPTime, const_fn=_esptime_initializer(_members)
),
call="make_call",
)
-14
View File
@@ -98,20 +98,6 @@ class DateCall {
inline DateCall DateEntity::make_call() { return DateCall(this); }
template<typename... Ts> class DateSetAction final : public Action<Ts...>, public Parented<DateEntity> {
public:
TEMPLATABLE_VALUE(ESPTime, date)
void play(const Ts &...x) override {
auto call = this->parent_->make_call();
if (this->date_.has_value()) {
call.set_date(this->date_.value(x...));
}
call.perform();
}
};
} // namespace esphome::datetime
#endif // USE_DATETIME_DATE
@@ -123,20 +123,6 @@ class DateTimeCall {
inline DateTimeCall DateTimeEntity::make_call() { return DateTimeCall(this); }
template<typename... Ts> class DateTimeSetAction final : public Action<Ts...>, public Parented<DateTimeEntity> {
public:
TEMPLATABLE_VALUE(ESPTime, datetime)
void play(const Ts &...x) override {
auto call = this->parent_->make_call();
if (this->datetime_.has_value()) {
call.set_datetime(this->datetime_.value(x...));
}
call.perform();
}
};
#ifdef USE_TIME
class OnDateTimeTrigger final : public Trigger<>, public Component, public Parented<DateTimeEntity> {
public:
-14
View File
@@ -100,20 +100,6 @@ class TimeCall {
inline TimeCall TimeEntity::make_call() { return TimeCall(this); }
template<typename... Ts> class TimeSetAction final : public Action<Ts...>, public Parented<TimeEntity> {
public:
TEMPLATABLE_VALUE(ESPTime, time)
void play(const Ts &...x) override {
auto call = this->parent_->make_call();
if (this->time_.has_value()) {
call.set_time(this->time_.value(x...));
}
call.perform();
}
};
#ifdef USE_TIME
class OnTimeTrigger final : public Trigger<>, public Component, public Parented<TimeEntity> {
public:
+40
View File
@@ -1,3 +1,43 @@
esphome:
on_boot:
then:
- datetime.date.set:
id: datetime_test_date
date:
year: 2021
month: 1
day: 1
- datetime.date.set:
id: datetime_test_date
date: !lambda "return {.day_of_month = 1, .month = 1, .year = 2021};"
- datetime.time.set:
id: datetime_test_time
time: "12:34:56"
- datetime.time.set:
id: datetime_test_time
time: !lambda "return {.second = 56, .minute = 34, .hour = 12};"
- datetime.datetime.set:
id: datetime_test_datetime
datetime: "2021-01-01 12:34:56"
- datetime.datetime.set:
id: datetime_test_datetime
datetime: !lambda "return {.second = 56, .minute = 34, .hour = 12, .day_of_month = 1, .month = 1, .year = 2021};"
datetime:
- platform: template
name: Datetime Test Date
id: datetime_test_date
type: date
optimistic: true
- platform: template
name: Datetime Test Time
id: datetime_test_time
type: time
optimistic: true
- platform: template
name: Datetime Test DateTime
id: datetime_test_datetime
type: datetime
optimistic: true
time: