# 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` 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 and a diagnostic constant. 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 templates The editor ships editable templates for: - workday comfort, - weather-aware comfort, - smart AND/OR demand, - device resilience, - night group control, - Home Assistant window guard, - presence comfort/eco, - frost protection, - nested OR + NOT guard, - application Night-mode quiet profile. ## 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.