mirror of
https://github.com/esphome/esphome.git
synced 2026-11-10 23:25:58 +00:00
[ld6002b] Use Apply entities and find the setting by entity pointer (#20937)
This commit is contained in:
1 parent
78f0b1ceba
commit
a680974da2
18 files changed
+454
-372
No files matched your search
@@ -0,0 +1,49 @@
|
||||
esphome:
|
||||
name: test
|
||||
|
||||
esp32:
|
||||
board: esp32dev
|
||||
framework:
|
||||
type: esp-idf
|
||||
|
||||
uart:
|
||||
- id: uart_a
|
||||
tx_pin: GPIO17
|
||||
rx_pin: GPIO16
|
||||
baud_rate: 115200
|
||||
- id: uart_b
|
||||
tx_pin: GPIO18
|
||||
rx_pin: GPIO19
|
||||
baud_rate: 115200
|
||||
|
||||
ld6002b:
|
||||
- id: hub_a
|
||||
uart_id: uart_a
|
||||
wakeup_pin: GPIO14
|
||||
- id: hub_b
|
||||
uart_id: uart_b
|
||||
|
||||
button:
|
||||
# Two blocks on hub_a: the dispatcher names must not clash.
|
||||
- platform: ld6002b
|
||||
ld6002b_id: hub_a
|
||||
get_delay:
|
||||
id: a_get_delay
|
||||
name: A Get Delay
|
||||
get_sensitivity:
|
||||
id: a_get_sensitivity
|
||||
name: A Get Sensitivity
|
||||
wake:
|
||||
id: a_wake
|
||||
name: A Wake
|
||||
- platform: ld6002b
|
||||
ld6002b_id: hub_a
|
||||
get_z_range:
|
||||
id: a_get_z_range
|
||||
name: A Get Z Range
|
||||
# A single button on hub_b: no pointer chain, only the fallback type.
|
||||
- platform: ld6002b
|
||||
ld6002b_id: hub_b
|
||||
get_installation:
|
||||
id: b_get_installation
|
||||
name: B Get Installation
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Code generation tests for the ld6002b button dispatcher.
|
||||
|
||||
Each button block gets one function that maps the pressed entity to its button
|
||||
type and calls its own hub; the last button of a block is the fallback type.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
YAML = Path(__file__).parent / "button_dispatch.yaml"
|
||||
|
||||
|
||||
def _fn_body(main_cpp: str, fn: str) -> str:
|
||||
match = re.search(
|
||||
rf"static void {fn}\(button::Button \* entity\) \{{\n(.*?)\n\}}",
|
||||
main_cpp,
|
||||
re.DOTALL,
|
||||
)
|
||||
assert match is not None, f"{fn} not defined"
|
||||
return match.group(1)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("fn", "type_expr", "hub"),
|
||||
[
|
||||
# Two blocks on hub_a: each named after its first button, chain ends in the fallback.
|
||||
(
|
||||
"esphome__a_get_delay__button_fn",
|
||||
(
|
||||
"entity == ::a_get_delay ? ld6002b::ButtonType::GET_DELAY : "
|
||||
"entity == ::a_get_sensitivity ? ld6002b::ButtonType::GET_SENSITIVITY : "
|
||||
"ld6002b::ButtonType::WAKE"
|
||||
),
|
||||
"hub_a",
|
||||
),
|
||||
(
|
||||
"esphome__a_get_z_range__button_fn",
|
||||
"ld6002b::ButtonType::GET_Z_RANGE",
|
||||
"hub_a",
|
||||
),
|
||||
# A single button on a second hub: no chain, its own hub.
|
||||
(
|
||||
"esphome__b_get_installation__button_fn",
|
||||
"ld6002b::ButtonType::GET_INSTALLATION",
|
||||
"hub_b",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_dispatch_function(
|
||||
generate_main: Callable[[str | Path], str], fn: str, type_expr: str, hub: str
|
||||
) -> None:
|
||||
main_cpp = generate_main(YAML)
|
||||
|
||||
assert main_cpp.count(f"static void {fn}(button::Button * entity) {{") == 1
|
||||
assert _fn_body(main_cpp, fn) == (
|
||||
f" const auto type = {type_expr};\n ::{hub}->press_button(type);"
|
||||
)
|
||||
|
||||
|
||||
def test_each_button_uses_its_block_function(
|
||||
generate_main: Callable[[str | Path], str],
|
||||
) -> None:
|
||||
main_cpp = generate_main(YAML)
|
||||
|
||||
expected = {
|
||||
"a_get_delay": "esphome__a_get_delay__button_fn",
|
||||
"a_get_sensitivity": "esphome__a_get_delay__button_fn",
|
||||
"a_wake": "esphome__a_get_delay__button_fn",
|
||||
"a_get_z_range": "esphome__a_get_z_range__button_fn",
|
||||
"b_get_installation": "esphome__b_get_installation__button_fn",
|
||||
}
|
||||
for button_id, fn in expected.items():
|
||||
assert f"new({button_id}) button::ApplyButton<{fn}>();" in main_cpp
|
||||
# One definition per block, no more.
|
||||
assert (
|
||||
len(re.findall(r"static void esphome__\w+__button_fn\(.*\) \{", main_cpp)) == 3
|
||||
)
|
||||
@@ -9,11 +9,17 @@ from __future__ import annotations
|
||||
|
||||
import pytest
|
||||
|
||||
from esphome.components.ld6002b import validate_unique_settings
|
||||
from esphome.components.ld6002b.button import (
|
||||
CONFIG_SCHEMA as BUTTON_CONFIG_SCHEMA,
|
||||
FINAL_VALIDATE_SCHEMA as BUTTON_FINAL_VALIDATE_SCHEMA,
|
||||
)
|
||||
from esphome.components.ld6002b.const import CONF_AREA_CONFIG, CONF_Z_MIN
|
||||
from esphome.components.ld6002b.const import (
|
||||
CONF_AREA_CONFIG,
|
||||
CONF_HOLD_DELAY,
|
||||
CONF_Z_MAX,
|
||||
CONF_Z_MIN,
|
||||
)
|
||||
from esphome.components.ld6002b.number import (
|
||||
CONFIG_SCHEMA as NUMBER_CONFIG_SCHEMA,
|
||||
FINAL_VALIDATE_SCHEMA as NUMBER_FINAL_VALIDATE_SCHEMA,
|
||||
@@ -40,6 +46,7 @@ def _full_config(
|
||||
*,
|
||||
selects: list[ConfigType] | None = None,
|
||||
buttons: list[ConfigType] | None = None,
|
||||
numbers: list[ConfigType] | None = None,
|
||||
) -> Config:
|
||||
"""A full config carrying one ld6002b hub, as the ID pass leaves it.
|
||||
|
||||
@@ -57,6 +64,8 @@ def _full_config(
|
||||
full["select"] = selects
|
||||
if buttons is not None:
|
||||
full[CONF_BUTTON] = buttons
|
||||
if numbers is not None:
|
||||
full["number"] = numbers
|
||||
return full
|
||||
|
||||
|
||||
@@ -214,3 +223,53 @@ def test_area_config_without_select_is_rejected(
|
||||
),
|
||||
):
|
||||
_validated_numbers(_area_numbers())
|
||||
|
||||
|
||||
def _number_block(**settings: ConfigType) -> ConfigType:
|
||||
"""A number platform block on the shared hub, as final validation sees it."""
|
||||
return {
|
||||
"platform": "ld6002b",
|
||||
"ld6002b_id": ID(HUB_ID, is_declaration=False, type="ld6002b"),
|
||||
**settings,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("first", "second", "error"),
|
||||
[
|
||||
(
|
||||
{CONF_HOLD_DELAY: {"name": "A"}},
|
||||
{CONF_HOLD_DELAY: {"name": "B"}},
|
||||
r"^hold_delay is already set .* @ data\['hold_delay'\]$",
|
||||
),
|
||||
(
|
||||
{CONF_AREA_CONFIG: {CONF_Z_MIN: {"name": "A"}}},
|
||||
{CONF_AREA_CONFIG: {CONF_Z_MIN: {"name": "B"}}},
|
||||
r"^area_config\.z_min is already set .* @ data\['area_config'\]\['z_min'\]$",
|
||||
),
|
||||
(
|
||||
{CONF_AREA_CONFIG: {CONF_Z_MIN: {"name": "A"}}},
|
||||
{CONF_AREA_CONFIG: {CONF_Z_MAX: {"name": "B"}}},
|
||||
None,
|
||||
),
|
||||
({CONF_HOLD_DELAY: {"name": "A"}}, {CONF_Z_MIN: {"name": "B"}}, None),
|
||||
],
|
||||
)
|
||||
def test_setting_in_two_blocks_of_one_hub(
|
||||
set_core_config: SetCoreConfigCallable,
|
||||
first: ConfigType,
|
||||
second: ConfigType,
|
||||
error: str | None,
|
||||
) -> None:
|
||||
"""Each setting maps to one entity pointer, so two blocks cannot share one."""
|
||||
blocks = [_number_block(**first), _number_block(**second)]
|
||||
set_core_config(
|
||||
PlatformFramework.ESP32_IDF,
|
||||
full_config=_full_config(_hub(wakeup_pin=False), numbers=blocks),
|
||||
)
|
||||
|
||||
if error is None:
|
||||
validate_unique_settings("number", blocks[1])
|
||||
return
|
||||
with pytest.raises(cv.Invalid, match=error):
|
||||
validate_unique_settings("number", blocks[1])
|
||||
Reference in new issue
Block a user