Skip to content

ConfigFlow Phase 2: deliveries and scenarios in the UI — proposal + prototypes #166

Description

@lollox80

With v2.0.0 landing the "Immediate" phase of docs/roadmap/configflow_approach.md (#60, #136), I'd like to open a place to discuss the next step — deliveries and scenarios in the UI — before anyone (me included) writes more code in the wrong direction. Splitting it out of the closed threads so it's easy to find.

I have three pieces of work sitting on my fork that are relevant. None of them need to land as-is; I'm listing them so you can pick what's useful and reject the rest.

  1. Deliveries as config subentries (prototype, working end-to-end)

A DeliverySubentryFlowHandler (ConfigSubentryFlow, HA 2025.3+ API) that creates/edits/removes a delivery from the integration page. Typed fields for transport (SelectSelector), enabled, priority, occupancy, selection, action, target, plus an ObjectSelector for the transport-specific data/options/conditions. The raw form dict is stored in the subentry and validated through DELIVERY_SCHEMA at runtime; subentry deliveries are merged with the YAML ones (subentry wins on a name clash), so YAML users can add UI deliveries incrementally without migrating anything. Tested on my instance: create → persists across restart → notify.supernotify delivers to it.

Two non-obvious things I hit that apply to any implementation storing deliveries in the entry, whichever model you choose:

Anything that has gone through SUPERNOTIFY_SCHEMA contains Template objects (e.g. volume_template), which are not JSON-serializable. Storing validated dicts in entry.data/options breaks the whole entry save (TypeError: Type is not JSON serializable: Template) the first time anything else touches the entry. Store raw strings and re-validate at load time.
Update listeners registered with entry.add_update_listener() must be coroutine functions; a @callback sync listener makes async_create_task(listener(hass, entry)) blow up with "a coroutine was expected, got None" at the first options save.

The question I'd like your steer on: the roadmap says deliveries/transports/scenarios/recipients should be "maintained as YAML, in a similar fashion to how HA treats automations" (UI edits round-trip to the file). That's a different model from subentries (data lives in the entry, no separate file). Before I go further:

Does the YAML file stay hand-editable in parallel once someone has used the UI (like automations.yaml), or is it UI-owned after migration?
Is the entry meant to hold only global settings, with the delivery/scenario file entirely outside it?
Is there a reason to prefer round-trip YAML over subentries that I'm missing? I'm not attached to the prototype — if round-trip is the direction, I'll adapt it; the field-typing work (transport-specific data) is the same problem either way.
2. Scenario state as a real binary_sensor (small patch, self-contained)

expose_entities() already creates binary_sensor.supernotify_scenario_, but with state=STATE_UNKNOWN hard-coded and never refreshed. The patch (≈70 lines in notify.py) evaluates each scenario's conditions with neutral variables (real occupancy + PRIORITY_MEDIUM, same as enquire_active_scenarios), sets ON/OFF, and refreshes on a 1-minute timer plus async_track_state_change_event on the entities extracted from the conditions via condition.async_extract_entities. Scenarios whose conditions reference no entities (priority-only, or pure applied_scenarios triggers like a manual emergency) stay unknown, which is the honest answer for them.

This maps onto your "Fourth" phase (scenarios: view / enable-disable) and is independent of the config flow. I can open it as a PR straight away if you want it; happy to do an issue-first round if you'd rather shape it.

Design note behind it (from mapping my own 25 scenarios): only 1 is a manual switch, 17 self-activate on priority/time/occupancy, 7 are driven by existing helpers. So "scenario = helper" would break most of them; "scenario state exposed read-only, helpers referenced as inputs" keeps the automation intact. Details in the write-up if useful.

  1. delivery_selection semantics (UX, no code yet)

Not a bug, but the thing that trips up every new user I've walked through the config, and it will surface hard once deliveries are editable in a form:

Passing delivery: as a map defaults to IMPLICIT (default + scenarios + listed), as a list to EXPLICIT (no defaults, but scenarios still apply). Same key, different behaviour depending on YAML shape.
Only fixed gives "just these" — and 1.17.0's change to fixed (overrides priority/conditions, only enabled blocks) is a good step, thanks.
Separately, when two active scenarios disagree on a delivery's enabled (e.g. dnd_globale says alexa: false, high_priority says alexa: true), false wins silently. That's a defensible safety default, but it's undocumented and the scenario author has no way to express "this one should win".

Proposal for Phase 2: expose delivery_selection explicitly in the delivery form with the three modes spelled out, decouple the default from the map/list shape, and document (or make configurable) the merge rule when scenarios conflict on enabled.

Suggested order from my side, if it helps: (2) as a small PR now, (3) as a doc/decision, (1) once you've said which storage model you want. I'll also be sending the Matrix/Discord/HTML5/Kodi transports as separate PRs over the next days — those are independent of all of the above.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions