Compare commits

..
176 changed files with 2538 additions and 1836 deletions
+1 -3
View File
@@ -737,9 +737,7 @@ file does, and it is the authority when they disagree. The most useful starting
6. **Avoid `std::deque`:** It allocates in 512-byte blocks regardless of element size, guaranteeing at least 512 bytes of RAM usage immediately. This is a major source of crashes on memory-constrained devices.
7. **Never use `new (std::nothrow)`:** On ESP-IDF exceptions are disabled, so a failed nothrow allocation aborts instead of returning `nullptr`. Use `RAMAllocator` from `esphome/core/helpers.h`; CI rejects `std::nothrow`.
8. **Detection:** Look for these patterns in compiler output:
7. **Detection:** Look for these patterns in compiler output:
- Large code sections with STL symbols (vector, map, set)
- `alloc`, `realloc`, `dealloc` in symbol names
- `_M_realloc_insert`, `_M_default_append` (vector reallocation)
-6
View File
@@ -762,7 +762,6 @@ def _wrap_to_code(name, comp, yaml_util):
@functools.wraps(comp.to_code)
async def wrapped(conf):
cg.add(cg.ComponentMarker(name))
cg.add(cg.LineComment(f"{name}:"))
if comp.config_schema is not None:
# sort_keys: voluptuous fills defaults in set order, so an
@@ -1344,12 +1343,8 @@ def _upload_via_native_api(
# fall back to a plaintext upload
noise_psk = None
plaintext_fallback = False
allow_plaintext_upload = False
if (encryption_conf := ota_conf.get(CONF_ENCRYPTION)) is not None:
noise_psk = encryption_conf.get(CONF_KEY)
allow_plaintext_upload = bool(
encryption_conf.get(espota2.CONF_ALLOW_PLAINTEXT_UPLOAD)
)
if not noise_psk:
raise EsphomeError(
"OTA encryption is configured but no key was resolved; "
@@ -1400,7 +1395,6 @@ def _upload_via_native_api(
ota_type,
noise_psk,
plaintext_fallback=plaintext_fallback,
allow_plaintext_upload=allow_plaintext_upload,
)
+1 -2
View File
@@ -5,7 +5,6 @@ from __future__ import annotations
from collections import defaultdict
from collections.abc import Callable
import heapq
import json
from operator import itemgetter
from pathlib import Path
import sys
@@ -43,7 +42,7 @@ class MemoryAnalyzerCLI(MemoryAnalyzer):
# Symbol size threshold for detailed analysis
SYMBOL_SIZE_THRESHOLD: int = (
10 # Show symbols larger than this in detailed analysis
100 # Show symbols larger than this in detailed analysis
)
# Lower threshold for RAM symbols (RAM is more constrained)
RAM_SYMBOL_SIZE_THRESHOLD: int = 24
-1
View File
@@ -10,7 +10,6 @@
# pylint: disable=unused-import
from esphome.cpp_generator import ( # noqa: F401
ArrayInitializer,
ComponentMarker,
Expression,
FlashStringLiteral,
LineComment,
@@ -41,6 +41,10 @@ StateAnyForwarder = alarm_control_panel_ns.class_("StateAnyForwarder")
StateEnterForwarder = alarm_control_panel_ns.class_("StateEnterForwarder")
AlarmControlPanelState = alarm_control_panel_ns.enum("AlarmControlPanelState")
PendingAction = alarm_control_panel_ns.class_("PendingAction", automation.Action)
TriggeredAction = alarm_control_panel_ns.class_("TriggeredAction", automation.Action)
ChimeAction = alarm_control_panel_ns.class_("ChimeAction", automation.Action)
ReadyAction = alarm_control_panel_ns.class_("ReadyAction", automation.Action)
AlarmControlPanelCondition = alarm_control_panel_ns.class_(
"AlarmControlPanelCondition", automation.Condition
@@ -204,30 +208,65 @@ for _name, _arm in (
)
for _name, _call in (
("alarm_control_panel.pending", "pending()"),
("alarm_control_panel.triggered", "triggered()"),
):
automation.register_apply_action(
_name,
ALARM_CONTROL_PANEL_ACTION_SCHEMA,
automation.ApplyCall(_call),
call="make_call",
)
@automation.register_action(
"alarm_control_panel.pending",
PendingAction,
ALARM_CONTROL_PANEL_ACTION_SCHEMA,
synchronous=True,
)
async def alarm_action_pending_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_simple_condition(
@automation.register_action(
"alarm_control_panel.triggered",
TriggeredAction,
ALARM_CONTROL_PANEL_ACTION_SCHEMA,
synchronous=True,
)
async def alarm_action_trigger_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_action(
"alarm_control_panel.chime",
ChimeAction,
ALARM_CONTROL_PANEL_ACTION_SCHEMA,
synchronous=True,
)
async def alarm_action_chime_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_action(
"alarm_control_panel.ready",
ReadyAction,
ALARM_CONTROL_PANEL_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_condition(
"alarm_control_panel.ready",
AlarmControlPanelCondition,
ALARM_CONTROL_PANEL_CONDITION_SCHEMA,
)
async def alarm_action_ready_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_simple_condition(
@automation.register_condition(
"alarm_control_panel.is_armed",
AlarmControlPanelCondition,
ALARM_CONTROL_PANEL_CONDITION_SCHEMA,
)
async def alarm_control_panel_is_armed_to_code(
config, condition_id, template_arg, args
):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(condition_id, template_arg, paren)
@coroutine_with_priority(CoroPriority.CORE)
@@ -27,6 +27,26 @@ static_assert(std::is_trivially_copyable_v<StateAnyForwarder>);
static_assert(sizeof(StateEnterForwarder<ACP_STATE_TRIGGERED>) <= sizeof(void *));
static_assert(std::is_trivially_copyable_v<StateEnterForwarder<ACP_STATE_TRIGGERED>>);
template<typename... Ts> class PendingAction final : public Action<Ts...> {
public:
explicit PendingAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
void play(const Ts &...x) override { this->alarm_control_panel_->make_call().pending().perform(); }
protected:
AlarmControlPanel *alarm_control_panel_;
};
template<typename... Ts> class TriggeredAction final : public Action<Ts...> {
public:
explicit TriggeredAction(AlarmControlPanel *alarm_control_panel) : alarm_control_panel_(alarm_control_panel) {}
void play(const Ts &...x) override { this->alarm_control_panel_->make_call().triggered().perform(); }
protected:
AlarmControlPanel *alarm_control_panel_;
};
template<typename... Ts> class AlarmControlPanelCondition final : public Condition<Ts...> {
public:
AlarmControlPanelCondition(AlarmControlPanel *parent) : parent_(parent) {}
+4 -1
View File
@@ -655,7 +655,7 @@ async def to_code(config):
cg.add_global(binary_sensor_ns.using)
automation.register_simple_action(
@automation.register_action(
"binary_sensor.invalidate_state",
BinarySensorInvalidateAction,
cv.maybe_simple_value(
@@ -666,6 +666,9 @@ automation.register_simple_action(
),
synchronous=True,
)
async def binary_sensor_invalidate_state_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.cpp only implements the click/double_click/multi_click triggers
+12 -1
View File
@@ -32,6 +32,8 @@ from esphome.const import (
UNIT_VOLT,
UNIT_WATT,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
# Import ICONS not included in esphome's const.py, from the local components const.py
@@ -136,7 +138,7 @@ FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
)
automation.register_parented_action(
@automation.register_action(
"bl0906.reset_energy",
ResetEnergyAction,
maybe_simple_id(
@@ -146,6 +148,15 @@ automation.register_parented_action(
),
synchronous=True,
)
async def reset_energy_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config: ConfigType) -> None:
+12 -3
View File
@@ -207,20 +207,26 @@ BLE_REMOVE_BOND_ACTION_SCHEMA = cv.Schema(
)
automation.register_simple_action(
@automation.register_action(
"ble_client.disconnect",
BLEDisconnectAction,
BLE_CONNECT_ACTION_SCHEMA,
synchronous=False,
)
async def ble_disconnect_to_code(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, parent)
automation.register_simple_action(
@automation.register_action(
"ble_client.connect",
BLEConnectAction,
BLE_CONNECT_ACTION_SCHEMA,
synchronous=False,
)
async def ble_connect_to_code(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, parent)
@automation.register_action(
@@ -322,12 +328,15 @@ async def passkey_reply_to_code(config, action_id, template_arg, args):
return var
automation.register_simple_action(
@automation.register_action(
"ble_client.remove_bond",
BLERemoveBondAction,
BLE_REMOVE_BOND_ACTION_SCHEMA,
synchronous=True,
)
async def remove_bond_to_code(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, parent)
async def to_code(config):
+20 -2
View File
@@ -28,7 +28,7 @@ CONFIG_SCHEMA = (
)
automation.register_parented_action(
@automation.register_action(
"bm8563.write_time",
WriteAction,
automation.maybe_simple_id(
@@ -38,6 +38,15 @@ automation.register_parented_action(
),
synchronous=True,
)
async def bm8563_write_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@automation.register_action(
@@ -64,7 +73,7 @@ async def bm8563_start_timer_to_code(
return var
automation.register_parented_action(
@automation.register_action(
"bm8563.read_time",
ReadAction,
automation.maybe_simple_id(
@@ -74,6 +83,15 @@ automation.register_parented_action(
),
synchronous=True,
)
async def bm8563_read_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config: ConfigType) -> None:
+14 -4
View File
@@ -16,14 +16,14 @@ from esphome.const import (
DEVICE_CLASS_RESTART,
DEVICE_CLASS_UPDATE,
)
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
from esphome.core.entity_helpers import (
entity_duplicate_validator,
queue_entity_register,
setup_device_class,
setup_entity,
)
from esphome.cpp_generator import MockObj, MockObjClass
from esphome.cpp_generator import MockObj, MockObjClass, TemplateArgsType
from esphome.types import ConfigType, SafeExpType
CODEOWNERS = ["@esphome/core"]
@@ -40,6 +40,8 @@ button_ns = cg.esphome_ns.namespace("button")
Button = button_ns.class_("Button", cg.EntityBase)
ButtonPtr = Button.operator("ptr")
PressAction = button_ns.class_("PressAction", automation.Action)
validate_device_class = cv.one_of(*DEVICE_CLASSES, lower=True, space="_")
@@ -121,9 +123,17 @@ BUTTON_PRESS_SCHEMA = maybe_simple_id(
)
automation.register_apply_action(
"button.press", BUTTON_PRESS_SCHEMA, automation.ApplyCall("press()")
@automation.register_action(
"button.press", PressAction, BUTTON_PRESS_SCHEMA, synchronous=True
)
async def button_press_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
@coroutine_with_priority(CoroPriority.CORE)
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "esphome/components/button/button.h"
#include "esphome/core/automation.h"
#include "esphome/core/component.h"
namespace esphome::button {
template<typename... Ts> class PressAction final : public Action<Ts...> {
public:
explicit PressAction(Button *button) : button_(button) {}
void play(const Ts &...x) override { this->button_->press(); }
protected:
Button *button_;
};
} // namespace esphome::button
+12 -26
View File
@@ -364,36 +364,22 @@ CC1101_ACTION_SCHEMA = cv.Schema(
)
automation.register_parented_action(
"cc1101.begin_tx",
BeginTxAction,
CC1101_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"cc1101.begin_tx", BeginTxAction, CC1101_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
"cc1101.begin_rx",
BeginRxAction,
CC1101_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"cc1101.begin_rx", BeginRxAction, CC1101_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
"cc1101.reset",
ResetAction,
CC1101_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"cc1101.reset", ResetAction, CC1101_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
"cc1101.set_idle",
SetIdleAction,
CC1101_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"cc1101.set_idle", SetIdleAction, CC1101_ACTION_SCHEMA, synchronous=True
)
async def cc1101_action_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
def validate_raw_data(value):
+12 -1
View File
@@ -13,6 +13,8 @@ from esphome.const import (
STATE_CLASS_MEASUREMENT,
UNIT_PARTS_PER_MILLION,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
DEPENDENCIES = ["uart"]
@@ -70,9 +72,18 @@ CALIBRATION_ACTION_SCHEMA = maybe_simple_id(
)
automation.register_simple_action(
@automation.register_action(
"cm1106.calibrate_zero",
CM1106CalibrateZeroAction,
CALIBRATION_ACTION_SCHEMA,
synchronous=True,
)
async def cm1106_calibration_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
"""Service code generation entry point."""
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
+11 -1
View File
@@ -17,6 +17,8 @@ from esphome.const import (
UNIT_VOLT,
UNIT_WATT,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@balrog-kun"]
@@ -129,7 +131,7 @@ async def to_code(config: ConfigType) -> None:
cg.add(var.set_power_sensor(sens))
automation.register_simple_action(
@automation.register_action(
"cs5460a.restart",
CS5460ARestartAction,
maybe_simple_id(
@@ -139,3 +141,11 @@ automation.register_simple_action(
),
synchronous=True,
)
async def restart_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
+31 -9
View File
@@ -214,6 +214,16 @@ def _validate_sleep_duration(value: core.TimePeriod) -> core.TimePeriod:
deep_sleep_ns = cg.esphome_ns.namespace("deep_sleep")
DeepSleepComponent = deep_sleep_ns.class_("DeepSleepComponent", cg.Component)
EnterDeepSleepAction = deep_sleep_ns.class_("EnterDeepSleepAction", automation.Action)
PreventDeepSleepAction = deep_sleep_ns.class_(
"PreventDeepSleepAction",
automation.Action,
cg.Parented.template(DeepSleepComponent),
)
AllowDeepSleepAction = deep_sleep_ns.class_(
"AllowDeepSleepAction",
automation.Action,
cg.Parented.template(DeepSleepComponent),
)
WakeupPinMode = deep_sleep_ns.enum("WakeupPinMode")
WAKEUP_PIN_MODES = {
@@ -480,15 +490,27 @@ async def deep_sleep_enter_to_code(
return var
for _name, _call in (
("deep_sleep.prevent", "prevent_deep_sleep()"),
("deep_sleep.allow", "allow_deep_sleep()"),
):
automation.register_apply_action(
_name,
automation.maybe_simple_id(DEEP_SLEEP_ACTION_SCHEMA),
automation.ApplyCall(_call),
)
@automation.register_action(
"deep_sleep.prevent",
PreventDeepSleepAction,
automation.maybe_simple_id(DEEP_SLEEP_ACTION_SCHEMA),
synchronous=True,
)
@automation.register_action(
"deep_sleep.allow",
AllowDeepSleepAction,
automation.maybe_simple_id(DEEP_SLEEP_ACTION_SCHEMA),
synchronous=True,
)
async def deep_sleep_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
FILTER_SOURCE_FILES = filter_source_files_from_platform(
@@ -121,6 +121,8 @@ class Ext1WakeTrigger : public Trigger<>, public Component {
template<typename... Ts> class EnterDeepSleepAction;
template<typename... Ts> class PreventDeepSleepAction;
/** This component allows setting up the node to go into deep sleep mode to conserve battery.
*
* To set this component up, first set *when* the deep sleep should trigger using set_run_cycles
@@ -296,4 +298,15 @@ template<typename... Ts> class EnterDeepSleepAction final : public Action<Ts...>
#endif
};
template<typename... Ts>
class PreventDeepSleepAction final : public Action<Ts...>, public Parented<DeepSleepComponent> {
public:
void play(const Ts &...x) override { this->parent_->prevent_deep_sleep(); }
};
template<typename... Ts> class AllowDeepSleepAction final : public Action<Ts...>, public Parented<DeepSleepComponent> {
public:
void play(const Ts &...x) override { this->parent_->allow_deep_sleep(); }
};
} // namespace esphome::deep_sleep
+5 -1
View File
@@ -199,7 +199,7 @@ automation.register_apply_action(
)
automation.register_parented_condition(
@automation.register_condition(
"dfplayer.is_playing",
DFPlayerIsPlayingCondition,
cv.Schema(
@@ -208,3 +208,7 @@ automation.register_parented_condition(
}
),
)
async def dfplayer_is_playing_to_code(config, condition_id, template_arg, args):
var = cg.new_Pvariable(condition_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+11 -1
View File
@@ -49,7 +49,7 @@ async def to_code(config: ConfigType) -> None:
await uart.register_uart_device(var, config)
automation.register_parented_action(
@automation.register_action(
"dfrobot_sen0395.reset",
DfrobotSen0395ResetAction,
maybe_simple_id(
@@ -59,6 +59,16 @@ automation.register_parented_action(
),
synchronous=True,
)
async def dfrobot_sen0395_reset_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
def range_segment_list(input: Any) -> list:
@@ -55,6 +55,18 @@ MenuItemSwitch = display_menu_base_ns.class_("MenuItemSwitch")
MenuItemCommand = display_menu_base_ns.class_("MenuItemCommand")
MenuItemCustom = display_menu_base_ns.class_("MenuItemCustom")
UpAction = display_menu_base_ns.class_("UpAction", automation.Action)
DownAction = display_menu_base_ns.class_("DownAction", automation.Action)
LeftAction = display_menu_base_ns.class_("LeftAction", automation.Action)
RightAction = display_menu_base_ns.class_("RightAction", automation.Action)
EnterAction = display_menu_base_ns.class_("EnterAction", automation.Action)
ShowAction = display_menu_base_ns.class_("ShowAction", automation.Action)
HideAction = display_menu_base_ns.class_("HideAction", automation.Action)
ShowMainAction = display_menu_base_ns.class_("ShowMainAction", automation.Action)
IsActiveCondition = display_menu_base_ns.class_(
"IsActiveCondition", automation.Condition
)
MenuItemType = display_menu_base_ns.enum("MenuItemType")
@@ -282,23 +294,85 @@ MENU_ACTION_SCHEMA = maybe_simple_id(
)
for _name, _call in (
("display_menu.up", "up()"),
("display_menu.down", "down()"),
("display_menu.left", "left()"),
("display_menu.right", "right()"),
("display_menu.enter", "enter()"),
("display_menu.show", "show()"),
("display_menu.hide", "hide()"),
("display_menu.show_main", "show_main()"),
):
automation.register_apply_action(
_name, MENU_ACTION_SCHEMA, automation.ApplyCall(_call)
)
automation.register_apply_condition(
"display_menu.is_active", MENU_ACTION_SCHEMA, "is_active()"
@automation.register_action(
"display_menu.up", UpAction, MENU_ACTION_SCHEMA, synchronous=True
)
async def menu_up_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_action(
"display_menu.down", DownAction, MENU_ACTION_SCHEMA, synchronous=True
)
async def menu_down_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_action(
"display_menu.left", LeftAction, MENU_ACTION_SCHEMA, synchronous=True
)
async def menu_left_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_action(
"display_menu.right", RightAction, MENU_ACTION_SCHEMA, synchronous=True
)
async def menu_right_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_action(
"display_menu.enter", EnterAction, MENU_ACTION_SCHEMA, synchronous=True
)
async def menu_enter_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_action(
"display_menu.show", ShowAction, MENU_ACTION_SCHEMA, synchronous=True
)
async def menu_show_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_action(
"display_menu.hide", HideAction, MENU_ACTION_SCHEMA, synchronous=True
)
async def menu_hide_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_action(
"display_menu.show_main",
ShowMainAction,
MENU_ACTION_SCHEMA,
synchronous=True,
)
async def menu_show_main_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(
"display_menu.is_active",
IsActiveCondition,
automation.maybe_simple_id(
{
cv.GenerateID(CONF_ID): cv.use_id(DisplayMenuComponent),
}
),
)
async def display_menu_is_active_to_code(config, condition_id, template_arg, args):
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(condition_id, template_arg, paren)
async def menu_item_to_code(menu, config, parent):
@@ -5,6 +5,94 @@
namespace esphome::display_menu_base {
template<typename... Ts> class UpAction final : public Action<Ts...> {
public:
explicit UpAction(DisplayMenuComponent *menu) : menu_(menu) {}
void play(const Ts &...x) override { this->menu_->up(); }
protected:
DisplayMenuComponent *menu_;
};
template<typename... Ts> class DownAction final : public Action<Ts...> {
public:
explicit DownAction(DisplayMenuComponent *menu) : menu_(menu) {}
void play(const Ts &...x) override { this->menu_->down(); }
protected:
DisplayMenuComponent *menu_;
};
template<typename... Ts> class LeftAction final : public Action<Ts...> {
public:
explicit LeftAction(DisplayMenuComponent *menu) : menu_(menu) {}
void play(const Ts &...x) override { this->menu_->left(); }
protected:
DisplayMenuComponent *menu_;
};
template<typename... Ts> class RightAction final : public Action<Ts...> {
public:
explicit RightAction(DisplayMenuComponent *menu) : menu_(menu) {}
void play(const Ts &...x) override { this->menu_->right(); }
protected:
DisplayMenuComponent *menu_;
};
template<typename... Ts> class EnterAction final : public Action<Ts...> {
public:
explicit EnterAction(DisplayMenuComponent *menu) : menu_(menu) {}
void play(const Ts &...x) override { this->menu_->enter(); }
protected:
DisplayMenuComponent *menu_;
};
template<typename... Ts> class ShowAction final : public Action<Ts...> {
public:
explicit ShowAction(DisplayMenuComponent *menu) : menu_(menu) {}
void play(const Ts &...x) override { this->menu_->show(); }
protected:
DisplayMenuComponent *menu_;
};
template<typename... Ts> class HideAction final : public Action<Ts...> {
public:
explicit HideAction(DisplayMenuComponent *menu) : menu_(menu) {}
void play(const Ts &...x) override { this->menu_->hide(); }
protected:
DisplayMenuComponent *menu_;
};
template<typename... Ts> class ShowMainAction final : public Action<Ts...> {
public:
explicit ShowMainAction(DisplayMenuComponent *menu) : menu_(menu) {}
void play(const Ts &...x) override { this->menu_->show_main(); }
protected:
DisplayMenuComponent *menu_;
};
template<typename... Ts> class IsActiveCondition final : public Condition<Ts...> {
public:
explicit IsActiveCondition(DisplayMenuComponent *menu) : menu_(menu) {}
bool check(const Ts &...x) override { return this->menu_->is_active(); }
protected:
DisplayMenuComponent *menu_;
};
class DisplayMenuOnEnterTrigger final : public Trigger<const MenuItem *> {
public:
explicit DisplayMenuOnEnterTrigger(MenuItem *parent) : parent_(parent) {
+22 -2
View File
@@ -3,6 +3,8 @@ import esphome.codegen as cg
from esphome.components import i2c, time
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@badbadc0ffee"]
@@ -20,7 +22,7 @@ CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
).extend(i2c.i2c_device_schema(0x68))
automation.register_parented_action(
@automation.register_action(
"ds1307.write_time",
WriteAction,
cv.Schema(
@@ -30,9 +32,18 @@ automation.register_parented_action(
),
synchronous=True,
)
async def ds1307_write_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_parented_action(
@automation.register_action(
"ds1307.read_time",
ReadAction,
automation.maybe_simple_id(
@@ -42,6 +53,15 @@ automation.register_parented_action(
),
synchronous=True,
)
async def ds1307_read_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config: ConfigType) -> None:
+45 -21
View File
@@ -1,4 +1,10 @@
from esphome import automation
from esphome.automation import (
Action,
Condition,
maybe_simple_id,
register_action,
register_condition,
)
import esphome.codegen as cg
from esphome.components import binary_sensor, sensor
import esphome.config_validation as cv
@@ -23,13 +29,13 @@ duty_time_sensor_ns = cg.esphome_ns.namespace("duty_time_sensor")
DutyTimeSensor = duty_time_sensor_ns.class_(
"DutyTimeSensor", sensor.Sensor, cg.PollingComponent
)
BaseAction = duty_time_sensor_ns.class_("BaseAction", automation.Action, cg.Parented)
BaseAction = duty_time_sensor_ns.class_("BaseAction", Action, cg.Parented)
StartAction = duty_time_sensor_ns.class_("StartAction", BaseAction)
StopAction = duty_time_sensor_ns.class_("StopAction", BaseAction)
ResetAction = duty_time_sensor_ns.class_("ResetAction", BaseAction)
SetAction = duty_time_sensor_ns.class_("SetAction", BaseAction)
RunningCondition = duty_time_sensor_ns.class_(
"RunningCondition", automation.Condition, cg.Parented
"RunningCondition", Condition, cg.Parented
)
@@ -80,38 +86,56 @@ async def to_code(config: ConfigType) -> None:
# AUTOMATIONS
DUTY_TIME_ID_SCHEMA = automation.maybe_simple_id(
DUTY_TIME_ID_SCHEMA = maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(DutyTimeSensor),
}
)
automation.register_parented_action(
"sensor.duty_time.start",
StartAction,
DUTY_TIME_ID_SCHEMA,
synchronous=True,
@register_action(
"sensor.duty_time.start", StartAction, DUTY_TIME_ID_SCHEMA, synchronous=True
)
async def sensor_runtime_start_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_parented_action(
"sensor.duty_time.stop",
StopAction,
DUTY_TIME_ID_SCHEMA,
synchronous=True,
@register_action(
"sensor.duty_time.stop", StopAction, DUTY_TIME_ID_SCHEMA, synchronous=True
)
async def sensor_runtime_stop_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_parented_action(
"sensor.duty_time.reset",
ResetAction,
DUTY_TIME_ID_SCHEMA,
synchronous=True,
@register_action(
"sensor.duty_time.reset", ResetAction, DUTY_TIME_ID_SCHEMA, synchronous=True
)
async def sensor_runtime_reset_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@automation.register_condition(
@register_condition(
"sensor.duty_time.is_running", RunningCondition, DUTY_TIME_ID_SCHEMA
)
async def duty_time_is_running_to_code(
@@ -124,7 +148,7 @@ async def duty_time_is_running_to_code(
return cg.new_Pvariable(condition_id, template_arg, paren, True)
@automation.register_condition(
@register_condition(
"sensor.duty_time.is_not_running", RunningCondition, DUTY_TIME_ID_SCHEMA
)
async def duty_time_is_not_running_to_code(
+1 -54
View File
@@ -11,10 +11,7 @@ from typing import Any
from esphome import yaml_util
import esphome.codegen as cg
from esphome.components.const import (
CONF_ENABLE_OTA_DOWNGRADE_PROTECTION,
CONF_IGNORE_NOT_FOUND,
)
from esphome.components.const import CONF_ENABLE_OTA_DOWNGRADE_PROTECTION
from esphome.config_helpers import filter_source_files_from_defines
import esphome.config_validation as cv
from esphome.const import (
@@ -114,7 +111,6 @@ CONF_ENGINEERING_SAMPLE = "engineering_sample"
CONF_INCLUDE_BUILTIN_IDF_COMPONENTS = "include_builtin_idf_components"
CONF_ENABLE_LWIP_ASSERT = "enable_lwip_assert"
CONF_EXECUTE_FROM_PSRAM = "execute_from_psram"
CONF_NVS_CACHE_IN_PSRAM = "nvs_cache_in_psram"
CONF_FLASH_CHIP = "flash_chip"
CONF_KEY_ID = "key_id"
CONF_MINIMUM_CHIP_REVISION = "minimum_chip_revision"
@@ -1599,29 +1595,6 @@ def final_validate(config) -> None:
path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_EXECUTE_FROM_PSRAM],
)
)
if advanced.get(CONF_NVS_CACHE_IN_PSRAM):
psram_conf = full_config.get(PSRAM_DOMAIN)
if (
psram_conf is None
or psram_conf[CONF_DISABLED]
or psram_conf[CONF_IGNORE_NOT_FOUND]
):
errs.append(
cv.Invalid(
f"'{CONF_NVS_CACHE_IN_PSRAM}' requires PSRAM with 'ignore_not_found: false'",
path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_NVS_CACHE_IN_PSRAM],
)
)
if (
advanced.get(CONF_NVS_ENCRYPTION) is not None
or conf_fw[CONF_SDKCONFIG_OPTIONS].get("CONFIG_NVS_ENCRYPTION") == "y"
):
errs.append(
cv.Invalid(
f"'{CONF_NVS_CACHE_IN_PSRAM}' cannot be used with NVS encryption; the keys must stay in internal RAM",
path=[CONF_FRAMEWORK, CONF_ADVANCED, CONF_NVS_CACHE_IN_PSRAM],
)
)
final_validate_pins(full_config)
@@ -2062,7 +2035,6 @@ FRAMEWORK_SCHEMA = cv.Schema(
cv.Optional(CONF_RINGBUF_IN_IRAM, default=False): cv.boolean,
cv.Optional(CONF_HEAP_IN_IRAM, default=False): cv.boolean,
cv.Optional(CONF_EXECUTE_FROM_PSRAM, default=False): cv.boolean,
cv.Optional(CONF_NVS_CACHE_IN_PSRAM): cv.boolean,
cv.Optional(CONF_LOOP_TASK_STACK_SIZE, default=8192): cv.int_range(
min=8192, max=32768
),
@@ -2389,20 +2361,6 @@ async def _set_libc_picolibc_newlib_compat() -> None:
)
@coroutine_with_priority(CoroPriority.FINAL)
async def _apply_nvs_cache_in_psram(explicit: bool) -> None:
"""Keep the NVS cache in PSRAM unless NVS encryption is on, however it was enabled."""
# The encrypted partition object holds the derived keys, which must stay in internal RAM
if is_idf_sdkconfig_option_enabled("CONFIG_NVS_ENCRYPTION"):
if explicit:
_LOGGER.warning(
"%s ignored: NVS encryption keeps the NVS cache in internal RAM",
CONF_NVS_CACHE_IN_PSRAM,
)
return
set_idf_sdkconfig_default("CONFIG_NVS_ALLOCATE_CACHE_IN_SPIRAM", True)
@coroutine_with_priority(CoroPriority.FINAL)
async def _reconcile_certificate_bundle_sdkconfig() -> None:
"""Enable the mbedTLS certificate bundle only when something asked for it.
@@ -2955,17 +2913,6 @@ async def to_code(config):
if advanced[CONF_EXECUTE_FROM_PSRAM]:
add_idf_sdkconfig_option("CONFIG_SPIRAM_XIP_FROM_PSRAM", True)
# Imported here as psram imports this module
from esphome.components.psram import is_guaranteed as psram_is_guaranteed
# Frees internal heap (the cache scales with the NVS partition) but slows NVS, so only
# where PSRAM is known to be fitted. Decided at FINAL so every way of enabling NVS
# encryption has been seen and a user's sdkconfig_options value wins.
# Unset means on; only an explicit true is worth a warning when it has to be dropped.
requested = advanced.get(CONF_NVS_CACHE_IN_PSRAM)
if requested is not False and psram_is_guaranteed():
CORE.add_job(_apply_nvs_cache_in_psram, requested is True)
# Apply LWIP core locking for better socket performance
# This is already enabled by default in Arduino framework, where it provides
# significant performance benefits. Our benchmarks show socket operations are
+30 -18
View File
@@ -32,7 +32,8 @@ from esphome.const import (
CONF_NAME,
CONF_NAME_ADD_MAC_SUFFIX,
)
from esphome.core import CORE, TimePeriod
from esphome.core import CORE, ID, TimePeriod
from esphome.cpp_generator import MockObj, TemplateArgsType
import esphome.final_validate as fv
from esphome.types import ConfigType
@@ -605,27 +606,38 @@ async def to_code(config: ConfigType) -> None:
cg.add_define("USE_ESP32_BLE_UUID")
automation.register_bare_condition(
"ble.enabled",
BLEEnabledCondition,
cv.Schema({}),
@automation.register_condition("ble.enabled", BLEEnabledCondition, cv.Schema({}))
async def ble_enabled_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
return cg.new_Pvariable(condition_id, template_arg)
@automation.register_action(
"ble.enable", BLEEnableAction, cv.Schema({}), synchronous=True
)
async def ble_enable_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
return cg.new_Pvariable(action_id, template_arg)
automation.register_bare_action(
"ble.enable",
BLEEnableAction,
cv.Schema({}),
synchronous=True,
)
automation.register_bare_action(
"ble.disable",
BLEDisableAction,
cv.Schema({}),
synchronous=True,
@automation.register_action(
"ble.disable", BLEDisableAction, cv.Schema({}), synchronous=True
)
async def ble_disable_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
return cg.new_Pvariable(action_id, template_arg)
# ble_advertising.cpp is fully #ifdef'd on USE_ESP32_BLE_ADVERTISING, set
+1 -10
View File
@@ -339,16 +339,7 @@ async def to_code(config: ConfigType) -> None:
cg.add_platformio_option("platform", conf[CONF_PLATFORM_VERSION])
cg.add_platformio_option(
"platform_packages",
[
f"platformio/framework-arduinoespressif8266@{conf[CONF_SOURCE]}",
# Override the ancient tool-esptoolpy ~1.30000.0 pinned by
# platform-espressif8266 4.2.1 with the same 5.x build the
# pioarduino ESP32 platform uses, so both platforms share the
# same installed package and stop reinstalling on every switch.
# The 0.0.1 path component is pioarduino's stable registry
# release tag (not the tool version); the tool itself is 5.2.0.
"pioarduino/tool-esptoolpy@https://github.com/pioarduino/registry/releases/download/0.0.1/esptoolpy-v5.2.0.zip",
],
[f"platformio/framework-arduinoespressif8266@{conf[CONF_SOURCE]}"],
)
# Default for platformio is LWIP2_LOW_MEMORY with:
+9 -36
View File
@@ -2,7 +2,7 @@ import logging
import esphome.codegen as cg
from esphome.components.noise import (
ENCRYPTION_SCHEMA,
encryption_schema,
new_psk_progmem,
static_encryption_key,
)
@@ -27,7 +27,6 @@ from esphome.const import (
)
from esphome.core import CORE, coroutine_with_priority
from esphome.coroutine import CoroPriority
from esphome.espota2 import CONF_ALLOW_PLAINTEXT_UPLOAD
import esphome.final_validate as fv
from esphome.types import ConfigType
@@ -232,38 +231,15 @@ def _resolve_encryption_key(encryption_conf: ConfigType, api_conf: ConfigType) -
encryption_conf[CONF_KEY] = api_key
# Uploader side options live only on the ota block; the api block keeps the
# shared schema
_ENCRYPTION_SCHEMA = ENCRYPTION_SCHEMA.extend(
{
cv.Optional(CONF_ALLOW_PLAINTEXT_UPLOAD): cv.boolean,
}
)
def _encryption_schema(config: ConfigType | None) -> ConfigType:
# Only a bare `encryption:` block is keyless; `false` or a list must fail
return _ENCRYPTION_SCHEMA({} if config is None else config)
# Also called on merged same-port configs in final validate, where schemas
# do not run
def _validate_no_password_with_encryption(config: ConfigType) -> ConfigType:
if (
CONF_PASSWORD not in config
or (encryption := config.get(CONF_ENCRYPTION)) is None
):
return config
# The migration install may still have to answer the old firmware's
# password prompt on the plaintext leg; the password is not built in
if encryption.get(CONF_ALLOW_PLAINTEXT_UPLOAD):
return config
raise cv.Invalid(
f"'{CONF_PASSWORD}' cannot be combined with '{CONF_ENCRYPTION}'; the "
f"encryption key already authenticates the uploader, remove '{CONF_PASSWORD}' "
f"(or set '{CONF_ALLOW_PLAINTEXT_UPLOAD}: true' for the one install that "
f"migrates a device still asking for it)"
)
if CONF_PASSWORD in config and CONF_ENCRYPTION in config:
raise cv.Invalid(
f"'{CONF_PASSWORD}' cannot be combined with '{CONF_ENCRYPTION}'; the "
f"encryption key already authenticates the uploader, remove '{CONF_PASSWORD}'"
)
return config
def _consume_ota_sockets(config: ConfigType) -> ConfigType:
@@ -293,7 +269,7 @@ CONFIG_SCHEMA = cv.All(
): cv.port,
cv.Optional(CONF_ALLOW_PARTITION_ACCESS, default=False): cv.boolean,
cv.Optional(CONF_PASSWORD): cv.sensitive(),
cv.Optional(CONF_ENCRYPTION): _encryption_schema,
cv.Optional(CONF_ENCRYPTION): encryption_schema,
cv.Optional(CONF_NUM_ATTEMPTS): cv.invalid(
f"'{CONF_SAFE_MODE}' (and its related configuration variables) has moved from 'ota' to its own component. See https://esphome.io/components/safe_mode"
),
@@ -328,10 +304,7 @@ async def to_code(config: ConfigType) -> None:
# An empty password opts in to the auth code path so set_auth_password() can be
# called at runtime (e.g. to rotate the password from a lambda). When `password:`
# is omitted entirely, the auth path is excluded to save flash on small devices.
# A password is never built in next to encryption: validation only lets
# the two coexist for the migration install, where the password answers
# the running firmware and the build is authenticated by the key
if CONF_PASSWORD in config and CONF_ENCRYPTION not in config:
if CONF_PASSWORD in config:
cg.add_define("USE_OTA_PASSWORD")
if config[CONF_PASSWORD]:
cg.add(var.set_auth_password(config[CONF_PASSWORD]))
+26 -14
View File
@@ -53,10 +53,12 @@ from esphome.const import (
)
from esphome.core import (
CORE,
ID,
CoroPriority,
TimePeriodMilliseconds,
coroutine_with_priority,
)
from esphome.cpp_generator import MockObj, TemplateArgsType
import esphome.final_validate as fv
from esphome.types import ConfigType
@@ -239,8 +241,6 @@ EthernetComponent = ethernet_ns.class_("EthernetComponent", cg.Component)
ManualIP = ethernet_ns.struct("ManualIP")
EthernetConnectedCondition = ethernet_ns.class_("EthernetConnectedCondition", Condition)
EthernetEnabledCondition = ethernet_ns.class_("EthernetEnabledCondition", Condition)
EthernetEnableAction = ethernet_ns.class_("EthernetEnableAction", automation.Action)
EthernetDisableAction = ethernet_ns.class_("EthernetDisableAction", automation.Action)
def _is_framework_spi_polling_mode_supported() -> bool:
@@ -922,15 +922,27 @@ def _filter_source_files() -> list[str]:
FILTER_SOURCE_FILES = _filter_source_files
automation.register_bare_condition(
"ethernet.connected", EthernetConnectedCondition, cv.Schema({})
)
automation.register_bare_condition(
"ethernet.enabled", EthernetEnabledCondition, cv.Schema({})
)
automation.register_bare_action(
"ethernet.enable", EthernetEnableAction, cv.Schema({}), synchronous=True
)
automation.register_bare_action(
"ethernet.disable", EthernetDisableAction, cv.Schema({}), synchronous=True
)
async def _new_pvariable_to_code(
config: ConfigType,
id_: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
return cg.new_Pvariable(id_, template_arg)
for _name, _cls in (
("ethernet.connected", EthernetConnectedCondition),
("ethernet.enabled", EthernetEnabledCondition),
):
automation.register_condition(_name, _cls, cv.Schema({}))(_new_pvariable_to_code)
ETHERNET_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(EthernetComponent)})
for _name, _method in (
("ethernet.enable", "enable()"),
("ethernet.disable", "disable()"),
):
automation.register_apply_action(
_name, ETHERNET_ACTION_SCHEMA, automation.ApplyCall(_method)
)
-10
View File
@@ -16,15 +16,5 @@ template<typename... Ts> class EthernetEnabledCondition final : public Condition
bool check(const Ts &...x) override { return global_eth_component->is_enabled(); }
};
template<typename... Ts> class EthernetEnableAction final : public Action<Ts...> {
public:
void play(const Ts &...x) override { global_eth_component->enable(); }
};
template<typename... Ts> class EthernetDisableAction final : public Action<Ts...> {
public:
void play(const Ts &...x) override { global_eth_component->disable(); }
};
} // namespace esphome::ethernet
#endif
+26 -6
View File
@@ -80,52 +80,72 @@ EzoPMPArbitraryCommandAction = ezo_pmp_ns.class_(
)
automation.register_simple_action(
@automation.register_action(
"ezo_pmp.find",
EzoPMPFindAction,
EZO_PMP_NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def ezo_pmp_find_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_simple_action(
@automation.register_action(
"ezo_pmp.dose_continuously",
EzoPMPDoseContinuouslyAction,
EZO_PMP_NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def ezo_pmp_dose_continuously_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_simple_action(
@automation.register_action(
"ezo_pmp.clear_total_volume_dosed",
EzoPMPClearTotalVolumeDispensedAction,
EZO_PMP_NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def ezo_pmp_clear_total_volume_dosed_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_simple_action(
@automation.register_action(
"ezo_pmp.clear_calibration",
EzoPMPClearCalibrationAction,
EZO_PMP_NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def ezo_pmp_clear_calibration_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_simple_action(
@automation.register_action(
"ezo_pmp.pause_dosing",
EzoPMPPauseDosingAction,
EZO_PMP_NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def ezo_pmp_pause_dosing_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_simple_action(
@automation.register_action(
"ezo_pmp.stop_dosing",
EzoPMPStopDosingAction,
EZO_PMP_NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def ezo_pmp_stop_dosing_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)
# Actions that require Multiple Args
+17 -2
View File
@@ -61,6 +61,8 @@ RESTORE_MODES = {
}
# Actions
TurnOffAction = fan_ns.class_("TurnOffAction", automation.Action)
ToggleAction = fan_ns.class_("ToggleAction", automation.Action)
CycleSpeedAction = fan_ns.class_("CycleSpeedAction", automation.Action)
FanStateTrigger = fan_ns.class_(
@@ -308,8 +310,21 @@ FAN_ACTION_SCHEMA = maybe_simple_id(
)
automation.register_apply_action("fan.toggle", FAN_ACTION_SCHEMA, call="toggle")
automation.register_apply_action("fan.turn_off", FAN_ACTION_SCHEMA, call="turn_off")
@automation.register_action(
"fan.toggle", ToggleAction, FAN_ACTION_SCHEMA, synchronous=True
)
async def fan_toggle_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_action(
"fan.turn_off", TurnOffAction, FAN_ACTION_SCHEMA, synchronous=True
)
async def fan_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)
automation.register_apply_action(
"fan.turn_on",
+18
View File
@@ -6,6 +6,24 @@
namespace esphome::fan {
template<typename... Ts> class TurnOffAction final : public Action<Ts...> {
public:
explicit TurnOffAction(Fan *state) : state_(state) {}
void play(const Ts &...x) override { this->state_->turn_off().perform(); }
Fan *state_;
};
template<typename... Ts> class ToggleAction final : public Action<Ts...> {
public:
explicit ToggleAction(Fan *state) : state_(state) {}
void play(const Ts &...x) override { this->state_->toggle().perform(); }
Fan *state_;
};
template<typename... Ts> class CycleSpeedAction final : public Action<Ts...> {
public:
explicit CycleSpeedAction(Fan *state) : state_(state) {}
+1 -1
View File
@@ -83,7 +83,7 @@ void FanCall::validate_() {
auto traits = this->parent_.get_traits();
if (this->speed_.has_value()) {
this->speed_ = clamp(*this->speed_, 1, static_cast<int>(traits.supported_speed_count()));
this->speed_ = clamp(*this->speed_, 1, traits.supported_speed_count());
// https://developers.home-assistant.io/docs/core/entity/fan/#preset-modes
// "Manually setting a speed must disable any set preset mode"
+3 -3
View File
@@ -14,7 +14,7 @@ class FanTraits {
public:
FanTraits() = default;
FanTraits(bool oscillation, bool speed, bool direction, uint8_t speed_count)
FanTraits(bool oscillation, bool speed, bool direction, int speed_count)
: oscillation_(oscillation), speed_(speed), direction_(direction), speed_count_(speed_count) {}
/// Return if this fan supports oscillation.
@@ -26,9 +26,9 @@ class FanTraits {
/// Set whether this fan supports speed levels.
void set_speed(bool speed) { this->speed_ = speed; }
/// Return how many speed levels the fan has
uint8_t supported_speed_count() const { return this->speed_count_; }
int supported_speed_count() const { return this->speed_count_; }
/// Set how many speed levels this fan has.
void set_supported_speed_count(uint8_t speed_count) { this->speed_count_ = speed_count; }
void set_supported_speed_count(int speed_count) { this->speed_count_ = speed_count; }
/// Return if this fan supports changing direction
bool supports_direction() const { return this->direction_; }
/// Set whether this fan supports changing direction
@@ -206,7 +206,7 @@ async def fingerprint_grow_enroll_to_code(config, action_id, template_arg, args)
return var
automation.register_parented_action(
@automation.register_action(
"fingerprint_grow.cancel_enroll",
CancelEnrollmentAction,
cv.Schema(
@@ -216,6 +216,10 @@ automation.register_parented_action(
),
synchronous=True,
)
async def fingerprint_grow_cancel_enroll_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@automation.register_action(
@@ -239,7 +243,7 @@ async def fingerprint_grow_delete_to_code(config, action_id, template_arg, args)
return var
automation.register_parented_action(
@automation.register_action(
"fingerprint_grow.delete_all",
DeleteAllAction,
cv.Schema(
@@ -249,6 +253,10 @@ automation.register_parented_action(
),
synchronous=True,
)
async def fingerprint_grow_delete_all_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
FINGERPRINT_GROW_LED_CONTROL_ACTION_SCHEMA = cv.maybe_simple_value(
+12 -2
View File
@@ -126,7 +126,7 @@ async def grove_tb6612fng_stop_to_code(config, action_id, template_arg, args):
return var
automation.register_parented_action(
@automation.register_action(
"grove_tb6612fng.standby",
GROVETB6612FNGMotorStandbyAction,
cv.Schema(
@@ -136,9 +136,14 @@ automation.register_parented_action(
),
synchronous=True,
)
async def grove_tb6612fng_standby_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_parented_action(
@automation.register_action(
"grove_tb6612fng.no_standby",
GROVETB6612FNGMotorNoStandbyAction,
cv.Schema(
@@ -148,6 +153,11 @@ automation.register_parented_action(
),
synchronous=True,
)
async def grove_tb6612fng_no_standby_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@automation.register_action(
+128
View File
@@ -0,0 +1,128 @@
#pragma once
#include "esphome/core/automation.h"
#include "haier_base.h"
#include "hon_climate.h"
namespace esphome::haier {
template<typename... Ts> class DisplayOnAction final : public Action<Ts...> {
public:
DisplayOnAction(HaierClimateBase *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->set_display_state(true); }
protected:
HaierClimateBase *parent_;
};
template<typename... Ts> class DisplayOffAction final : public Action<Ts...> {
public:
DisplayOffAction(HaierClimateBase *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->set_display_state(false); }
protected:
HaierClimateBase *parent_;
};
template<typename... Ts> class BeeperOnAction final : public Action<Ts...> {
public:
BeeperOnAction(HonClimate *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->set_beeper_state(true); }
protected:
HonClimate *parent_;
};
template<typename... Ts> class BeeperOffAction final : public Action<Ts...> {
public:
BeeperOffAction(HonClimate *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->set_beeper_state(false); }
protected:
HonClimate *parent_;
};
template<typename... Ts> class VerticalAirflowAction final : public Action<Ts...> {
public:
VerticalAirflowAction(HonClimate *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(hon_protocol::VerticalSwingMode, direction)
void play(const Ts &...x) { this->parent_->set_vertical_airflow(this->direction_.value(x...)); }
protected:
HonClimate *parent_;
};
template<typename... Ts> class HorizontalAirflowAction final : public Action<Ts...> {
public:
HorizontalAirflowAction(HonClimate *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(hon_protocol::HorizontalSwingMode, direction)
void play(const Ts &...x) { this->parent_->set_horizontal_airflow(this->direction_.value(x...)); }
protected:
HonClimate *parent_;
};
template<typename... Ts> class HealthOnAction final : public Action<Ts...> {
public:
HealthOnAction(HaierClimateBase *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->set_health_mode(true); }
protected:
HaierClimateBase *parent_;
};
template<typename... Ts> class HealthOffAction final : public Action<Ts...> {
public:
HealthOffAction(HaierClimateBase *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->set_health_mode(false); }
protected:
HaierClimateBase *parent_;
};
template<typename... Ts> class StartSelfCleaningAction final : public Action<Ts...> {
public:
StartSelfCleaningAction(HonClimate *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->start_self_cleaning(); }
protected:
HonClimate *parent_;
};
template<typename... Ts> class StartSteriCleaningAction final : public Action<Ts...> {
public:
StartSteriCleaningAction(HonClimate *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->start_steri_cleaning(); }
protected:
HonClimate *parent_;
};
template<typename... Ts> class PowerOnAction final : public Action<Ts...> {
public:
PowerOnAction(HaierClimateBase *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->send_power_on_command(); }
protected:
HaierClimateBase *parent_;
};
template<typename... Ts> class PowerOffAction final : public Action<Ts...> {
public:
PowerOffAction(HaierClimateBase *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->send_power_off_command(); }
protected:
HaierClimateBase *parent_;
};
template<typename... Ts> class PowerToggleAction final : public Action<Ts...> {
public:
PowerToggleAction(HaierClimateBase *parent) : parent_(parent) {}
void play(const Ts &...x) { this->parent_->toggle_power(); }
protected:
HaierClimateBase *parent_;
};
} // namespace esphome::haier
+134 -34
View File
@@ -9,6 +9,7 @@ from esphome.const import (
CONF_BEEPER,
CONF_CURRENT_TEMPERATURE,
CONF_DISPLAY,
CONF_ID,
CONF_LEVEL,
CONF_LOGGER,
CONF_LOGS,
@@ -253,6 +254,23 @@ CONFIG_SCHEMA = cv.All(
)
# Actions
DisplayOnAction = haier_ns.class_("DisplayOnAction", automation.Action)
DisplayOffAction = haier_ns.class_("DisplayOffAction", automation.Action)
BeeperOnAction = haier_ns.class_("BeeperOnAction", automation.Action)
BeeperOffAction = haier_ns.class_("BeeperOffAction", automation.Action)
StartSelfCleaningAction = haier_ns.class_("StartSelfCleaningAction", automation.Action)
StartSteriCleaningAction = haier_ns.class_(
"StartSteriCleaningAction", automation.Action
)
VerticalAirflowAction = haier_ns.class_("VerticalAirflowAction", automation.Action)
HorizontalAirflowAction = haier_ns.class_("HorizontalAirflowAction", automation.Action)
HealthOnAction = haier_ns.class_("HealthOnAction", automation.Action)
HealthOffAction = haier_ns.class_("HealthOffAction", automation.Action)
PowerOnAction = haier_ns.class_("PowerOnAction", automation.Action)
PowerOffAction = haier_ns.class_("PowerOffAction", automation.Action)
PowerToggleAction = haier_ns.class_("PowerToggleAction", automation.Action)
HAIER_BASE_ACTION_SCHEMA = automation.maybe_simple_id(
{
cv.GenerateID(): cv.use_id(HaierClimateBase),
@@ -266,35 +284,62 @@ HAIER_HON_BASE_ACTION_SCHEMA = automation.maybe_simple_id(
)
for _name, _schema, _call in (
("climate.haier.display_on", HAIER_BASE_ACTION_SCHEMA, "set_display_state(true)"),
("climate.haier.display_off", HAIER_BASE_ACTION_SCHEMA, "set_display_state(false)"),
("climate.haier.beeper_on", HAIER_HON_BASE_ACTION_SCHEMA, "set_beeper_state(true)"),
(
"climate.haier.beeper_off",
HAIER_HON_BASE_ACTION_SCHEMA,
"set_beeper_state(false)",
),
(
"climate.haier.start_self_cleaning",
HAIER_HON_BASE_ACTION_SCHEMA,
"start_self_cleaning()",
),
(
"climate.haier.start_steri_cleaning",
HAIER_HON_BASE_ACTION_SCHEMA,
"start_steri_cleaning()",
),
("climate.haier.health_on", HAIER_BASE_ACTION_SCHEMA, "set_health_mode(true)"),
("climate.haier.health_off", HAIER_BASE_ACTION_SCHEMA, "set_health_mode(false)"),
("climate.haier.power_on", HAIER_BASE_ACTION_SCHEMA, "send_power_on_command()"),
("climate.haier.power_off", HAIER_BASE_ACTION_SCHEMA, "send_power_off_command()"),
("climate.haier.power_toggle", HAIER_BASE_ACTION_SCHEMA, "toggle_power()"),
):
automation.register_apply_action(_name, _schema, automation.ApplyCall(_call))
@automation.register_action(
"climate.haier.display_on",
DisplayOnAction,
HAIER_BASE_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"climate.haier.display_off",
DisplayOffAction,
HAIER_BASE_ACTION_SCHEMA,
synchronous=True,
)
async def display_action_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_apply_action(
@automation.register_action(
"climate.haier.beeper_on",
BeeperOnAction,
HAIER_HON_BASE_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"climate.haier.beeper_off",
BeeperOffAction,
HAIER_HON_BASE_ACTION_SCHEMA,
synchronous=True,
)
async def beeper_action_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)
# Start self cleaning or steri-cleaning action action
@automation.register_action(
"climate.haier.start_self_cleaning",
StartSelfCleaningAction,
HAIER_HON_BASE_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"climate.haier.start_steri_cleaning",
StartSteriCleaningAction,
HAIER_HON_BASE_ACTION_SCHEMA,
synchronous=True,
)
async def start_cleaning_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)
# Set vertical airflow direction action
@automation.register_action(
"climate.haier.set_vertical_airflow",
VerticalAirflowAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(HonClimate),
@@ -303,13 +348,22 @@ automation.register_apply_action(
),
}
),
automation.ApplyField(
CONF_VERTICAL_AIRFLOW, "set_vertical_airflow", AirflowVerticalDirection
),
synchronous=True,
)
async def haier_set_vertical_airflow_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_VERTICAL_AIRFLOW], args, AirflowVerticalDirection
)
cg.add(var.set_direction(template_))
return var
automation.register_apply_action(
# Set horizontal airflow direction action
@automation.register_action(
"climate.haier.set_horizontal_airflow",
HorizontalAirflowAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(HonClimate),
@@ -318,10 +372,56 @@ automation.register_apply_action(
),
}
),
automation.ApplyField(
CONF_HORIZONTAL_AIRFLOW, "set_horizontal_airflow", AirflowHorizontalDirection
),
synchronous=True,
)
async def haier_set_horizontal_airflow_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_HORIZONTAL_AIRFLOW], args, AirflowHorizontalDirection
)
cg.add(var.set_direction(template_))
return var
@automation.register_action(
"climate.haier.health_on",
HealthOnAction,
HAIER_BASE_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"climate.haier.health_off",
HealthOffAction,
HAIER_BASE_ACTION_SCHEMA,
synchronous=True,
)
async def health_action_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_action(
"climate.haier.power_on",
PowerOnAction,
HAIER_BASE_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"climate.haier.power_off",
PowerOffAction,
HAIER_BASE_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"climate.haier.power_toggle",
PowerToggleAction,
HAIER_BASE_ACTION_SCHEMA,
synchronous=True,
)
async def power_action_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 _final_validate(config) -> None:
+13 -2
View File
@@ -7,11 +7,14 @@ import esphome.config_validation as cv
from esphome.const import (
CONF_DECAY_MODE,
CONF_ENABLE_PIN,
CONF_ID,
CONF_PIN_A,
CONF_PIN_B,
CONF_PRESET_MODES,
CONF_SPEED_COUNT,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
from .. import hbridge_ns
@@ -39,7 +42,7 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_DECAY_MODE, default="SLOW"): cv.enum(
DECAY_MODE_OPTIONS, upper=True
),
cv.Optional(CONF_SPEED_COUNT, default=100): cv.int_range(min=1, max=255),
cv.Optional(CONF_SPEED_COUNT, default=100): cv.int_range(min=1),
cv.Optional(CONF_ENABLE_PIN): cv.use_id(output.FloatOutput),
cv.Optional(CONF_PRESET_MODES): validate_preset_modes,
}
@@ -48,12 +51,20 @@ CONFIG_SCHEMA = (
)
automation.register_simple_action(
@automation.register_action(
"fan.hbridge.brake",
BrakeAction,
maybe_simple_id({cv.GenerateID(): cv.use_id(HBridgeFan)}),
synchronous=True,
)
async def fan_hbridge_brake_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
async def to_code(config: ConfigType) -> None:
+2 -2
View File
@@ -14,7 +14,7 @@ enum DecayMode {
class HBridgeFan final : public Component, public fan::Fan {
public:
HBridgeFan(uint8_t speed_count, DecayMode decay_mode) : speed_count_(speed_count), decay_mode_(decay_mode) {}
HBridgeFan(int speed_count, DecayMode decay_mode) : speed_count_(speed_count), decay_mode_(decay_mode) {}
void set_pin_a(output::FloatOutput *pin_a) { pin_a_ = pin_a; }
void set_pin_b(output::FloatOutput *pin_b) { pin_b_ = pin_b; }
@@ -35,7 +35,7 @@ class HBridgeFan final : public Component, public fan::Fan {
output::FloatOutput *pin_b_;
output::FloatOutput *enable_{nullptr};
output::BinaryOutput *oscillating_{nullptr};
uint8_t speed_count_{};
int speed_count_{};
DecayMode decay_mode_{DECAY_MODE_SLOW};
fan::FanTraits traits_;
+10 -1
View File
@@ -139,9 +139,18 @@ async def hdc302x_heater_on_to_code(
return var
automation.register_parented_action(
@automation.register_action(
"hdc302x.heater_off",
HeaterOffAction,
HDC302X_ACTION_SCHEMA,
synchronous=True,
)
async def hdc302x_heater_off_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+1 -1
View File
@@ -187,7 +187,7 @@ void HeatpumpIRClimate::transmit_state() {
swing_h_cmd = HDIR_SWING;
}
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_ON)) {
switch (this->fan_mode.value_or(climate::CLIMATE_FAN_AUTO)) {
case climate::CLIMATE_FAN_LOW:
fan_speed_cmd = FAN_2;
break;
+1 -1
View File
@@ -118,7 +118,7 @@ void IDFI2CBus::dump_config() {
if (s.second) {
ESP_LOGCONFIG(TAG, "Found device at address 0x%02X", s.first);
} else {
ESP_LOGCONFIG(TAG, "Unknown error at address 0x%02X", s.first);
ESP_LOGE(TAG, "Unknown error at address 0x%02X", s.first);
}
}
}
@@ -71,4 +71,16 @@ class IntegrationSensor final : public sensor::Sensor, public Component {
float last_value_{0.0f};
};
template<typename... Ts> class ResetAction final : public Action<Ts...>, public Parented<IntegrationSensor> {
public:
void play(const Ts &...x) override { this->parent_->reset(); }
};
template<typename... Ts> class SetValueAction final : public Action<Ts...>, public Parented<IntegrationSensor> {
public:
TEMPLATABLE_VALUE(float, value)
void play(const Ts &...x) override { this->parent_->set_value(this->value_.value(x...)); }
};
} // namespace esphome::integration
+31 -4
View File
@@ -11,13 +11,17 @@ from esphome.const import (
CONF_UNIT_OF_MEASUREMENT,
CONF_VALUE,
)
from esphome.core import ID
from esphome.core.entity_helpers import inherit_property_from
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
integration_ns = cg.esphome_ns.namespace("integration")
IntegrationSensor = integration_ns.class_(
"IntegrationSensor", sensor.Sensor, cg.Component
)
ResetAction = integration_ns.class_("ResetAction", automation.Action)
SetValueAction = integration_ns.class_("SetValueAction", automation.Action)
IntegrationSensorTime = integration_ns.enum("IntegrationSensorTime")
INTEGRATION_TIMES = {
@@ -102,23 +106,46 @@ async def to_code(config: ConfigType) -> None:
cg.add(var.set_restore(config[CONF_RESTORE]))
automation.register_apply_action(
@automation.register_action(
"sensor.integration.reset",
ResetAction,
automation.maybe_simple_id(
{
cv.Required(CONF_ID): cv.use_id(IntegrationSensor),
}
),
automation.ApplyCall("reset()"),
synchronous=True,
)
async def sensor_integration_reset_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_apply_action(
@automation.register_action(
"sensor.integration.set_value",
SetValueAction,
cv.Schema(
{
cv.Required(CONF_ID): cv.use_id(IntegrationSensor),
cv.Required(CONF_VALUE): cv.templatable(cv.float_),
}
),
automation.ApplyField(CONF_VALUE, "set_value", cg.float_),
synchronous=True,
)
async def sensor_integration_set_value_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
template_ = await cg.templatable(config[CONF_VALUE], args, cg.float_)
cg.add(var.set_value(template_))
return var
+21 -2
View File
@@ -15,6 +15,7 @@ from esphome.const import (
CONF_TIMEOUT,
CONF_TRIGGER_ID,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, literal
from esphome.types import ConfigType, TemplateArgsType
@@ -134,7 +135,7 @@ async def to_code(config: ConfigType) -> None:
cg.add(var.set_enabled(config[CONF_ENABLE_ON_BOOT]))
automation.register_parented_action(
@automation.register_action(
"key_collector.enable",
EnableAction,
automation.maybe_simple_id(
@@ -144,9 +145,18 @@ automation.register_parented_action(
),
synchronous=True,
)
async def enable_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_parented_action(
@automation.register_action(
"key_collector.disable",
DisableAction,
automation.maybe_simple_id(
@@ -156,3 +166,12 @@ automation.register_parented_action(
),
synchronous=True,
)
async def disable_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
-3
View File
@@ -31,9 +31,6 @@
namespace esphome::ld24xx {
/// Parse a little-endian 16-bit unsigned value from two bytes.
static constexpr uint16_t two_byte_to_uint16(uint8_t low, uint8_t high) { return ((uint16_t) high << 8) | low; }
// Helper to find index of value in constexpr array
template<size_t N> optional<size_t> find_index(const uint32_t (&arr)[N], uint32_t value) {
for (size_t i = 0; i < N; i++) {
+22 -10
View File
@@ -12,13 +12,13 @@ from esphome.const import (
CONF_ON_UNLOCK,
CONF_WEB_SERVER,
)
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.core import CORE, ID, 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
from esphome.cpp_generator import MockObj, MockObjClass, TemplateArgsType
from esphome.types import ConfigType, SafeExpType
CODEOWNERS = ["@esphome/core"]
@@ -29,6 +29,9 @@ Lock = lock_ns.class_("Lock", cg.EntityBase)
LockPtr = Lock.operator("ptr")
LockCall = lock_ns.class_("LockCall")
UnlockAction = lock_ns.class_("UnlockAction", automation.Action)
LockAction = lock_ns.class_("LockAction", automation.Action)
OpenAction = lock_ns.class_("OpenAction", automation.Action)
LockPublishAction = lock_ns.class_("LockPublishAction", automation.Action)
LockStateForwarder = lock_ns.class_("LockStateForwarder")
@@ -131,14 +134,23 @@ LOCK_ACTION_SCHEMA = maybe_simple_id(
)
for _name, _call in (
("lock.unlock", "unlock()"),
("lock.lock", "lock()"),
("lock.open", "open()"),
):
automation.register_apply_action(
_name, LOCK_ACTION_SCHEMA, automation.ApplyCall(_call)
)
@automation.register_action(
"lock.unlock", UnlockAction, LOCK_ACTION_SCHEMA, synchronous=True
)
@automation.register_action(
"lock.lock", LockAction, LOCK_ACTION_SCHEMA, synchronous=True
)
@automation.register_action(
"lock.open", OpenAction, LOCK_ACTION_SCHEMA, synchronous=True
)
async def lock_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
automation.register_apply_condition(
+30
View File
@@ -6,6 +6,36 @@
namespace esphome::lock {
template<typename... Ts> class LockAction final : public Action<Ts...> {
public:
explicit LockAction(Lock *a_lock) : lock_(a_lock) {}
void play(const Ts &...x) override { this->lock_->lock(); }
protected:
Lock *lock_;
};
template<typename... Ts> class UnlockAction final : public Action<Ts...> {
public:
explicit UnlockAction(Lock *a_lock) : lock_(a_lock) {}
void play(const Ts &...x) override { this->lock_->unlock(); }
protected:
Lock *lock_;
};
template<typename... Ts> class OpenAction final : public Action<Ts...> {
public:
explicit OpenAction(Lock *a_lock) : lock_(a_lock) {}
void play(const Ts &...x) override { this->lock_->open(); }
protected:
Lock *lock_;
};
/// Callback forwarder that triggers an Automation<> only when a specific lock state is entered.
/// Pointer-sized (single Automation* field) to fit inline in Callback::ctx_.
template<LockState State> struct LockStateForwarder {
+12 -5
View File
@@ -14,6 +14,8 @@ from esphome.const import (
UNIT_PERCENT,
UNIT_VOLT,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
DEPENDENCIES = ["i2c"]
@@ -72,9 +74,14 @@ MAX17043_ACTION_SCHEMA = maybe_simple_id(
)
automation.register_simple_action(
"max17043.sleep_mode",
SleepAction,
MAX17043_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"max17043.sleep_mode", SleepAction, MAX17043_ACTION_SCHEMA, synchronous=True
)
async def max17043_sleep_mode_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
+21 -13
View File
@@ -144,28 +144,36 @@ TERMINAL_ACTION_SCHEMA = cv.Schema(
)
automation.register_simple_action(
"mcp4461.wiper.increase",
WiperIncreaseAction,
WIPER_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"mcp4461.wiper.increase", WiperIncreaseAction, WIPER_ACTION_SCHEMA, synchronous=True
)
automation.register_simple_action(
"mcp4461.wiper.decrease",
WiperDecreaseAction,
WIPER_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"mcp4461.wiper.decrease", WiperDecreaseAction, WIPER_ACTION_SCHEMA, synchronous=True
)
async def mcp4461_wiper_step_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
wiper = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, wiper)
automation.register_simple_action(
@automation.register_action(
"mcp4461.wiper.store_nonvolatile",
WiperStoreNonvolatileAction,
WIPER_ACTION_SCHEMA,
synchronous=True,
)
async def mcp4461_wiper_store_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
wiper = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, wiper)
@automation.register_action(
+12 -7
View File
@@ -122,28 +122,33 @@ NO_ARGS_ACTION_SCHEMA = maybe_simple_id(
)
automation.register_parented_action(
@automation.register_action(
"mhz19.calibrate_zero",
MHZ19CalibrateZeroAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"mhz19.abc_enable",
MHZ19ABCEnableAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"mhz19.abc_disable",
MHZ19ABCDisableAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def mhz19_no_args_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
RANGE_ACTION_SCHEMA = maybe_simple_id(
+36 -14
View File
@@ -6,6 +6,7 @@ import re
from urllib.parse import urljoin
from esphome import automation, external_files, git
from esphome.automation import register_action, register_condition
from esphome.bundle import add_bundle_file
import esphome.codegen as cg
from esphome.components import esp32, microphone, ota, psram
@@ -57,6 +58,17 @@ micro_wake_word_ns = cg.esphome_ns.namespace("micro_wake_word")
MicroWakeWord = micro_wake_word_ns.class_("MicroWakeWord", cg.Component)
DisableModelAction = micro_wake_word_ns.class_("DisableModelAction", automation.Action)
EnableModelAction = micro_wake_word_ns.class_("EnableModelAction", automation.Action)
StartAction = micro_wake_word_ns.class_("StartAction", automation.Action)
StopAction = micro_wake_word_ns.class_("StopAction", automation.Action)
ModelIsEnabledCondition = micro_wake_word_ns.class_(
"ModelIsEnabledCondition", automation.Condition
)
IsRunningCondition = micro_wake_word_ns.class_(
"IsRunningCondition", automation.Condition
)
WakeWordModel = micro_wake_word_ns.class_("WakeWordModel")
@@ -607,19 +619,23 @@ async def to_code(config):
MICRO_WAKE_WORD_ACTION_SCHEMA = cv.Schema({cv.GenerateID(): cv.use_id(MicroWakeWord)})
automation.register_apply_action(
@register_action(
"micro_wake_word.start",
StartAction,
MICRO_WAKE_WORD_ACTION_SCHEMA,
automation.ApplyCall("start()"),
synchronous=True,
)
automation.register_apply_action(
"micro_wake_word.stop",
MICRO_WAKE_WORD_ACTION_SCHEMA,
automation.ApplyCall("stop()"),
@register_action(
"micro_wake_word.stop", StopAction, MICRO_WAKE_WORD_ACTION_SCHEMA, synchronous=True
)
automation.register_apply_condition(
"micro_wake_word.is_running", MICRO_WAKE_WORD_ACTION_SCHEMA, "is_running()"
@register_condition(
"micro_wake_word.is_running", IsRunningCondition, MICRO_WAKE_WORD_ACTION_SCHEMA
)
async def micro_wake_word_action_to_code(config, action_id, template_arg, args):
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
MICRO_WAKE_WORLD_MODEL_ACTION_SCHEMA = automation.maybe_simple_id(
@@ -628,18 +644,24 @@ MICRO_WAKE_WORLD_MODEL_ACTION_SCHEMA = automation.maybe_simple_id(
}
)
automation.register_apply_action(
@register_action(
"micro_wake_word.enable_model",
EnableModelAction,
MICRO_WAKE_WORLD_MODEL_ACTION_SCHEMA,
automation.ApplyCall("enable()"),
synchronous=True,
)
automation.register_apply_action(
@register_action(
"micro_wake_word.disable_model",
DisableModelAction,
MICRO_WAKE_WORLD_MODEL_ACTION_SCHEMA,
automation.ApplyCall("disable()"),
synchronous=True,
)
automation.register_apply_condition(
@register_condition(
"micro_wake_word.model_is_enabled",
ModelIsEnabledCondition,
MICRO_WAKE_WORLD_MODEL_ACTION_SCHEMA,
"is_enabled()",
)
async def model_action(config, action_id, template_arg, args):
parent = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, parent)
@@ -0,0 +1,54 @@
#pragma once
#include "micro_wake_word.h"
#include "streaming_model.h"
#ifdef USE_ESP32
namespace esphome::micro_wake_word {
template<typename... Ts> class StartAction final : public Action<Ts...>, public Parented<MicroWakeWord> {
public:
void play(const Ts &...x) override { this->parent_->start(); }
};
template<typename... Ts> class StopAction final : public Action<Ts...>, public Parented<MicroWakeWord> {
public:
void play(const Ts &...x) override { this->parent_->stop(); }
};
template<typename... Ts> class IsRunningCondition final : public Condition<Ts...>, public Parented<MicroWakeWord> {
public:
bool check(const Ts &...x) override { return this->parent_->is_running(); }
};
template<typename... Ts> class EnableModelAction final : public Action<Ts...> {
public:
explicit EnableModelAction(WakeWordModel *wake_word_model) : wake_word_model_(wake_word_model) {}
void play(const Ts &...x) override { this->wake_word_model_->enable(); }
protected:
WakeWordModel *wake_word_model_;
};
template<typename... Ts> class DisableModelAction final : public Action<Ts...> {
public:
explicit DisableModelAction(WakeWordModel *wake_word_model) : wake_word_model_(wake_word_model) {}
void play(const Ts &...x) override { this->wake_word_model_->disable(); }
protected:
WakeWordModel *wake_word_model_;
};
template<typename... Ts> class ModelIsEnabledCondition final : public Condition<Ts...> {
public:
explicit ModelIsEnabledCondition(WakeWordModel *wake_word_model) : wake_word_model_(wake_word_model) {}
bool check(const Ts &...x) override { return this->wake_word_model_->is_enabled(); }
protected:
WakeWordModel *wake_word_model_;
};
} // namespace esphome::micro_wake_word
#endif
+58 -17
View File
@@ -14,9 +14,9 @@ from esphome.const import (
CONF_ON_DATA,
CONF_TRIGGER_ID,
)
from esphome.core import CORE
from esphome.core import CORE, ID
from esphome.coroutine import CoroPriority, coroutine_with_priority
from esphome.cpp_generator import MockObj
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
AUTO_LOAD = ["audio"]
@@ -29,11 +29,30 @@ microphone_ns = cg.esphome_ns.namespace("microphone")
Microphone = microphone_ns.class_("Microphone")
MicrophoneSource = microphone_ns.class_("MicrophoneSource")
CaptureAction = microphone_ns.class_(
"CaptureAction", automation.Action, cg.Parented.template(Microphone)
)
StopCaptureAction = microphone_ns.class_(
"StopCaptureAction", automation.Action, cg.Parented.template(Microphone)
)
MuteAction = microphone_ns.class_(
"MuteAction", automation.Action, cg.Parented.template(Microphone)
)
UnmuteAction = microphone_ns.class_(
"UnmuteAction", automation.Action, cg.Parented.template(Microphone)
)
DataTrigger = microphone_ns.class_(
"DataTrigger",
automation.Trigger.template(cg.std_vector.template(cg.uint8).operator("ref")),
)
IsCapturingCondition = microphone_ns.class_(
"IsCapturingCondition", automation.Condition
)
IsMutedCondition = microphone_ns.class_("IsMutedCondition", automation.Condition)
async def setup_microphone_core_(var: MockObj, config: ConfigType) -> None:
for conf in config.get(CONF_ON_DATA, []):
@@ -170,22 +189,44 @@ async def microphone_source_to_code(
return mic_source
for _name, _call in (
("microphone.capture", "start()"),
("microphone.stop_capture", "stop()"),
("microphone.mute", "set_mute_state(true)"),
("microphone.unmute", "set_mute_state(false)"),
):
automation.register_apply_action(
_name, MICROPHONE_ACTION_SCHEMA, automation.ApplyCall(_call)
)
async def microphone_action(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_apply_condition(
"microphone.is_capturing", MICROPHONE_ACTION_SCHEMA, "is_running()"
)
automation.register_apply_condition(
"microphone.is_muted", MICROPHONE_ACTION_SCHEMA, "get_mute_state()"
)
automation.register_action(
"microphone.capture",
CaptureAction,
MICROPHONE_ACTION_SCHEMA,
synchronous=True,
)(microphone_action)
automation.register_action(
"microphone.stop_capture",
StopCaptureAction,
MICROPHONE_ACTION_SCHEMA,
synchronous=True,
)(microphone_action)
automation.register_action(
"microphone.mute", MuteAction, MICROPHONE_ACTION_SCHEMA, synchronous=True
)(microphone_action)
automation.register_action(
"microphone.unmute", UnmuteAction, MICROPHONE_ACTION_SCHEMA, synchronous=True
)(microphone_action)
automation.register_condition(
"microphone.is_capturing", IsCapturingCondition, MICROPHONE_ACTION_SCHEMA
)(microphone_action)
automation.register_condition(
"microphone.is_muted", IsMutedCondition, MICROPHONE_ACTION_SCHEMA
)(microphone_action)
@coroutine_with_priority(CoroPriority.CORE)
@@ -7,6 +7,21 @@
namespace esphome::microphone {
template<typename... Ts> class CaptureAction final : public Action<Ts...>, public Parented<Microphone> {
void play(const Ts &...x) override { this->parent_->start(); }
};
template<typename... Ts> class StopCaptureAction final : public Action<Ts...>, public Parented<Microphone> {
void play(const Ts &...x) override { this->parent_->stop(); }
};
template<typename... Ts> class MuteAction final : public Action<Ts...>, public Parented<Microphone> {
void play(const Ts &...x) override { this->parent_->set_mute_state(true); }
};
template<typename... Ts> class UnmuteAction final : public Action<Ts...>, public Parented<Microphone> {
void play(const Ts &...x) override { this->parent_->set_mute_state(false); }
};
class DataTrigger final : public Trigger<const std::vector<uint8_t> &> {
public:
explicit DataTrigger(Microphone *mic) {
@@ -14,4 +29,14 @@ class DataTrigger final : public Trigger<const std::vector<uint8_t> &> {
}
};
template<typename... Ts> class IsCapturingCondition final : public Condition<Ts...>, public Parented<Microphone> {
public:
bool check(const Ts &...x) override { return this->parent_->is_running(); }
};
template<typename... Ts> class IsMutedCondition final : public Condition<Ts...>, public Parented<Microphone> {
public:
bool check(const Ts &...x) override { return this->parent_->get_mute_state(); }
};
} // namespace esphome::microphone
+66
View File
@@ -0,0 +1,66 @@
#pragma once
#if (defined(USE_ARDUINO) && !defined(USE_RP2) && !defined(USE_LIBRETINY)) || defined(USE_ESP_IDF)
#include "esphome/core/automation.h"
#include "air_conditioner.h"
namespace esphome::midea::ac {
template<typename... Ts> class MideaActionBase : public Action<Ts...> {
public:
void set_parent(AirConditioner *parent) { this->parent_ = parent; }
protected:
AirConditioner *parent_;
};
template<typename... Ts> class FollowMeAction : public MideaActionBase<Ts...> {
TEMPLATABLE_VALUE(float, temperature)
TEMPLATABLE_VALUE(bool, use_fahrenheit)
TEMPLATABLE_VALUE(bool, beeper)
void play(const Ts &...x) override {
this->parent_->do_follow_me(this->temperature_.value(x...), this->use_fahrenheit_.value(x...),
this->beeper_.value(x...));
}
};
template<typename... Ts> class SwingStepAction : public MideaActionBase<Ts...> {
public:
void play(const Ts &...x) override { this->parent_->do_swing_step(); }
};
template<typename... Ts> class DisplayToggleAction : public MideaActionBase<Ts...> {
public:
void play(const Ts &...x) override { this->parent_->do_display_toggle(); }
};
template<typename... Ts> class BeeperOnAction : public MideaActionBase<Ts...> {
public:
void play(const Ts &...x) override { this->parent_->do_beeper_on(); }
};
template<typename... Ts> class BeeperOffAction : public MideaActionBase<Ts...> {
public:
void play(const Ts &...x) override { this->parent_->do_beeper_off(); }
};
template<typename... Ts> class PowerOnAction : public MideaActionBase<Ts...> {
public:
void play(const Ts &...x) override { this->parent_->do_power_on(); }
};
template<typename... Ts> class PowerOffAction : public MideaActionBase<Ts...> {
public:
void play(const Ts &...x) override { this->parent_->do_power_off(); }
};
template<typename... Ts> class PowerToggleAction : public MideaActionBase<Ts...> {
public:
void play(const Ts &...x) override { this->parent_->do_power_toggle(); }
};
} // namespace esphome::midea::ac
#endif // USE_ARDUINO || USE_ESP_IDF
+107 -25
View File
@@ -32,7 +32,7 @@ from esphome.const import (
UNIT_PERCENT,
UNIT_WATT,
)
from esphome.core import CORE
from esphome.core import CORE, coroutine
CODEOWNERS = ["@dudanov"]
DEPENDENCIES = ["climate", "uart"]
@@ -53,6 +53,25 @@ def templatize(value):
return cv.Schema(ret)
def register_action(name, type_, schema):
validator = templatize(schema).extend(MIDEA_ACTION_BASE_SCHEMA)
registerer = automation.register_action(
f"midea_ac.{name}", type_, validator, synchronous=True
)
def decorator(func):
async def new_func(config, action_id, template_arg, args):
ac_ = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg)
cg.add(var.set_parent(ac_))
await coroutine(func)(var, config, args)
return var
return registerer(new_func)
return decorator
ALLOWED_CLIMATE_MODES = {
"HEAT_COOL": ClimateMode.CLIMATE_MODE_HEAT_COOL,
"COOL": ClimateMode.CLIMATE_MODE_COOL,
@@ -142,6 +161,16 @@ CONFIG_SCHEMA = cv.All(
),
)
# Actions
FollowMeAction = midea_ac_ns.class_("FollowMeAction", automation.Action)
DisplayToggleAction = midea_ac_ns.class_("DisplayToggleAction", automation.Action)
SwingStepAction = midea_ac_ns.class_("SwingStepAction", automation.Action)
BeeperOnAction = midea_ac_ns.class_("BeeperOnAction", automation.Action)
BeeperOffAction = midea_ac_ns.class_("BeeperOffAction", automation.Action)
PowerOnAction = midea_ac_ns.class_("PowerOnAction", automation.Action)
PowerOffAction = midea_ac_ns.class_("PowerOffAction", automation.Action)
PowerToggleAction = midea_ac_ns.class_("PowerToggleAction", automation.Action)
MIDEA_ACTION_BASE_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_ID): cv.use_id(AirConditioner),
@@ -158,31 +187,84 @@ MIDEA_FOLLOW_ME_SCHEMA = cv.Schema(
)
automation.register_apply_action(
"midea_ac.follow_me",
templatize(MIDEA_FOLLOW_ME_SCHEMA).extend(MIDEA_ACTION_BASE_SCHEMA),
automation.ApplyCall(
"do_follow_me({}, {}, {})",
(
(CONF_TEMPERATURE, cg.float_),
(CONF_USE_FAHRENHEIT, cg.bool_),
(CONF_BEEPER, cg.bool_),
),
),
)
@register_action("follow_me", FollowMeAction, MIDEA_FOLLOW_ME_SCHEMA)
async def follow_me_to_code(var, config, args):
template_ = await cg.templatable(config[CONF_BEEPER], args, cg.bool_)
cg.add(var.set_beeper(template_))
template_ = await cg.templatable(config[CONF_USE_FAHRENHEIT], args, cg.bool_)
cg.add(var.set_use_fahrenheit(template_))
template_ = await cg.templatable(config[CONF_TEMPERATURE], args, cg.float_)
cg.add(var.set_temperature(template_))
for _name, _call in (
("midea_ac.display_toggle", "do_display_toggle()"),
("midea_ac.swing_step", "do_swing_step()"),
("midea_ac.beeper_on", "do_beeper_on()"),
("midea_ac.beeper_off", "do_beeper_off()"),
("midea_ac.power_on", "do_power_on()"),
("midea_ac.power_off", "do_power_off()"),
("midea_ac.power_toggle", "do_power_toggle()"),
):
automation.register_apply_action(
_name, MIDEA_ACTION_BASE_SCHEMA, automation.ApplyCall(_call)
)
# Toggle Display action
@register_action(
"display_toggle",
DisplayToggleAction,
cv.Schema({}),
)
async def display_toggle_to_code(var, config, args):
pass
# Swing Step action
@register_action(
"swing_step",
SwingStepAction,
cv.Schema({}),
)
async def swing_step_to_code(var, config, args):
pass
# Beeper On action
@register_action(
"beeper_on",
BeeperOnAction,
cv.Schema({}),
)
async def beeper_on_to_code(var, config, args):
pass
# Beeper Off action
@register_action(
"beeper_off",
BeeperOffAction,
cv.Schema({}),
)
async def beeper_off_to_code(var, config, args):
pass
# Power On action
@register_action(
"power_on",
PowerOnAction,
cv.Schema({}),
)
async def power_on_to_code(var, config, args):
pass
# Power Off action
@register_action(
"power_off",
PowerOffAction,
cv.Schema({}),
)
async def power_off_to_code(var, config, args):
pass
# Power Toggle action
@register_action(
"power_toggle",
PowerToggleAction,
cv.Schema({}),
)
async def power_inv_to_code(var, config, args):
pass
FINAL_VALIDATE_SCHEMA = uart.final_validate_device_schema(
+1 -1
View File
@@ -155,7 +155,7 @@ void MideaIR::transmit_state() {
data.set_fahrenheit(this->fahrenheit_);
data.set_temp(this->target_temperature);
data.set_mode(this->mode);
data.set_fan_mode(this->fan_mode.value_or(ClimateFanMode::CLIMATE_FAN_ON));
data.set_fan_mode(this->fan_mode.value_or(ClimateFanMode::CLIMATE_FAN_AUTO));
data.set_sleep_preset(this->preset == climate::CLIMATE_PRESET_SLEEP);
data.fix();
this->transmit_(data);
@@ -162,12 +162,21 @@ async def remote_temperature_action_to_code(
return var
automation.register_parented_action(
@automation.register_action(
f"{DOMAIN}.clear_remote_temperature",
ClearRemoteTemperatureAction,
CLEAR_REMOTE_TEMPERATURE_ACTION_SCHEMA,
synchronous=True,
)
async def clear_temperature_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
VANE_CONTROL_ACTION_SCHEMA = cv.Schema(
+46 -29
View File
@@ -117,7 +117,10 @@ mqtt_ns = cg.esphome_ns.namespace("mqtt")
MQTTMessage = mqtt_ns.struct("MQTTMessage")
MQTTClientDisconnectReason = mqtt_ns.enum("MQTTClientDisconnectReason")
MQTTClientComponent = mqtt_ns.class_("MQTTClientComponent", cg.Component)
MQTTPublishAction = mqtt_ns.class_("MQTTPublishAction", automation.Action)
MQTTPublishJsonAction = mqtt_ns.class_("MQTTPublishJsonAction", automation.Action)
MQTTEnableAction = mqtt_ns.class_("MQTTEnableAction", automation.Action)
MQTTDisableAction = mqtt_ns.class_("MQTTDisableAction", automation.Action)
MQTTMessageTrigger = mqtt_ns.class_(
"MQTTMessageTrigger", automation.Trigger.template(cg.std_string), cg.Component
)
@@ -500,26 +503,22 @@ MQTT_PUBLISH_ACTION_SCHEMA = cv.Schema(
)
# A bare literal is ambiguous between the std::string and (const char *, size_t) publish
# overloads, so constants and inlined `return "...";` lambdas are both spelled as std::string.
def _std_string(config: ConfigType, value: str) -> str:
rendered = automation.flash_string(config, value)
return rendered if CORE.is_esp8266 else f"std::string({rendered})"
automation.register_apply_action(
"mqtt.publish",
MQTT_PUBLISH_ACTION_SCHEMA,
automation.ApplyCall(
"publish({}, {}, {}, {})",
(
(CONF_TOPIC, "std::string", _std_string),
(CONF_PAYLOAD, "std::string", _std_string),
(CONF_QOS, cg.uint8),
(CONF_RETAIN, cg.bool_),
),
),
@automation.register_action(
"mqtt.publish", MQTTPublishAction, MQTT_PUBLISH_ACTION_SCHEMA, synchronous=True
)
async def mqtt_publish_action_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_TOPIC], args, cg.std_string)
cg.add(var.set_topic(template_))
template_ = await cg.templatable(config[CONF_PAYLOAD], args, cg.std_string)
cg.add(var.set_payload(template_))
template_ = await cg.templatable(config[CONF_QOS], args, cg.uint8)
cg.add(var.set_qos(template_))
template_ = await cg.templatable(config[CONF_RETAIN], args, cg.bool_)
cg.add(var.set_retain(template_))
return var
MQTT_PUBLISH_JSON_ACTION_SCHEMA = cv.Schema(
@@ -609,16 +608,34 @@ automation.register_apply_condition(
)
for _name, _call in (("mqtt.enable", "enable()"), ("mqtt.disable", "disable()")):
automation.register_apply_action(
_name,
cv.Schema(
{
cv.GenerateID(): cv.use_id(MQTTClientComponent),
}
),
automation.ApplyCall(_call),
)
@automation.register_action(
"mqtt.enable",
MQTTEnableAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(MQTTClientComponent),
}
),
synchronous=True,
)
async def mqtt_enable_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_action(
"mqtt.disable",
MQTTDisableAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(MQTTClientComponent),
}
),
synchronous=True,
)
async def mqtt_disable_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)
_platform_filter = filter_source_files_from_platform(
+37
View File
@@ -378,6 +378,23 @@ class MQTTDisconnectTrigger final : public Trigger<MQTTClientDisconnectReason> {
}
};
template<typename... Ts> class MQTTPublishAction final : public Action<Ts...> {
public:
MQTTPublishAction(MQTTClientComponent *parent) : parent_(parent) {}
TEMPLATABLE_VALUE(std::string, topic)
TEMPLATABLE_VALUE(std::string, payload)
TEMPLATABLE_VALUE(uint8_t, qos)
TEMPLATABLE_VALUE(bool, retain)
void play(const Ts &...x) override {
this->parent_->publish(this->topic_.value(x...), this->payload_.value(x...), this->qos_.value(x...),
this->retain_.value(x...));
}
protected:
MQTTClientComponent *parent_;
};
template<typename... Ts> class MQTTPublishJsonAction final : public Action<Ts...> {
public:
MQTTPublishJsonAction(MQTTClientComponent *parent) : parent_(parent) {}
@@ -400,6 +417,26 @@ template<typename... Ts> class MQTTPublishJsonAction final : public Action<Ts...
MQTTClientComponent *parent_;
};
template<typename... Ts> class MQTTEnableAction final : public Action<Ts...> {
public:
MQTTEnableAction(MQTTClientComponent *parent) : parent_(parent) {}
void play(const Ts &...x) override { this->parent_->enable(); }
protected:
MQTTClientComponent *parent_;
};
template<typename... Ts> class MQTTDisableAction final : public Action<Ts...> {
public:
MQTTDisableAction(MQTTClientComponent *parent) : parent_(parent) {}
void play(const Ts &...x) override { this->parent_->disable(); }
protected:
MQTTClientComponent *parent_;
};
} // namespace esphome::mqtt
#endif // USE_MQTT
+14 -7
View File
@@ -4,6 +4,8 @@ import esphome.codegen as cg
from esphome.components import i2c, sensor
import esphome.config_validation as cv
from esphome.const import CONF_GAIN, CONF_ID, ICON_SCALE, STATE_CLASS_MEASUREMENT
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@cujomalainey"]
@@ -114,25 +116,30 @@ NAU7802_CALIBRATE_SCHEMA = maybe_simple_id(
)
automation.register_parented_action(
@automation.register_action(
"nau7802.calibrate_internal_offset",
NAU7802CalbrateInternalOffsetAction,
NAU7802_CALIBRATE_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"nau7802.calibrate_external_offset",
NAU7802CalbrateExternalOffsetAction,
NAU7802_CALIBRATE_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"nau7802.calibrate_gain",
NAU7802CalbrateGainAction,
NAU7802_CALIBRATE_SCHEMA,
synchronous=True,
)
async def nau7802_calibrate_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
-1
View File
@@ -28,7 +28,6 @@ void DeviceFirmwareUpdate::setup() {
this->reset_pin_->digital_write(true);
} else {
NRF_POWER->GPREGRET = DFU_MAGIC_UF2_RESET;
arch_feed_wdt();
App.reboot();
}
}
+22 -2
View File
@@ -3,6 +3,8 @@ import esphome.codegen as cg
from esphome.components import i2c, time
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@brogon"]
@@ -22,7 +24,7 @@ CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
).extend(i2c.i2c_device_schema(0x51))
automation.register_parented_action(
@automation.register_action(
"pcf85063.write_time",
WriteAction,
cv.Schema(
@@ -32,9 +34,18 @@ automation.register_parented_action(
),
synchronous=True,
)
async def pcf85063_write_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_parented_action(
@automation.register_action(
"pcf85063.read_time",
ReadAction,
automation.maybe_simple_id(
@@ -44,6 +55,15 @@ automation.register_parented_action(
),
synchronous=True,
)
async def pcf85063_read_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config: ConfigType) -> None:
+22 -2
View File
@@ -3,6 +3,8 @@ import esphome.codegen as cg
from esphome.components import i2c, time
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@KoenBreeman"]
@@ -25,7 +27,7 @@ CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
).extend(i2c.i2c_device_schema(0x51))
automation.register_parented_action(
@automation.register_action(
"pcf8563.write_time",
WriteAction,
automation.maybe_simple_id(
@@ -35,9 +37,18 @@ automation.register_parented_action(
),
synchronous=True,
)
async def pcf8563_write_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_parented_action(
@automation.register_action(
"pcf8563.read_time",
ReadAction,
automation.maybe_simple_id(
@@ -47,6 +58,15 @@ automation.register_parented_action(
),
synchronous=True,
)
async def pcf8563_read_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config: ConfigType) -> None:
+10 -4
View File
@@ -105,20 +105,26 @@ PMWCS3_CALIBRATION_SCHEMA = cv.Schema(
)
automation.register_simple_action(
@automation.register_action(
"pmwcs3.air_calibration",
PMWCS3AirCalibrationAction,
PMWCS3_CALIBRATION_SCHEMA,
synchronous=True,
)
automation.register_simple_action(
@automation.register_action(
"pmwcs3.water_calibration",
PMWCS3WaterCalibrationAction,
PMWCS3_CALIBRATION_SCHEMA,
synchronous=True,
)
async def pmwcs3_calibration_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
parent = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, parent)
PMWCS3_NEW_I2C_ADDRESS_SCHEMA = cv.maybe_simple_value(
+13 -2
View File
@@ -3,12 +3,14 @@ import esphome.codegen as cg
from esphome.components import nfc
import esphome.config_validation as cv
from esphome.const import (
CONF_ID,
CONF_ON_FINISHED_WRITE,
CONF_ON_TAG,
CONF_ON_TAG_REMOVED,
CONF_TRIGGER_ID,
)
from esphome.cpp_generator import MockObj
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@OttoWinter", "@jesserockz"]
@@ -77,7 +79,7 @@ async def setup_pn532(var: MockObj, config: ConfigType) -> None:
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
automation.register_parented_condition(
@automation.register_condition(
"pn532.is_writing",
PN532IsWritingCondition,
cv.Schema(
@@ -86,3 +88,12 @@ automation.register_parented_condition(
}
),
)
async def pn532_is_writing_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(condition_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+30 -35
View File
@@ -127,68 +127,54 @@ async def pn7150_set_message_to_code(
return var
automation.register_parented_action(
@automation.register_action(
"tag.emulation_off",
EmulationOffAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
"tag.emulation_on",
EmulationOnAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"tag.emulation_on", EmulationOnAction, SIMPLE_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
"tag.polling_off",
PollingOffAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"tag.polling_off", PollingOffAction, SIMPLE_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
"tag.polling_on",
PollingOnAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"tag.polling_on", PollingOnAction, SIMPLE_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
@automation.register_action(
"tag.set_clean_mode",
SetCleanModeAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"tag.set_format_mode",
SetFormatModeAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"tag.set_read_mode",
SetReadModeAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"tag.set_write_mode",
SetWriteModeAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
async def pn7150_simple_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
_CALLBACK_AUTOMATIONS = (
@@ -234,7 +220,7 @@ async def setup_pn7150(var: MockObj, config: ConfigType) -> None:
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
automation.register_parented_condition(
@automation.register_condition(
"pn7150.is_writing",
PN7150IsWritingCondition,
cv.Schema(
@@ -243,3 +229,12 @@ automation.register_parented_condition(
}
),
)
async def pn7150_is_writing_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(condition_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+30 -35
View File
@@ -131,68 +131,54 @@ async def pn7160_set_message_to_code(
return var
automation.register_parented_action(
@automation.register_action(
"tag.emulation_off",
EmulationOffAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
"tag.emulation_on",
EmulationOnAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"tag.emulation_on", EmulationOnAction, SIMPLE_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
"tag.polling_off",
PollingOffAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"tag.polling_off", PollingOffAction, SIMPLE_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
"tag.polling_on",
PollingOnAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"tag.polling_on", PollingOnAction, SIMPLE_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
@automation.register_action(
"tag.set_clean_mode",
SetCleanModeAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"tag.set_format_mode",
SetFormatModeAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"tag.set_read_mode",
SetReadModeAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"tag.set_write_mode",
SetWriteModeAction,
SIMPLE_ACTION_SCHEMA,
synchronous=True,
)
async def pn7160_simple_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
_CALLBACK_AUTOMATIONS = (
@@ -246,7 +232,7 @@ async def setup_pn7160(var: MockObj, config: ConfigType) -> None:
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
automation.register_parented_condition(
@automation.register_condition(
"pn7160.is_writing",
PN7160IsWritingCondition,
cv.Schema(
@@ -255,3 +241,12 @@ automation.register_parented_condition(
}
),
)
async def pn7160_is_writing_to_code(
config: ConfigType,
condition_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(condition_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+11 -1
View File
@@ -26,6 +26,8 @@ from esphome.const import (
UNIT_WATT,
UNIT_WATT_HOURS,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
AUTO_LOAD = ["modbus"]
@@ -83,7 +85,7 @@ CONFIG_SCHEMA = (
)
automation.register_simple_action(
@automation.register_action(
"pzemac.reset_energy",
ResetEnergyAction,
maybe_simple_id(
@@ -93,6 +95,14 @@ automation.register_simple_action(
),
synchronous=True,
)
async def reset_energy_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
def _final_validate(config: ConfigType) -> None:
+11 -1
View File
@@ -20,6 +20,8 @@ from esphome.const import (
UNIT_VOLT,
UNIT_WATT,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
AUTO_LOAD = ["modbus"]
@@ -65,7 +67,7 @@ CONFIG_SCHEMA = (
)
automation.register_simple_action(
@automation.register_action(
"pzemdc.reset_energy",
ResetEnergyAction,
maybe_simple_id(
@@ -75,6 +77,14 @@ automation.register_simple_action(
),
synchronous=True,
)
async def reset_energy_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
def _final_validate(config: ConfigType) -> None:
-1
View File
@@ -1,6 +1,5 @@
import esphome.codegen as cg
CONF_ENABLE_FULL_PRINTF = "enable_full_printf"
KEY_BOARD = "board"
KEY_LWIP_OPTS = "lwip_opts"
KEY_RP2 = "rp2"
@@ -81,19 +81,6 @@ void RuntimeStatsCollector::log_stats_() {
ESP_LOGI(TAG, " main_loop_overhead_section: before=%.1fms, tail=%.1fms, inter_component=%.1fms",
static_cast<double>(before) / 1000.0, static_cast<double>(tail) / 1000.0,
static_cast<double>(inter) / 1000.0);
uint64_t sched = this->period_before_sched_time_us_;
uint64_t wdt = this->period_before_wdt_time_us_;
uint64_t before_residual = before > sched + wdt ? before - sched - wdt : 0;
ESP_LOGI(TAG, " main_loop_before_breakdown: sched=%.1fms, wdt=%.1fms, residual=%.1fms",
static_cast<double>(sched) / 1000.0, static_cast<double>(wdt) / 1000.0,
static_cast<double>(before_residual) / 1000.0);
uint32_t wdt_slow_hits = App.wdt_slow_count_;
App.wdt_slow_count_ = 0;
ESP_LOGI(TAG, " wdt_slow_path: hits=%" PRIu32 " (%.1f%% of iters, avg=%.2fus/hit)", wdt_slow_hits,
this->period_active_count_ > 0
? 100.0 * static_cast<double>(wdt_slow_hits) / static_cast<double>(this->period_active_count_)
: 0.0,
wdt_slow_hits > 0 ? static_cast<double>(wdt) / static_cast<double>(wdt_slow_hits) : 0.0);
}
// Log total stats since boot (only for active components - idle ones haven't changed)
@@ -129,12 +116,6 @@ void RuntimeStatsCollector::log_stats_() {
ESP_LOGI(TAG, " main_loop_overhead_section: before=%.1fms, tail=%.1fms, inter_component=%.1fms",
static_cast<double>(before) / 1000.0, static_cast<double>(tail) / 1000.0,
static_cast<double>(inter) / 1000.0);
uint64_t sched = this->total_before_sched_time_us_;
uint64_t wdt = this->total_before_wdt_time_us_;
uint64_t before_residual = before > sched + wdt ? before - sched - wdt : 0;
ESP_LOGI(TAG, " main_loop_before_breakdown: sched=%.1fms, wdt=%.1fms, residual=%.1fms",
static_cast<double>(sched) / 1000.0, static_cast<double>(wdt) / 1000.0,
static_cast<double>(before_residual) / 1000.0);
}
// Reset period stats
@@ -145,8 +126,6 @@ void RuntimeStatsCollector::log_stats_() {
this->period_active_time_us_ = 0;
this->period_active_max_us_ = 0;
this->period_before_time_us_ = 0;
this->period_before_sched_time_us_ = 0;
this->period_before_wdt_time_us_ = 0;
this->period_tail_time_us_ = 0;
}
@@ -49,8 +49,7 @@ class RuntimeStatsCollector final {
// which captures per-iteration inter-component bookkeeping (set_current_component,
// LoopBlockingGuard construction/destruction, feed_wdt_with_time calls,
// the for-loop itself).
void record_loop_active(uint32_t active_us, uint32_t before_us, uint32_t sched_us, uint32_t wdt_us,
uint32_t tail_us) {
void record_loop_active(uint32_t active_us, uint32_t before_us, uint32_t tail_us) {
this->period_active_count_++;
this->period_active_time_us_ += active_us;
if (active_us > this->period_active_max_us_)
@@ -62,10 +61,6 @@ class RuntimeStatsCollector final {
this->period_before_time_us_ += before_us;
this->total_before_time_us_ += before_us;
this->period_before_sched_time_us_ += sched_us;
this->total_before_sched_time_us_ += sched_us;
this->period_before_wdt_time_us_ += wdt_us;
this->total_before_wdt_time_us_ += wdt_us;
this->period_tail_time_us_ += tail_us;
this->total_tail_time_us_ += tail_us;
}
@@ -93,11 +88,6 @@ class RuntimeStatsCollector final {
// Split of overhead sections — accumulated per iteration.
uint64_t period_before_time_us_{0};
uint64_t total_before_time_us_{0};
// Sub-split of `before` into scheduler_tick_ vs. post-scheduler feed_wdt_with_time.
uint64_t period_before_sched_time_us_{0};
uint64_t total_before_sched_time_us_{0};
uint64_t period_before_wdt_time_us_{0};
uint64_t total_before_wdt_time_us_{0};
uint64_t period_tail_time_us_{0};
uint64_t total_tail_time_us_{0};
};
+22 -2
View File
@@ -3,6 +3,8 @@ import esphome.codegen as cg
from esphome.components import i2c, time
import esphome.config_validation as cv
from esphome.const import CONF_ID
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@beormund"]
@@ -20,7 +22,7 @@ CONFIG_SCHEMA = time.TIME_SCHEMA.extend(
).extend(i2c.i2c_device_schema(0x32))
automation.register_parented_action(
@automation.register_action(
"rx8130.write_time",
WriteAction,
cv.Schema(
@@ -30,9 +32,18 @@ automation.register_parented_action(
),
synchronous=True,
)
async def rx8130_write_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
automation.register_parented_action(
@automation.register_action(
"rx8130.read_time",
ReadAction,
automation.maybe_simple_id(
@@ -42,6 +53,15 @@ automation.register_parented_action(
),
synchronous=True,
)
async def rx8130_read_time_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config: ConfigType) -> None:
+16 -4
View File
@@ -10,8 +10,8 @@ from esphome.const import (
CONF_STORAGE,
KEY_PAST_SAFE_MODE,
)
from esphome.core import CORE, CoroPriority, coroutine_with_priority
from esphome.cpp_generator import RawExpression
from esphome.core import CORE, ID, CoroPriority, coroutine_with_priority
from esphome.cpp_generator import MockObj, RawExpression, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@paulmonigatti", "@jsuanet", "@kbx81"]
@@ -22,6 +22,7 @@ CONF_ON_SAFE_MODE = "on_safe_mode"
safe_mode_ns = cg.esphome_ns.namespace("safe_mode")
SafeModeComponent = safe_mode_ns.class_("SafeModeComponent", cg.Component)
MarkSuccessfulAction = safe_mode_ns.class_("MarkSuccessfulAction", automation.Action)
def _remove_id_if_disabled(value: ConfigType) -> ConfigType:
@@ -52,15 +53,26 @@ CONFIG_SCHEMA = cv.All(
)
automation.register_apply_action(
@automation.register_action(
"safe_mode.mark_successful",
MarkSuccessfulAction,
cv.Schema(
{
cv.GenerateID(): cv.use_id(SafeModeComponent),
}
),
automation.ApplyCall("mark_successful()"),
synchronous=True,
)
async def safe_mode_mark_successful_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
parent = await cg.get_variable(config[CONF_ID])
var = cg.new_Pvariable(action_id, template_arg)
cg.add(var.set_parent(parent))
return var
_CALLBACK_AUTOMATIONS = (
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include "esphome/core/automation.h"
#include "safe_mode.h"
namespace esphome::safe_mode {
template<typename... Ts> class MarkSuccessfulAction final : public Action<Ts...>, public Parented<SafeModeComponent> {
public:
void play(const Ts &...x) override { this->parent_->mark_successful(); }
};
} // namespace esphome::safe_mode
+10 -1
View File
@@ -166,9 +166,18 @@ SCD4X_RESET_ACTION_SCHEMA = maybe_simple_id(
)
automation.register_parented_action(
@automation.register_action(
"scd4x.factory_reset",
FactoryResetAction,
SCD4X_RESET_ACTION_SCHEMA,
synchronous=True,
)
async def scd4x_reset_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+8 -2
View File
@@ -9,6 +9,7 @@ CODEOWNERS = ["@esphome/core"]
script_ns = cg.esphome_ns.namespace("script")
Script = script_ns.class_("Script", automation.Trigger.template())
ScriptExecuteAction = script_ns.class_("ScriptExecuteAction", automation.Action)
ScriptStopAction = script_ns.class_("ScriptStopAction", automation.Action)
ScriptWaitAction = script_ns.class_("ScriptWaitAction", automation.Action, cg.Component)
SingleScript = script_ns.class_("SingleScript", Script)
RestartScript = script_ns.class_("RestartScript", Script)
@@ -205,11 +206,16 @@ async def script_execute_action_to_code(config, action_id, template_arg, args):
return var
automation.register_apply_action(
@automation.register_action(
"script.stop",
ScriptStopAction,
maybe_simple_id({cv.Required(CONF_ID): cv.use_id(Script)}),
automation.ApplyCall("stop()"),
synchronous=True,
)
async def script_stop_action_to_code(config, action_id, template_arg, args):
full_id, paren = await cg.get_variable_with_full_id(config[CONF_ID])
template_arg = cg.TemplateArguments(full_id.type, *template_arg)
return cg.new_Pvariable(action_id, template_arg, paren)
@automation.register_action(
+10
View File
@@ -257,6 +257,16 @@ template<class... As, typename... Ts> class ScriptExecuteAction<Script<As...>, T
Args args_;
};
template<class C, typename... Ts> class ScriptStopAction final : public Action<Ts...> {
public:
ScriptStopAction(C *script) : script_(script) {}
void play(const Ts &...x) override { this->script_->stop(); }
protected:
C *script_;
};
/** Wait for a script to finish before continuing.
*
* Uses queue-based storage to safely handle concurrent executions.
+11 -1
View File
@@ -43,6 +43,8 @@ from esphome.const import (
UNIT_MICROGRAMS_PER_CUBIC_METER,
UNIT_PERCENT,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@martgras"]
@@ -280,9 +282,17 @@ SEN5X_ACTION_SCHEMA = maybe_simple_id(
)
automation.register_simple_action(
@automation.register_action(
"sen5x.start_fan_autoclean",
StartFanAction,
SEN5X_ACTION_SCHEMA,
synchronous=True,
)
async def sen54_fan_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
+21 -4
View File
@@ -21,8 +21,8 @@ from esphome.const import (
CONF_VERSION,
CONF_WIDTH,
)
from esphome.core import CORE
from esphome.cpp_generator import MockObj
from esphome.core import CORE, ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
# mdns for autodiscovery
@@ -109,6 +109,13 @@ SendspinHub = sendspin_ns.class_(
)
SendspinSwitchCommandAction = sendspin_ns.class_(
"SendspinSwitchCommandAction",
automation.Action,
cg.Parented.template(SendspinHub),
)
@dataclass
class SendspinConfiguration:
artwork_support: bool = False
@@ -233,11 +240,21 @@ SENDSPIN_SIMPLE_ACTION_SCHEMA = cv.All(
)
automation.register_apply_action(
@automation.register_action(
"sendspin.switch",
SendspinSwitchCommandAction,
SENDSPIN_SIMPLE_ACTION_SCHEMA,
automation.ApplyCall("switch_client()"),
synchronous=True,
)
async def sendspin_switch_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
async def to_code(config: ConfigType) -> None:
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_ESP32
#include "esphome/core/automation.h"
#include "sendspin_hub.h"
namespace esphome::sendspin_ {
#ifdef USE_SENDSPIN_CONTROLLER
template<typename... Ts> class SendspinSwitchCommandAction final : public Action<Ts...>, public Parented<SendspinHub> {
public:
void play(const Ts &...x) override {
// Clear any EXTERNAL_SOURCE state so the switch command is followed
this->parent_->update_state(sendspin::SendspinClientState::SYNCHRONIZED);
this->parent_->send_client_command(sendspin::SendspinControllerCommand::SWITCH);
}
};
#endif // USE_SENDSPIN_CONTROLLER
} // namespace esphome::sendspin_
#endif // USE_ESP32
+20 -2
View File
@@ -16,6 +16,7 @@ from esphome.const import (
CONF_WIDTH,
)
from esphome.core import ID
from esphome.cpp_generator import TemplateArgsType
from esphome.types import ConfigType
from .. import (
@@ -197,8 +198,16 @@ async def to_code(config: ConfigType) -> None:
await automation.build_callback_automations(var, config, _CALLBACK_AUTOMATIONS)
automation.register_apply_action(
SendspinImageTransitionFinishedAction = sendspin_ns.class_(
"SendspinImageTransitionFinishedAction",
automation.Action,
cg.Parented.template(SendspinImageSlot),
)
@automation.register_action(
"sendspin.image.transition_finished",
SendspinImageTransitionFinishedAction,
automation.maybe_simple_id(
cv.Schema(
{
@@ -206,5 +215,14 @@ automation.register_apply_action(
}
)
),
automation.ApplyCall("transition_finished()"),
synchronous=True,
)
async def sendspin_image_transition_finished_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> cg.MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@@ -0,0 +1,20 @@
#pragma once
#include "esphome/core/defines.h"
#if defined(USE_ESP32) && defined(USE_SENDSPIN_ARTWORK)
#include "esphome/core/automation.h"
#include "sendspin_image.h"
namespace esphome::sendspin_ {
template<typename... Ts>
class SendspinImageTransitionFinishedAction final : public Action<Ts...>, public Parented<SendspinImageSlot> {
public:
void play(const Ts &...x) override { this->parent_->transition_finished(); }
};
} // namespace esphome::sendspin_
#endif
@@ -8,6 +8,8 @@ from esphome.const import (
CONF_SAMPLE_RATE,
CONF_TASK_STACK_IN_PSRAM,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
from .. import (
@@ -39,6 +41,18 @@ SendspinMediaSource = sendspin_ns.class_(
media_source.MediaSource,
)
EnableStaticDelayAdjustmentAction = sendspin_ns.class_(
"EnableStaticDelayAdjustmentAction",
automation.Action,
cg.Parented.template(SendspinMediaSource),
)
DisableStaticDelayAdjustmentAction = sendspin_ns.class_(
"DisableStaticDelayAdjustmentAction",
automation.Action,
cg.Parented.template(SendspinMediaSource),
)
def _resolve_codecs(config: ConfigType) -> ConfigType:
"""Validate the codec preference list, filling in the default when it is not set."""
@@ -130,16 +144,25 @@ SENDSPIN_MEDIA_SOURCE_ACTION_SCHEMA = automation.maybe_simple_id(
)
)
for _name, _call in (
(
"sendspin.media_source.enable_static_delay_adjustment",
"set_static_delay_adjustable(true)",
),
(
"sendspin.media_source.disable_static_delay_adjustment",
"set_static_delay_adjustable(false)",
),
):
automation.register_apply_action(
_name, SENDSPIN_MEDIA_SOURCE_ACTION_SCHEMA, automation.ApplyCall(_call)
)
@automation.register_action(
"sendspin.media_source.enable_static_delay_adjustment",
EnableStaticDelayAdjustmentAction,
SENDSPIN_MEDIA_SOURCE_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"sendspin.media_source.disable_static_delay_adjustment",
DisableStaticDelayAdjustmentAction,
SENDSPIN_MEDIA_SOURCE_ACTION_SCHEMA,
synchronous=True,
)
async def sendspin_static_delay_adjustment_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
@@ -0,0 +1,26 @@
#pragma once
#include "esphome/core/defines.h"
#if defined(USE_ESP32) && defined(USE_SENDSPIN_PLAYER) && defined(USE_SENDSPIN_CONTROLLER)
#include "esphome/core/automation.h"
#include "sendspin_media_source.h"
namespace esphome::sendspin_ {
template<typename... Ts>
class EnableStaticDelayAdjustmentAction final : public Action<Ts...>, public Parented<SendspinMediaSource> {
public:
void play(const Ts &...x) override { this->parent_->set_static_delay_adjustable(true); }
};
template<typename... Ts>
class DisableStaticDelayAdjustmentAction final : public Action<Ts...>, public Parented<SendspinMediaSource> {
public:
void play(const Ts &...x) override { this->parent_->set_static_delay_adjustable(false); }
};
} // namespace esphome::sendspin_
#endif
@@ -284,13 +284,6 @@ void SendspinHub::send_client_command(sendspin::SendspinControllerCommand comman
}
}
// THREAD CONTEXT: Main loop (invoked from the sendspin.switch action)
void SendspinHub::switch_client() {
// Clear any EXTERNAL_SOURCE state so the switch command is followed
this->update_state(sendspin::SendspinClientState::SYNCHRONIZED);
this->send_client_command(sendspin::SendspinControllerCommand::SWITCH);
}
// THREAD CONTEXT: Main loop (ControllerRoleListener override, fired from client_->loop())
void SendspinHub::on_controller_state(const sendspin::ServerStateControllerObject &state) {
this->controller_state_callbacks_.call(state);
@@ -181,9 +181,6 @@ class SendspinHub final : public Component,
void send_client_command(sendspin::SendspinControllerCommand command, std::optional<uint8_t> volume = std::nullopt,
std::optional<bool> mute = std::nullopt);
/// @brief Sends the SWITCH controller command; exposed as the sendspin.switch action.
void switch_client();
template<typename F> void add_controller_state_callback(F &&callback) {
this->controller_state_callbacks_.add(std::forward<F>(callback));
}
+15 -13
View File
@@ -11,6 +11,8 @@ from esphome.const import (
STATE_CLASS_MEASUREMENT,
UNIT_PARTS_PER_MILLION,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
DEPENDENCIES = ["uart"]
@@ -80,41 +82,41 @@ CALIBRATION_ACTION_SCHEMA = maybe_simple_id(
)
automation.register_simple_action(
@automation.register_action(
"senseair.background_calibration",
SenseAirBackgroundCalibrationAction,
CALIBRATION_ACTION_SCHEMA,
synchronous=True,
)
automation.register_simple_action(
@automation.register_action(
"senseair.background_calibration_result",
SenseAirBackgroundCalibrationResultAction,
CALIBRATION_ACTION_SCHEMA,
synchronous=True,
)
automation.register_simple_action(
@automation.register_action(
"senseair.abc_enable",
SenseAirABCEnableAction,
CALIBRATION_ACTION_SCHEMA,
synchronous=True,
)
automation.register_simple_action(
@automation.register_action(
"senseair.abc_disable",
SenseAirABCDisableAction,
CALIBRATION_ACTION_SCHEMA,
synchronous=True,
)
automation.register_simple_action(
@automation.register_action(
"senseair.abc_get_period",
SenseAirABCGetPeriodAction,
CALIBRATION_ACTION_SCHEMA,
synchronous=True,
)
async def senseair_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
paren = await cg.get_variable(config[CONF_ID])
return cg.new_Pvariable(action_id, template_arg, paren)
+8 -2
View File
@@ -125,12 +125,15 @@ async def sim800l_dial_to_code(config, action_id, template_arg, args):
return var
automation.register_simple_action(
@automation.register_action(
"sim800l.connect",
Sim800LConnectAction,
cv.Schema({cv.GenerateID(): cv.use_id(Sim800LComponent)}),
synchronous=True,
)
async def sim800l_connect_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)
SIM800L_SEND_USSD_SCHEMA = cv.Schema(
@@ -155,9 +158,12 @@ async def sim800l_send_ussd_to_code(config, action_id, template_arg, args):
return var
automation.register_simple_action(
@automation.register_action(
"sim800l.disconnect",
Sim800LDisconnectAction,
cv.Schema({cv.GenerateID(): cv.use_id(Sim800LComponent)}),
synchronous=True,
)
async def sim800l_disconnect_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)
+15 -12
View File
@@ -11,6 +11,8 @@ from esphome.const import (
STATE_CLASS_MEASUREMENT,
UNIT_DECIBEL,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
AUTO_LOAD = ["audio"]
@@ -90,17 +92,18 @@ SOUND_LEVEL_ACTION_SCHEMA = automation.maybe_simple_id(
)
automation.register_parented_action(
"sound_level.start",
StartAction,
SOUND_LEVEL_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"sound_level.start", StartAction, SOUND_LEVEL_ACTION_SCHEMA, synchronous=True
)
automation.register_parented_action(
"sound_level.stop",
StopAction,
SOUND_LEVEL_ACTION_SCHEMA,
synchronous=True,
@automation.register_action(
"sound_level.stop", StopAction, SOUND_LEVEL_ACTION_SCHEMA, synchronous=True
)
async def sound_level_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+1 -1
View File
@@ -26,7 +26,7 @@ CONFIG_SCHEMA = (
cv.Optional(CONF_SPEED): cv.invalid(
"Configuring individual speeds is deprecated."
),
cv.Optional(CONF_SPEED_COUNT, default=100): cv.int_range(min=1, max=255),
cv.Optional(CONF_SPEED_COUNT, default=100): cv.int_range(min=1),
cv.Optional(CONF_PRESET_MODES): validate_preset_modes,
}
)
+2 -2
View File
@@ -9,7 +9,7 @@ namespace esphome::speed {
class SpeedFan final : public Component, public fan::Fan {
public:
SpeedFan(uint8_t speed_count) : speed_count_(speed_count) {}
SpeedFan(int speed_count) : speed_count_(speed_count) {}
void setup() override;
void dump_config() override;
void set_output(output::FloatOutput *output) { this->output_ = output; }
@@ -28,7 +28,7 @@ class SpeedFan final : public Component, public fan::Fan {
output::FloatOutput *output_;
output::BinaryOutput *oscillating_{nullptr};
output::BinaryOutput *direction_{nullptr};
uint8_t speed_count_{};
int speed_count_{};
fan::FanTraits traits_;
};
+89 -59
View File
@@ -66,10 +66,19 @@ SprinklerControllerSwitch = sprinkler_ns.class_(
"SprinklerControllerSwitch", switch.Switch, cg.Component
)
ClearQueuedValvesAction = sprinkler_ns.class_(
"ClearQueuedValvesAction", automation.Action
)
StartFromQueueAction = sprinkler_ns.class_("StartFromQueueAction", automation.Action)
StartFullCycleAction = sprinkler_ns.class_("StartFullCycleAction", automation.Action)
StartSingleValveAction = sprinkler_ns.class_(
"StartSingleValveAction", automation.Action
)
ShutdownAction = sprinkler_ns.class_("ShutdownAction", automation.Action)
NextValveAction = sprinkler_ns.class_("NextValveAction", automation.Action)
PreviousValveAction = sprinkler_ns.class_("PreviousValveAction", automation.Action)
PauseAction = sprinkler_ns.class_("PauseAction", automation.Action)
ResumeAction = sprinkler_ns.class_("ResumeAction", automation.Action)
ResumeOrStartAction = sprinkler_ns.class_("ResumeOrStartAction", automation.Action)
@@ -406,61 +415,57 @@ CONFIG_SCHEMA = cv.All(
_VALVE_AND_DURATION = ((CONF_VALVE_NUMBER, cg.size_t), (CONF_RUN_DURATION, cg.uint32))
for _name, _schema, _apply in (
(
"sprinkler.set_divider",
SPRINKLER_ACTION_SET_DIVIDER_SCHEMA,
automation.ApplyField(CONF_DIVIDER, "set_divider", cg.uint32),
),
(
"sprinkler.set_multiplier",
SPRINKLER_ACTION_SET_MULTIPLIER_SCHEMA,
automation.ApplyField(CONF_MULTIPLIER, "set_multiplier", cg.float_),
),
(
"sprinkler.queue_valve",
SPRINKLER_ACTION_QUEUE_VALVE_SCHEMA,
automation.ApplyCall("queue_valve({}, {})", _VALVE_AND_DURATION),
),
(
"sprinkler.set_repeat",
SPRINKLER_ACTION_REPEAT_SCHEMA,
automation.ApplyField(CONF_REPEAT, "set_repeat", cg.uint32),
),
(
"sprinkler.set_valve_run_duration",
SPRINKLER_ACTION_SET_RUN_DURATION_SCHEMA,
automation.ApplyCall("set_valve_run_duration({}, {})", _VALVE_AND_DURATION),
),
(
"sprinkler.start_from_queue",
SPRINKLER_ACTION_SCHEMA,
automation.ApplyCall("start_from_queue()"),
),
(
"sprinkler.start_full_cycle",
SPRINKLER_ACTION_SCHEMA,
automation.ApplyCall("start_full_cycle()"),
),
(
"sprinkler.clear_queued_valves",
SPRINKLER_ACTION_SCHEMA,
automation.ApplyCall("clear_queued_valves()"),
),
(
"sprinkler.next_valve",
SPRINKLER_ACTION_SCHEMA,
automation.ApplyCall("next_valve()"),
),
(
"sprinkler.previous_valve",
SPRINKLER_ACTION_SCHEMA,
automation.ApplyCall("previous_valve()"),
),
("sprinkler.pause", SPRINKLER_ACTION_SCHEMA, automation.ApplyCall("pause()")),
("sprinkler.resume", SPRINKLER_ACTION_SCHEMA, automation.ApplyCall("resume()")),
):
automation.register_apply_action(_name, _schema, _apply)
automation.register_apply_action(
"sprinkler.set_divider",
SPRINKLER_ACTION_SET_DIVIDER_SCHEMA,
automation.ApplyField(CONF_DIVIDER, "set_divider", cg.uint32),
)
automation.register_apply_action(
"sprinkler.set_multiplier",
SPRINKLER_ACTION_SET_MULTIPLIER_SCHEMA,
automation.ApplyField(CONF_MULTIPLIER, "set_multiplier", cg.float_),
)
automation.register_apply_action(
"sprinkler.queue_valve",
SPRINKLER_ACTION_QUEUE_VALVE_SCHEMA,
automation.ApplyCall("queue_valve({}, {})", _VALVE_AND_DURATION),
)
automation.register_apply_action(
"sprinkler.set_repeat",
SPRINKLER_ACTION_REPEAT_SCHEMA,
automation.ApplyField(CONF_REPEAT, "set_repeat", cg.uint32),
)
automation.register_apply_action(
"sprinkler.set_valve_run_duration",
SPRINKLER_ACTION_SET_RUN_DURATION_SCHEMA,
automation.ApplyCall("set_valve_run_duration({}, {})", _VALVE_AND_DURATION),
)
@automation.register_action(
"sprinkler.start_from_queue",
StartFromQueueAction,
SPRINKLER_ACTION_SCHEMA,
synchronous=True,
)
async def sprinkler_start_from_queue_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_action(
"sprinkler.start_full_cycle",
StartFullCycleAction,
SPRINKLER_ACTION_SCHEMA,
synchronous=True,
)
async def sprinkler_start_full_cycle_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_action(
@@ -480,20 +485,45 @@ async def sprinkler_start_single_valve_to_code(config, action_id, template_arg,
return var
automation.register_simple_action(
@automation.register_action(
"sprinkler.clear_queued_valves",
ClearQueuedValvesAction,
SPRINKLER_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"sprinkler.next_valve",
NextValveAction,
SPRINKLER_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"sprinkler.previous_valve",
PreviousValveAction,
SPRINKLER_ACTION_SCHEMA,
synchronous=True,
)
@automation.register_action(
"sprinkler.pause", PauseAction, SPRINKLER_ACTION_SCHEMA, synchronous=True
)
@automation.register_action(
"sprinkler.resume", ResumeAction, SPRINKLER_ACTION_SCHEMA, synchronous=True
)
@automation.register_action(
"sprinkler.resume_or_start_full_cycle",
ResumeOrStartAction,
SPRINKLER_ACTION_SCHEMA,
synchronous=True,
)
automation.register_simple_action(
@automation.register_action(
"sprinkler.shutdown",
ShutdownAction,
SPRINKLER_ACTION_SCHEMA,
synchronous=True,
)
async def sprinkler_simple_action_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)
async def to_code(config):
+70
View File
@@ -6,6 +6,36 @@
namespace esphome::sprinkler {
template<typename... Ts> class ClearQueuedValvesAction final : public Action<Ts...> {
public:
explicit ClearQueuedValvesAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
void play(const Ts &...x) override { this->sprinkler_->clear_queued_valves(); }
protected:
Sprinkler *sprinkler_;
};
template<typename... Ts> class StartFromQueueAction final : public Action<Ts...> {
public:
explicit StartFromQueueAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
void play(const Ts &...x) override { this->sprinkler_->start_from_queue(); }
protected:
Sprinkler *sprinkler_;
};
template<typename... Ts> class StartFullCycleAction final : public Action<Ts...> {
public:
explicit StartFullCycleAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
void play(const Ts &...x) override { this->sprinkler_->start_full_cycle(); }
protected:
Sprinkler *sprinkler_;
};
template<typename... Ts> class StartSingleValveAction final : public Action<Ts...> {
public:
explicit StartSingleValveAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
@@ -34,6 +64,46 @@ template<typename... Ts> class ShutdownAction final : public Action<Ts...> {
Sprinkler *sprinkler_;
};
template<typename... Ts> class NextValveAction final : public Action<Ts...> {
public:
explicit NextValveAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
void play(const Ts &...x) override { this->sprinkler_->next_valve(); }
protected:
Sprinkler *sprinkler_;
};
template<typename... Ts> class PreviousValveAction final : public Action<Ts...> {
public:
explicit PreviousValveAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
void play(const Ts &...x) override { this->sprinkler_->previous_valve(); }
protected:
Sprinkler *sprinkler_;
};
template<typename... Ts> class PauseAction final : public Action<Ts...> {
public:
explicit PauseAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
void play(const Ts &...x) override { this->sprinkler_->pause(); }
protected:
Sprinkler *sprinkler_;
};
template<typename... Ts> class ResumeAction final : public Action<Ts...> {
public:
explicit ResumeAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
void play(const Ts &...x) override { this->sprinkler_->resume(); }
protected:
Sprinkler *sprinkler_;
};
template<typename... Ts> class ResumeOrStartAction final : public Action<Ts...> {
public:
explicit ResumeOrStartAction(Sprinkler *a_sprinkler) : sprinkler_(a_sprinkler) {}
+14 -7
View File
@@ -26,6 +26,8 @@ from esphome.const import (
UNIT_MICROGRAMS_PER_CUBIC_METER,
UNIT_MICROMETER,
)
from esphome.core import ID
from esphome.cpp_generator import MockObj, TemplateArgsType
from esphome.types import ConfigType
CODEOWNERS = ["@martgras"]
@@ -180,25 +182,30 @@ SPS30_ACTION_SCHEMA = maybe_simple_id(
)
automation.register_parented_action(
@automation.register_action(
"sps30.start_fan_autoclean",
StartFanAction,
SPS30_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sps30.start_measurement",
StartMeasurementAction,
SPS30_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sps30.stop_measurement",
StopMeasurementAction,
SPS30_ACTION_SCHEMA,
synchronous=True,
)
async def sps30_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
+13 -10
View File
@@ -302,36 +302,39 @@ NO_ARGS_ACTION_SCHEMA = automation.maybe_simple_id(
)
automation.register_parented_action(
@automation.register_action(
"sx126x.run_image_cal",
RunImageCalAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sx126x.set_mode_tx",
SetModeTxAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sx126x.set_mode_rx",
SetModeRxAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sx126x.set_mode_standby",
SetModeStandbyAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def no_args_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
SET_MODE_SLEEP_ACTION_SCHEMA = automation.maybe_simple_id(
+14 -13
View File
@@ -286,44 +286,45 @@ NO_ARGS_ACTION_SCHEMA = automation.maybe_simple_id(
)
automation.register_parented_action(
@automation.register_action(
"sx127x.run_image_cal",
RunImageCalAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sx127x.set_mode_tx",
SetModeTxAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sx127x.set_mode_rx",
SetModeRxAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sx127x.set_mode_sleep",
SetModeSleepAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
automation.register_parented_action(
@automation.register_action(
"sx127x.set_mode_standby",
SetModeStandbyAction,
NO_ARGS_ACTION_SCHEMA,
synchronous=True,
)
async def no_args_action_to_code(
config: ConfigType,
action_id: ID,
template_arg: cg.TemplateArguments,
args: TemplateArgsType,
) -> MockObj:
var = cg.new_Pvariable(action_id, template_arg)
await cg.register_parented(var, config[CONF_ID])
return var
SEND_PACKET_ACTION_SCHEMA = cv.maybe_simple_value(

Some files were not shown because too many files have changed in this diff Show More