Files
gree-controller/README.md
T
2026-09-17 11:32:06 +02:00

32 KiB
Raw Blame History

GREE Controller

Self-hosted controller for GREE-compatible air conditioners with a local Web UI, thermostat zones, schedules, Home Assistant integration, history, notifications and a documented HTTP/WebSocket API.

Version: 0.15.0

Version 0.15.0 adds full vertical/horizontal louver positioning across direct control, thermostat views, automations, Visual Flow and Home Assistant, while keeping legacy boolean swing payloads compatible. Direct add-on access also shows an invalid-token error only after an explicit token submission. The bundled Home Assistant climate cards also localize louver/fan/profile labels without changing their stable technical service values.

Full API reference — authentication, every endpoint, request bodies, response models, WebSocket events and examples.

What it does

  • Discovers and binds GREE Wi-Fi units on the LAN, including mixed protocol generations.
  • Provides direct technical device control and a separate thermostat layer built around zones.
  • Supports cooling/heating profiles: Comfort, Sleep, Away and custom quick targets.
  • Coordinates house, group and per-zone control without silently fighting physical/manual overrides.
  • Supports schedules, automations, night mode and temporary Quick Thermostat sessions.
  • Can use GREE sensors, Home Assistant room sensors or a weighted combination.
  • Stores recent history in SQLite and can archive/query long-term history in InfluxDB 1.x or 2.x.
  • Exposes native Home Assistant entities through the bundled custom integration.
  • Includes PWA-capable responsive UI, Polish/English localization and live diagnostics.
  • Can run in Simulation mode without physical air conditioners. A large warning is shown whenever simulation is enabled.

UI overview

The interface is intentionally split by responsibility:

Area Purpose
Dashboard Whole-house summary, Quick Thermostat and full manual GREE unit control.
Devices Technical unit configuration, binding, connection diagnostics and live ping.
Zones Thermostat configuration, profiles, sensors and control ownership.
Groups Climate group membership plus optional group-level mode/preset/custom-temperature control. Group ON activates member thermostat control; Group OFF powers member units down and releases group ownership so individual thermostats are not left group-blocked.
Flow Full-screen visual logic editor. Flow is the source of truth and is automatically compiled into generated schedules and automations.
Schedules Weekly thermostat schedules and ready-made templates, including read-only entries generated by Flow.
Automations Time/temperature/Flow-triggered device, group or thermostat actions.
History Overview, zones, devices and HA sensors with precise chart tooltips and zoom.
Simulation Simulated units for safe testing.
Night mode Quiet/Sleep/fan limits during an overnight window.
Home Assistant Sensor connection, aliases and restricted integration tokens.
Settings → Application Simulation, notifications, metrics/logs, InfluxDB, debug and backup.
Settings → GREE Controller identity, polling/discovery, GREE commands and live GREE traffic.
Events Operational event log and diagnostics.

The top bar uses the same compact language and theme controls on desktop and mobile. The live debug overlay can be filtered to All, Requests or GREE frames.

Quick start for development

Requirements are installed automatically on supported Debian/Ubuntu environments unless --no-install is used.

cp .env.example .env
./scripts/dev.sh

Useful development commands:

./scripts/dev.sh --check       # format, tests, build and HTTP smoke test
./scripts/dev.sh --release     # optimized local build
./scripts/dev.sh --reset       # recreate the local SQLite database
./scripts/smoke.sh             # API smoke test against an isolated simulated instance

The default panel is available at http://127.0.0.1:8787 when the process is bound locally.

LXC / systemd installation

The production scripts target Debian/Ubuntu systemd hosts and LXC containers.

First installation

sudo ./scripts/install.sh

Optional flags:

sudo ./scripts/install.sh --skip-tests
sudo ./scripts/install.sh --no-start

Installed layout:

Path Purpose
/opt/gree-controller/gree-controller Release binary.
/etc/gree-controller.env Environment configuration; mode 0600.
/var/lib/gree-controller/gree-controller.db SQLite database.
/etc/systemd/system/gree-controller.service systemd unit.
/var/backups/gree-controller/ Update backups used for rollback.

Update

Run from the extracted source tree of the new release:

sudo ./scripts/update.sh

The updater builds/tests first, stops the old service, backs up the binary/unit/environment/database, installs the release, checks /api/health and rolls back automatically if startup fails.

Service helper

./scripts/service.sh status
./scripts/service.sh health
./scripts/service.sh logs
sudo ./scripts/service.sh restart

./scripts/install-lxc.sh remains as a compatibility alias to install.sh.

Configuration

Copy .env.example for the full supported example. Command-line arguments exist for the core Config options, while most day-to-day runtime settings are also editable in the Web UI and persisted in SQLite.

Environment values explicitly supplied for supported runtime overrides win over the persisted value after restart.

Core variables

Variable Default Description
GREE_CONTROLLER_BIND 0.0.0.0:8787 HTTP/WebSocket listen address.
GREE_CONTROLLER_DATABASE ./data/gree-controller.db SQLite database path.
GREE_CONTROLLER_APP_TOKEN empty Administrator API/Web UI token. Empty means trusted-LAN mode in standalone installs; with HA Supervisor auth active, empty disables direct dashboard/API access on the exposed port.
GREE_CONTROLLER_BASE_PATH empty Optional reverse-proxy prefix such as /gree.
GREE_CONTROLLER_PUBLIC_CHART_BASE_URL empty Optional absolute HTTP(S) base URL used only when generating public Custom Chart links; useful behind a reverse proxy or alternate external port.
GREE_CONTROLLER_ID gree-controller GREE client/controller identifier.
GREE_CONTROLLER_SIMULATE false Initial Simulation mode.
GREE_CONTROLLER_AUTO_SEED false Seed simulated sample data when applicable.
GREE_CONTROLLER_POLL_INTERVAL_SECONDS 15 Device polling interval.
GREE_CONTROLLER_ZONE_INTERVAL_SECONDS 5 Thermostat control interval.
GREE_CONTROLLER_DISCOVERY_TIMEOUT_MS 3000 Discovery timeout.
GREE_CONTROLLER_DISCOVERY_BROADCAST 255.255.255.255:7000 GREE discovery target.
GREE_CONTROLLER_GREE_INTERFACE auto Optional interface name or local IP used for GREE UDP traffic.
GREE_CONTROLLER_COMPRESSOR_PROTECTION_ENABLED true Enable controller-side compressor restart/mode-change protection.
GREE_CONTROLLER_COMPRESSOR_PROTECTION_SECONDS 180 Compressor protection window (301800 seconds; 180 seconds recommended).

Additional environment variables cover history retention, debug, night mode, Home Assistant and InfluxDB. See .env.example.

Local vs GREE Cloud

Each device has an explicit connection_type:

  • Local uses the existing GREE LAN protocol over UDP/7000, including discovery, bind, status and commands. It never calls GREE Cloud.
  • GREE Cloud uses the configured account plus MQTT/TLS. It never performs UDP discovery, bind, probe or commands.

The same physical air conditioner may intentionally be added twice, once as Local and once as GREE Cloud. The controller does not automatically fail over between transports, preventing duplicate commands.

GREE Cloud setup

Open Settings → GREE Cloud, enable the provider, select the same region used by the official GREE app, enter the account login/email and password, then use Test connection. After a successful test, use Refresh devices and explicitly add the units you want to control through Cloud. Credentials are account-level settings; they are not copied into every device.

The password field is write-only from the UI: a saved password is reported only as configured/not configured. The installation UUID used by the GREE Cloud User-Agent is generated once and persisted.

Cloud status

Cloud devices distinguish online, offline, cloud_disconnected, authentication_error and unknown. Account/MQTT state is shown separately so an offline air conditioner is not confused with a broker, credential or internet failure. Device diagnostics include safe broker/topic/status information and decrypted/sanitized properties, never authentication tokens or cipher keys.

