Add control entities: box to-do list, skip switch, donate button, subscriptions
Validate / hassfest (push) Failing after 6s
Validate / pytest (push) Failing after 8s
Validate / HACS (push) Failing after 1m8s

The to-do list exists so Home Assistant's own conversation agent can manage the
order through HassListAddItem rather than through anything bespoke. Skip is a
switch because skipped/not-skipped is state worth reading back; donate is a
button because it cannot be undone. Un-skip raises rather than guessing at an
endpoint that has never been observed.

Fixes subscription parsing, which matched the heading row and so reported zero
on an account that has one.
This commit is contained in:
flan
2026-08-03 20:13:32 +00:00
parent 213c16d98e
commit 551d3240a2
14 changed files with 592 additions and 14 deletions
+27 -1
View File
@@ -13,7 +13,12 @@ from pathlib import Path
import pytest
COMPONENT = Path(__file__).parent.parent / "custom_components" / "freshharvest"
PLATFORMS = {"sensor": "sensor.py", "binary_sensor": "binary_sensor.py"}
PLATFORMS = {
"sensor": "sensor.py",
"binary_sensor": "binary_sensor.py",
"switch": "switch.py",
"button": "button.py",
}
def declared_keys(filename: str) -> set[str]:
@@ -29,6 +34,22 @@ def declared_keys(filename: str) -> set[str]:
}
def attr_keys(filename: str) -> set[str]:
"""Collect `_attr_translation_key = "..."` assignments (entities without a
description object declare their name this way)."""
tree = ast.parse((COMPONENT / filename).read_text(encoding="utf-8"))
return {
node.value.value
for node in ast.walk(tree)
if isinstance(node, ast.Assign)
and any(
getattr(t, "id", getattr(t, "attr", None)) == "_attr_translation_key"
for t in node.targets
)
and isinstance(node.value, ast.Constant)
}
@pytest.fixture(name="strings")
def strings_fixture() -> dict:
return json.loads((COMPONENT / "strings.json").read_text(encoding="utf-8"))
@@ -64,3 +85,8 @@ def test_manifest_is_well_formed():
assert manifest[key].startswith("https://github.com/"), (
f"{key} must be a public URL, got {manifest[key]}"
)
def test_todo_entity_is_named(strings):
"""todo.py declares its name via _attr_translation_key, not a description."""
assert attr_keys("todo.py") == set(strings["entity"]["todo"])