Files
gree-controller/docs/API.md
T
2026-08-24 14:05:43 +02:00

230 lines
9.6 KiB
Markdown

# API examples
`TOKEN` is optional when `GREE_CONTROLLER_APP_TOKEN` is empty.
```bash
AUTH='Authorization: Bearer TOKEN'
BASE='http://127.0.0.1:8787'
```
## Home Assistant access tokens
Create and revoke integration tokens from the controller Web UI under **Settings -> Home Assistant integration access**. The clear-text secret is returned only once and the SQLite database stores only its SHA-256 hash.
Administrator endpoints:
```text
GET /api/access-tokens
POST /api/access-tokens
DELETE /api/access-tokens/{id}
```
The Home Assistant custom integration uses a restricted API surface:
```text
GET /api/integrations/home-assistant/devices
POST /api/integrations/home-assistant/devices/{id}/command
GET /api/integrations/home-assistant/control-plan
POST /api/integrations/home-assistant/zones/{id}/control
```
These endpoints always require `Authorization: Bearer <generated-token>` (or the administrator `GREE_CONTROLLER_APP_TOKEN`). A generated HA token cannot update settings, run discovery, delete devices, manage tokens, or use the controller WebSocket.
## Discovery
```bash
curl -X POST "$BASE/api/discovery" -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"timeout_ms":6000,"broadcast":"255.255.255.255:7000","protocol_version":0,"passes":3}'
```
`protocol_version` is `0` for auto/both, `1` for AES-ECB only, and `2` for AES-GCM only. `passes` is `1..10`. Auto is recommended when different GREE Wi-Fi module generations share the network.
## Device command
```json
{
"power": true,
"mode": "cool",
"target_temperature": 22.0,
"fan_speed": 3,
"swing_vertical": true,
"quiet": false,
"turbo": false,
"light": true
}
```
Supported modes: `auto`, `cool`, `dry`, `fan`, `heat`. Fan speed: `0..5`. Physical GREE Celsius setpoints are normalized to whole degrees in the `8..30°C` range.
## Smart thermostat / house control
The controller separates the seasonal house mode from per-zone profiles. Normal operation uses setpoint modulation: units remain powered while the controller moves the device target between an active and satisfied setpoint. `off` is the explicit hard-off house mode.
```bash
curl -X POST "$BASE/api/house/control" -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"mode":"cool"}'
curl -X POST "$BASE/api/house/preset" -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"preset":"sleep"}'
```
House modes: `cool`, `heat`, `off`. House presets: `auto`, `comfort`, `sleep`, `away`. A non-`auto` house preset creates temporary per-zone overrides that expire at each zone's next schedule boundary.
A zone stores separate profile temperatures for both seasons:
```json
{
"name": "Paweł",
"device_id": "gree-aabbccddeeff",
"enabled": true,
"mode": "cool",
"inherit_house_mode": true,
"setpoint": 23.0,
"cool_comfort_setpoint": 23.0,
"cool_sleep_setpoint": 24.5,
"cool_away_setpoint": 27.0,
"heat_comfort_setpoint": 21.0,
"heat_sleep_setpoint": 19.0,
"heat_away_setpoint": 17.0,
"hysteresis": 0.6,
"min_adjust_seconds": 120,
"standby_offset_c": 2.0,
"smart_fan": true,
"sensor_source": "combined",
"ha_entity_id": "sensor.pawel_temperature",
"external_sensor_weight": 0.4,
"max_sensor_difference": 3.0
}
```
Quick control does not directly fight the schedule engine:
```bash
# Sleep now until the next schedule boundary
curl -X POST "$BASE/api/zones/ZONE_ID/control" -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"preset":"sleep"}'
# Return to automatic schedule
curl -X POST "$BASE/api/zones/ZONE_ID/control" -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"preset":"auto"}'
# Temporary custom room target
curl -X POST "$BASE/api/zones/ZONE_ID/control" -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"setpoint":22.5}'
```
`mode` on the quick zone endpoint accepts `house`, `cool`, or `heat`. Global `off` always wins over local zone mode overrides.
### Ready-made schedule templates
Templates generate normal schedule records and replace the current schedules for the selected zone. Every generated entry remains editable.
```bash
curl -X POST "$BASE/api/zones/ZONE_ID/schedule-template" -H "$AUTH" -H 'Content-Type: application/json' \
-d '{"template":"child"}'
```
Templates: `family`, `child`, `bedroom`, `workday`, `always`.
Schedules use a profile (`comfort`, `sleep`, `away`) or a custom temperature:
```json
{
"zone_id": "UUID",
"name": "Sleep",
"enabled": true,
"weekdays": [1,2,3,4,5,6,7],
"start_time": "20:30",
"end_time": "06:30",
"preset": "sleep",
"setpoint": 24.0
}
```
For non-`custom` schedules, `setpoint` is only a compatibility value; the actual target comes from the zone's seasonal profile.
### Home Assistant outdoor assist and local HTTPS
Runtime settings can specify `home_assistant.outdoor_entity_id` and `outdoor_assist_enabled`. Outdoor temperature never replaces the zone room temperature. It is only used to make active setpoints/fan speed slightly more assertive in extreme weather.
For trusted local Home Assistant servers with self-signed/invalid HTTPS certificates, set:
```json
{
"home_assistant": {
"url": "https://10.87.65.2",
"allow_invalid_tls": true
}
}
```
This setting is opt-in and applies only to the controller's outbound Home Assistant sensor client.
## Current control plan
`GET /api/control-plan` returns a machine-readable view of what the controller is doing now and what is expected next. It includes the house mode/strategy, each zone's active mode/preset/current and target temperatures, current schedule, manual override expiry, upcoming schedule transitions, enabled automation rules and predictable time-triggered automation events.
```bash
curl "$BASE/api/control-plan" -H "$AUTH"
```
The restricted Home Assistant equivalent is `GET /api/integrations/home-assistant/control-plan`. HA may change a zone target/preset/mode/enabled state through:
```bash
curl -X POST "$BASE/api/integrations/home-assistant/zones/ZONE_ID/control" \
-H 'Authorization: Bearer HA_TOKEN' -H 'Content-Type: application/json' \
-d '{"setpoint":22.5}'
```
## Settings backup and debug
`GET /api/settings/export` downloads configuration JSON (settings, devices, zones, schedules and automations). It intentionally excludes metric history, event logs and generated API-token records. The export includes GREE device binding keys plus configured Home Assistant and InfluxDB credentials, so treat it as a secret.
`POST /api/settings/import` accepts that JSON format and replaces application configuration while preserving metric history, events and generated API tokens.
Debug overlay state can be read or changed independently of the full settings document:
```text
GET /api/debug
PUT /api/debug
```
Example body: `{"overlay_enabled":true,"gree_frames":true}`. With the overlay enabled, live `api.request` WebSocket events contain only HTTP method, path, status and duration. When GREE frame debug is enabled, sanitized `gree.frame` events are also emitted; the bound encryption key is not exposed.
## WebSocket
Connect to `ws://HOST:8787/ws?token=TOKEN`. The first message uses event type `bootstrap`; later events include `device.updated`, `zone.updated`, `settings.updated`, `debug.settings`, `api.request`, `gree.frame` and `log.created`.
## Localization assets
Localization endpoints are public because the login dialog also needs translations. Language packs are embedded in the Rust binary at build time.
```bash
curl "$BASE/lang/index.json"
curl "$BASE/lang/en.json"
```
`GET /lang/index.json` returns the automatically generated language catalog. `GET /lang/<code>.json` returns the corresponding language pack. Add a valid `lang/<code>.json` file and rebuild to expose a new language.
### `GET /api/history`
The history API exposes three independent data families and a combined overview. `hours` may cover up to 10 years and `limit` is capped at 20,000 rows. Query buckets become progressively wider: 30 s (<=6 h), 2 min (<=24 h), 10 min (<=7 d), 30 min (<=30 d), 2 h (<=90 d), 6 h (<=1 y), then 24 h.
```text
GET /api/history?scope=overview&hours=24
GET /api/history?scope=devices&device_id=DEVICE_ID&hours=2160
GET /api/history?scope=zones&zone_id=ZONE_ID&hours=8760
GET /api/history?scope=sensors&entity_id=sensor.room_temperature&hours=24
```
Local SQLite is the hot store. When compaction is enabled, full-resolution samples are kept for 24 h, then one sample per 10-minute bucket through day 7 and one per 30-minute bucket afterwards. `history_retention_days` controls final local pruning.
When InfluxDB is enabled, samples are written in parallel. Maintenance also backfills compacted legacy SQLite samples older than `influxdb.history_threshold_days`; those local rows are deleted only after the archive batch is accepted. Requests that cross the threshold read the older portion from InfluxDB 1.x or 2.x and merge it with recent SQLite data. If the Influx query fails, the endpoint falls back to the available SQLite history and returns `storage_warning`.
`scope=overview` returns `zones`, `devices`, `sensors`, row `counts`, `bucket_seconds`, plus `storage`/optional `storage_warning`. Device rows contain indoor/outdoor/target/power; zone rows contain GREE/external/control/target/device-setpoint/outdoor/power/mode/fan/demand/source/preset; HA rows contain entity, optional zone, kind and temperature.
## InfluxDB long-term storage
Runtime settings support either InfluxDB 1.x (`version=1`, URL, database and optional username/password) or InfluxDB 2.x (`version=2`, URL, org, bucket and token). The same values can be supplied with `GREE_CONTROLLER_INFLUX_*` environment variables; see `.env.example`. An explicitly configured environment value overrides the persisted setting at startup.