Cloud polling and synchronization

MQTT push is the normal synchronization path. REST login is reused for the MQTT session and is not repeated for every status request. Polling is used for initial state, recovery, fallback and periodic verification; the configurable Cloud interval is clamped to at least 30 seconds. MQTT reconnect uses bounded backoff and restored subscriptions. A Cloud outage does not switch a device to LAN and does not block Local polling/control.

Energy

Energy can come from either GREE Cloud or a cumulative Home Assistant energy sensor. Devices with both sources can select Auto, GREE Cloud or Home Assistant. Home Assistant candidates are limited to device_class=energy, state_class=total|total_increasing and Wh/kWh units.

GREE ElcAll is a cumulative counter in tenths of a kWh and is normalized to kWh. Cumulative counters are converted to per-sample consumption deltas before history aggregation. The first sample establishes a baseline; duplicate samples consume zero; a falling/reset counter creates a new baseline; negative consumption is never stored. Energy history is separate from temperature history and can be aggregated hourly, daily, weekly or monthly, with Today, Yesterday, Current month, Previous month and Period total summaries. Older energy samples can be archived to InfluxDB using the same retention policy as other metrics.

GREE Cloud security

Cloud REST and MQTT use TLS with certificate/hostname validation enabled. Passwords, REST tokens, MQTT credentials, Authorization headers and device cipher keys are excluded from normal API responses, Cloud diagnostics and logs. Network, connect and command operations have bounded timeouts; retries/reconnects are rate-limited rather than tight-looped.

Limitations

  • GREE Cloud availability and behavior depend on GREE's external services and the selected account region.
  • The Cloud status protocol does not expose a universal buzzer capability. When suppress device beep is enabled, Cloud commands follow greeclimate semantics and include Buzzer_ON_OFF=1; models that ignore this command-only field simply continue without a separately advertised buzzer capability.
  • Capability detection is based on discovery/model data plus properties actually returned by the device. Controls are hidden or rejected when support is known to be absent.
  • There is intentionally no automatic Local↔Cloud fallback.

Connecting physical GREE units

  1. Place the controller host on a network that can reach the air-conditioner Wi-Fi modules by UDP.
  2. Open Devices and start discovery.
  3. Auto protocol mode is recommended; the controller accepts both supported GREE encryption generations.
  4. Newly discovered devices are bound automatically when possible. Manual bind is also available.
  5. Create a thermostat zone for each unit you want the thermostat engine to own.

Discovery uses UDP broadcast, so routed/VLAN networks must explicitly permit or relay the required traffic.

Compatibility with newer GREE firmware

GREE Controller supports the two commonly reverse-engineered local LAN protocol generations used by compatible units: the older AES-ECB variant and the newer AES-GCM variant. Protocol auto-detection and binding already cover both generations.

Some newer GREE Wi-Fi modules and firmware releases have been reported to behave differently: the unit is reachable on the network and continues to work in the official GREE+ application, but does not answer the usual local UDP traffic on port 7000. Reports include firmware branches such as 2.12 and 3.x, although firmware numbering differs between Wi-Fi module families and should not be treated as a universal compatibility boundary.

For such a unit, failure to discover or bind is not necessarily an encryption problem. If the device sends no response at all to UDP/7000, changing between AES-ECB and AES-GCM cannot restore communication. The current evidence suggests that at least some newer modules may rely primarily on an outbound connection from the device to GREE cloud services instead of exposing the legacy local UDP/7000 interface. It is still possible that particular models use another LAN protocol, port or activation handshake; this has not been confirmed.

A useful diagnostic distinction is:

  • UDP/7000 replies are present, but bind/decryption fails — likely a protocol, key or binding issue.
  • UDP/7000 replies use an unexpected payload — potentially a newer local protocol variant.
  • The unit has an IP address and works in GREE+, but sends no UDP/7000 reply — likely not fixable by changing the existing encryption mode; the local LAN API may be disabled or replaced.

