GREE Controller
Identifier convention: project-owned namespace identifiers use
gree_controller. Home Assistant usesgree_controller, UI storage usesgree_controller_*, and environment variables useGREE_CONTROLLER_*.
Standalone local GREE air-conditioner controller written in Rust. It runs on a regular Linux host or an LXC container and provides a mobile-first web interface without depending on the vendor cloud.
Current version: 0.8.4.
Highlights
- local GREE discovery over UDP/7000,
- V1 AES-128-ECB and V2 AES-128-GCM discovery/bind/status/command transport,
- automatic ECB/GCM detection from discovery responses and bind fallback,
- power, HVAC mode, target temperature, fan, vertical/horizontal swing, quiet, turbo and display light,
- capability discovery and control for optional GREE X-FAN, Air, Health and native Sleep features,
- SQLite state/history/event storage,
- automatic SQLite history compaction plus optional InfluxDB 1.x/2.x long-term archive,
- smart thermostat zones with global house Heat/Cool/Off mode and per-zone overrides,
- setpoint modulation that keeps indoor units powered during normal operation instead of repeatedly cycling power,
- Comfort/Sleep/Away profiles, temporary overrides and one-tap Sleep,
- named climate groups (for example Upstairs/Downstairs) with independent power, Heat/Cool/house-follow mode and profile control, including automation targets,
- editable weekly schedules plus Family/Child room/Bedroom/Workday/Always-comfort templates,
- temperature/time automations for advanced exceptions,
- per-zone optional Home Assistant room-temperature sensors with GREE fallback,
- optional Home Assistant outdoor-temperature assist for setpoint/fan decisions,
- opt-in support for self-signed/invalid HTTPS certificates on the outbound HA sensor connection,
- combined zone temperature using configurable GREE/external sensor weighting and discrepancy protection,
- REST API and WebSocket updates,
- responsive PWA optimized for phones,
- dashboard automation-plan blocks showing current zone decisions and upcoming schedule changes,
- Node-RED-style live automation flow board with sensor → thermostat → decision → unit command nodes, group/unit filtering, standalone-tab view and browser full-screen mode,
- configurable night mode with quiet hours, maximum fan speed and optional GREE Quiet/native Sleep requests,
- configurable event-log retention and presentation-only Home Assistant sensor aliases used by history charts/selectors,
- settings import/export and an optional live debug overlay with API logs and decrypted GREE frame payloads,
- JSON-based UI localization loaded from embedded
lang/*.jsonlanguage packs, - light, dark and system appearance modes stored in a browser cookie,
- optional Bearer-token authentication,
- simulator mode for development without physical hardware,
- Debian/Ubuntu LXC systemd installer,
- Home Assistant custom integration that proxies device
climatecommands, exposes full zone thermostat entities and publishes every climate group as a separate HA device with power, mode, profile and control-plan entities, - migration mapping generator for retaining existing HA entity IDs such as
climate.klima_salon.
See BUILD_REPORT.md for package validation details and docs/LXC.md for the LXC deployment/update workflow.
Quick start
On Debian, Ubuntu or an LXC container:
unzip gree-controller-v0.8.4.zip
cd gree-controller
chmod +x scripts/*.sh
./scripts/dev.sh
scripts/dev.sh installs missing build tools when possible, installs stable Rust with rustup when required, creates .env, builds the application and starts the web panel.
Default address:
http://HOST_ADDRESS:8787
The first empty database can be seeded with Living Room (simulator) so the UI, history, zones and automations can be tested without an AC.
Development commands
./scripts/dev.sh --check
./scripts/dev.sh --release
./scripts/dev.sh --reset
./scripts/dev.sh --host 0.0.0.0 --port 8787
./scripts/dev.sh --no-install
Web interface
The UI is mobile-first and uses no external CDN.
Language selector:
- English is the required default/fallback language,
- Polish is included,
- additional languages are discovered automatically from
lang/*.jsonat build time.
The selected language is stored in the gree_controller_language cookie. The UI contains no hard-coded list of supported languages. To add a language, copy lang/en.json, translate the translations values, set the meta fields, save it as <code>.json, and rebuild. For example, lang/de.json becomes an additional language after cargo build / ./scripts/dev.sh. Missing translation keys fall back to English.
See docs/LOCALIZATION.md for the language-pack format and validation rules.
Appearance selector:
- System,
- Light,
- Dark.
The selected appearance is stored in the gree_controller_theme cookie. The current UI keeps the classic GREE Controller interface: large rounded cards, circular thermostat controls, compact desktop navigation and mobile bottom navigation. It keeps the newer neutral dark/light palette and green accent (#3ecf8e in dark mode and #24b47e in light mode).
Static offline CSS
The interface is plain static CSS. web/styles.css is committed with the project and embedded directly into the Rust binary. There is no frontend package manager, CDN, or CSS build step. Edit web/styles.css and web/index.html directly, then rebuild the Rust application.
Connecting a physical GREE device
- Put the controller and AC in a network where UDP/7000 traffic is allowed.
- Open the web interface and select Discover.
- Start with Auto (V1 + V2) and 3 scan passes. The controller recognizes ECB responses and GCM responses carrying a
tagand automatically binds discovered units. - If required, repeat discovery using V1 AES-ECB or V2 AES-GCM to isolate a model family.
- New devices immediately open a naming step so you can enter room-friendly names such as Salon or Sypialnia. They can also be renamed later from Devices -> Rename. Re-discovery preserves your custom name.
- If LXC/VLAN broadcast does not pass, add the unit manually with IP and MAC/CID.
Version 0.3.7 additionally uses forgiving GREE Base64 decoding for non-canonical GCM tags seen on real Wi-Fi modules, automatically selects the directly connected local IPv4 interface for unicast GREE traffic, and refreshes the short bind window with a subnet broadcast immediately before bind. A single lost UDP response no longer marks a device offline; three consecutive communication failures are required.
LXC/systemd installation and updates
All operator scripts are under scripts/. On a clean Debian/Ubuntu LXC container:
chmod +x scripts/*.sh
sudo ./scripts/install.sh
The installer installs build dependencies/Rust when required, runs the Rust tests, builds a release binary, creates the gree-controller service account, stores runtime data in /var/lib/gree-controller, installs the binary under /opt/gree-controller, creates /etc/gree-controller.env, generates an administrator token and enables the systemd service. Existing /etc/gree-controller.env is preserved.
For a later release, unpack the new source archive and run:
sudo ./scripts/update.sh
The update is designed for LXC testing and production-style upgrades: compilation/tests happen before the running service is stopped; then the script backs up the installed binary, service unit, environment file and stopped SQLite database under /var/backups/gree-controller/<timestamp>/. After replacement it checks /api/health. A failed startup triggers automatic rollback to the previous binary, unit and database backup.
Service helpers:
./scripts/service.sh status
sudo ./scripts/service.sh restart
./scripts/service.sh logs
./scripts/service.sh health
Use --skip-tests with install.sh or update.sh only when you explicitly want to skip cargo test --all-targets. scripts/install-lxc.sh remains as a compatibility alias to scripts/install.sh.
Environment configuration
| Variable | Default | Purpose |
|---|---|---|
GREE_CONTROLLER_BIND |
0.0.0.0:8787 |
HTTP/WebSocket bind address |
GREE_CONTROLLER_DATABASE |
./data/gree-controller.db |
SQLite file |
GREE_CONTROLLER_APP_TOKEN |
empty | Bearer token; empty disables API authentication |
GREE_CONTROLLER_SIMULATE |
false |
Enables simulator seeding for development/testing |
GREE_CONTROLLER_AUTO_SEED |
false |
Seeds a simulator into an empty database when simulation is enabled |
GREE_CONTROLLER_POLL_INTERVAL_SECONDS |
15 |
Device polling interval |
GREE_CONTROLLER_ZONE_INTERVAL_SECONDS |
5 |
Zone-control interval |
GREE_CONTROLLER_DISCOVERY_TIMEOUT_MS |
3000 |
UDP discovery timeout |
GREE_CONTROLLER_DISCOVERY_BROADCAST |
255.255.255.255:7000 |
Discovery broadcast target |
GREE_CONTROLLER_GREE_INTERFACE |
empty | Optional Linux interface used for all GREE UDP traffic, e.g. eth1 |
GREE_CONTROLLER_ID |
gree-controller |
Controller instance identifier used for logs/metadata; the GREE wire protocol uses the standard cid=app |
GREE_CONTROLLER_HOUSE_MODE |
cool |
Initial seasonal house mode: cool, heat or off |
GREE_CONTROLLER_OUTDOOR_ASSIST_ENABLED |
true |
Initial outdoor-temperature assist state |
GREE_CONTROLLER_HISTORY_RETENTION_DAYS |
30 |
Local SQLite retention before pruning |
GREE_CONTROLLER_HISTORY_COMPACTION_ENABLED |
true |
Compact old local samples to chart-oriented resolution |
GREE_CONTROLLER_SUPPRESS_DEVICE_BEEP |
false |
Send only changed fields and request GREE buzzer suppression where supported |
GREE_CONTROLLER_INFLUX_ENABLED |
inferred from URL | Enable optional long-term InfluxDB archive |
GREE_CONTROLLER_INFLUX_VERSION |
2 |
1 for InfluxDB 1.x or 2 for InfluxDB 2.x |
GREE_CONTROLLER_INFLUX_URL / INFLUXDB_URL |
empty | InfluxDB base URL |
GREE_CONTROLLER_INFLUX_THRESHOLD_DAYS |
30 |
Read history older than this age from InfluxDB |
GREE_CONTROLLER_INFLUX_DATABASE |
gree_controller |
InfluxDB 1.x database |
GREE_CONTROLLER_INFLUX_USERNAME / GREE_CONTROLLER_INFLUX_PASSWORD |
empty | Optional InfluxDB 1.x credentials |
GREE_CONTROLLER_INFLUX_ORG / GREE_CONTROLLER_INFLUX_BUCKET / GREE_CONTROLLER_INFLUX_TOKEN |
empty | InfluxDB 2.x organization, bucket and token |
GREE_CONTROLLER_DEBUG_OVERLAY |
false |
Show the live debug window on every web view |
GREE_CONTROLLER_DEBUG_GREE_FRAMES |
false |
Stream decrypted GREE request/response payloads into debug |
HA_URL |
empty | Optional Home Assistant URL |
HA_TOKEN |
empty | Optional Home Assistant Long-Lived Access Token |
HA_ENTITY_ID |
empty | Optional default HA room-temperature sensor |
HA_OUTDOOR_ENTITY_ID |
empty | Optional HA outdoor-temperature sensor |
HA_ALLOW_INVALID_TLS |
false |
Opt in to invalid/self-signed HA HTTPS certificates |
Settings changed from the web panel are stored in SQLite. Explicit history/debug/Influx environment variables override their persisted values at process startup. Supplying an Influx URL enables the archive unless GREE_CONTROLLER_INFLUX_ENABLED=false is explicitly set. GREE_CONTROLLER_APP_TOKEN is loaded at process startup.
Web UI organization: Settings contains controller/application and technical storage/debug options, while Night mode and Home Assistant / Sensors are separate pages under More. Disabled zones continue reporting room temperature even though thermostat control is stopped.
Climate history
History is collected independently for physical GREE devices, control zones, and configured Home Assistant temperature sensors. Device samples continue to use the long-standing readings table, so upgrading does not require waiting for a new zone-history table to fill. When rich zone_readings are not available yet, the API automatically reconstructs a compatible zone timeline from existing device readings.
The History area has linkable sub-pages:
/history/overview— all GREE indoor temperatures, available GREE/HA outdoor temperatures, and all zone control temperatures,/history/zones— all zones or one detailed zone with GREE, HA room, control, target and device-setpoint series,/history/devices— indoor temperature, availableOutEnvTem, and target for every GREE unit,/history/sensors— configured Home Assistant room/outdoor temperature sensors,/history/custom— compose arbitrary series, save chart definitions in the browser and copy a URL that recreates the chart.
A zone timeline includes GREE indoor temperature, optional HA room temperature, calculated control temperature, active profile target, actual setpoint sent to the AC, available outdoor temperature, demand, power, mode and fan speed. HA sensor samples and zone samples are throttled to at least 15 seconds (or the configured device poll interval, whichever is longer). Local samples older than 24 hours are compacted to 10-minute resolution and samples older than 7 days to 30-minute resolution. When InfluxDB is configured, older queries are merged from InfluxDB with recent SQLite history. The maintenance task backfills compacted legacy samples into InfluxDB and deletes an old SQLite sample only after the archive write succeeds, so an unavailable archive does not cause local data loss.
All main UI views also use browser URLs (/dashboard, /devices, /zones, /groups, /schedules, /automations, /simulation, /settings, /events) so refresh, browser Back/Forward, bookmarks and direct links work normally.
Per-zone room temperature sensors
Each control zone can pair one GREE indoor unit with its own optional room sensor from Home Assistant. This is intentionally configured per zone, so rooms do not share a global temperature source.
Example:
Living room -> GREE Living Room + sensor.living_room_temperature
Bedroom -> GREE Bedroom + sensor.bedroom_temperature
Office -> GREE Office + sensor.office_temperature
Zone temperature strategies:
- GREE only — use the AC internal sensor.
- GREE + room sensor — recommended; calculate a weighted control temperature from both sensors. The default room-sensor weight is 40%.
- Room sensor only — use the assigned HA room sensor, with automatic fallback to GREE if HA or the entity becomes unavailable.
For combined control, max_sensor_difference protects against an obviously incorrect external measurement. If the two sensors differ by more than the configured threshold (default 3.0°C), the zone uses the GREE temperature and logs a sensor-discrepancy event.
The zone API exposes device_temperature, external_temperature, current_temperature (the actual control temperature) and control_temperature_source for diagnostics. Existing SQLite zone records remain compatible because the new fields have defaults and are stored in the existing JSON payload.
Zone cards are fast thermostats: - / +, Auto schedule / Comfort / Sleep / Away, Global / Heat / Cool, and local thermostat ON/OFF are available without opening the edit dialog. Local ON/OFF is thermostat ownership, not direct/pilot control: a locally started zone can bypass a disabled climate-group power gate while still using its room sensor, hysteresis, selected target/profile, Smart Fan and GREE setpoint modulation. Resume automation removes that local power override and returns the zone to group/schedule ownership; if its group is off, the unit then stays off. Only a real physical/remote change or the technical Devices command path creates device_manual_override. Controller-originated GREE transitions are tracked through the short device settling window so group/thermostat commands are not misclassified as remote takeover. Temporary thermostat overrides otherwise end at the next schedule boundary; when a local thermostat is explicitly active, its selected manual target/profile is retained until Auto/Resume is chosen.
Smart thermostat and schedules
Version 0.4.0 is designed around a simple rule: during normal heating/cooling, keep the indoor unit powered and modulate its target instead of repeatedly switching the unit OFF and ON. When a room is satisfied, cooling moves the device target above the comfort target and heating moves it below the comfort target. When hysteresis requests conditioning again, the working target is restored. Smart Quiet and standby Low fan are transition hints rather than commands that are blindly reasserted every adjustment interval, avoiding unnecessary beeps when the room and device setpoint are already stable. House Off is now a no-control state for inherited zones, so manual device operation is not overwritten; whole-house master power on/off is available separately and can authoritatively keep every unit off without changing the selected thermostat mode. Disabled zones are excluded from normal house/group/automation control; their physical unit remains available for explicit technical control from the Devices view.
Choose one seasonal global mode — Cooling in summer, Heating in winter, or Off. Zones inherit this global mode by default, while a zone may explicitly override Heat/Cool when required. In Mode policy, leave Follow global mode unchanged when the zone should inherit the mode selected globally in GREE Controller; Cooling only / Heating only are deliberate per-zone overrides. Each zone has separate Comfort/Sleep/Away temperatures for cooling and heating.
Schedules store profiles rather than duplicating temperatures. Ready-made Family, Child room, Bedroom, Workday and Always comfort templates generate ordinary editable schedule entries. For example, a child room template can enter Sleep earlier; if the child goes to bed even earlier, press Sleep and that zone remains in Sleep until its next schedule boundary (or until manually cleared when no future boundary exists). Whole-house Comfort all / Sleep all / Away all / Auto schedule actions are also available.
The optional HA outdoor sensor is an assist signal only. It never replaces the room-control temperature. In extreme weather it can make the active device setpoint slightly more assertive and let Smart Fan increase airflow. When cooling is actually controlled from a valid external/combined room sensor, demand also forces the next lower whole-degree unit target (typically 0.5–1.0°C below the room target); the correction is disabled on GREE fallback and is not stacked above the outdoor-assist maximum.
At startup, thermostat, schedule and automation commands are held until one complete live device poll has finished. This prevents a restart from issuing commands based only on stale persisted device state while still preserving all saved zone, group, schedule, override and device configuration.
Home Assistant
There are two independent HA directions:
- HA as an optional sensor source: the Rust controller can read a selected HA sensor and use it for a zone.
- HA as a client of GREE Controller: the included custom integration creates
climateentities whose commands are sent to this Rust application.
For the HA client connection, open More -> Home Assistant / Sensors in GREE Controller and press Create new token. The secret is shown once. Paste that token into the Home Assistant GREE Controller integration together with the controller URL. Managed HA tokens are stored as SHA-256 hashes and are scoped to the dedicated HA device/control-plan/house-control/zone-control API; they cannot change controller settings or manage other tokens.
The outbound HA sensor client also supports local HTTPS endpoints such as https://192.168.50.25. If the server uses a self-signed, expired or hostname-mismatched certificate, enable Home Assistant / Sensors -> Allow invalid/self-signed HTTPS certificate. This disables certificate/hostname validation only for the controller's outbound Home Assistant sensor client and should only be used on a trusted LAN.
The second option is designed to replace the built-in/default GREE integration without changing automation/dashboard references.
Example migration target:
old: climate.klima_salon -> built-in GREE integration
new: climate.klima_salon -> GREE Controller custom integration -> Rust API -> AC
Generate an entity mapping:
./scripts/generate_ha_migration.py \
--entity climate.klima_salon \
--device gree-aabbccddeeff
Or validate against the controller and automatically use its only device:
./scripts/generate_ha_migration.py \
--entity climate.klima_salon \
--controller-url http://192.168.1.20:8787 \
--controller-token YOUR_CONTROLLER_TOKEN
The generated file must be copied to:
/config/gree_controller_entities.json
Full installation and safe takeover procedure: home-assistant/README.md and docs/HOME_ASSISTANT_MIGRATION.md.
API
Important endpoints:
GET /api/health
GET /api/bootstrap
POST /api/discovery
GET /api/devices
POST /api/devices
GET /api/devices/:id
PATCH /api/devices/:id
POST /api/devices/:id/bind
POST /api/devices/:id/poll
POST /api/devices/:id/command
GET /api/zones
POST /api/zones
POST /api/zones/:id/control
POST /api/zones/:id/schedule-template
GET /api/groups
POST /api/groups
GET /api/groups/:id
PUT /api/groups/:id
DELETE /api/groups/:id
POST /api/groups/:id/control
POST /api/house/control
POST /api/house/power
POST /api/house/preset
GET /api/schedules
POST /api/schedules
GET /api/automations
POST /api/automations
GET /api/readings
GET /api/history
GET /api/control-plan
GET /api/events
GET /api/settings
PUT /api/settings
GET /api/settings/export
POST /api/settings/import
GET /api/debug
PUT /api/debug
GET /api/access-tokens
POST /api/access-tokens
DELETE /api/access-tokens/{id}
POST /api/integrations/home-assistant/test
GET /api/integrations/home-assistant/devices
POST /api/integrations/home-assistant/devices/{id}/command
GET /api/integrations/home-assistant/control-plan
GET /api/integrations/home-assistant/groups
POST /api/integrations/home-assistant/groups/{id}/control
POST /api/integrations/home-assistant/house/control
POST /api/integrations/home-assistant/house/preset
POST /api/integrations/home-assistant/house/power
POST /api/integrations/home-assistant/zones/{id}/control
WS /ws
Example command:
curl -X POST http://127.0.0.1:8787/api/devices/sim-salon/command \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{"power":true,"mode":"cool","target_temperature":22,"fan_speed":3}'
/api/health is public. The normal controller API and Web UI require GREE_CONTROLLER_APP_TOKEN only when that administrator token is configured. The dedicated /api/integrations/home-assistant/* client endpoints always require either a generated HA access token or the administrator token. WebSocket accepts only the administrator token using ?token=....
More examples: docs/API.md.
Security
- The application does not terminate TLS. Use HTTPS reverse proxy or VPN on untrusted networks.
- Do not expose port 8787 directly to the public Internet.
- Use a long random
GREE_CONTROLLER_APP_TOKEN. - Protect
.env,/etc/gree-controller.env, SQLite data and HA tokens. - The controller sends device commands only to configured local-network devices.
Backup
For a systemd installation:
systemctl stop gree-controller
cp /var/lib/gree-controller/gree-controller.db /safe/backup/location/
systemctl start gree-controller
Development data is stored under data/ by default.
Project layout
src/api.rs HTTP API, WebSocket, embedded web assets
src/db.rs SQLite persistence and row/domain mapping
src/queries.rs all SQLite schema and SQL statements
src/engine.rs polling, zones, schedules and automations
src/protocol/ GREE UDP/AES discovery, bind, status, command
src/home_assistant.rs optional HA sensor client
web/ mobile-first bilingual PWA
home-assistant/custom_components/ HA custom integration
scripts/install.sh first LXC/systemd installation
scripts/update.sh safe LXC/systemd update with backup/rollback
scripts/service.sh service status/start/stop/restart/logs/health
scripts/dev.sh development build/run/check workflow
scripts/generate_ha_migration.py legacy HA entity-ID mapping generator
scripts/smoke.sh API smoke test
systemd/ systemd service unit
License
MIT. This project uses a community-reconstructed local device protocol and is not an official product of GREE Electric Appliances Inc.
Multi-NIC / dedicated GREE interface
For LXC hosts with a management NIC and a separate GREE/VLAN NIC, bind GREE UDP traffic explicitly to the GREE interface:
GREE_CONTROLLER_GREE_INTERFACE=eth1
GREE_CONTROLLER_DISCOVERY_BROADCAST=auto
GREE_CONTROLLER_SIMULATE=false
GREE_CONTROLLER_AUTO_SEED=false
GREE_CONTROLLER_GREE_INTERFACE is resolved to the interface current IPv4 address whenever a UDP socket is created, so DHCP address changes do not require hard-coding the source IP. GREE_CONTROLLER_DISCOVERY_BROADCAST=auto derives the subnet broadcast from the selected interface and overrides an older runtime value stored in SQLite.
Run sudo ./scripts/network-debug.sh eth1 10.87.65.127 to verify addressing and routing.
v0.3.7 LXC networking fix
The systemd service explicitly allows AF_NETLINK. This is required by Linux getifaddrs() when resolving GREE_CONTROLLER_GREE_INTERFACE on multi-NIC LXC installations. Without it, older releases could fail with Address family not supported by protocol (os error 97) even though the configured interface was correct.
v0.3.8 legacy V1 device compatibility
GREE protocol identifiers are now emitted as canonical lowercase hexadecimal in tcid and pack.mac. This improves compatibility with older V1 Wi-Fi modules (including devices in the 502cc6... family) that can answer discovery but silently ignore bind/status packets when MAC casing differs from their discovery identity. Stored device IDs and friendly names are not changed.
v0.4.0 smart thermostat
Zones now use setpoint modulation, global seasonal house mode, cooling/heating Comfort/Sleep/Away profiles, temporary per-zone overrides, ready-made editable schedule templates, whole-house preset actions and optional outdoor-temperature assist. The UI also uses theme-aware thin scrollbars and can opt in to invalid/self-signed certificates for the outbound Home Assistant sensor connection. Existing zones remain readable; a legacy zone keeps its previous setpoint as its comfort target until it is edited and saved with the new profile fields.
0.7.1 quick-control visual consistency
- Unified dashboard Quick Thermostats and Quick Manual Control under shared
quick-control-*CSS classes instead of separate dashboard-ID overrides. - Standardized compact option buttons, gaps and row grids across presets, HVAC modes, fan speeds and quick unit toggles.
- Kept full Zones and Devices pages at their existing larger control sizes; the compact style applies only to dashboard quick controls.
- Renamed the compact zone mode from House to Global to make its meaning explicit: the zone inherits the global Heating/Cooling mode selected in GREE Controller.
- Renamed Sleep now to Sleep in quick thermostat presets.
- Advanced the PWA cache key to
gree-controller-v071-quick-controls.
0.7.2 zone configuration separation
- The Zones view is now configuration-only: no live +/- temperature, preset or mode buttons are shown there.
- Current zone status remains visible as read-only context, together with mode policy, sensor strategy, hysteresis and Smart Fan configuration.
- The Control button opens the Dashboard, expands Quick thermostats and scrolls to the matching zone.
- The zone form no longer exposes the legacy/base
setpointas a live-looking control; profile temperatures remain configurable. - Live zone temperature, preset, mode and enable/disable controls remain available in Dashboard -> Quick thermostats.
0.7.3 Home Assistant climate groups
- Added climate groups to the restricted Home Assistant API.
- Each configured group is exposed as its own Home Assistant device with Power, Thermostat mode, Work profile and Control plan entities.
- Group mode options are Global, Cooling and Heating; Global means the member zones inherit the controller-wide Heating/Cooling selection.
- Group profile options are Auto schedule, Comfort, Sleep and Away.
- The group control-plan sensor reports member zones, online unit count, current average temperature, demand count and upcoming member schedule events.
- Mixed member modes/profiles are reported without inventing a false common value; choosing a group option normalizes all member zones through the existing group-control engine.
- Group commands use the restricted Home Assistant access token and the dedicated
/api/integrations/home-assistant/groups/*endpoints. - After adding/removing/renaming groups, reload the GREE Controller integration in Home Assistant so its entity/device registry is rebuilt.
0.7.6 Home Assistant command-state stability
- Physical-unit commands now tolerate the short GREE firmware settling window after a successful command ACK before publishing a contradictory status. This prevents stale immediate polls from producing visible
ON -> OFF -> ONstate bounce. - The Home Assistant coordinator keeps a just-accepted device command as a short-lived pending value while refreshing controller metadata. An overlapping stale read cannot temporarily roll back the HA climate/feature state; normal factual polling resumes automatically after the bounded guard window.
0.7.5 group power state visibility
- Group ON/OFF buttons now use the same strong active-state highlight as group mode and profile controls, so the current power gate is immediately visible.
- Simulator summary wording now uses Zones with demand / Strefy z zapotrzebowaniem instead of the less natural comfort-request wording.
0.7.4 manual remote override
- Physical GREE changes detected during polling for power, HVAC mode, target temperature and meaningful fan-speed changes now enter a per-zone Manual control / remote takeover state.
- While takeover is active, thermostat modulation, schedules, groups and direct-device automations observe the zone but do not overwrite the unit.
- The pre-takeover climate state is remembered. If the user returns the unit to that operational state, takeover clears automatically and Resume automation is no longer shown. If the unit was OFF before takeover, returning it to OFF is enough even when the remote retained a different dormant setpoint. Otherwise takeover expires at the next schedule transition when available; without one it remains until Resume automation or another explicit quick-thermostat action.
- Technical climate control from the Devices view uses the same takeover semantics, while unrelated controls such as panel light do not pause the thermostat.
- Disabled zones remain outside normal group/automation ownership; their unit can be operated manually.
- Turn all off remains authoritative: it clears all takeovers, disables groups and powers off enabled units. Whole-house/group ON paths do not wake zones currently protected by manual takeover.
- The UI and control-plan API expose the takeover state and its optional expiry.
0.7.7 Quick-control label fit
- Adjusted the five-column quick-device mode row so longer Polish labels such as Chłodzenie and Osuszanie receive more width without reducing the whole row font size.
- The change is limited to the dashboard quick-device mode row; thermostat/group layouts are unchanged.
- Rotated the PWA cache key so browsers fetch the corrected stylesheet after upgrade.
0.8.4 Scheduled Temporary Quick Thermostat start and ownership hardening
- Temporary Quick Thermostat can start immediately, after a configurable delay, or at a specific local date/time.
- Delayed sessions do not take thermostat ownership early: normal schedules and automations continue until the effective start instant.
- Duration, safety timeout and next-schedule-boundary finish rules are calculated from the effective start, not from the time the session is configured.
- Active temporary ownership keeps its requested target across schedule transitions and schedule edits; direct device automations and group climate changes cannot overwrite it while it is active.
- A local Quick Thermostat can run using the zone's local Heat/Cool mode even when the inherited house climate mode is set to Do not control; the separate whole-house master power remains authoritative.
- Cancelling a not-yet-started session only removes that session and does not clear unrelated quick-control state.
0.8.3 Temporary Quick Thermostat sessions
- Adds a separate persisted timed Quick Thermostat session without reusing the existing 15-minute local-OFF hand-back timer.
- Supports ending after a duration, at a date/time, after reaching a temperature, after continuously holding a temperature condition, or at the next schedule boundary.
- Temperature conditions support within/at-or-below/at-or-above operators, tolerance and an optional safety timeout.
- Active sessions show their countdown/status directly on the Quick Thermostat card and restore the previous automation-enabled state when finished.
- Moves the zone automation enabled switch out of Quick Thermostat controls so automation availability and temporary thermostat ownership are visually separate.
0.8.2 UI/i18n and Home Assistant sensor freshness
- fixes ownership translations that were accidentally stored outside the language-pack
translationsobject, - adds a configurable Home Assistant sensor freshness limit in the Home Assistant / Sensors settings page (default 5 minutes),
- keeps legacy non-default per-zone stale limits as API-level overrides,
- prevents taller Quick Thermostat / Direct Device cards from stretching neighbouring dashboard cards,
- adds build-time validation for misplaced language-pack keys.
0.8.0 Control ownership and thermostat safety
- Adds an explicit zone control-ownership model (
control_owner, command source, since/resume/reason) shared by the engine, API, Web UI and Home Assistant control plan. - Distinguishes direct Web, direct Home Assistant and external/remote takeovers. Quick Thermostat commands explicitly return ownership to the thermostat.
- Adds per-zone operation mutexes plus an optional monotonic
revisioncheck for conflict-safe zone updates without breaking older clients that do not send a revision. - Recomputes both thermostat override and physical-device manual takeover deadlines after schedule edits.
- Rejects stale Home Assistant temperature samples (default 300 seconds per zone) and falls back to the GREE sensor through the existing fallback path.
- Enforces automatic HVAC compressor protection: minimum OFF time before restart and an OFF delay when automatically changing Heat/Cool modes. Direct/manual commands and global safety OFF remain authoritative.
- Extends control-plan with desired vs actual HVAC state, ownership, block reason and lockout deadline.
- Shows the current control owner and timing in the Web dashboard. Home Assistant zone climate exposes the same diagnostics; the physical climate is named
Direct controlto make its semantics explicit.
0.7.13 Quick-thermostat race protection and GREE frame counters
- Quick thermostat actions from Web/Home Assistant are serialized with device polling, so a poll running at the same time cannot restore an older
device_manual_overridesnapshot after the thermostat deliberately takes control back. - Recent controller-originated climate transitions keep a bounded settling history of both requested and pre-command values. Delayed or out-of-order GREE status frames can pass through those known states without being misclassified as physical/pilot takeover.
- In Dashboard -> Quick thermostats, Global is disabled when the whole-house thermostat mode is Do not control. Heat/Cool remain available as explicit per-zone overrides.
- Settings now shows live UDP receive counters, both total and per configured air conditioner, since controller startup. Counters are independent of the debug-frame overlay and update over WebSocket.
0.7.12 Timed quick-thermostat hand-back
- Switching a single Quick Thermostat OFF now starts a 15-minute local-OFF window instead of leaving the zone outside automation indefinitely.
- The Web UI shows a live
MM:SScountdown and a Resume now action during that window. - At expiry, only local quick-thermostat ownership and its temporary quick profile/setpoint are cleared. The controller does not restore a stale physical ON/OFF state; it recalculates the current group, house mode, schedule, profile, room temperature and hysteresis.
- Every fresh local OFF action creates a new backend-owned 15-minute deadline; switching the local thermostat back ON cancels it.
- A physical/direct
device_manual_overrideremains separate and temporarily suspends expiry of an existing local-OFF hand-back. Returning the unit to its previous OFF state re-arms a fresh 15-minute countdown from that moment. - Persisted local-OFF state from 0.7.10/0.7.11 receives a fresh 15-minute hand-back deadline on the first controller cycle after upgrade.
0.7.11 Cleanup and Rust test fix
- Removed the obsolete
/api/zones/{id}/manual-powercompatibility endpoint and its handler; local thermostat power has one canonical API path:/api/zones/{id}/control. - Renamed dashboard internals from
manual-powerterminology tolocal-thermostat-powerto match the actual control model. - Fixed the Rust ownership error in
local_thermostat_ownership_blocks_direct_automationby borrowing the test zone viastd::slice::from_ref, so the test no longer moveszonewhile borrowingzone.device_id.
0.7.10 Local quick-thermostat ownership
- Quick thermostat ON/OFF now controls a dedicated local thermostat state instead of using remote/manual-device semantics.
- A locally started zone bypasses its disabled group power gate but keeps full thermostat regulation: room sensor, hysteresis, profile/target, Smart Fan and GREE setpoint modulation.
- Resume automation clears local thermostat ownership and returns the zone to group/schedule control.
- Physical remote/direct device changes remain the only source of
device_manual_override; explicit thermostat actions can take ownership back. - Controller-originated GREE changes that appear after the device settling window are correlated with the pending controller command, preventing group ON and thermostat commands from falsely showing Manual control / remote.
- Home Assistant zone climate ON/OFF now uses the same local thermostat power semantics instead of technically disabling the zone.
0.7.9 Zone profile control and Home Assistant stability
- Quick thermostat profile/mode/target/enable actions now wake the thermostat regulator immediately instead of waiting for the next fixed zone interval.
- A manual/remote takeover keeps the configured thermostat profile target visible; the physical GREE target is reported separately as the device setpoint. This prevents standby setpoints such as 25 C from being shown as the Sleep/Comfort target.
- Control-plan
enablednow represents the configured per-zone switch. A neweffective_enabledfield reports group gating, so Home Assistant zone switches/climate entities no longer bounce back to Off solely because a climate group is disabled. - Home Assistant zone controls use a short pending-state guard, matching the existing physical-device anti-bounce protection.
- Every zone now exposes a Work profile select and the zone
climateentity supports preset modes: Auto schedule, Comfort, Sleep and Away.
0.7.8 Zone status wording and unit power
- Zone runtime status now says Zapotrzebowanie aktywne when the thermostat is requesting work and Cel osiągnięty when the target/hysteresis condition is satisfied; Komfort remains only the preset name. Paused control is shown as Oczekiwanie, and missing control temperature as Brak pomiaru.
- Quick thermostats use one contextual Włącz jednostkę / Wyłącz jednostkę control instead of the redundant Jednostka · pilot caption and separate ON/OFF buttons.
- Direct unit power still behaves as manual/remote takeover and does not enable the whole group.