95 lines
6.5 KiB
Markdown
95 lines
6.5 KiB
Markdown
# Visual Flow architecture
|
|
|
|
Flow is an authoring/orchestration layer. It does not replace the thermostat, schedule, group or device engines.
|
|
|
|
## Compilation
|
|
|
|
- `weekday + time_range -> zone_thermostat` with schedule-compatible settings compiles to a native `Schedule`.
|
|
- Richer DAGs compile to native `Automation` rows with `trigger_kind = "flow"`.
|
|
- Generated rows keep `flow_id` and `flow_node_id`, use stable `flow-<stable-unique-id>` names, and are read-only in the legacy editors.
|
|
- The Flow source graph plus all of its generated schedule/automation rows are replaced in one SQLite transaction.
|
|
- Flow updates require `expected_revision`; stale editor tabs receive HTTP 409.
|
|
|
|
## Existing control domains remain authoritative
|
|
|
|
- `zone_thermostat` writes the existing persistent Zone intent and wakes the normal thermostat cycle.
|
|
- `group_action` calls the existing `control_group` path, including custom group targets.
|
|
- `device_action` uses the existing `DeviceCommand` / automatic-device path.
|
|
- Thermostat hysteresis, compressor protection, schedule hand-back, manual/local ownership and Temporary Quick Thermostat keep their existing priority.
|
|
- GREE fan/quiet/sleep and dry/fan HVAC modes are suppressed on thermostat-assigned devices when they would fight the regulator. Device-only features such as light/turbo/swing/air/xfan/health remain available through the normal command path.
|
|
|
|
## Concurrency invariants
|
|
|
|
Structural Flow writes use the global order:
|
|
|
|
`configuration -> automation -> schedule -> thermostat-cycle`
|
|
|
|
Thermostat/device actions then use:
|
|
|
|
`automation -> schedule -> thermostat-cycle -> zone -> device`
|
|
|
|
Group actions use the existing group order:
|
|
|
|
`automation -> house -> thermostat-cycle -> group -> zone(s) -> device`
|
|
|
|
The control loop runs thermostat arbitration and automation arbitration sequentially. Automation execution reloads the row after acquiring the automation lock and skips it when `updated_at` changed. Same-cycle due automations deterministically claim target devices so two rules cannot issue conflicting commands to the same unit in one pass. Polling and physical commands share per-zone/per-device locks.
|
|
|
|
Holding the automation lock across the physical action is deliberate: Flow cannot be deleted/recompiled while an already-selected action is in flight. Do not shorten this ownership window without adding an explicit execution-generation/token mechanism.
|
|
|
|
External sensor values can naturally change between condition sampling and action execution. This is normal sampled-control semantics, not a persistent-state race; safety/ownership is rechecked at the action boundary.
|
|
|
|
## Home Assistant safety
|
|
|
|
`ha_state`, `ha_numeric`, `ha_attribute` and `ha_available` fail closed. Connection failures, missing attributes and non-numeric numeric states evaluate to `false` and appear as an error object in dry-run traces. This prevents `NOT` / `neq` branches from becoming true merely because Home Assistant is unavailable.
|
|
|
|
## Diagnostics
|
|
|
|
The Flow editor exposes:
|
|
|
|
- dry-run at an arbitrary date/time,
|
|
- per-source overrides,
|
|
- per-node trace,
|
|
- `would_execute` and ownership/block reason,
|
|
- Flow-scoped execution/dry-run logs,
|
|
- import/export of versioned `.flow.json` source graphs.
|
|
|
|
Dry-run never mutates thermostats, devices, groups, schedules or automations.
|
|
|
|
## Blocks
|
|
|
|
Condition/source blocks currently include weekday, time range, date range, application Night mode, outdoor/device/zone temperature, house mode, device state, thermostat/zone state, group state, Home Assistant state/numeric/attribute/availability, a diagnostic constant, and `shared_input`. Shared inputs are configured centrally in Home Assistant / Sensors and referenced by ID, so one source definition can be reused by multiple Flows. Logic blocks are AND, OR and NOT.
|
|
|
|
Actions include thermostat zone, GREE device and climate group. Direct GREE actions expose power, HVAC mode, target temperature, fan speed, vertical/horizontal swing, quiet, turbo, light, air, xfan, health and sleep.
|
|
|
|
## Built-in presets
|
|
|
|
The editor ships 37 editable presets grouped into seven categories: Comfort, Energy & cost, Protection & safety, Night, Reliability, Home Assistant / heat sources and Advanced. The library UI also provides search, Favorites, Recent, a mini graph preview and requirement checks before applying a preset. The library includes workday/weekend comfort, weather-aware demand, morning boost, presence and energy-price eco modes, peak-power limiting, open-window/humidity/overheat/frost guards, night profiles, sensor/device resilience, dual heating/cooling thresholds, multi-room group control, nested AND/OR/NOT Home Assistant scenarios, and gas-boiler/external-heat-source coordination including off, reduced-target, boost and fallback heating patterns.
|
|
|
|
Shared Flow inputs show the Flows that reference them and link directly to those editors. Home Assistant-backed shared inputs can be tested live in the input modal, including the current raw value/attribute and the resulting TRUE/FALSE condition.
|
|
|
|
Presets are data files, not JavaScript definitions. Every preset lives in `presets/<id>.json` and contains `id`, `category`, localized `name`, localized `description`, and the complete `flow` graph (`nodes` + `edges`). `build.rs` validates and embeds the directory, exposes `/presets/index.json` plus `/presets/<file>.json`, and the Flow editor loads that library dynamically. Device/zone/group placeholders such as `$zone1`, `$zone2`, `$device1` and `$group1` are resolved when a preset is applied. Adding a preset therefore does not require adding graph-building code to `web/js/flows.js`.
|
|
|
|
The canvas supports multi-selection (Shift/Ctrl/Cmd), `Ctrl/Cmd+A`, Select all / Clear selection toolbar actions, and dragging the whole selected group while preserving relative positions.
|
|
|
|
## Good next stateful blocks
|
|
|
|
The next useful additions should be implemented with persisted runtime state rather than pretending they are stateless predicates:
|
|
|
|
- `for X minutes` / stable-for,
|
|
- debounce,
|
|
- hysteresis block,
|
|
- rising/falling edge,
|
|
- cooldown/rate limit independent of the action,
|
|
- delay/timer,
|
|
- retry/backoff,
|
|
- variables/counters,
|
|
- reusable subflows/macros,
|
|
- explicit priority/mutex groups for actions,
|
|
- trace replay from historical sensor samples.
|
|
|
|
These need durable state and restart semantics before they should be exposed in the editor.
|
|
|
|
### Display name / alias
|
|
|
|
The Flow name edited in `/flows` is a presentation alias. Renaming it changes labels shown in the UI (including the dashboard) but does not change the stable Flow ID or generated `flow-<unique-id>` schedule/automation names.
|