Some newer GREE models can also expose energy-consumption information in GREE+. This is a separate capability and does not prove that the legacy UDP API is available. GREE Controller currently does not read or expose energy/power-consumption telemetry from the unit.

If a newly manufactured or recently updated unit cannot be discovered, capture its model, Wi-Fi module model, firmware version and GREE traffic diagnostics before reporting the issue. Avoid assuming that a higher firmware number alone identifies the protocol generation.

Multi-NIC / dedicated GREE interface

For a host with separate management and GREE networks, set for example:

GREE_CONTROLLER_GREE_INTERFACE=eth1

or a local address:

GREE_CONTROLLER_GREE_INTERFACE=192.168.50.2

The controller will use that interface for GREE UDP traffic while keeping the HTTP UI on GREE_CONTROLLER_BIND.

Diagnostics:

sudo ./scripts/configure-gree-network.sh eth1
./scripts/network-debug.sh eth1

The hardened systemd unit allows AF_NETLINK, which is required for interface discovery on multi-NIC Linux/LXC systems.

Thermostat model

Devices vs zones

A Device is the physical GREE unit. Device commands are direct/technical commands.

A Zone is the thermostat owner for a device. It decides demand from room temperature, setpoint, hysteresis, schedules, house rules, manual ownership and safety lockouts. Group control can temporarily apply shared settings. Turning a group OFF powers its member units down and releases group ownership; each thermostat can then be switched back on independently without an OFF group acting as a membership block. After handing an OFF thermostat back to automation, an implicit Comfort target alone does not start it: the zone waits for an active schedule, manual preset/setpoint, Temporary Quick Thermostat, active group/local control or another explicit automatic power intent.

Compressor protection

Controller-side compressor protection is enabled by default and uses a 3-minute window. The switch and duration are available under Settings → GREE. Thermostat, group and whole-house starts or Heat/Cool reversals that fall inside the window are kept as visible pending tasks instead of being discarded. The pending task is shown on both the thermostat and its device card. A permanent Queue button above Thermostats opens a global modal sorted by execution time, with device/zone, command, owner, protection deadline, live countdown, per-task cancellation and Cancel all. Safety OFF commands remain immediate.

This distinction is important: direct device control intentionally behaves differently from thermostat control.

Control ownership

The zone state exposes who currently owns control (control_owner, control_source, timestamps and reason). Physical remote/direct device actions can create a manual-device takeover so normal schedules do not immediately overwrite the user. Explicit zone thermostat control hands ownership back to the thermostat engine when appropriate.

Global Turn all off is an immediate bulk thermostat action: it powers every enabled unit off and leaves every thermostat locally OFF with no hand-back timer, but it does not create a persistent blocking gate. A later Resume automation releases only that zone to automatic arbitration; when no schedule/override/temporary or other explicit intent is active, it stays OFF. Turn all on is different: it is an explicit whole-house ON intent, releases local OFF markers and sends ON to enabled units; compressor protection may queue protected starts. Explicit local/group/manual control still has priority.

Profiles and schedules

Each zone stores separate cooling and heating temperatures for:

  • Comfort
  • Sleep
  • Away
  • Custom/manual target

Schedules select profiles or a custom target for selected ISO weekdays (1=Monday, 7=Sunday). Overnight windows are supported. Overlapping enabled schedules for the same zone are rejected.

Visual Flow

Flow is the authoring layer for combined schedules and automations. The full-screen editor stores a block graph as the source of truth and compiles it automatically: a pure weekday + time-range + thermostat path becomes a native schedule, while richer logic becomes a generated automation. Generated schedule/automation rows carry their Flow provenance and are read-only in the legacy editors. Stateful blocks include optional 5-field CRON triggers, continuous stable_for, bounded state duration, change/edge detection, rolling execution rate limits, delay-before-action, rolling mean/median windows and oscillation detection; their runtime state survives restarts. Generic Home Assistant service actions can call any configured domain.service with an optional entity and JSON service data.

