Document the automation package and test event validity
This commit was merged in pull request #121.
This commit is contained in:
@@ -67,6 +67,94 @@ actions:
|
|||||||
message: "Every quest cleared — legendary!"
|
message: "Every quest cleared — legendary!"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Automation Blueprints
|
||||||
|
|
||||||
|
NestQuest ships four automation blueprints in
|
||||||
|
`custom_components/nestquest/blueprints/automation/`. Import them in
|
||||||
|
Home Assistant under **Settings → Automations & Scenes → Blueprints**
|
||||||
|
(or place the files in your `config/blueprints/automation/` folder),
|
||||||
|
then create one automation per blueprint, filling the inputs with your
|
||||||
|
household's choices.
|
||||||
|
|
||||||
|
### Wiring to the integration's notification settings
|
||||||
|
|
||||||
|
The integration's options flow records your notification choices —
|
||||||
|
notify target, morning/afternoon/end-of-day times, and a toggle per
|
||||||
|
automation. The blueprints take their own inputs at import time;
|
||||||
|
fill them from the same values you stored in the options flow (the
|
||||||
|
integration does not push its settings into imported automations):
|
||||||
|
|
||||||
|
| Blueprint input | Options-flow counterpart |
|
||||||
|
|---|---|
|
||||||
|
| `morning_time` (default 08:00) | `morning_summary_time` |
|
||||||
|
| `afternoon_time` (default 15:00) | `afternoon_reminder_time` |
|
||||||
|
| `report_time` (default 20:00) | `end_of_day_report_time` |
|
||||||
|
| `send_summary` / `send_reminder` / `send_report` / `celebrate` | the four `*_enabled` toggles |
|
||||||
|
| `notify_target` | `notify_target` (your notify service, e.g. `notify.mobile_app_your_phone`) |
|
||||||
|
|
||||||
|
The end-of-day report deliberately runs BEFORE the midnight missed
|
||||||
|
sweep and reads the same day's data — do not schedule it at the
|
||||||
|
day-rollover time.
|
||||||
|
|
||||||
|
### The four blueprints
|
||||||
|
|
||||||
|
1. **Morning summary** (`morning_summary.yaml`) — at the configured
|
||||||
|
time, lists every child whose `binary_sensor.nestquest_<child>_present_today`
|
||||||
|
is on and what they owe from `sensor.nestquest_<child>_quests_remaining_today`.
|
||||||
|
Children not present today are omitted entirely.
|
||||||
|
|
||||||
|
2. **Afternoon reminder** (`afternoon_reminder.yaml`) — at the
|
||||||
|
configured time, notifies only about present children who still
|
||||||
|
have open quests. Sends nothing at all when every present child is
|
||||||
|
clear.
|
||||||
|
|
||||||
|
3. **End-of-day report** (`end_of_day_report.yaml`) — one message per
|
||||||
|
evening: each present child's completion count and the quests they
|
||||||
|
still owe (the ones the midnight sweep will mark
|
||||||
|
`nestquest_quest_missed`). Absent children are omitted. Sends
|
||||||
|
nothing on an all-clear day unless `send_even_when_clear` is on.
|
||||||
|
|
||||||
|
4. **Day-complete celebration** (`day_complete_celebration.yaml`) —
|
||||||
|
triggers on the `nestquest_child_day_complete` event (which only
|
||||||
|
fires when quests were owed and all are complete, so a zero-quest
|
||||||
|
day never celebrates). Create one `input_text` helper
|
||||||
|
(`nestquest_last_celebrated`) for the dedupe: the automation
|
||||||
|
records each celebrated child as `<child_id>:<today>` and
|
||||||
|
celebrates each child at most once per day — a re-cleared day does
|
||||||
|
not re-fire, but a second child clearing the same day still
|
||||||
|
celebrates.
|
||||||
|
|
||||||
|
### Example package
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# One automation per blueprint — Settings → Automations & Scenes →
|
||||||
|
# Create → Blueprint, then pick each NestQuest blueprint.
|
||||||
|
#
|
||||||
|
# morning_summary: morning_time 08:00, notify_target notify.mobile_app_your_phone
|
||||||
|
# afternoon_reminder: afternoon_time 15:00, same notify target
|
||||||
|
# end_of_day_report: report_time 20:00, send_even_when_clear false, same target
|
||||||
|
# day_complete_celebration: input_text.nestquest_last_celebrated,
|
||||||
|
# celebration_message "Legendary! {{ trigger.payload.child_name }} cleared every quest today!"
|
||||||
|
#
|
||||||
|
# Every blueprint has its own send/celebrate toggle input; turn an
|
||||||
|
# automation off entirely from HA's automation menu.
|
||||||
|
```
|
||||||
|
|
||||||
|
### Events the automations rely on
|
||||||
|
|
||||||
|
| Event | Payload |
|
||||||
|
|---|---|
|
||||||
|
| `nestquest_quest_completed` | child_id, child_name, instance_id, quest_title, window, due_date, due_time, occurred_at (UTC ISO-8601), was_on_time |
|
||||||
|
| `nestquest_quest_uncompleted` | child_id, child_name, instance_id, quest_title, window, due_date, due_time, occurred_at |
|
||||||
|
| `nestquest_child_day_complete` | child_id, child_name, quests_due, quests_completed, occurred_at |
|
||||||
|
| `nestquest_quest_missed` | child_id, child_name, instance_id, quest_title, window, due_date, due_time, occurred_at (fired by the nightly sweep) |
|
||||||
|
|
||||||
|
Sensors the automations read: `sensor.nestquest_<child>_quests_due_today`
|
||||||
|
(attributes: `child_id`, `child_name`, `present`, `instances`,
|
||||||
|
`admin_instances`), `..._quests_remaining_today`,
|
||||||
|
`..._quests_completed_today`, and
|
||||||
|
`binary_sensor.nestquest_<child>_present_today`.
|
||||||
|
|
||||||
## Developer Setup and Testing
|
## Developer Setup and Testing
|
||||||
|
|
||||||
This project uses [`uv`](https://github.com/astral-sh/uv) for fast Python package and dependency management.
|
This project uses [`uv`](https://github.com/astral-sh/uv) for fast Python package and dependency management.
|
||||||
|
|||||||
@@ -241,4 +241,28 @@ def test_afternoon_reminder_never_hard_codes_notify_target() -> None:
|
|||||||
assert re.search(r"notify\.[a-z_]+", target_description), (
|
assert re.search(r"notify\.[a-z_]+", target_description), (
|
||||||
"the input description should show a placeholder example"
|
"the input description should show a placeholder example"
|
||||||
)
|
)
|
||||||
assert single_action(bp)["action"] == BlueprintInput("notify_target")
|
assert single_action(bp)["action"] == BlueprintInput("notify_target")
|
||||||
|
|
||||||
|
def test_afternoon_reminder_absent_child_regression() -> None:
|
||||||
|
"""The Feature 11 guardrail, stated as one regression test: no
|
||||||
|
reminder message is ever produced for an absent child."""
|
||||||
|
states = make_states(
|
||||||
|
sensors=[
|
||||||
|
TemplateState(
|
||||||
|
"sensor.nestquest_bob_quests_due_today",
|
||||||
|
"3",
|
||||||
|
{"child_name": "Bob", "child_id": 1, "present": False},
|
||||||
|
),
|
||||||
|
TemplateState(
|
||||||
|
"sensor.nestquest_bob_quests_remaining_today",
|
||||||
|
"3",
|
||||||
|
{"child_id": 1},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
guard = afternoon_conditions(afternoon_reminder())[-1]
|
||||||
|
assert render(guard["value_template"], states=states).strip() == "False"
|
||||||
|
message = render(
|
||||||
|
notify_data(afternoon_reminder())["message"], states=states
|
||||||
|
)
|
||||||
|
assert "Bob" not in message
|
||||||
|
|||||||
@@ -272,3 +272,25 @@ def test_celebration_mode_is_queued() -> None:
|
|||||||
"""Two children completing at nearly the same time must both be
|
"""Two children completing at nearly the same time must both be
|
||||||
processed: queued mode does not drop the second event."""
|
processed: queued mode does not drop the second event."""
|
||||||
assert celebration()["mode"] == "queued"
|
assert celebration()["mode"] == "queued"
|
||||||
|
|
||||||
|
|
||||||
|
def test_every_blueprint_event_reference_is_real() -> None:
|
||||||
|
"""Every event a blueprint triggers on is one NestQuest actually
|
||||||
|
fires or defines (Feature 10/11) — no invented event names."""
|
||||||
|
from tests.blueprint_helpers import load_blueprints
|
||||||
|
|
||||||
|
real_events = {
|
||||||
|
"nestquest_quest_completed",
|
||||||
|
"nestquest_quest_uncompleted",
|
||||||
|
"nestquest_quest_missed",
|
||||||
|
"nestquest_child_day_complete",
|
||||||
|
}
|
||||||
|
for name, bp in load_blueprints().items():
|
||||||
|
for trigger in bp.get("triggers", []):
|
||||||
|
if trigger.get("trigger") == "event":
|
||||||
|
assert trigger["event_type"] in real_events, (
|
||||||
|
f"{name}: invented event {trigger['event_type']!r}"
|
||||||
|
)
|
||||||
|
assert celebration()["triggers"][0]["event_type"] == (
|
||||||
|
"nestquest_child_day_complete"
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user