mirror of
https://github.com/esphome/esphome.git
synced 2026-10-20 04:56:48 +00:00
[ld6002b] Find the number, select and switch setting by entity pointer in the hub
This commit is contained in:
@@ -1,12 +1,9 @@
|
||||
from collections.abc import Awaitable, Callable
|
||||
|
||||
from esphome import pins
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import uart
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_WAKEUP_PIN
|
||||
from esphome.cpp_generator import MockObj
|
||||
from esphome.types import ConfigType, Expression
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .const import CONF_AUTO_WAKE, CONF_WAKEUP_PULSE
|
||||
|
||||
@@ -76,47 +73,3 @@ async def to_code(config: ConfigType) -> None:
|
||||
cg.add(var.set_wakeup_pulse_ms(config[CONF_WAKEUP_PULSE].total_milliseconds))
|
||||
|
||||
cg.add(var.set_auto_wake(config[CONF_AUTO_WAKE]))
|
||||
|
||||
|
||||
# (type, entity config, creates the entity from its template arguments, hub setter or None)
|
||||
DispatchEntity = tuple[
|
||||
MockObj,
|
||||
ConfigType,
|
||||
Callable[[cg.TemplateArguments], Awaitable[MockObj]],
|
||||
Callable[[MockObj], Expression] | None,
|
||||
]
|
||||
|
||||
|
||||
async def build_type_dispatch(
|
||||
hub: MockObj,
|
||||
params: str,
|
||||
call: str,
|
||||
entities: list[DispatchEntity],
|
||||
publish_before: str | None = None,
|
||||
publish_after: str | None = None,
|
||||
) -> None:
|
||||
"""Give all of a platform's entities one generated function that finds the type by pointer.
|
||||
|
||||
One class per domain instead of one per entity; ``call`` names the type as ``type``.
|
||||
"""
|
||||
if not entities:
|
||||
return
|
||||
fn = f"esphome__{entities[0][1][CONF_ID].id}__fn"
|
||||
# Declared first: the entities' types name it and its body names the entities.
|
||||
cg.add_global(cg.RawStatement(f"static void {fn}({params});"))
|
||||
template = cg.TemplateArguments(cg.RawExpression(fn))
|
||||
created: list[tuple[MockObj, MockObj]] = []
|
||||
for type_, _, create, setter in entities:
|
||||
var = await create(template)
|
||||
if setter is not None:
|
||||
cg.add(setter(var))
|
||||
created.append((type_, var))
|
||||
*head, (last_type, _) = created
|
||||
chain = "".join(f"entity == ::{var} ? {type_} : " for type_, var in head)
|
||||
body = [f"const auto type = {chain}{last_type};", f"::{hub}->{call};"]
|
||||
if publish_before:
|
||||
body.insert(0, publish_before)
|
||||
if publish_after:
|
||||
body.append(publish_after)
|
||||
lines = "\n ".join(body)
|
||||
cg.add_global(cg.RawStatement(f"static void {fn}({params}) {{\n {lines}\n}}"))
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from functools import partial
|
||||
|
||||
from esphome.automation import parent_ref
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import button
|
||||
from esphome.components.select import DOMAIN as SELECT_DOMAIN
|
||||
@@ -10,10 +9,11 @@ from esphome.const import (
|
||||
ENTITY_CATEGORY_CONFIG,
|
||||
ENTITY_CATEGORY_DIAGNOSTIC,
|
||||
)
|
||||
from esphome.cpp_generator import ParameterListExpression
|
||||
import esphome.final_validate as fv
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import LD6002BComponent, build_type_dispatch, ld6002b_ns
|
||||
from .. import LD6002BComponent, ld6002b_ns
|
||||
from ..const import (
|
||||
CONF_APPLY_AREA,
|
||||
CONF_AUTO_INTERFERENCE,
|
||||
@@ -131,12 +131,33 @@ BUTTON_MAP = {
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
hub = await cg.get_variable(config[CONF_LD6002B_ID])
|
||||
entities = [
|
||||
(button_type, conf, partial(button.new_button, conf), None)
|
||||
confs = [
|
||||
(button_type, conf)
|
||||
for key, button_type in BUTTON_MAP.items()
|
||||
if (conf := config.get(key)) is not None
|
||||
]
|
||||
await build_type_dispatch(
|
||||
hub, "button::Button *entity", "press_button(type)", entities
|
||||
if not confs:
|
||||
return
|
||||
hub = await cg.get_variable(config[CONF_LD6002B_ID])
|
||||
params = button.sub_buttons(config).apply_entity.params
|
||||
# One function for all buttons, picking the type by pointer: one class instead of one per button.
|
||||
fn = f"esphome__{hub}__button_fn"
|
||||
cg.add_global(
|
||||
cg.RawStatement(f"static void {fn}({ParameterListExpression(*params)});")
|
||||
)
|
||||
template = cg.TemplateArguments(cg.RawExpression(fn))
|
||||
created = [
|
||||
(button_type, await button.new_button(conf, template))
|
||||
for button_type, conf in confs
|
||||
]
|
||||
*head, (last_type, _) = created
|
||||
chain = "".join(f"entity == {parent_ref(var)} ? {t} : " for t, var in head)
|
||||
cg.static_function(
|
||||
fn,
|
||||
cg.void,
|
||||
list(params),
|
||||
[
|
||||
f"const auto type = {chain}{last_type};",
|
||||
f"{parent_ref(hub)}->press_button(type);",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1368,7 +1368,30 @@ void LD6002BComponent::wake_() {
|
||||
[this]() { this->wakeup_pin_->digital_write(true); });
|
||||
}
|
||||
|
||||
void LD6002BComponent::set_number_value(NumberType type, float value) {
|
||||
#ifdef USE_NUMBER
|
||||
void LD6002BComponent::set_number_value(number::Number *entity, float value) {
|
||||
// Found by pointer, so the entities share one generated class instead of storing a type each
|
||||
NumberType type;
|
||||
if (entity == this->hold_delay_number_)
|
||||
type = NumberType::HOLD_DELAY;
|
||||
else if (entity == this->z_min_number_)
|
||||
type = NumberType::Z_MIN;
|
||||
else if (entity == this->z_max_number_)
|
||||
type = NumberType::Z_MAX;
|
||||
else if (entity == this->low_power_sleep_number_)
|
||||
type = NumberType::LOW_POWER_SLEEP;
|
||||
else if (entity == this->area_x_min_number_)
|
||||
type = NumberType::AREA_X_MIN;
|
||||
else if (entity == this->area_x_max_number_)
|
||||
type = NumberType::AREA_X_MAX;
|
||||
else if (entity == this->area_y_min_number_)
|
||||
type = NumberType::AREA_Y_MIN;
|
||||
else if (entity == this->area_y_max_number_)
|
||||
type = NumberType::AREA_Y_MAX;
|
||||
else if (entity == this->area_z_min_number_)
|
||||
type = NumberType::AREA_Z_MIN;
|
||||
else
|
||||
type = NumberType::AREA_Z_MAX;
|
||||
switch (type) {
|
||||
case NumberType::HOLD_DELAY: {
|
||||
uint32_t delay = static_cast<uint32_t>(value);
|
||||
@@ -1418,8 +1441,20 @@ void LD6002BComponent::set_number_value(NumberType type, float value) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void LD6002BComponent::set_select_value(SelectType type, size_t index) {
|
||||
#ifdef USE_SELECT
|
||||
void LD6002BComponent::set_select_value(select::Select *entity, size_t index) {
|
||||
// Found by pointer, so the entities share one generated class instead of storing a type each
|
||||
SelectType type;
|
||||
if (entity == this->sensitivity_select_)
|
||||
type = SelectType::SENSITIVITY;
|
||||
else if (entity == this->trigger_speed_select_)
|
||||
type = SelectType::TRIGGER_SPEED;
|
||||
else if (entity == this->installation_select_)
|
||||
type = SelectType::INSTALLATION_MODE;
|
||||
else
|
||||
type = SelectType::AREA_ID;
|
||||
switch (type) {
|
||||
case SelectType::SENSITIVITY:
|
||||
if (index == 0) {
|
||||
@@ -1454,6 +1489,7 @@ void LD6002BComponent::set_select_value(SelectType type, size_t index) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void LD6002BComponent::update_area_numbers_(const AreaConfig &area) {
|
||||
// A report refreshes every axis the user is not in the middle of changing. An
|
||||
@@ -1781,7 +1817,16 @@ void LD6002BComponent::clear_target_state_() {
|
||||
}
|
||||
}
|
||||
|
||||
void LD6002BComponent::set_switch_state(SwitchType type, bool state) {
|
||||
#ifdef USE_SWITCH
|
||||
void LD6002BComponent::set_switch_state(switch_::Switch *entity, bool state) {
|
||||
// Found by pointer, so the entities share one generated class instead of storing a type each
|
||||
SwitchType type;
|
||||
if (entity == this->low_power_switch_)
|
||||
type = SwitchType::LOW_POWER;
|
||||
else if (entity == this->point_cloud_switch_)
|
||||
type = SwitchType::POINT_CLOUD;
|
||||
else
|
||||
type = SwitchType::TARGET_DISPLAY;
|
||||
switch (type) {
|
||||
case SwitchType::LOW_POWER:
|
||||
this->low_power_enabled_ = state;
|
||||
@@ -1812,6 +1857,7 @@ void LD6002BComponent::set_switch_state(SwitchType type, bool state) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void LD6002BComponent::press_button(ButtonType type) {
|
||||
switch (type) {
|
||||
|
||||
@@ -264,9 +264,15 @@ class LD6002BComponent : public Component, public uart::UARTDevice {
|
||||
void set_target_display_switch(switch_::Switch *sw) { this->target_display_switch_ = sw; }
|
||||
#endif
|
||||
|
||||
void set_number_value(NumberType type, float value);
|
||||
void set_select_value(SelectType type, size_t index);
|
||||
void set_switch_state(SwitchType type, bool state);
|
||||
#ifdef USE_NUMBER
|
||||
void set_number_value(number::Number *entity, float value);
|
||||
#endif
|
||||
#ifdef USE_SELECT
|
||||
void set_select_value(select::Select *entity, size_t index);
|
||||
#endif
|
||||
#ifdef USE_SWITCH
|
||||
void set_switch_state(switch_::Switch *entity, bool state);
|
||||
#endif
|
||||
void press_button(ButtonType type);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
from functools import partial
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import number
|
||||
from esphome.components.button import DOMAIN as BUTTON_DOMAIN
|
||||
@@ -17,7 +15,7 @@ from esphome.const import (
|
||||
import esphome.final_validate as fv
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import DispatchEntity, LD6002BComponent, build_type_dispatch, ld6002b_ns
|
||||
from .. import LD6002BComponent
|
||||
from ..const import (
|
||||
CONF_APPLY_AREA,
|
||||
CONF_AREA_CONFIG,
|
||||
@@ -34,8 +32,6 @@ from ..const import (
|
||||
|
||||
DEPENDENCIES = ["ld6002b"]
|
||||
|
||||
NumberType = ld6002b_ns.enum("NumberType", is_class=True)
|
||||
|
||||
CONFIG_SCHEMA = cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_LD6002B_ID): cv.use_id(LD6002BComponent),
|
||||
@@ -140,52 +136,36 @@ FINAL_VALIDATE_SCHEMA = final_validate
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
hub = await cg.get_variable(config[CONF_LD6002B_ID])
|
||||
entities: list[DispatchEntity] = []
|
||||
|
||||
for key, number_type, setter, min_value, max_value, step in (
|
||||
(CONF_HOLD_DELAY, NumberType.HOLD_DELAY, "set_hold_delay_number", 0, 65535, 1),
|
||||
(CONF_Z_MIN, NumberType.Z_MIN, "set_z_min_number", -10, 10, 0.1),
|
||||
(CONF_Z_MAX, NumberType.Z_MAX, "set_z_max_number", -10, 10, 0.1),
|
||||
# 0x0205 carries a uint32 of milliseconds; the vendor documents 500 ms as
|
||||
# the default and no upper bound, so the range ends at a minute rather
|
||||
# than at a default the module is free to be sleeping past.
|
||||
(
|
||||
CONF_LOW_POWER_SLEEP_TIME,
|
||||
NumberType.LOW_POWER_SLEEP,
|
||||
"set_low_power_sleep_number",
|
||||
0,
|
||||
60000,
|
||||
100,
|
||||
),
|
||||
):
|
||||
if (conf := config.get(key)) is not None:
|
||||
create = partial(
|
||||
number.new_number,
|
||||
conf,
|
||||
min_value=min_value,
|
||||
max_value=max_value,
|
||||
step=step,
|
||||
)
|
||||
entities.append((number_type, conf, create, getattr(hub, setter)))
|
||||
control = {"apply": "set_number_value(entity, value)", "publish": "before"}
|
||||
numbers = number.sub_numbers(config, parent=hub)
|
||||
await numbers(
|
||||
CONF_HOLD_DELAY,
|
||||
hub.set_hold_delay_number,
|
||||
min_value=0,
|
||||
max_value=65535,
|
||||
step=1,
|
||||
**control,
|
||||
)
|
||||
meters = {"min_value": -10, "max_value": 10, "step": 0.1, **control}
|
||||
await numbers(CONF_Z_MIN, hub.set_z_min_number, **meters)
|
||||
await numbers(CONF_Z_MAX, hub.set_z_max_number, **meters)
|
||||
# 0x0205 carries a uint32 of milliseconds; the vendor documents 500 ms as
|
||||
# the default and no upper bound, so the range ends at a minute rather
|
||||
# than at a default the module is free to be sleeping past.
|
||||
await numbers(
|
||||
CONF_LOW_POWER_SLEEP_TIME,
|
||||
hub.set_low_power_sleep_number,
|
||||
min_value=0,
|
||||
max_value=60000,
|
||||
step=100,
|
||||
**control,
|
||||
)
|
||||
|
||||
if area_config := config.get(CONF_AREA_CONFIG):
|
||||
for key, number_type, setter in (
|
||||
(KEY_X_MIN, NumberType.AREA_X_MIN, "set_area_x_min_number"),
|
||||
(KEY_X_MAX, NumberType.AREA_X_MAX, "set_area_x_max_number"),
|
||||
(KEY_Y_MIN, NumberType.AREA_Y_MIN, "set_area_y_min_number"),
|
||||
(KEY_Y_MAX, NumberType.AREA_Y_MAX, "set_area_y_max_number"),
|
||||
(CONF_Z_MIN, NumberType.AREA_Z_MIN, "set_area_z_min_number"),
|
||||
(CONF_Z_MAX, NumberType.AREA_Z_MAX, "set_area_z_max_number"),
|
||||
):
|
||||
if (conf := area_config.get(key)) is not None:
|
||||
create = partial(
|
||||
number.new_number, conf, min_value=-10, max_value=10, step=0.1
|
||||
)
|
||||
entities.append((number_type, conf, create, getattr(hub, setter)))
|
||||
await build_type_dispatch(
|
||||
hub,
|
||||
"number::Number *entity, float value",
|
||||
"set_number_value(type, value)",
|
||||
entities,
|
||||
publish_before="entity->publish_state(value);",
|
||||
)
|
||||
area = number.sub_numbers(area_config, parent=hub)
|
||||
await area(KEY_X_MIN, hub.set_area_x_min_number, **meters)
|
||||
await area(KEY_X_MAX, hub.set_area_x_max_number, **meters)
|
||||
await area(KEY_Y_MIN, hub.set_area_y_min_number, **meters)
|
||||
await area(KEY_Y_MAX, hub.set_area_y_max_number, **meters)
|
||||
await area(CONF_Z_MIN, hub.set_area_z_min_number, **meters)
|
||||
await area(CONF_Z_MAX, hub.set_area_z_max_number, **meters)
|
||||
|
||||
@@ -1,18 +1,14 @@
|
||||
from functools import partial
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import select
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_AREA_ID, CONF_SENSITIVITY, ENTITY_CATEGORY_CONFIG
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import DispatchEntity, LD6002BComponent, build_type_dispatch, ld6002b_ns
|
||||
from .. import LD6002BComponent
|
||||
from ..const import CONF_INSTALLATION_MODE, CONF_LD6002B_ID, CONF_TRIGGER_SPEED
|
||||
|
||||
DEPENDENCIES = ["ld6002b"]
|
||||
|
||||
SelectType = ld6002b_ns.enum("SelectType", is_class=True)
|
||||
|
||||
AREA_ID_OPTIONS = [
|
||||
"interference_area_0",
|
||||
"interference_area_1",
|
||||
@@ -43,40 +39,28 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
)
|
||||
|
||||
|
||||
SELECT_MAP = (
|
||||
(
|
||||
CONF_SENSITIVITY,
|
||||
SelectType.SENSITIVITY,
|
||||
"set_sensitivity_select",
|
||||
["low", "medium", "high"],
|
||||
),
|
||||
(
|
||||
CONF_TRIGGER_SPEED,
|
||||
SelectType.TRIGGER_SPEED,
|
||||
"set_trigger_speed_select",
|
||||
["slow", "medium", "fast"],
|
||||
),
|
||||
(
|
||||
CONF_INSTALLATION_MODE,
|
||||
SelectType.INSTALLATION_MODE,
|
||||
"set_installation_select",
|
||||
["top", "side"],
|
||||
),
|
||||
(CONF_AREA_ID, SelectType.AREA_ID, "set_area_id_select", AREA_ID_OPTIONS),
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
hub = await cg.get_variable(config[CONF_LD6002B_ID])
|
||||
entities: list[DispatchEntity] = []
|
||||
for key, select_type, setter, options in SELECT_MAP:
|
||||
if (conf := config.get(key)) is not None:
|
||||
create = partial(select.new_select, conf, options=options)
|
||||
entities.append((select_type, conf, create, getattr(hub, setter)))
|
||||
await build_type_dispatch(
|
||||
hub,
|
||||
"select::Select *entity, size_t index",
|
||||
"set_select_value(type, index)",
|
||||
entities,
|
||||
publish_before="entity->publish_state(index);",
|
||||
control = {"apply": "set_select_value(entity, index)", "publish": "before"}
|
||||
selects = select.sub_selects(config, parent=hub)
|
||||
await selects(
|
||||
CONF_SENSITIVITY,
|
||||
hub.set_sensitivity_select,
|
||||
options=["low", "medium", "high"],
|
||||
**control,
|
||||
)
|
||||
await selects(
|
||||
CONF_TRIGGER_SPEED,
|
||||
hub.set_trigger_speed_select,
|
||||
options=["slow", "medium", "fast"],
|
||||
**control,
|
||||
)
|
||||
await selects(
|
||||
CONF_INSTALLATION_MODE,
|
||||
hub.set_installation_select,
|
||||
options=["top", "side"],
|
||||
**control,
|
||||
)
|
||||
await selects(
|
||||
CONF_AREA_ID, hub.set_area_id_select, options=AREA_ID_OPTIONS, **control
|
||||
)
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
from functools import partial
|
||||
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import switch
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import DEVICE_CLASS_SWITCH, ENTITY_CATEGORY_CONFIG
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .. import DispatchEntity, LD6002BComponent, build_type_dispatch, ld6002b_ns
|
||||
from .. import LD6002BComponent
|
||||
from ..const import (
|
||||
CONF_LD6002B_ID,
|
||||
CONF_LOW_POWER,
|
||||
@@ -16,8 +14,6 @@ from ..const import (
|
||||
|
||||
DEPENDENCIES = ["ld6002b"]
|
||||
|
||||
SwitchType = ld6002b_ns.enum("SwitchType", is_class=True)
|
||||
|
||||
# None of these three carry an inversion. They name what the module is doing, not
|
||||
# how something is wired to it, so an inverted one would only report the opposite
|
||||
# of the truth -- and the boot restore, which applies a state nothing reports back,
|
||||
@@ -50,19 +46,8 @@ CONFIG_SCHEMA = cv.Schema(
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
hub = await cg.get_variable(config[CONF_LD6002B_ID])
|
||||
entities: list[DispatchEntity] = []
|
||||
for key, switch_type, setter in (
|
||||
(CONF_LOW_POWER, SwitchType.LOW_POWER, "set_low_power_switch"),
|
||||
(CONF_POINT_CLOUD, SwitchType.POINT_CLOUD, "set_point_cloud_switch"),
|
||||
(CONF_TARGET_DISPLAY, SwitchType.TARGET_DISPLAY, "set_target_display_switch"),
|
||||
):
|
||||
if (conf := config.get(key)) is not None:
|
||||
create = partial(switch.new_switch, conf)
|
||||
entities.append((switch_type, conf, create, getattr(hub, setter)))
|
||||
await build_type_dispatch(
|
||||
hub,
|
||||
"switch_::Switch *entity, bool state",
|
||||
"set_switch_state(type, state)",
|
||||
entities,
|
||||
publish_after="entity->publish_state(state);",
|
||||
)
|
||||
control = {"apply": "set_switch_state(entity, state)", "publish": "after"}
|
||||
switches = switch.sub_switches(config, parent=hub)
|
||||
await switches(CONF_LOW_POWER, hub.set_low_power_switch, **control)
|
||||
await switches(CONF_POINT_CLOUD, hub.set_point_cloud_switch, **control)
|
||||
await switches(CONF_TARGET_DISPLAY, hub.set_target_display_switch, **control)
|
||||
|
||||
Reference in New Issue
Block a user