This commit is contained in:
Mateusz Gruszczyński
2026-09-03 13:08:28 +02:00
parent d7b6d0478f
commit b8ff31f205
52 changed files with 3874 additions and 1912 deletions
+133 -127
View File
@@ -1,6 +1,6 @@
# GREE Controller API reference
HTTP and WebSocket API for GREE Controller **0.11.6**.
HTTP and WebSocket API for GREE Controller **0.12.0**.
[← Main documentation](../README.md)
@@ -180,19 +180,21 @@ Common statuses:
| GET | `/api/history` | Rich device/zone/HA history. |
| GET | `/api/control-plan` | Current resolved thermostat plan. |
| GET | `/api/events` | Event/debug log. |
| GET | `/api/events/retention` | Current event retention. |
| PUT | `/api/events/retention` | Update retention and prune immediately. |
### Settings, backup and diagnostics
### Settings, configuration and diagnostics
| Method | Endpoint | Description |
| --- | --- | --- |
| GET | `/api/settings` | Public-safe runtime settings. |
| PUT | `/api/settings` | Update runtime settings. |
| GET | `/api/settings/export` | Export full application configuration. |
| POST | `/api/settings/import` | Import/replace application configuration. |
| GET | `/api/debug` | Read debug overlay settings. |
| PUT | `/api/debug` | Update debug overlay settings. |
| GET/PUT | `/api/settings/application` | Application runtime switches. |
| GET/PUT | `/api/settings/gree` | GREE controller, polling, discovery and compressor settings. |
| GET/PUT | `/api/settings/history` | Metric/event retention and compaction settings. |
| GET/PUT | `/api/settings/influxdb` | InfluxDB history settings. |
| GET/PUT | `/api/settings/notifications` | Notification provider and alert settings. |
| GET/PUT | `/api/settings/night` | Night mode settings. |
| GET/PUT | `/api/settings/home-assistant` | Home Assistant, aliases, shared Flow inputs and outdoor assist. |
| GET/PUT | `/api/settings/debug` | Debug overlay/GREE frame settings. |
| GET | `/api/configuration/export` | Export full application configuration. |
| POST | `/api/configuration/import` | Import/replace application configuration. |
| POST | `/api/integrations/home-assistant/test` | Test HA temperature read. |
| POST | `/api/integrations/home-assistant/entity` | Read raw HA entity state/attributes for shared Flow input diagnostics. |
| POST | `/api/integrations/notifications/test` | Send a test notification. |
@@ -228,7 +230,7 @@ Response:
{
"status": "ok",
"name": "gree-controller",
"version": "0.11.6",
"version": "0.12.0",
"uptime_seconds": 1234,
"control_ready": true,
"time": "2026-08-30T06:54:00Z"
@@ -249,10 +251,10 @@ Returns the initial Web UI snapshot:
"schedules": [],
"automations": [],
"access_tokens": [],
"settings": {},
"house": {"mode": "cool"},
"outdoor_temperature": null,
"system": {
"version": "0.11.6",
"version": "0.12.0",
"uptime_seconds": 1234,
"auth_required": false,
"control_ready": true,
@@ -1003,88 +1005,62 @@ Response:
}
```
### `GET /api/events/retention`
```json
{
"days": 30
}
```
### `PUT /api/events/retention`
```json
{
"days": 30
}
```
Value is clamped to `1..3650`; pruning happens immediately. Response includes `days` and number of removed rows.
---
## Runtime settings
## Runtime settings — 0.12.0
### `GET /api/settings`
Version `0.12.0` replaces the monolithic settings document with functional resources. There are no compatibility aliases for the removed `/api/settings`, `/api/debug` or `/api/events/retention` endpoints.
Returns a public-safe settings document. Secrets are blanked and accompanied by `*_configured` booleans where relevant.
Every settings resource supports `GET` and `PUT`. A `PUT` replaces only that functional section; it never requires or overwrites unrelated settings.
Shape:
### `/api/settings/application`
```json
{
"simulator_enabled": false
}
```
### `/api/settings/gree`
```json
{
"controller_id": "gree-controller",
"simulator_enabled": false,
"poll_interval_seconds": 15,
"zone_interval_seconds": 5,
"discovery_timeout_ms": 3000,
"discovery_broadcast": "255.255.255.255:7000",
"house_mode": "cool",
"house_power_enabled": true,
"control_strategy": "setpoint",
"outdoor_assist_enabled": true,
"history_retention_days": 30,
"history_compaction_enabled": true,
"event_log_retention_days": 30,
"suppress_device_beep": false,
"debug": {
"overlay_enabled": false,
"gree_frames": false
},
"night_mode": {
"enabled": false,
"start_time": "22:00",
"end_time": "06:00",
"max_fan_speed": 1,
"force_quiet": true,
"use_native_sleep": true
},
"notifications": {},
"influxdb": {},
"home_assistant": {}
"compressor_protection_enabled": true,
"compressor_protection_seconds": 180
}
```
#### Home Assistant settings
Validation/normalization:
- `controller_id` cannot be empty;
- polling and zone intervals: `2..3600` seconds;
- discovery timeout: `300..30000` ms;
- discovery broadcast: `auto`, `auto:*` or a socket address;
- compressor protection: `30..1800` seconds.
Changing compressor protection clears pending compressor runtime queues before thermostat control continues.
### `/api/settings/history`
```json
{
"url": "http://homeassistant.local:8123",
"token": "",
"token_configured": true,
"default_entity_id": "sensor.room_temperature",
"outdoor_entity_id": "sensor.outdoor_temperature",
"sensor_stale_after_seconds": 300,
"allow_invalid_tls": false,
"sensor_aliases": {
"sensor.room_temperature": "Living room"
}
"retention_days": 30,
"compaction_enabled": true,
"event_retention_days": 30
}
```
`default_entity_id` is primarily the entity used by the Home Assistant connection test when the request does not provide another entity. Thermostat zones use their own configured `ha_entity_id`; this setting does not automatically become a zone temperature source.
Retention values are clamped to `1..3650` days. Updating this section immediately prunes expired event rows. The former `/api/events/retention` endpoint no longer exists.
#### InfluxDB settings
### `/api/settings/influxdb`
`GET` returns a secret-safe view:
```json
{
@@ -1093,31 +1069,27 @@ Shape:
"url": "http://influxdb:8086",
"database": "gree_controller",
"username": "",
"password": "",
"password_configured": false,
"org": "home",
"bucket": "gree_controller",
"token": "",
"token_configured": true,
"history_threshold_days": 30
}
```
Version `1` uses database/optional username/password. Version `2` uses org/bucket/token.
`PUT` uses the same non-secret fields plus optional `password` and `token`. Omitting either field (or sending `null`) preserves the stored secret. Sending an explicit empty string clears it. `history_threshold_days` is clamped to `1..3650`; the complete InfluxDB configuration is validated before persistence.
#### Notification settings
### `/api/settings/notifications`
`GET` returns provider state without secret values:
```json
{
"enabled": true,
"mode": "problems",
"provider": "pushover",
"pushover_app_token": "",
"pushover_user_key": "",
"pushover_configured": true,
"slack_webhook_url": "",
"slack_configured": false,
"discord_webhook_url": "",
"discord_configured": false,
"cooldown_seconds": 300,
"communication_failure_threshold": 3,
@@ -1135,33 +1107,80 @@ Version `1` uses database/optional username/password. Version `2` uses org/bucke
}
```
Modes: `problems`, `important`. Providers: `pushover`, `slack`, `discord`.
`PUT` accepts the same behavioral fields plus optional `pushover_app_token`, `pushover_user_key`, `slack_webhook_url` and `discord_webhook_url`. Omitted/`null` secrets are preserved; an explicit empty string clears them. Modes: `problems`, `important`. Providers: `pushover`, `slack`, `discord`. Cooldown is clamped to `30..86400` seconds, failure threshold to `2..100`, target timeout to `5..1440` minutes.
### `PUT /api/settings`
### `/api/settings/night`
Accepts the complete `RuntimeSettings` document. Important behavior:
```json
{
"enabled": false,
"start_time": "22:00",
"end_time": "06:00",
"max_fan_speed": 1,
"force_quiet": true,
"use_native_sleep": true
}
```
- `house_mode` cannot be changed here; use House Control API. `house_power_enabled` is a legacy compatibility field and is normalized to `true`; global ON/OFF no longer uses a persistent master gate.
- polling interval is clamped `2..3600` seconds.
- zone interval is clamped `2..3600` seconds.
- discovery timeout is clamped `300..30000` ms.
- `control_strategy` is normalized to `setpoint`.
- discovery broadcast must be `auto`, `auto:*` or a valid socket address.
- blank HA token preserves the saved token.
- blank Influx token/password preserve saved secrets.
- blank Pushover/Slack/Discord secret fields preserve saved secrets.
- HA sensor age is clamped `30..86400` seconds.
- notification cooldown: `30..86400` seconds.
- communication failure threshold: `2..100`.
- target timeout: `5..1440` minutes.
- retention windows: `1..3650` days.
- night mode times must be `HH:MM`; max fan is clamped `1..5`.
Times must use `HH:MM`; maximum fan speed is clamped to `1..5`.
Returns the safe public settings form.
### `/api/settings/home-assistant`
### `GET /api/settings/export`
`GET` returns:
Returns configuration format version `1`:
```json
{
"url": "http://homeassistant.local:8123",
"token_configured": true,
"default_entity_id": "sensor.room_temperature",
"outdoor_entity_id": "sensor.outdoor_temperature",
"sensor_stale_after_seconds": 300,
"allow_invalid_tls": false,
"sensor_aliases": {
"sensor.room_temperature": "Living room"
},
"flow_inputs": [],
"outdoor_assist_enabled": true
}
```
`PUT` replaces `token_configured` with optional `token`. Omitted/`null` token preserves the saved token; an explicit empty string clears it. Sensor age is clamped to `30..86400` seconds. URLs, aliases, entity IDs and shared Flow inputs are normalized/validated before persistence. Shared inputs are value sources only; comparison operators and thresholds belong to Flow nodes.
### `/api/settings/debug`
```json
{
"overlay_enabled": true,
"gree_frames": true
}
```
When `overlay_enabled=true`, live HTTP diagnostics can emit `api.request`; `gree_frames=true` enables sanitized `gree.frame` events.
### Settings WebSocket events
Each section has its own event and payload:
```text
settings.application.updated
settings.gree.updated
settings.history.updated
settings.influxdb.updated
settings.notifications.updated
settings.night.updated
settings.home_assistant.updated
settings.debug.updated
```
The generic `settings.updated` and `debug.settings` events were removed in `0.12.0`.
---
## Configuration backup and restore
### `GET /api/configuration/export`
Returns configuration format version `3`:
```text
format_version
@@ -1172,13 +1191,14 @@ zones[]
groups[]
schedules[]
automations[]
flows[]
```
Export includes GREE binding keys and integration credentials. It excludes metric history, event rows and generated API-token records. Treat the export as a secret.
The export contains GREE binding keys and integration credentials. It excludes metric history, event rows and generated API-token records. Treat it as a secret backup.
### `POST /api/settings/import`
### `POST /api/configuration/import`
Accepts exactly the export document. The backend validates IDs/references/schedules/settings, safely stops devices whose ownership is being removed, clears transient ownership/timers/stale live state, replaces configuration, re-polls devices, then re-enables thermostat control.
Accepts only format version `3` and the `setpoint` control strategy used by `0.12.0`. The backend validates IDs/references (including shared Flow inputs against resources inside the backup), Flow draft safety, schedules, settings and ownership relationships; safely powers off devices being detached; clears transient runtime/ownership state; replaces configuration; re-polls imported devices; then resumes thermostat control.
Metric/event history and generated access-token records are preserved.
@@ -1192,27 +1212,6 @@ Response:
---
## Debug API
### `GET /api/debug`
```json
{
"overlay_enabled": true,
"gree_frames": true
}
```
### `PUT /api/debug`
Accepts the same object, persists it and broadcasts `debug.settings`.
When overlay diagnostics are enabled, live HTTP requests generate `api.request` WebSocket events containing method, path, status and duration. When `gree_frames=true`, sanitized GREE protocol events are also sent as `gree.frame`.
The Web UI can display **All**, **Requests** or **GREE** subsets.
---
## Integration tests
### `POST /api/integrations/home-assistant/test`
@@ -1424,9 +1423,16 @@ schedule.template_applied
automation.created
automation.updated
automation.deleted
settings.updated
settings.application.updated
settings.gree.updated
settings.history.updated
settings.influxdb.updated
settings.notifications.updated
settings.night.updated
settings.home_assistant.updated
settings.debug.updated
house.mode_changed
configuration.imported
debug.settings
api.request
gree.frame
log.created
@@ -1545,7 +1551,7 @@ Flow is the source-of-truth representation for visual schedule/automation logic.
Saving an executable Flow validates the DAG and compiles it atomically. If the editor receives HTTP 400 during normal save, it can offer to retry with `draft=true`; draft validation preserves the editable graph while allowing missing actions or unfinished semantic wiring. Drafts never execute, and converting an existing Flow to a draft atomically removes its previously generated outputs. A thermostat action driven only by one weekday block and one time-range block is emitted as a native schedule when its settings are schedule-compatible. More complex graphs are emitted as Flow-triggered automations. Generated schedules and automations expose `flow_id` / `flow_node_id`, use stable names in the form `flow-<stable-unique-id>`, and cannot be edited or deleted through their legacy endpoints; edit the owning Flow instead.
Condition blocks support weekday, time/date ranges, optional 5-field CRON, application Night mode, outdoor/device/zone temperatures, house/device/zone/group state, arbitrary Home Assistant state/numeric/attribute/availability sources, rolling mean/median, oscillation detection, and `shared_input` references. Stateful gate blocks include `stable_for`, `delay`, `state_duration` (`min_seconds`, optional `max_seconds`), `on_change` (`mode: result|value`) and `rate_limit` (`max_count`, `period_seconds`). `on_change` establishes a baseline on its first observation and does not fire immediately. `rate_limit` must feed an action directly and consumes quota only after a successful action execution. Shared inputs are stored in `home_assistant.flow_inputs` and resolve dynamically at evaluation time. Shared inputs store reusable value sources only. They never store a comparison operator or threshold. For comparison-capable source kinds, each `shared_input` Flow node defines its own `operator` and `value`. `PUT /api/settings` rejects shared-input configs that contain an `operator`, and rejects comparison `value` fields for comparison-capable source kinds. Logic blocks support AND, OR and NOT. Action blocks target thermostat zones, GREE devices, climate groups or a generic Home Assistant service. Direct GREE actions map to the existing `DeviceCommand` fields including fan, swing, quiet, turbo, light, air, xfan, health and sleep; ownership rules may suppress fields that would fight an active thermostat. Flow group actions use the existing group controller and support power, house/heat/cool mode, auto/comfort/sleep/away and the existing custom group target.
Condition blocks support weekday, time/date ranges, optional 5-field CRON, application Night mode, outdoor/device/zone temperatures, house/device/zone/group state, arbitrary Home Assistant state/numeric/attribute/availability sources, rolling mean/median, oscillation detection, and `shared_input` references. Stateful gate blocks include `stable_for`, `delay`, `state_duration` (`min_seconds`, optional `max_seconds`), `on_change` (`mode: result|value`) and `rate_limit` (`max_count`, `period_seconds`). `on_change` establishes a baseline on its first observation and does not fire immediately. `rate_limit` must feed an action directly and consumes quota only after a successful action execution. Shared inputs are stored in `home_assistant.flow_inputs` and resolve dynamically at evaluation time. Shared inputs store reusable value sources only. They never store a comparison operator or threshold. For comparison-capable source kinds, each `shared_input` Flow node defines its own `operator` and `value`. `PUT /api/settings/home-assistant` rejects shared-input configs that contain an `operator`, and rejects comparison `value` fields for comparison-capable source kinds. Logic blocks support AND, OR and NOT. Action blocks target thermostat zones, GREE devices, climate groups or a generic Home Assistant service. Direct GREE actions map to the existing `DeviceCommand` fields including fan, swing, quiet, turbo, light, air, xfan, health and sleep; ownership rules may suppress fields that would fight an active thermostat. Flow group actions use the existing group controller and support power, house/heat/cool mode, auto/comfort/sleep/away and the existing custom group target.
## Compressor protection queue
+75
View File
@@ -0,0 +1,75 @@
# Code audit — 0.12.0
Scope: settings/configuration API, frontend consumers, configuration import/export, and the largest control handlers touched by the API/runtime ownership changes.
## Breaking API redesign
0.12.0 intentionally removes the previous monolithic/compatibility routes. There are no aliases.
| Removed | Replacement |
| --- | --- |
| `GET/PUT /api/settings` | functional `/api/settings/*` resources |
| `GET/PUT /api/debug` | `GET/PUT /api/settings/debug` |
| `PUT /api/events/retention` | `GET/PUT /api/settings/history` |
| `GET /api/settings/export` | `GET /api/configuration/export` |
| `POST /api/settings/import` | `POST /api/configuration/import` |
Functional settings resources:
- `/api/settings/application`
- `/api/settings/gree`
- `/api/settings/history`
- `/api/settings/influxdb`
- `/api/settings/notifications`
- `/api/settings/night`
- `/api/settings/home-assistant`
- `/api/settings/debug`
The bootstrap payload no longer exposes runtime settings. The Web UI fetches each settings resource explicitly.
## Correctness and security findings addressed
- Settings writes no longer require a full `RuntimeSettings` document, so changing one section cannot overwrite unrelated settings.
- Integration secrets are never returned by settings GET endpoints. Secret-bearing PUT fields are optional: omitted/null preserves the stored value; an explicit empty string clears it.
- Configuration backup/restore was separated from runtime settings into `/api/configuration/*`.
- Configuration format was raised to version `3`; imports accept only version `3`.
- Format-v3 imports reject unsupported control strategies; `0.12.0` accepts only `setpoint`.
- Import validates and normalizes the same GREE/history/InfluxDB/notification/night/Home Assistant constraints used by functional settings endpoints.
- Shared Flow inputs in an imported backup are validated against devices/zones/groups from that backup, not against the configuration currently stored in the database.
- Obsolete `house_power_enabled` and `master_power_enabled` compatibility state was removed from runtime/settings/group responses.
- Settings WebSocket broadcasts are section-specific (`settings.<section>.updated`) instead of the former whole-settings event.
## Refactoring performed
Approximate function lengths are shown to make the audit measurable; line count is only a hotspot signal, not a quality metric by itself.
| Area | Before | After |
| --- | ---: | ---: |
| `engine::control_group` | 292 | 137 |
| `api::apply_zone_control_patch` | 415 | 214 |
| `engine::control_zones` | 666 | 413 |
| monolithic `api::update_settings` | 83 | removed |
| monolithic configuration validator | 155 | removed/split |
| monolithic settings import handler | 98 | removed/split |
New smaller responsibilities include:
- GREE settings normalization and compressor-runtime cleanup;
- InfluxDB and notification update/secret merge helpers;
- Home Assistant alias/entity/input validation;
- configuration header, IDs, flows, schedules and automation validation;
- configuration runtime sanitation, resource locking, detached-device shutdown and reconciliation;
- group patch validation, climate changes, power changes and ownership updates;
- Temporary Quick Thermostat start, target and finish resolution;
- control-cycle outdoor sensor resolution, parallel room sensor reads, temperature-source selection and pre-control state handling.
## Remaining hotspots
`control_zones` remains the largest function because it is the ordered thermostat-cycle orchestrator and contains compressor/setpoint command planning. It was reduced substantially without changing lock ordering or splitting the core state machine across opaque abstractions. Flow evaluation/compiler functions remain domain-heavy but were not changed as part of this API release because they are independent of the settings redesign and already have dedicated logical verification.
## Frontend/documentation
- Web UI settings loading/saving uses only the new functional endpoints.
- Configuration import/export uses `/api/configuration/*`.
- Realtime settings handling uses section-specific events and serializes WebSocket message processing so reconnect bootstrap cannot race later updates.
- `docs/API.md`, `docs/openapi.json`, README and smoke/static Flow checks were updated for 0.12.0.
+1311 -388
View File
File diff suppressed because it is too large Load Diff