The reusable Flow preset library is stored as standalone JSON files in presets/. Each file contains its name, description and complete Flow graph, while the UI loads the embedded preset catalog dynamically instead of hard-coding graphs in JavaScript. The library has category tabs, search, local favorites/recent presets, a graph preview and requirement checks before applying a preset.

Available blocks include weekday/time/date ranges, the application Night mode, outdoor/device/zone temperature, house/device/zone/group state, arbitrary Home Assistant state/numeric/attribute/availability checks, a constant diagnostic source, AND/OR/NOT, thermostat actions, direct GREE actions and group actions. The GREE action uses the existing DeviceCommand fields (power, mode, target, fan, swing, quiet, turbo, light, air, xfan, health and sleep). Multiple branches can feed an action; the compiled runtime preserves the graph logic.

Quick preset/setpoint overrides normally hand control back at the next schedule boundary. Temporary Quick Thermostat adds explicit start/finish rules such as duration, exact time, temperature reached/stable or next schedule boundary.

Implementation and concurrency invariants are documented in docs/FLOW.md.

Home Assistant

There are two independent Home Assistant directions.

1. Home Assistant as a temperature source

In the Home Assistant add-on, the connection to Home Assistant Core is automatic through the Supervisor API proxy; no Home Assistant URL or Long-Lived Access Token is required.

When the add-on detects SUPERVISOR_TOKEN, Home Assistant ingress remains trusted, but direct Web UI/API access on TCP 8787 requires app_token. If app_token is empty, direct dashboard/API access is disabled. The Home Assistant add-on intentionally uses 8787 as a fixed internal ingress/application port; it is not a user-configurable Network option. The startup script verifies the Supervisor-reported ingress_port and refuses to start on a mismatched manually modified package. History → Custom Charts → Copy link creates a random persisted share token and returns a chart-only URL. The add-on resolves the primary HA host IPv4 through the Supervisor API and uses http://<HA-IP>:8787 by default; public_chart_base_url can override that address for a reverse proxy or non-standard routing. Standalone mode uses the current controller origin/base path and follows GREE_CONTROLLER_BIND. Only the generated chart view/data endpoint is public to the network.

For standalone installations, configure Home Assistant / Sensors in the Web UI or use:

HA_URL=
HA_TOKEN=
HA_OUTDOOR_ENTITY_ID=
HA_SENSOR_STALE_AFTER_SECONDS=300
HA_ALLOW_INVALID_TLS=false

In standalone mode, the Home Assistant connection test checks only HA_URL and HA_TOKEN; no entity is required. HA_OUTDOOR_ENTITY_ID is the optional global outdoor-temperature sensor. Per zone, sensor_source can be:

  • device — GREE indoor sensor,
  • home_assistant — Home Assistant room sensor,
  • combined — weighted GREE + Home Assistant value.

For home_assistant and combined, each zone must set its own ha_entity_id room-temperature sensor. Room sensors are independent from the outdoor-temperature source and stale/unavailable room data falls back to the GREE sensor when possible.

HA_OUTDOOR_ENTITY_ID is the global outdoor-temperature source used by outdoor-temperature assist. A zone may leave ha_outdoor_entity_id empty to use that global sensor, or set ha_outdoor_entity_id to use a different outdoor sensor only for that zone. If a zone override is unavailable, the controller falls back to the global outdoor source. Global and per-zone outdoor sensors are exposed through the normal alias/history/metric paths and appear in Home Assistant entity suggestions used by Visual Flows.

2. GREE Controller entities inside Home Assistant

Bundled integration directory:

ha-addon/home-assistant/custom_components/gree_controller/

Copy gree_controller to Home Assistant's custom_components directory, restart Home Assistant and add GREE Controller from Integrations.

