Compare commits

...
Author SHA1 Message Date
J. Nick Koston 0094cee7b6 Merge remote-tracking branch 'origin/dev' into apply-entities-button 2026-10-21 08:40:54 -10:00
J. Nick Koston 98ab149c24 [dfrobot_sen0609] Use Apply buttons for the hub buttons 2026-10-20 17:08:45 -10:00
J. Nick Koston 49a8c1d4cc Merge remote-tracking branch 'origin/dev' into apply-entities-button 2026-10-19 07:52:24 -10:00
J. Nick Koston 39bfdecf75 Merge branch 'apply-entities' into apply-entities-button 2026-10-16 14:07:10 -10:00
J. Nick Koston 754a960ed1 [core] Declare apply locals right before their first use
A local declared at the top ran option_at before a publish placed before
the statement, which changed the call order and grew ld2412 by 16 bytes.
2026-10-16 14:06:17 -10:00
J. Nick Koston 4f1db5b3d1 Merge branch 'apply-entities' into apply-entities-button 2026-10-16 14:04:31 -10:00
J. Nick Koston f7a60f5859 [core] Give select apply statements an option local
Select apply statements can name the selected option text as option; the
local is declared only when a statement uses it.
2026-10-16 14:04:26 -10:00
J. Nick Koston d0d79d5c54 [tfluna] Use Apply buttons 2026-10-16 13:46:03 -10:00
J. Nick Koston ab2383e7c5 [seeed_mr60fda2] Use Apply buttons 2026-10-16 13:46:03 -10:00
J. Nick Koston def600ff6a [seeed_mr24hpc1] Use Apply buttons 2026-10-16 13:46:02 -10:00
J. Nick Koston f1dda7da41 [ld2450] Use Apply buttons 2026-10-16 13:46:02 -10:00
J. Nick Koston b6f101d5a6 [ld2420] Use Apply buttons 2026-10-16 13:46:01 -10:00
J. Nick Koston 7c6c0fb4bc [ld2412] Use Apply buttons 2026-10-16 13:46:01 -10:00
J. Nick Koston 75ac3f51b5 [ld2410] Use Apply buttons 2026-10-16 13:46:01 -10:00
J. Nick Koston d9e3f2ae3e [hoermann_hcp] Use Apply buttons 2026-10-16 13:46:01 -10:00
J. Nick Koston 5cc6f6a89d [haier] Use Apply buttons 2026-10-16 13:46:01 -10:00
J. Nick Koston 23bc50d229 [espectre] Use Apply buttons 2026-10-16 13:46:00 -10:00
J. Nick Koston 472b2281d1 [bq25186] Use Apply buttons 2026-10-16 13:46:00 -10:00
J. Nick Koston b8a0de91db [core] Simplify the Apply entity helpers
Fold the function cache into SubEntities, make each domain's APPLY_ENTITY public,
shorten the class and docstring comments and reuse the shared test hub.
2026-10-16 13:42:23 -10:00
J. Nick Koston 2937d81216 Mark the test recorders as intentional mutable globals 2026-10-16 12:20:50 -10:00
J. Nick Koston 05a4b256db Reject an unknown publish= value 2026-10-16 11:45:47 -10:00
J. Nick Koston d0427c36eb [core] Share the apply function naming with automations and check the Apply class at codegen 2026-10-16 11:04:36 -10:00
J. Nick Koston a990231342 [core] Add Apply button, switch, number and select entities for hub forwarders 2026-10-16 10:48:29 -10:00
55 changed files with 162 additions and 748 deletions
@@ -1,25 +0,0 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_BUTTON
#include "bq25186.h"
#include "esphome/components/button/button.h"
namespace esphome::bq25186 {
/// Writes one SHIP_RST field when pressed
class BQ25186Button final : public button::Button, public Parented<BQ25186Component> {
public:
BQ25186Button(uint8_t mask, uint8_t value) : mask_(mask), value_(value) {}
protected:
void press_action() override { this->parent_->write_ship_rst(this->mask_, this->value_); }
const uint8_t mask_;
const uint8_t value_;
};
} // namespace esphome::bq25186
#endif // USE_BUTTON
+4 -7
View File
@@ -1,4 +1,3 @@
import esphome.codegen as cg
from esphome.components import button
import esphome.config_validation as cv
from esphome.const import (
@@ -10,11 +9,10 @@ from esphome.const import (
)
from esphome.types import ConfigType
from . import BQ25186_CHILD_SCHEMA, CONF_BQ25186_ID, bq25186_ns
from . import BQ25186_CHILD_SCHEMA, CONF_BQ25186_ID
DEPENDENCIES = ["bq25186"]
BQ25186Button = bq25186_ns.class_("BQ25186Button", button.Button)
# SHIP_RST: bit 7 is the software reset, bits 6:5 the shutdown, ship and hardware reset codes
SOFTWARE_RESET_MASK = 0x80
@@ -33,7 +31,7 @@ CONFIG_SCHEMA = cv.All(
BQ25186_CHILD_SCHEMA.extend(
{
cv.Optional(key): button.button_schema(
BQ25186Button,
button.ApplyButton,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=icon,
device_class=device_class,
@@ -46,7 +44,6 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config: ConfigType) -> None:
buttons = button.sub_buttons(config, parent=config[CONF_BQ25186_ID])
for key, mask, value, _, _ in _BUTTONS:
if (conf := config.get(key)) is not None:
var = await button.new_button(conf, mask, value)
await cg.register_parented(var, config[CONF_BQ25186_ID])
await buttons(key, None, apply=f"write_ship_rst({mask:#04x}, {value:#04x})")
@@ -15,27 +15,24 @@ from esphome.const import (
)
from esphome.types import ConfigType
from .. import CONF_DFROBOT_SEN0609_ID, DFRobotSEN0609Component, dfrobot_sen0609_ns
DFRobotSEN0609Button = dfrobot_sen0609_ns.class_("DFRobotSEN0609Button", button.Button)
ButtonAction = dfrobot_sen0609_ns.enum("ButtonAction")
from .. import CONF_DFROBOT_SEN0609_ID, DFRobotSEN0609Component
CONFIG_SCHEMA = {
cv.GenerateID(CONF_ID): cv.declare_id(cg.EntityBase),
cv.GenerateID(CONF_DFROBOT_SEN0609_ID): cv.use_id(DFRobotSEN0609Component),
cv.Optional(CONF_FACTORY_RESET): button.button_schema(
DFRobotSEN0609Button,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART_ALERT,
),
cv.Optional(CONF_QUERY_PARAMS): button.button_schema(
DFRobotSEN0609Button,
button.ApplyButton,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_DATABASE,
),
cv.Optional(CONF_RESTART): button.button_schema(
DFRobotSEN0609Button,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_RESTART,
@@ -47,11 +44,7 @@ async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_DFROBOT_SEN0609_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(
CONF_FACTORY_RESET,
hub.set_factory_reset_button,
ButtonAction.BUTTON_FACTORY_RESET,
CONF_FACTORY_RESET, hub.set_factory_reset_button, apply="factory_reset()"
)
await buttons(
CONF_QUERY_PARAMS, hub.set_query_button, ButtonAction.BUTTON_QUERY_PARAMS
)
await buttons(CONF_RESTART, hub.set_restart_button, ButtonAction.BUTTON_RESTART)
await buttons(CONF_QUERY_PARAMS, hub.set_query_button, apply="query_params()")
await buttons(CONF_RESTART, hub.set_restart_button, apply="restart()")
@@ -1,30 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../dfrobot_sen0609.h"
namespace esphome::dfrobot_sen0609 {
class DFRobotSEN0609Button final : public button::Button, public Parented<DFRobotSEN0609Component> {
public:
explicit DFRobotSEN0609Button(ButtonAction action) : action_(action) {}
protected:
void press_action() override {
switch (this->action_) {
case BUTTON_RESTART:
this->parent_->restart();
break;
case BUTTON_FACTORY_RESET:
this->parent_->factory_reset();
break;
case BUTTON_QUERY_PARAMS:
this->parent_->query_params();
break;
}
}
ButtonAction action_;
};
} // namespace esphome::dfrobot_sen0609
@@ -62,12 +62,6 @@ enum SwitchSetting : uint8_t {
SWITCH_COUNT,
};
enum ButtonAction : uint8_t {
BUTTON_RESTART,
BUTTON_FACTORY_RESET,
BUTTON_QUERY_PARAMS,
};
/// Module parameters; a write or read of each is one command. Pending work runs in this order.
enum Param : uint8_t {
PARAM_RUN_APP,
@@ -1,20 +1,18 @@
import esphome.codegen as cg
from esphome.components import button
import esphome.config_validation as cv
from esphome.const import ENTITY_CATEGORY_CONFIG
from esphome.types import ConfigType
from .. import CONF_ESPECTRE_ID, ESPectreComponent, espectre_ns
from .. import CONF_ESPECTRE_ID, ESPectreComponent
DEPENDENCIES = ["espectre"]
RecalibrateButton = espectre_ns.class_("RecalibrateButton", button.Button)
CONFIG_SCHEMA = button.button_schema(
RecalibrateButton, entity_category=ENTITY_CATEGORY_CONFIG
button.ApplyButton, entity_category=ENTITY_CATEGORY_CONFIG
).extend({cv.GenerateID(CONF_ESPECTRE_ID): cv.use_id(ESPectreComponent)})
async def to_code(config: ConfigType) -> None:
var = await button.new_button(config)
await cg.register_parented(var, config[CONF_ESPECTRE_ID])
buttons = button.sub_buttons(config, parent=config[CONF_ESPECTRE_ID])
await buttons.create(config, None, apply="recalibrate()")
@@ -1,19 +0,0 @@
#pragma once
#include "esphome/core/defines.h"
#ifdef USE_ESPECTRE
#include "esphome/components/button/button.h"
#include "../espectre.h"
namespace esphome::espectre {
class RecalibrateButton final : public button::Button, public Parented<ESPectreComponent> {
protected:
void press_action() override { this->parent_->recalibrate(); }
};
} // namespace esphome::espectre
#endif // USE_ESPECTRE
+8 -11
View File
@@ -1,12 +1,10 @@
import esphome.codegen as cg
from esphome.components import button
import esphome.config_validation as cv
from esphome.types import ConfigType
from ..climate import CONF_HAIER_ID, HonClimate, haier_ns
from ..climate import CONF_HAIER_ID, HonClimate
CODEOWNERS = ["@paveldn"]
SelfCleaningButton = haier_ns.class_("SelfCleaningButton", button.Button)
SteriCleaningButton = haier_ns.class_("SteriCleaningButton", button.Button)
# Haier buttons
@@ -20,19 +18,18 @@ CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(CONF_HAIER_ID): cv.use_id(HonClimate),
cv.Optional(CONF_SELF_CLEANING): button.button_schema(
SelfCleaningButton,
button.ApplyButton,
icon=ICON_SPRAY_BOTTLE,
),
cv.Optional(CONF_STERI_CLEANING): button.button_schema(
SteriCleaningButton,
button.ApplyButton,
icon=ICON_SPRAY_BOTTLE,
),
}
)
async def to_code(config):
for button_type in [CONF_SELF_CLEANING, CONF_STERI_CLEANING]:
if conf := config.get(button_type):
btn = await button.new_button(conf)
await cg.register_parented(btn, config[CONF_HAIER_ID])
async def to_code(config: ConfigType) -> None:
buttons = button.sub_buttons(config, parent=config[CONF_HAIER_ID])
await buttons(CONF_SELF_CLEANING, None, apply="start_self_cleaning()")
await buttons(CONF_STERI_CLEANING, None, apply="start_steri_cleaning()")
@@ -1,7 +0,0 @@
#include "self_cleaning.h"
namespace esphome::haier {
void SelfCleaningButton::press_action() { this->parent_->start_self_cleaning(); }
} // namespace esphome::haier
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../hon_climate.h"
namespace esphome::haier {
class SelfCleaningButton final : public button::Button, public Parented<HonClimate> {
public:
SelfCleaningButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::haier
@@ -1,7 +0,0 @@
#include "steri_cleaning.h"
namespace esphome::haier {
void SteriCleaningButton::press_action() { this->parent_->start_steri_cleaning(); }
} // namespace esphome::haier
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../hon_climate.h"
namespace esphome::haier {
class SteriCleaningButton final : public button::Button, public Parented<HonClimate> {
public:
SteriCleaningButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::haier
@@ -1,10 +1,9 @@
import esphome.codegen as cg
from esphome.components import button
import esphome.config_validation as cv
from esphome.const import ICON_AIR_FILTER
from esphome.types import ConfigType
from .. import CONF_HOERMANN_HCP_ID, HoermannHcp, hoermann_hcp_ns
from .. import CONF_HOERMANN_HCP_ID, HoermannHcp
DEPENDENCIES = ["hoermann_hcp"]
@@ -13,10 +12,6 @@ CONF_VENT = "vent"
ICON_GARAGE_OPEN_VARIANT = "mdi:garage-open-variant"
HoermannHcpVentButton = hoermann_hcp_ns.class_("HoermannHcpVentButton", button.Button)
HoermannHcpHalfOpenButton = hoermann_hcp_ns.class_(
"HoermannHcpHalfOpenButton", button.Button
)
BUTTON_KEYS = (CONF_VENT, CONF_HALF_OPEN)
@@ -25,10 +20,10 @@ CONFIG_SCHEMA = cv.All(
{
cv.GenerateID(CONF_HOERMANN_HCP_ID): cv.use_id(HoermannHcp),
cv.Optional(CONF_VENT): button.button_schema(
HoermannHcpVentButton, icon=ICON_AIR_FILTER
button.ApplyButton, icon=ICON_AIR_FILTER
),
cv.Optional(CONF_HALF_OPEN): button.button_schema(
HoermannHcpHalfOpenButton, icon=ICON_GARAGE_OPEN_VARIANT
button.ApplyButton, icon=ICON_GARAGE_OPEN_VARIANT
),
}
),
@@ -37,7 +32,6 @@ CONFIG_SCHEMA = cv.All(
async def to_code(config: ConfigType) -> None:
parent = await cg.get_variable(config[CONF_HOERMANN_HCP_ID])
for key in BUTTON_KEYS:
if (conf := config.get(key)) is not None:
await button.new_button(conf, parent)
buttons = button.sub_buttons(config, parent=config[CONF_HOERMANN_HCP_ID])
await buttons(CONF_VENT, None, apply="vent_door()")
await buttons(CONF_HALF_OPEN, None, apply="half_open_door()")
@@ -1,34 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../hoermann_hcp.h"
namespace esphome::hoermann_hcp {
// The door commands the cover has no equivalent for. A refused command is already reported by the hub and
// leaves nothing to correct here, because a button carries no state of its own.
class HoermannHcpButton : public button::Button {
public:
explicit HoermannHcpButton(HoermannHcp *parent) : parent_(parent) {}
protected:
HoermannHcp *const parent_;
};
class HoermannHcpVentButton final : public HoermannHcpButton {
public:
using HoermannHcpButton::HoermannHcpButton;
protected:
void press_action() override { this->parent_->vent_door(); }
};
class HoermannHcpHalfOpenButton final : public HoermannHcpButton {
public:
using HoermannHcpButton::HoermannHcpButton;
protected:
void press_action() override { this->parent_->half_open_door(); }
};
} // namespace esphome::hoermann_hcp
+11 -11
View File
@@ -15,29 +15,25 @@ from esphome.const import (
)
from esphome.types import ConfigType
from .. import CONF_LD2410_ID, LD2410Component, ld2410_ns
FactoryResetButton = ld2410_ns.class_("FactoryResetButton", button.Button)
QueryButton = ld2410_ns.class_("QueryButton", button.Button)
RestartButton = ld2410_ns.class_("RestartButton", button.Button)
from .. import CONF_LD2410_ID, LD2410Component
CONFIG_SCHEMA = {
cv.GenerateID(CONF_ID): cv.declare_id(cg.EntityBase),
cv.GenerateID(CONF_LD2410_ID): cv.use_id(LD2410Component),
cv.Optional(CONF_FACTORY_RESET): button.button_schema(
FactoryResetButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART_ALERT,
),
cv.Optional(CONF_RESTART): button.button_schema(
RestartButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_RESTART,
),
cv.Optional(CONF_QUERY_PARAMS): button.button_schema(
QueryButton,
button.ApplyButton,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_DATABASE,
),
@@ -47,6 +43,10 @@ CONFIG_SCHEMA = {
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD2410_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(CONF_FACTORY_RESET, hub.set_factory_reset_button)
await buttons(CONF_RESTART, hub.set_restart_button)
await buttons(CONF_QUERY_PARAMS, hub.set_query_button)
await buttons(
CONF_FACTORY_RESET, hub.set_factory_reset_button, apply="factory_reset()"
)
await buttons(
CONF_RESTART, hub.set_restart_button, apply="restart_and_read_all_info()"
)
await buttons(CONF_QUERY_PARAMS, hub.set_query_button, apply="read_all_info()")
@@ -1,7 +0,0 @@
#include "factory_reset_button.h"
namespace esphome::ld2410 {
void FactoryResetButton::press_action() { this->parent_->factory_reset(); }
} // namespace esphome::ld2410
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2410.h"
namespace esphome::ld2410 {
class FactoryResetButton final : public button::Button, public Parented<LD2410Component> {
public:
FactoryResetButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::ld2410
@@ -1,7 +0,0 @@
#include "query_button.h"
namespace esphome::ld2410 {
void QueryButton::press_action() { this->parent_->read_all_info(); }
} // namespace esphome::ld2410
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2410.h"
namespace esphome::ld2410 {
class QueryButton final : public button::Button, public Parented<LD2410Component> {
public:
QueryButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::ld2410
@@ -1,7 +0,0 @@
#include "restart_button.h"
namespace esphome::ld2410 {
void RestartButton::press_action() { this->parent_->restart_and_read_all_info(); }
} // namespace esphome::ld2410
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2410.h"
namespace esphome::ld2410 {
class RestartButton final : public button::Button, public Parented<LD2410Component> {
public:
RestartButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::ld2410
+13 -14
View File
@@ -16,38 +16,32 @@ from esphome.const import (
)
from esphome.types import ConfigType
from .. import CONF_LD2412_ID, LD2412_ns, LD2412Component
from .. import CONF_LD2412_ID, LD2412Component
FactoryResetButton = LD2412_ns.class_("FactoryResetButton", button.Button)
QueryButton = LD2412_ns.class_("QueryButton", button.Button)
RestartButton = LD2412_ns.class_("RestartButton", button.Button)
StartDynamicBackgroundCorrectionButton = LD2412_ns.class_(
"StartDynamicBackgroundCorrectionButton", button.Button
)
CONF_START_DYNAMIC_BACKGROUND_CORRECTION = "start_dynamic_background_correction"
CONFIG_SCHEMA = {
cv.GenerateID(CONF_ID): cv.declare_id(cg.EntityBase),
cv.GenerateID(CONF_LD2412_ID): cv.use_id(LD2412Component),
cv.Optional(CONF_FACTORY_RESET): button.button_schema(
FactoryResetButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART_ALERT,
),
cv.Optional(CONF_QUERY_PARAMS): button.button_schema(
QueryButton,
button.ApplyButton,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_DATABASE,
),
cv.Optional(CONF_RESTART): button.button_schema(
RestartButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_RESTART,
),
cv.Optional(CONF_START_DYNAMIC_BACKGROUND_CORRECTION): button.button_schema(
StartDynamicBackgroundCorrectionButton,
button.ApplyButton,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_PULSE,
),
@@ -57,10 +51,15 @@ CONFIG_SCHEMA = {
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD2412_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(CONF_FACTORY_RESET, hub.set_factory_reset_button)
await buttons(CONF_QUERY_PARAMS, hub.set_query_button)
await buttons(CONF_RESTART, hub.set_restart_button)
await buttons(
CONF_FACTORY_RESET, hub.set_factory_reset_button, apply="factory_reset()"
)
await buttons(CONF_QUERY_PARAMS, hub.set_query_button, apply="read_all_info()")
await buttons(
CONF_RESTART, hub.set_restart_button, apply="restart_and_read_all_info()"
)
await buttons(
CONF_START_DYNAMIC_BACKGROUND_CORRECTION,
hub.set_start_dynamic_background_correction_button,
apply="start_dynamic_background_correction()",
)
@@ -1,7 +0,0 @@
#include "factory_reset_button.h"
namespace esphome::ld2412 {
void FactoryResetButton::press_action() { this->parent_->factory_reset(); }
} // namespace esphome::ld2412
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2412.h"
namespace esphome::ld2412 {
class FactoryResetButton final : public button::Button, public Parented<LD2412Component> {
public:
FactoryResetButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::ld2412
@@ -1,7 +0,0 @@
#include "query_button.h"
namespace esphome::ld2412 {
void QueryButton::press_action() { this->parent_->read_all_info(); }
} // namespace esphome::ld2412
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2412.h"
namespace esphome::ld2412 {
class QueryButton final : public button::Button, public Parented<LD2412Component> {
public:
QueryButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::ld2412
@@ -1,7 +0,0 @@
#include "restart_button.h"
namespace esphome::ld2412 {
void RestartButton::press_action() { this->parent_->restart_and_read_all_info(); }
} // namespace esphome::ld2412
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2412.h"
namespace esphome::ld2412 {
class RestartButton final : public button::Button, public Parented<LD2412Component> {
public:
RestartButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::ld2412
@@ -1,9 +0,0 @@
#include "start_dynamic_background_correction_button.h"
#include "restart_button.h"
namespace esphome::ld2412 {
void StartDynamicBackgroundCorrectionButton::press_action() { this->parent_->start_dynamic_background_correction(); }
} // namespace esphome::ld2412
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2412.h"
namespace esphome::ld2412 {
class StartDynamicBackgroundCorrectionButton final : public button::Button, public Parented<LD2412Component> {
public:
StartDynamicBackgroundCorrectionButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::ld2412
+23 -14
View File
@@ -12,12 +12,7 @@ from esphome.const import (
)
from esphome.types import ConfigType
from .. import CONF_LD2420_ID, LD2420Component, ld2420_ns
LD2420ApplyConfigButton = ld2420_ns.class_("LD2420ApplyConfigButton", button.Button)
LD2420RevertConfigButton = ld2420_ns.class_("LD2420RevertConfigButton", button.Button)
LD2420RestartModuleButton = ld2420_ns.class_("LD2420RestartModuleButton", button.Button)
LD2420FactoryResetButton = ld2420_ns.class_("LD2420FactoryResetButton", button.Button)
from .. import CONF_LD2420_ID, LD2420Component
CONF_APPLY_CONFIG = "apply_config"
CONF_REVERT_CONFIG = "revert_config"
@@ -27,24 +22,24 @@ CONF_RESTART_MODULE = "restart_module"
CONFIG_SCHEMA = {
cv.GenerateID(CONF_LD2420_ID): cv.use_id(LD2420Component),
cv.Required(CONF_APPLY_CONFIG): button.button_schema(
LD2420ApplyConfigButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART_ALERT,
),
cv.Optional(CONF_REVERT_CONFIG): button.button_schema(
LD2420RevertConfigButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART,
),
cv.Optional(CONF_RESTART_MODULE): button.button_schema(
LD2420RestartModuleButton,
button.ApplyButton,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_DATABASE,
),
cv.Optional(CONF_FACTORY_RESET): button.button_schema(
LD2420FactoryResetButton,
button.ApplyButton,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_DATABASE,
),
@@ -54,7 +49,21 @@ CONFIG_SCHEMA = {
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD2420_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(CONF_APPLY_CONFIG, hub.set_apply_config_button)
await buttons(CONF_REVERT_CONFIG, hub.set_revert_config_button)
await buttons(CONF_RESTART_MODULE, hub.set_restart_module_button)
await buttons(CONF_FACTORY_RESET, hub.set_factory_reset_button)
await buttons(
CONF_APPLY_CONFIG, hub.set_apply_config_button, apply="apply_config_action()"
)
await buttons(
CONF_REVERT_CONFIG,
hub.set_revert_config_button,
apply="revert_config_action()",
)
await buttons(
CONF_RESTART_MODULE,
hub.set_restart_module_button,
apply="restart_module_action()",
)
await buttons(
CONF_FACTORY_RESET,
hub.set_factory_reset_button,
apply="factory_reset_action()",
)
@@ -1,14 +0,0 @@
#include "reconfig_buttons.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
ESPHOME_LOG_TAG(TAG, "ld2420.button");
namespace esphome::ld2420 {
void LD2420ApplyConfigButton::press_action() { this->parent_->apply_config_action(); }
void LD2420RevertConfigButton::press_action() { this->parent_->revert_config_action(); }
void LD2420RestartModuleButton::press_action() { this->parent_->restart_module_action(); }
void LD2420FactoryResetButton::press_action() { this->parent_->factory_reset_action(); }
} // namespace esphome::ld2420
@@ -1,40 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2420.h"
namespace esphome::ld2420 {
class LD2420ApplyConfigButton final : public button::Button, public Parented<LD2420Component> {
public:
LD2420ApplyConfigButton() = default;
protected:
void press_action() override;
};
class LD2420RevertConfigButton final : public button::Button, public Parented<LD2420Component> {
public:
LD2420RevertConfigButton() = default;
protected:
void press_action() override;
};
class LD2420RestartModuleButton final : public button::Button, public Parented<LD2420Component> {
public:
LD2420RestartModuleButton() = default;
protected:
void press_action() override;
};
class LD2420FactoryResetButton final : public button::Button, public Parented<LD2420Component> {
public:
LD2420FactoryResetButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::ld2420
+9 -8
View File
@@ -13,22 +13,19 @@ from esphome.const import (
)
from esphome.types import ConfigType
from .. import CONF_LD2450_ID, LD2450Component, ld2450_ns
FactoryResetButton = ld2450_ns.class_("FactoryResetButton", button.Button)
RestartButton = ld2450_ns.class_("RestartButton", button.Button)
from .. import CONF_LD2450_ID, LD2450Component
CONFIG_SCHEMA = {
cv.GenerateID(CONF_ID): cv.declare_id(cg.EntityBase),
cv.GenerateID(CONF_LD2450_ID): cv.use_id(LD2450Component),
cv.Optional(CONF_FACTORY_RESET): button.button_schema(
FactoryResetButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART_ALERT,
),
cv.Optional(CONF_RESTART): button.button_schema(
RestartButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_RESTART,
@@ -39,5 +36,9 @@ CONFIG_SCHEMA = {
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_LD2450_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(CONF_FACTORY_RESET, hub.set_factory_reset_button)
await buttons(CONF_RESTART, hub.set_restart_button)
await buttons(
CONF_FACTORY_RESET, hub.set_factory_reset_button, apply="factory_reset()"
)
await buttons(
CONF_RESTART, hub.set_restart_button, apply="restart_and_read_all_info()"
)
@@ -1,7 +0,0 @@
#include "factory_reset_button.h"
namespace esphome::ld2450 {
void FactoryResetButton::press_action() { this->parent_->factory_reset(); }
} // namespace esphome::ld2450
@@ -1,17 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2450.h"
namespace esphome::ld2450 {
class FactoryResetButton : public button::Button, public Parented<LD2450Component> {
public:
// User provided, not "= default": `new(p) FactoryResetButton()` would zero-fill .bss that is already zero.
FactoryResetButton() {}
protected:
void press_action() override;
};
} // namespace esphome::ld2450
@@ -1,7 +0,0 @@
#include "restart_button.h"
namespace esphome::ld2450 {
void RestartButton::press_action() { this->parent_->restart_and_read_all_info(); }
} // namespace esphome::ld2450
@@ -1,17 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../ld2450.h"
namespace esphome::ld2450 {
class RestartButton : public button::Button, public Parented<LD2450Component> {
public:
// User provided, not "= default": `new(p) RestartButton()` would zero-fill .bss that is already zero.
RestartButton() {}
protected:
void press_action() override;
};
} // namespace esphome::ld2450
@@ -9,23 +9,20 @@ from esphome.const import (
)
from esphome.types import ConfigType
from .. import CONF_MR24HPC1_ID, MR24HPC1Component, mr24hpc1_ns
RestartButton = mr24hpc1_ns.class_("RestartButton", button.Button)
CustomSetEndButton = mr24hpc1_ns.class_("CustomSetEndButton", button.Button)
from .. import CONF_MR24HPC1_ID, MR24HPC1Component
CONF_CUSTOM_SET_END = "custom_set_end"
CONFIG_SCHEMA = {
cv.GenerateID(CONF_MR24HPC1_ID): cv.use_id(MR24HPC1Component),
cv.Optional(CONF_RESTART): button.button_schema(
RestartButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART_ALERT,
),
cv.Optional(CONF_CUSTOM_SET_END): button.button_schema(
CustomSetEndButton,
button.ApplyButton,
entity_category=ENTITY_CATEGORY_CONFIG,
icon="mdi:cog",
),
@@ -35,5 +32,9 @@ CONFIG_SCHEMA = {
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_MR24HPC1_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(CONF_RESTART, hub.set_restart_button)
await buttons(CONF_CUSTOM_SET_END, hub.set_custom_set_end_button)
await buttons(CONF_RESTART, hub.set_restart_button, apply="set_restart()")
await buttons(
CONF_CUSTOM_SET_END,
hub.set_custom_set_end_button,
apply="set_custom_end_mode()",
)
@@ -1,7 +0,0 @@
#include "custom_mode_end_button.h"
namespace esphome::seeed_mr24hpc1 {
void CustomSetEndButton::press_action() { this->parent_->set_custom_end_mode(); }
} // namespace esphome::seeed_mr24hpc1
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../seeed_mr24hpc1.h"
namespace esphome::seeed_mr24hpc1 {
class CustomSetEndButton final : public button::Button, public Parented<MR24HPC1Component> {
public:
CustomSetEndButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::seeed_mr24hpc1
@@ -1,7 +0,0 @@
#include "restart_button.h"
namespace esphome::seeed_mr24hpc1 {
void RestartButton::press_action() { this->parent_->set_restart(); }
} // namespace esphome::seeed_mr24hpc1
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../seeed_mr24hpc1.h"
namespace esphome::seeed_mr24hpc1 {
class RestartButton final : public button::Button, public Parented<MR24HPC1Component> {
public:
RestartButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::seeed_mr24hpc1
@@ -10,24 +10,22 @@ from esphome.const import (
)
from esphome.types import ConfigType
from .. import CONF_MR60FDA2_ID, MR60FDA2Component, mr60fda2_ns
from .. import CONF_MR60FDA2_ID, MR60FDA2Component
DEPENDENCIES = ["seeed_mr60fda2"]
GetRadarParametersButton = mr60fda2_ns.class_("GetRadarParametersButton", button.Button)
ResetRadarButton = mr60fda2_ns.class_("ResetRadarButton", button.Button)
CONF_GET_RADAR_PARAMETERS = "get_radar_parameters"
CONFIG_SCHEMA = {
cv.GenerateID(CONF_MR60FDA2_ID): cv.use_id(MR60FDA2Component),
cv.Optional(CONF_GET_RADAR_PARAMETERS): button.button_schema(
GetRadarParametersButton,
button.ApplyButton,
device_class=DEVICE_CLASS_UPDATE,
entity_category=ENTITY_CATEGORY_NONE,
),
cv.Optional(CONF_FACTORY_RESET): button.button_schema(
ResetRadarButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
@@ -37,5 +35,11 @@ CONFIG_SCHEMA = {
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_MR60FDA2_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(CONF_GET_RADAR_PARAMETERS, hub.set_get_radar_parameters_button)
await buttons(CONF_FACTORY_RESET, hub.set_factory_reset_button)
await buttons(
CONF_GET_RADAR_PARAMETERS,
hub.set_get_radar_parameters_button,
apply="get_radar_parameters()",
)
await buttons(
CONF_FACTORY_RESET, hub.set_factory_reset_button, apply="factory_reset()"
)
@@ -1,7 +0,0 @@
#include "get_radar_parameters_button.h"
namespace esphome::seeed_mr60fda2 {
void GetRadarParametersButton::press_action() { this->parent_->get_radar_parameters(); }
} // namespace esphome::seeed_mr60fda2
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../seeed_mr60fda2.h"
namespace esphome::seeed_mr60fda2 {
class GetRadarParametersButton final : public button::Button, public Parented<MR60FDA2Component> {
public:
GetRadarParametersButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::seeed_mr60fda2
@@ -1,7 +0,0 @@
#include "reset_radar_button.h"
namespace esphome::seeed_mr60fda2 {
void ResetRadarButton::press_action() { this->parent_->factory_reset(); }
} // namespace esphome::seeed_mr60fda2
@@ -1,16 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../seeed_mr60fda2.h"
namespace esphome::seeed_mr60fda2 {
class ResetRadarButton final : public button::Button, public Parented<MR60FDA2Component> {
public:
ResetRadarButton() = default;
protected:
void press_action() override;
};
} // namespace esphome::seeed_mr60fda2
+5 -7
View File
@@ -14,23 +14,21 @@ from esphome.const import (
import esphome.final_validate as fv
from esphome.types import ConfigType
from .. import CONF_TFLUNA_ID, FACTORY_DEFAULT_ADDRESS, TFLunaComponent, tfluna_ns
from .. import CONF_TFLUNA_ID, FACTORY_DEFAULT_ADDRESS, TFLunaComponent
DEPENDENCIES = ["tfluna"]
ResetButton = tfluna_ns.class_("ResetButton", button.Button)
RestartButton = tfluna_ns.class_("RestartButton", button.Button)
CONFIG_SCHEMA = {
cv.GenerateID(CONF_TFLUNA_ID): cv.use_id(TFLunaComponent),
cv.Optional(CONF_FACTORY_RESET): button.button_schema(
ResetButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_CONFIG,
icon=ICON_RESTART_ALERT,
),
cv.Optional(CONF_RESTART): button.button_schema(
RestartButton,
button.ApplyButton,
device_class=DEVICE_CLASS_RESTART,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
icon=ICON_RESTART,
@@ -63,5 +61,5 @@ FINAL_VALIDATE_SCHEMA = _final_validate
async def to_code(config: ConfigType) -> None:
hub = await cg.get_variable(config[CONF_TFLUNA_ID])
buttons = button.sub_buttons(config, parent=hub)
await buttons(CONF_FACTORY_RESET, hub.set_reset_button)
await buttons(CONF_RESTART, hub.set_restart_button)
await buttons(CONF_FACTORY_RESET, hub.set_reset_button, apply="factory_reset()")
await buttons(CONF_RESTART, hub.set_restart_button, apply="restart()")
@@ -1,7 +0,0 @@
#include "reset_button.h"
namespace esphome::tfluna {
void ResetButton::press_action() { this->parent_->factory_reset(); }
} // namespace esphome::tfluna
@@ -1,13 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../tfluna.h"
namespace esphome::tfluna {
class ResetButton : public button::Button, public Parented<TFLuna> {
protected:
void press_action() override;
};
} // namespace esphome::tfluna
@@ -1,7 +0,0 @@
#include "restart_button.h"
namespace esphome::tfluna {
void RestartButton::press_action() { this->parent_->restart(); }
} // namespace esphome::tfluna
@@ -1,13 +0,0 @@
#pragma once
#include "esphome/components/button/button.h"
#include "../tfluna.h"
namespace esphome::tfluna {
class RestartButton : public button::Button, public Parented<TFLuna> {
protected:
void press_action() override;
};
} // namespace esphome::tfluna
@@ -1,72 +0,0 @@
#include <gtest/gtest.h>
#include "esphome/components/hoermann_hcp/button/hoermann_hcp_button.h"
#include "../common.h"
namespace esphome::hoermann_hcp::testing {
// The intermediate positions are named in the second register, next to 0x0100 in the first.
TEST(HoermannHcpButtonTest, VentButtonSendsTheVentCommand) {
TestableHoermannHcp door;
HoermannHcpVentButton vent(&door);
connect_controller(door);
vent.press();
auto [value, value_2] = poll_command(door);
EXPECT_EQ(value, 0x0100);
EXPECT_EQ(value_2, 0x4000);
// Sent once, in the first register as well as in the second.
auto [after, after_2] = poll_command(door);
EXPECT_EQ(after, 0x0000);
EXPECT_EQ(after_2, 0x0000);
}
TEST(HoermannHcpButtonTest, HalfOpenButtonSendsTheHalfOpenCommand) {
TestableHoermannHcp door;
HoermannHcpHalfOpenButton half_open(&door);
connect_controller(door);
half_open.press();
auto [value, value_2] = poll_command(door);
EXPECT_EQ(value, 0x0100);
EXPECT_EQ(value_2, 0x0400);
// Sent once, in the first register as well as in the second.
auto [after, after_2] = poll_command(door);
EXPECT_EQ(after, 0x0000);
EXPECT_EQ(after_2, 0x0000);
}
// The door drives to the vent position on its own, so a position the cover was still travelling to must not
// stop it on the way there.
TEST(HoermannHcpButtonTest, VentAbandonsAnArmedTarget) {
TestableHoermannHcp door; // starts out fully closed
HoermannHcpVentButton vent(&door);
connect_controller(door);
door.set_position(0.5f);
consume_command(door);
door.on_write_registers(BROADCAST_REG, make_registers({0x0000, 0x0014, 0x0100}));
ASSERT_EQ(door.get_door_state(), DoorState::OPENING);
vent.press();
consume_command(door);
// Position 120/200 = 0.6 is past the abandoned target, which must no longer stop the door.
door.on_write_registers(BROADCAST_REG, make_registers({0x0000, 0x0078, 0x0100}));
EXPECT_EQ(poll_command(door).first, 0x0000);
}
// A button carries no state, so a refused press is simply dropped rather than fired once the controller
// turns up, which could be much later.
TEST(HoermannHcpButtonTest, PressWithoutABusControllerSendsNothing) {
HoermannHcp door; // never contacted by a bus controller
HoermannHcpVentButton vent(&door);
vent.press();
EXPECT_EQ(poll_command(door).first, 0x0000);
}
} // namespace esphome::hoermann_hcp::testing
@@ -697,4 +697,56 @@ TEST(HoermannHcpPosition, TargetIsDroppedWhenTheDoorNeverStarts) {
EXPECT_EQ(poll_command(door).first, 0x0000);
}
// The intermediate positions are named in the second register, next to 0x0100 in the first, and sent once.
static void expect_one_shot_command(HoermannHcp &door, uint16_t expected_2) {
auto [value, value_2] = poll_command(door);
EXPECT_EQ(value, 0x0100);
EXPECT_EQ(value_2, expected_2);
auto [after, after_2] = poll_command(door);
EXPECT_EQ(after, 0x0000);
EXPECT_EQ(after_2, 0x0000);
}
TEST(HoermannHcpDoorCommands, VentDoorSendsTheVentCommand) {
TestableHoermannHcp door;
connect_controller(door);
door.vent_door();
expect_one_shot_command(door, 0x4000);
}
TEST(HoermannHcpDoorCommands, HalfOpenDoorSendsTheHalfOpenCommand) {
TestableHoermannHcp door;
connect_controller(door);
door.half_open_door();
expect_one_shot_command(door, 0x0400);
}
// The door drives to the vent position on its own, so a position the cover was still travelling to must not
// stop it on the way there.
TEST(HoermannHcpDoorCommands, VentDoorAbandonsAnArmedTarget) {
TestableHoermannHcp door; // starts out fully closed
connect_controller(door);
door.set_position(0.5f);
consume_command(door);
door.on_write_registers(BROADCAST_REG, make_registers({0x0000, 0x0014, 0x0100}));
ASSERT_EQ(door.get_door_state(), DoorState::OPENING);
door.vent_door();
consume_command(door);
// Position 120/200 = 0.6 is past the abandoned target, which must no longer stop the door.
door.on_write_registers(BROADCAST_REG, make_registers({0x0000, 0x0078, 0x0100}));
EXPECT_EQ(poll_command(door).first, 0x0000);
}
// A door command carries no state, so a refused one is simply dropped rather than fired once the controller
// turns up, which could be much later.
TEST(HoermannHcpDoorCommands, VentDoorWithoutABusControllerSendsNothing) {
HoermannHcp door; // never contacted by a bus controller
door.vent_door();
EXPECT_EQ(poll_command(door).first, 0x0000);
}
} // namespace esphome::hoermann_hcp::testing