Create a restricted token in Home Assistant / Sensors → Access tokens. The token secret is displayed only once and the database stores only its SHA-256 hash. The integration uses a restricted /api/integrations/home-assistant/* surface rather than administrator endpoints.

The integration exposes physical device climate controls, thermostat zone climate entities, whole-house controls, groups and optional unit capabilities. Prefer zone thermostat entities for normal comfort control; physical device entities are direct/manual controls.

For entity-ID migration tooling:

python3 scripts/generate_ha_migration.py --help

The generated mapping example is under ha-addon/home-assistant/generated/.

History and InfluxDB

SQLite is the local hot store. History compaction reduces older local sample density while preserving the resolutions needed by charts. Retention is configurable from the UI or environment.

Optional InfluxDB writes samples in parallel and can serve the older part of long history queries:

  • InfluxDB 1.x: URL, database, optional username/password.
  • InfluxDB 2.x: URL, organization, bucket and token.

If an Influx query fails, the API returns available SQLite data and can include a storage_warning rather than discarding the whole history response.

See GET /api/history for scopes and bucket behavior.

Notifications

Optional notifications support:

  • Pushover
  • Slack webhook
  • Discord webhook

Modes can report problems only or problems plus important state changes. Individual categories include sensor freshness/errors, communication failures, target timeout, automation/control errors and other warnings. Cooldown and failure thresholds are configurable.

Debugging

Enable Settings → Application → On-screen debug.

The overlay has three filters:

  • All — request diagnostics, application events and GREE frames,
  • Requests — HTTP method/path/status/duration,
  • GREE — sanitized protocol frames when GREE frame logging is enabled.

Binding/encryption keys are not intentionally exposed in GREE debug frames.

For Linux/network issues also use:

./scripts/network-debug.sh
./scripts/service.sh logs

Backup and restore

Settings → Application → Configuration backup exports settings, devices, zones, groups, schedules, automations and Flows.

The export intentionally does not contain metric history, event history or generated API-token records. It does contain GREE binding keys and configured integration secrets, so store it like a credential file.

Import replaces application configuration while preserving local metric/event history and generated access-token records. Runtime ownership/timers are sanitized and live device state is re-polled before automatic control resumes.

Reverse proxy and sub-path deployment

For a root deployment, proxy HTTP and WebSocket traffic to the controller normally.

For a sub-path, configure:

GREE_CONTROLLER_BASE_PATH=/gree

Then serve the application under /gree/. The proxy must preserve WebSocket upgrade headers. A typical nginx location is:

location /gree/ {
    proxy_pass http://127.0.0.1:8787/gree/;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    proxy_set_header Host $host;
}

If your proxy strips the prefix, keep its upstream/base-path handling consistent. Do not publish the controller directly to an untrusted network without authentication and TLS at the proxy/VPN layer.

Security

The default empty GREE_CONTROLLER_APP_TOKEN is intended for a trusted LAN only. Set a long random token when the interface is reachable by other networks.

Implemented safeguards include:

  • optional bearer administrator authentication,
  • separate restricted generated tokens for Home Assistant,
  • hashed generated-token storage,
  • secrets omitted from normal settings responses,
  • restrictive security headers and no permissive CORS,
  • API responses marked no-store,
  • hardened systemd service,
  • safe device power-off behavior when thermostat ownership is removed,
  • startup synchronization before the thermostat engine begins issuing commands.

For remote access, prefer a VPN or authenticated TLS reverse proxy. Treat configuration exports and /etc/gree-controller.env as secrets.

Localization

Language packs are JSON files under lang/. The build validates/embeds them and generates the public language catalog.

To add a language:

  1. Copy lang/en.json to lang/<code>.json.
  2. Update meta.code, names and locale.
  3. Keep the same translation keys as the reference pack.
  4. Rebuild the Rust binary.

Runtime assets are available at /lang/index.json and /lang/<code>.json.

API

The HTTP API is the same backend used by the Web UI. It includes devices, zones, groups, house control, schedules, automations, history, control plan, events, functional settings resources, configuration backup/restore, tokens and integration tests.

Breaking in 0.12.0: the monolithic /api/settings, /api/debug, /api/events/retention and /api/settings/{export,import} routes were removed. Settings now live under /api/settings/application, /gree, /history, /influxdb, /notifications, /night, /home-assistant and /debug; configuration backup uses /api/configuration/export and /api/configuration/import.

Start here:

docs/API.md — complete API reference

Interactive API documentation is built into the controller:

  • Swagger UI: http://127.0.0.1:8787/api-docs
  • OpenAPI 3.1 JSON: http://127.0.0.1:8787/api-docs/openapi.json

Swagger UI includes endpoint descriptions, authentication schemes, request/response models, examples and documented error responses. If GREE_CONTROLLER_BASE_PATH is configured, prefix both paths with that base path.

Health check (public in standalone mode; in Supervisor mode anonymous only from the Supervisor watchdog, otherwise protected by GREE_CONTROLLER_APP_TOKEN):

curl http://127.0.0.1:8787/api/health

Authenticated example when an app token is configured:

curl -H 'Authorization: Bearer YOUR_TOKEN' \
  http://127.0.0.1:8787/api/system/info

Project layout

src/                         Rust backend, GREE protocol and thermostat engine
web/                         Embedded Web UI / PWA
web/js/                      Standalone/static frontend scripts
web/js-dynamic/              Application JS modules bundled by build.rs
lang/                        Runtime language packs
ha-addon/                    Home Assistant add-on, custom integration and release tooling
scripts/                     Development, install, update, service and diagnostics
systemd/                     Production service unit
docs/API.md                  Complete API documentation
.env.example                 Environment reference

The application is intentionally self-contained: static assets and language packs are embedded into the binary at build time; SQLite is the default data store; no external frontend build chain is required. build.rs concatenates the ordered files from web/js-dynamic/ into one generated application bundle and exposes it under a content-hashed URL.

Validation before release

Recommended full check on a host with Rust installed:

./scripts/dev.sh --check

This runs formatting checks, Rust tests, a build and an isolated simulated API smoke test.

License

See LICENSE.

Flow diagnostics, portability and concurrency

Flow reuses the existing thermostat, group and device-control domains instead of maintaining a second HVAC controller. Thermostat actions update the persistent zone intent and wake the normal zone-control engine, so hysteresis, compressor protection, schedule hand-back, Temporary Quick Thermostat and ownership rules remain authoritative. Flow group actions call the existing group controller; direct device actions use the existing automatic-device action path and DeviceCommand. A Flow thermostat OFF also performs the existing forced physical OFF transition. Durable thermostat/device transitions are serialized with the thermostat cycle and then use the canonical zone -> device lock order.

The editor supports optimistic revisions, so saving an older copy from another browser/tab returns HTTP 409 instead of overwriting a newer graph. Flow compilation/replacement is serialized with configuration, automation, schedule and thermostat-cycle locks, and generated schedules/automations plus the Flow source are replaced in one SQLite transaction. Runtime condition evaluation happens before the automation execution lock; after acquiring it the rule is reloaded and stale snapshots are discarded. Same-cycle actions claim their target devices deterministically, and Flow/device thermostat writes take the schedule -> thermostat-cycle -> zone -> device path. Home Assistant read failures fail closed instead of making NOT/neq logic accidentally true.

Diagnostics include a non-mutating dry-run endpoint/UI with a selectable simulation time, optional per-block sensor/state overrides, a per-node condition trace and an ownership/block reason. Shared Home Assistant Flow inputs can also be tested directly in their editor against the current HA entity state. Flow-scoped execution and dry-run events can be viewed from the editor.

Individual Flows can be exported/imported as versioned gree-controller-flow JSON. Generated schedules and automations are intentionally excluded from the portable document and are regenerated from the source graph on import. Incomplete Flows can also be saved as disabled drafts; drafts preserve the editor graph but intentionally generate no schedules or automations until completed and saved normally. Shared inputs show which Flows reference them and link directly to those editors. The preset library includes 37 categorized scenarios for comfort, energy, safety, night, reliability, Home Assistant heat-source coordination and advanced multi-branch logic.