1472 lines
36 KiB
Markdown
1472 lines
36 KiB
Markdown
# GREE Controller API reference
|
||
|
||
HTTP and WebSocket API for GREE Controller **0.8.14**.
|
||
|
||
[← Main documentation](../README.md)
|
||
|
||
## Base URL and content type
|
||
|
||
Default local address:
|
||
|
||
```text
|
||
http://127.0.0.1:8787
|
||
```
|
||
|
||
JSON requests use:
|
||
|
||
```text
|
||
Content-Type: application/json
|
||
```
|
||
|
||
If `GREE_CONTROLLER_BASE_PATH=/gree` is configured, every HTTP and WebSocket path below is prefixed with `/gree`.
|
||
|
||
## Authentication
|
||
|
||
There are three access levels.
|
||
|
||
### Public
|
||
|
||
No token is required for:
|
||
|
||
```text
|
||
GET /api/health
|
||
GET /
|
||
GET /index.html
|
||
GET /app.js
|
||
GET /theme-init.js
|
||
GET /styles.css
|
||
GET /manifest.webmanifest
|
||
GET /sw.js
|
||
GET /favicon.svg
|
||
GET /lang/index.json
|
||
GET /lang/{file}
|
||
```
|
||
|
||
### Administrator API
|
||
|
||
All normal `/api/*` routes are administrator routes. If `GREE_CONTROLLER_APP_TOKEN` is empty, the controller intentionally operates in trusted-LAN mode and these routes do not require authentication.
|
||
|
||
When an app token is configured, send either:
|
||
|
||
```text
|
||
Authorization: Bearer APP_TOKEN
|
||
```
|
||
|
||
or:
|
||
|
||
```text
|
||
x-api-token: APP_TOKEN
|
||
```
|
||
|
||
Example:
|
||
|
||
```bash
|
||
BASE='http://127.0.0.1:8787'
|
||
TOKEN='replace-me'
|
||
curl -H "Authorization: Bearer $TOKEN" "$BASE/api/bootstrap"
|
||
```
|
||
|
||
### Restricted Home Assistant API
|
||
|
||
Generated Home Assistant access tokens always authenticate only the restricted integration surface under `/api/integrations/home-assistant/*`. The administrator app token is also accepted there.
|
||
|
||
Generated token secrets are returned only at creation time. SQLite stores their SHA-256 hash and a display prefix.
|
||
|
||
## Errors and HTTP status codes
|
||
|
||
API errors are JSON:
|
||
|
||
```json
|
||
{
|
||
"error": "message"
|
||
}
|
||
```
|
||
|
||
Common statuses:
|
||
|
||
| Status | Meaning |
|
||
| --- | --- |
|
||
| `200 OK` | Successful read/update/action. |
|
||
| `201 Created` | Resource created. |
|
||
| `204 No Content` | Successful delete/revoke. |
|
||
| `400 Bad Request` | Validation error or unsafe/invalid operation. |
|
||
| `401 Unauthorized` | Missing/incorrect token. |
|
||
| `404 Not Found` | Resource ID does not exist. |
|
||
| `409 Conflict` | Revision/concurrency conflict. |
|
||
| `502 Bad Gateway` | GREE/HA/integration communication failure. |
|
||
| `500 Internal Server Error` | Unexpected server/storage error. |
|
||
|
||
## Endpoint index
|
||
|
||
### Public and system
|
||
|
||
| Method | Endpoint | Description |
|
||
| --- | --- | --- |
|
||
| GET | `/api/health` | Lightweight process/control-engine health. |
|
||
| GET | `/api/bootstrap` | Complete initial application snapshot. |
|
||
| GET | `/api/system/info` | Runtime/system diagnostic information. |
|
||
| GET | `/ws` | Live WebSocket event stream. |
|
||
|
||
### Devices and discovery
|
||
|
||
| Method | Endpoint | Description |
|
||
| --- | --- | --- |
|
||
| POST | `/api/discovery` | Discover/bind GREE devices. |
|
||
| GET | `/api/devices` | List devices. |
|
||
| POST | `/api/devices` | Add a device manually. |
|
||
| GET | `/api/devices/{id}` | Read a device. |
|
||
| PATCH | `/api/devices/{id}` | Edit technical device configuration. |
|
||
| DELETE | `/api/devices/{id}` | Delete a device after safety checks. |
|
||
| POST | `/api/devices/{id}/bind` | Bind/re-bind a physical unit. |
|
||
| POST | `/api/devices/{id}/poll` | Poll one unit immediately. |
|
||
| POST | `/api/devices/{id}/command` | Send a direct/manual device command. |
|
||
|
||
### Thermostat zones, groups and house
|
||
|
||
| Method | Endpoint | Description |
|
||
| --- | --- | --- |
|
||
| GET | `/api/zones` | List zones. |
|
||
| POST | `/api/zones` | Create a zone. |
|
||
| GET | `/api/zones/{id}` | Read a zone. |
|
||
| PUT | `/api/zones/{id}` | Replace editable zone configuration. |
|
||
| DELETE | `/api/zones/{id}` | Delete zone after safe device shutdown. |
|
||
| POST | `/api/zones/{id}/control` | Quick/thermostat control of a zone. |
|
||
| POST | `/api/zones/{id}/schedule-template` | Replace zone schedules with a built-in template. |
|
||
| GET | `/api/groups` | List climate groups. |
|
||
| POST | `/api/groups` | Create a climate group. |
|
||
| GET | `/api/groups/{id}` | Read a group. |
|
||
| PUT | `/api/groups/{id}` | Replace group definition. |
|
||
| DELETE | `/api/groups/{id}` | Delete a group. |
|
||
| POST | `/api/groups/{id}/control` | Group power/mode/preset control. |
|
||
| POST | `/api/house/control` | Set global thermostat mode. |
|
||
| POST | `/api/house/power` | Set whole-house master power. |
|
||
| POST | `/api/house/preset` | Set/clear whole-house preset override. |
|
||
|
||
### Schedules and automations
|
||
|
||
| Method | Endpoint | Description |
|
||
| --- | --- | --- |
|
||
| GET | `/api/schedules` | List schedules. |
|
||
| POST | `/api/schedules` | Create schedule. |
|
||
| GET | `/api/schedules/{id}` | Read schedule. |
|
||
| PUT | `/api/schedules/{id}` | Replace schedule. |
|
||
| DELETE | `/api/schedules/{id}` | Delete schedule. |
|
||
| GET | `/api/automations` | List automations. |
|
||
| POST | `/api/automations` | Create automation. |
|
||
| GET | `/api/automations/{id}` | Read automation. |
|
||
| PUT | `/api/automations/{id}` | Replace automation. |
|
||
| DELETE | `/api/automations/{id}` | Delete automation. |
|
||
|
||
### History, control plan and events
|
||
|
||
| Method | Endpoint | Description |
|
||
| --- | --- | --- |
|
||
| GET | `/api/readings` | Legacy/device reading history. |
|
||
| 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
|
||
|
||
| 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. |
|
||
| POST | `/api/integrations/home-assistant/test` | Test HA temperature read. |
|
||
| POST | `/api/integrations/notifications/test` | Send a test notification. |
|
||
|
||
### Access tokens and restricted Home Assistant API
|
||
|
||
| Method | Endpoint | Description |
|
||
| --- | --- | --- |
|
||
| GET | `/api/access-tokens` | List generated HA tokens without secrets. |
|
||
| POST | `/api/access-tokens` | Create restricted HA token. |
|
||
| DELETE | `/api/access-tokens/{id}` | Revoke token. |
|
||
| GET | `/api/integrations/home-assistant/devices` | Restricted device list. |
|
||
| POST | `/api/integrations/home-assistant/devices/{id}/command` | Restricted direct device command. |
|
||
| GET | `/api/integrations/home-assistant/control-plan` | Restricted control plan. |
|
||
| GET | `/api/integrations/home-assistant/groups` | HA-oriented group state. |
|
||
| POST | `/api/integrations/home-assistant/groups/{id}/control` | Restricted group control. |
|
||
| POST | `/api/integrations/home-assistant/house/control` | Restricted house mode. |
|
||
| POST | `/api/integrations/home-assistant/house/preset` | Restricted house preset. |
|
||
| POST | `/api/integrations/home-assistant/house/power` | Restricted master power. |
|
||
| POST | `/api/integrations/home-assistant/zones/{id}/control` | Restricted thermostat-zone control. |
|
||
|
||
---
|
||
|
||
## System endpoints
|
||
|
||
### `GET /api/health`
|
||
|
||
Public lightweight health check.
|
||
|
||
Response:
|
||
|
||
```json
|
||
{
|
||
"status": "ok",
|
||
"name": "gree-controller",
|
||
"version": "0.8.14",
|
||
"uptime_seconds": 1234,
|
||
"control_ready": true,
|
||
"time": "2026-08-30T06:54:00Z"
|
||
}
|
||
```
|
||
|
||
`control_ready=false` means the process is running but the thermostat engine has not yet completed its initial physical device synchronization.
|
||
|
||
### `GET /api/bootstrap`
|
||
|
||
Returns the initial Web UI snapshot:
|
||
|
||
```json
|
||
{
|
||
"devices": [],
|
||
"zones": [],
|
||
"groups": [],
|
||
"schedules": [],
|
||
"automations": [],
|
||
"access_tokens": [],
|
||
"settings": {},
|
||
"outdoor_temperature": null,
|
||
"system": {
|
||
"version": "0.8.14",
|
||
"uptime_seconds": 1234,
|
||
"auth_required": false,
|
||
"control_ready": true,
|
||
"database": "./data/gree-controller.db",
|
||
"device_count": 2,
|
||
"online_count": 2,
|
||
"simulator_count": 0,
|
||
"bind": "0.0.0.0:8787",
|
||
"base_path": "/",
|
||
"gree_interface": "auto",
|
||
"gree_received_frames": 809,
|
||
"gree_received_frames_by_device": {}
|
||
}
|
||
}
|
||
```
|
||
|
||
### `GET /api/system/info`
|
||
|
||
Returns the `system` diagnostic object independently of the full bootstrap. Useful for monitoring and **Settings → System status**.
|
||
|
||
---
|
||
|
||
## Device API
|
||
|
||
### Device object
|
||
|
||
A device response contains:
|
||
|
||
| Field | Type | Description |
|
||
| --- | --- | --- |
|
||
| `id` | string | Stable controller ID. |
|
||
| `mac` | string | Normalized GREE MAC/CID identity. |
|
||
| `name` | string | User-visible name. |
|
||
| `ip` | string | Device IPv4 address. |
|
||
| `port` | integer | Usually `7000`. |
|
||
| `protocol_version` | integer | `0` unknown/auto, `1` legacy AES-ECB, `2` AES-GCM. |
|
||
| `model`, `firmware` | string | Discovered metadata when available. |
|
||
| `key` | string/null | GREE binding key. Treat as secret. |
|
||
| `cid` | string/null | GREE client/device identifier. |
|
||
| `enabled` | boolean | Technical device enable state. |
|
||
| `simulated` | boolean | Simulated vs physical. |
|
||
| `power` | boolean | Last known power. |
|
||
| `mode` | string | `auto`, `cool`, `dry`, `fan`, `heat`. |
|
||
| `target_temperature` | number | Last known unit setpoint. |
|
||
| `fan_speed` | integer | `0..5`; `0` is Auto. |
|
||
| `swing_vertical`, `swing_horizontal` | boolean | Swing state. |
|
||
| `quiet`, `turbo`, `light`, `air`, `xfan`, `health`, `sleep` | boolean | Optional GREE features. |
|
||
| `supports_*` | boolean/null | Capability learned from device status. |
|
||
| `current_temperature` | number/null | GREE indoor temperature. |
|
||
| `outdoor_temperature` | number/null | GREE outdoor temperature if available. |
|
||
| `temperature_sensor_offset` | boolean/null | Whether +40 °C wire offset behavior was detected. |
|
||
| `online` | boolean | Current communication state. |
|
||
| `response_time_ms` | integer/null | Latest successful controller round-trip. |
|
||
| `last_seen` | ISO-8601/null | Last successful communication. |
|
||
| `last_error` | string/null | Latest communication error. |
|
||
| `communication_failures` | integer | Consecutive/recorded communication failure counter. |
|
||
| `created_at`, `updated_at` | ISO-8601 | Resource timestamps. |
|
||
|
||
### `POST /api/discovery`
|
||
|
||
Request body, all fields optional:
|
||
|
||
```json
|
||
{
|
||
"timeout_ms": 6000,
|
||
"broadcast": "255.255.255.255:7000",
|
||
"protocol_version": 0,
|
||
"passes": 3
|
||
}
|
||
```
|
||
|
||
Rules:
|
||
|
||
- `timeout_ms`: effective range `500..30000` ms.
|
||
- `protocol_version`: `0` auto/both, `1` AES-ECB only, `2` AES-GCM only.
|
||
- `passes`: `1..10`.
|
||
- Missing values use runtime GREE settings.
|
||
|
||
Successful discovery merges known devices, tries binding devices that do not have a key, persists results and returns:
|
||
|
||
```json
|
||
{
|
||
"count": 1,
|
||
"devices": [],
|
||
"new_device_ids": ["gree-aabbccddeeff"]
|
||
}
|
||
```
|
||
|
||
### `GET /api/devices`
|
||
|
||
Returns `Device[]`.
|
||
|
||
### `POST /api/devices`
|
||
|
||
Manual add request:
|
||
|
||
```json
|
||
{
|
||
"name": "Living room",
|
||
"mac": "AABBCCDDEEFF",
|
||
"ip": "192.168.50.30",
|
||
"port": 7000,
|
||
"protocol_version": 1,
|
||
"key": null,
|
||
"simulated": false
|
||
}
|
||
```
|
||
|
||
Defaults: `port=7000`, `protocol_version=1`, `simulated=false`. MAC values are normalized. Duplicate MACs are rejected.
|
||
|
||
Returns `201 Created` with `Device`.
|
||
|
||
### `GET /api/devices/{id}`
|
||
|
||
Returns one `Device` or `404`.
|
||
|
||
### `PATCH /api/devices/{id}`
|
||
|
||
All fields optional:
|
||
|
||
```json
|
||
{
|
||
"name": "Bedroom",
|
||
"ip": "192.168.50.31",
|
||
"port": 7000,
|
||
"protocol_version": 2,
|
||
"key": "optional-binding-key",
|
||
"enabled": true
|
||
}
|
||
```
|
||
|
||
`key:null` clears the key. Changing protocol version clears the existing key/capability cache so the unit can be re-bound cleanly. Disabling a device goes through the controller's safe disable path.
|
||
|
||
### `DELETE /api/devices/{id}`
|
||
|
||
Returns `204`. Deletion is rejected if the device is referenced by an automation or cannot be safely detached from thermostat ownership. Associated zones/groups are cleaned only after the safety checks pass.
|
||
|
||
### `POST /api/devices/{id}/bind`
|
||
|
||
Performs/repeats GREE binding and returns updated `Device`. Simulated devices return unchanged.
|
||
|
||
### `POST /api/devices/{id}/poll`
|
||
|
||
Immediately polls one unit and returns updated `Device`.
|
||
|
||
### `POST /api/devices/{id}/command`
|
||
|
||
Direct/manual device control. This is deliberately different from thermostat-zone control.
|
||
|
||
All fields optional; at least one meaningful field should be sent:
|
||
|
||
```json
|
||
{
|
||
"power": true,
|
||
"mode": "cool",
|
||
"target_temperature": 22,
|
||
"fan_speed": 3,
|
||
"swing_vertical": true,
|
||
"swing_horizontal": false,
|
||
"quiet": false,
|
||
"turbo": false,
|
||
"light": true,
|
||
"air": false,
|
||
"xfan": false,
|
||
"health": false,
|
||
"sleep": false
|
||
}
|
||
```
|
||
|
||
Rules:
|
||
|
||
- modes: `auto`, `cool`, `dry`, `fan`, `heat`,
|
||
- target temperature is normalized to the supported GREE Celsius range `8..30`,
|
||
- fan speed is `0..5`,
|
||
- optional feature commands should be used only when the corresponding `supports_*` capability is true.
|
||
|
||
The backend sends only properties that differ from the last known device state. Climate-relevant direct commands can create/continue a manual-device takeover for an enabled thermostat zone so automation does not immediately fight the user.
|
||
|
||
---
|
||
|
||
## Zones
|
||
|
||
### Zone configuration
|
||
|
||
`POST /api/zones` and `PUT /api/zones/{id}` use this editable shape:
|
||
|
||
```json
|
||
{
|
||
"name": "Living room",
|
||
"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_on_seconds": 180,
|
||
"min_off_seconds": 180,
|
||
"min_adjust_seconds": 120,
|
||
"standby_offset_c": 2.0,
|
||
"smart_fan": true,
|
||
"sensor_source": "combined",
|
||
"ha_entity_id": "sensor.living_room_temperature",
|
||
"external_sensor_weight": 0.4,
|
||
"max_sensor_difference": 3.0,
|
||
"sensor_stale_after_seconds": 300,
|
||
"revision": 12
|
||
}
|
||
```
|
||
|
||
Important rules:
|
||
|
||
- `name` is required.
|
||
- `device_id` must reference an existing device and thermostat ownership must remain valid/safe.
|
||
- `mode`: `cool` or `heat` when not inheriting house mode.
|
||
- temperature/profile values are constrained to the supported thermostat range.
|
||
- `hysteresis`: controller-valid range is approximately `0.1..5.0` °C.
|
||
- `standby_offset_c`: bounded thermostat offset.
|
||
- `sensor_source`: `device`, `home_assistant` or `combined`.
|
||
- `external_sensor_weight`: `0..1`.
|
||
- `revision` is used for optimistic concurrency where supplied; stale updates can return `409`.
|
||
|
||
The returned `Zone` also contains runtime state including sensor readings, resolved/effective setpoints, demand, current preset, manual overrides, local Quick Thermostat ownership, temporary session state, device-manual takeover, control owner/source/reason, lockout timestamps and `created_at`/`updated_at`.
|
||
|
||
### `GET /api/zones`
|
||
|
||
Returns `Zone[]`.
|
||
|
||
### `POST /api/zones`
|
||
|
||
Creates a zone and returns `201 Created` with `Zone`.
|
||
|
||
### `GET /api/zones/{id}`
|
||
|
||
Returns one `Zone`.
|
||
|
||
### `PUT /api/zones/{id}`
|
||
|
||
Replaces editable zone configuration while preserving/reconciling runtime safety state. Returns updated `Zone`.
|
||
|
||
### `DELETE /api/zones/{id}`
|
||
|
||
Safely powers the owned device off before detaching thermostat ownership. Returns `204`.
|
||
|
||
### `POST /api/zones/{id}/control`
|
||
|
||
Quick thermostat endpoint. Body fields are optional and can be combined:
|
||
|
||
```json
|
||
{
|
||
"setpoint": 22.5,
|
||
"power": true,
|
||
"mode": "house",
|
||
"enabled": true,
|
||
"preset": "comfort",
|
||
"clear_override": false,
|
||
"clear_device_manual_override": false,
|
||
"clear_local_thermostat_override": false,
|
||
"temporary_quick_thermostat": null,
|
||
"clear_temporary_quick_thermostat": false
|
||
}
|
||
```
|
||
|
||
Semantics:
|
||
|
||
- `setpoint`: creates a quick custom thermostat target.
|
||
- `preset`: `auto`, `comfort`, `sleep`, `away`, `custom`; `auto` clears the profile override.
|
||
- `mode`: `house`, `cool`, `heat`; `house` restores global mode inheritance.
|
||
- `enabled`: zone automation enable state.
|
||
- `power:true`: local Quick Thermostat ownership — this zone can run through full thermostat logic even if its climate group is off.
|
||
- `power:false`: turns this zone off and creates a fresh backend-owned local hand-back timer (currently 15 minutes).
|
||
- `clear_local_thermostat_override:true`: immediately return local Quick Thermostat ownership to normal group/schedule control.
|
||
- `clear_device_manual_override:true`: explicitly hand a physical/direct manual takeover back to the thermostat.
|
||
- `clear_override:true`: clear ordinary quick preset/setpoint override.
|
||
- `temporary_quick_thermostat`: start/replace a persisted temporary session.
|
||
- `clear_temporary_quick_thermostat:true`: cancel that temporary session only.
|
||
|
||
Returns updated `Zone`.
|
||
|
||
#### Temporary Quick Thermostat request
|
||
|
||
```json
|
||
{
|
||
"start_kind": "now",
|
||
"start_delay_minutes": null,
|
||
"start_at": null,
|
||
"finish_kind": "duration",
|
||
"duration_minutes": 90,
|
||
"until": null,
|
||
"target_temperature": 23.0,
|
||
"temperature_operator": "within",
|
||
"tolerance_c": 0.3,
|
||
"hold_minutes": 60,
|
||
"max_duration_minutes": 240
|
||
}
|
||
```
|
||
|
||
`start_kind`:
|
||
|
||
- `now`
|
||
- `delay` + `start_delay_minutes`
|
||
- `at` + ISO-8601 `start_at`
|
||
|
||
`finish_kind`:
|
||
|
||
- `duration` + `duration_minutes`
|
||
- `until` + ISO-8601 `until`
|
||
- `temperature_reached`
|
||
- `temperature_stable` + `hold_minutes`
|
||
- `schedule_boundary`
|
||
|
||
Temperature operators:
|
||
|
||
- `within`
|
||
- `at_or_below`
|
||
- `at_or_above`
|
||
|
||
`max_duration_minutes` is an optional fail-safe for temperature-based sessions. Delayed sessions do not own the zone until their effective start. Runtime session state is persisted and exposed inside the returned zone.
|
||
|
||
Examples:
|
||
|
||
```bash
|
||
# Preset until next schedule boundary
|
||
curl -X POST "$BASE/api/zones/ZONE_ID/control" -H "$AUTH" -H 'Content-Type: application/json' \
|
||
-d '{"preset":"sleep"}'
|
||
|
||
# Return to schedule
|
||
curl -X POST "$BASE/api/zones/ZONE_ID/control" -H "$AUTH" -H 'Content-Type: application/json' \
|
||
-d '{"preset":"auto"}'
|
||
|
||
# Run a 90-minute temporary thermostat
|
||
curl -X POST "$BASE/api/zones/ZONE_ID/control" -H "$AUTH" -H 'Content-Type: application/json' \
|
||
-d '{"temporary_quick_thermostat":{"start_kind":"now","finish_kind":"duration","duration_minutes":90,"target_temperature":23}}'
|
||
```
|
||
|
||
### `POST /api/zones/{id}/schedule-template`
|
||
|
||
Body:
|
||
|
||
```json
|
||
{
|
||
"template": "family"
|
||
}
|
||
```
|
||
|
||
Built-in templates:
|
||
|
||
| Template | Result |
|
||
| --- | --- |
|
||
| `family` | Comfort `06:30–22:30`, Sleep overnight. |
|
||
| `child` | Comfort `06:30–20:30`, Sleep overnight. |
|
||
| `bedroom` | Comfort `06:30–22:00`, Sleep overnight. |
|
||
| `workday` | Weekday morning/away/evening/sleep plus weekend blocks. |
|
||
| `always` | 24-hour Comfort. |
|
||
|
||
Existing schedules for the zone are replaced after overlap validation. Response:
|
||
|
||
```json
|
||
{
|
||
"zone": {},
|
||
"schedules": []
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Groups
|
||
|
||
### Group object
|
||
|
||
```json
|
||
{
|
||
"id": "uuid",
|
||
"name": "Bedrooms",
|
||
"zone_ids": ["zone-1", "zone-2"],
|
||
"power_enabled": true,
|
||
"created_at": "...",
|
||
"updated_at": "..."
|
||
}
|
||
```
|
||
|
||
### `GET /api/groups`
|
||
|
||
Returns groups.
|
||
|
||
### `POST /api/groups`
|
||
|
||
```json
|
||
{
|
||
"name": "Bedrooms",
|
||
"zone_ids": ["zone-1", "zone-2"],
|
||
"power_enabled": true
|
||
}
|
||
```
|
||
|
||
A group must contain at least one existing zone. Returns `201 Created`.
|
||
|
||
### `GET /api/groups/{id}` / `PUT /api/groups/{id}` / `DELETE /api/groups/{id}`
|
||
|
||
Read, replace or delete a group. `DELETE` returns `204`.
|
||
|
||
### `POST /api/groups/{id}/control`
|
||
|
||
```json
|
||
{
|
||
"power": true,
|
||
"mode": "house",
|
||
"preset": "comfort"
|
||
}
|
||
```
|
||
|
||
All fields optional:
|
||
|
||
- `power`: group gate,
|
||
- `mode`: `house`, `cool`, `heat`,
|
||
- `preset`: `auto`, `comfort`, `sleep`, `away`.
|
||
|
||
Returns a group control/result object including updated members/state.
|
||
|
||
---
|
||
|
||
## Whole-house control
|
||
|
||
House thermostat mode and master power are intentionally separate.
|
||
|
||
### `POST /api/house/control`
|
||
|
||
```json
|
||
{
|
||
"mode": "cool"
|
||
}
|
||
```
|
||
|
||
Valid modes: `cool`, `heat`, `off`.
|
||
|
||
- `cool`/`heat` are explicit whole-house activation requests: master power is enabled, group gates are enabled and the thermostat arbiter starts eligible managed zones.
|
||
- `off` means **do not perform house-level thermostat control** for inherited zones. It does not itself change master power and does not forcibly power direct/manual devices down.
|
||
|
||
Returns public runtime settings.
|
||
|
||
### `POST /api/house/power`
|
||
|
||
```json
|
||
{
|
||
"power": false
|
||
}
|
||
```
|
||
|
||
`false` is authoritative: it disables group gates, clears local/manual ownership markers as required and powers every enabled physical device down. `true` resumes thermostat arbitration rather than blindly sending a bare ON frame.
|
||
|
||
Response includes:
|
||
|
||
```json
|
||
{
|
||
"power": false,
|
||
"devices": [],
|
||
"groups": [],
|
||
"settings": {},
|
||
"failed": []
|
||
}
|
||
```
|
||
|
||
### `POST /api/house/preset`
|
||
|
||
```json
|
||
{
|
||
"preset": "sleep"
|
||
}
|
||
```
|
||
|
||
Valid: `auto`, `comfort`, `sleep`, `away`.
|
||
|
||
A non-`auto` preset creates zone overrides that normally expire at each zone's next schedule boundary. `auto` clears them. Selecting a house preset also explicitly re-enables master power/group gates.
|
||
|
||
---
|
||
|
||
## Schedules
|
||
|
||
Schedule object/request:
|
||
|
||
```json
|
||
{
|
||
"zone_id": "zone-1",
|
||
"name": "Night",
|
||
"enabled": true,
|
||
"weekdays": [1, 2, 3, 4, 5, 6, 7],
|
||
"start_time": "22:30",
|
||
"end_time": "06:30",
|
||
"preset": "sleep",
|
||
"setpoint": 24.5
|
||
}
|
||
```
|
||
|
||
Rules:
|
||
|
||
- weekdays use ISO numbers `1=Monday ... 7=Sunday`,
|
||
- times use local `HH:MM`,
|
||
- crossing midnight is supported,
|
||
- `start_time == end_time` represents a 24-hour window for selected weekdays,
|
||
- preset: `comfort`, `sleep`, `away`, `custom`,
|
||
- custom setpoint: `8..30` °C,
|
||
- enabled schedules for the same zone cannot overlap.
|
||
|
||
For non-custom presets, the effective target comes from the zone's seasonal profile; `setpoint` is retained for compatibility.
|
||
|
||
Routes:
|
||
|
||
```text
|
||
GET /api/schedules
|
||
POST /api/schedules
|
||
GET /api/schedules/{id}
|
||
PUT /api/schedules/{id}
|
||
DELETE /api/schedules/{id}
|
||
```
|
||
|
||
Create returns `201`; delete returns `204`.
|
||
|
||
---
|
||
|
||
## Automations
|
||
|
||
Automation request/object fields:
|
||
|
||
```json
|
||
{
|
||
"name": "Hot room",
|
||
"enabled": true,
|
||
"trigger_kind": "temperature_above",
|
||
"trigger_device_id": "gree-aabbccddeeff",
|
||
"threshold": 27.0,
|
||
"at_time": null,
|
||
"action_device_id": "gree-aabbccddeeff",
|
||
"action_group_id": null,
|
||
"action_preset": null,
|
||
"action": {
|
||
"power": true,
|
||
"mode": "cool",
|
||
"target_temperature": 23
|
||
},
|
||
"cooldown_seconds": 300
|
||
}
|
||
```
|
||
|
||
Triggers:
|
||
|
||
- `temperature_above`: requires `trigger_device_id` + `threshold`,
|
||
- `temperature_below`: requires `trigger_device_id` + `threshold`,
|
||
- `time`: requires local `at_time` in `HH:MM`.
|
||
|
||
Action target is either:
|
||
|
||
- direct device: `action_device_id` + full `DeviceCommand`, or
|
||
- group: `action_group_id`; group automation supports only power, `house`/`cool`/`heat` mode and optional `action_preset` (`auto|comfort|sleep|away`).
|
||
|
||
The response also contains runtime `last_fired_at`, `created_at`, `updated_at`.
|
||
|
||
Routes:
|
||
|
||
```text
|
||
GET /api/automations
|
||
POST /api/automations
|
||
GET /api/automations/{id}
|
||
PUT /api/automations/{id}
|
||
DELETE /api/automations/{id}
|
||
```
|
||
|
||
Create returns `201`; delete returns `204`.
|
||
|
||
---
|
||
|
||
## History and readings
|
||
|
||
### `GET /api/readings`
|
||
|
||
Legacy/lightweight device history.
|
||
|
||
Query parameters:
|
||
|
||
| Parameter | Default | Description |
|
||
| --- | --- | --- |
|
||
| `device_id` | all | Optional device filter. |
|
||
| `hours` | `24` | Clamped to `1..87600` (10 years). |
|
||
| `limit` | `1500` | Row limit. |
|
||
|
||
Response:
|
||
|
||
```json
|
||
{
|
||
"readings": [
|
||
{
|
||
"id": 1,
|
||
"device_id": "gree-aabbccddeeff",
|
||
"timestamp": "...",
|
||
"indoor_temperature": 23.4,
|
||
"outdoor_temperature": 30.1,
|
||
"target_temperature": 23,
|
||
"power": true,
|
||
"source": "poll"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### `GET /api/history`
|
||
|
||
Rich chart/history API.
|
||
|
||
Query parameters:
|
||
|
||
| Parameter | Description |
|
||
| --- | --- |
|
||
| `scope` | `overview`, `zones`/`zone`, `devices`, `sensors`; default `zones`. |
|
||
| `zone_id` | Zone filter for zone scope. |
|
||
| `device_id` | Device filter for device scope. |
|
||
| `entity_id` | Home Assistant entity filter for sensor scope. |
|
||
| `hours` | Default `24`, clamped to 10 years. |
|
||
| `limit` | Default `12000`, clamped to `1..20000`. |
|
||
|
||
Bucket resolution:
|
||
|
||
| Range | Bucket |
|
||
| --- | --- |
|
||
| ≤ 6 h | 30 s |
|
||
| ≤ 24 h | 2 min |
|
||
| ≤ 7 d | 10 min |
|
||
| ≤ 30 d | 30 min |
|
||
| ≤ 90 d | 2 h |
|
||
| ≤ 1 y | 6 h |
|
||
| > 1 y | 24 h |
|
||
|
||
Zone reading fields:
|
||
|
||
```text
|
||
id, zone_id, device_id, timestamp,
|
||
gree_temperature, external_temperature, control_temperature,
|
||
target_temperature, device_setpoint, outdoor_temperature,
|
||
power, mode, fan_speed, demand, control_source, active_preset
|
||
```
|
||
|
||
Device reading fields are the `Reading` fields documented above. HA sensor rows contain:
|
||
|
||
```text
|
||
id, entity_id, zone_id, kind, timestamp, temperature
|
||
```
|
||
|
||
`scope=overview` returns all three families plus counts and per-family storage source.
|
||
|
||
When InfluxDB is enabled, older history can be read from Influx and merged with recent SQLite rows. A failed Influx query falls back to available SQLite data and reports `storage_warning` rather than failing the entire chart response.
|
||
|
||
---
|
||
|
||
## Control plan
|
||
|
||
### `GET /api/control-plan`
|
||
|
||
Returns the resolved machine-readable thermostat plan:
|
||
|
||
Top-level fields:
|
||
|
||
```text
|
||
generated_at
|
||
house_mode
|
||
house_preset
|
||
house_power
|
||
outdoor_temperature
|
||
control_strategy
|
||
night_mode_active
|
||
night_mode_start
|
||
night_mode_end
|
||
night_mode_max_fan_speed
|
||
next_events[]
|
||
zones[]
|
||
rules[]
|
||
```
|
||
|
||
Each zone plan includes:
|
||
|
||
```text
|
||
zone_id, zone_name, device_id, device_name,
|
||
enabled, effective_enabled,
|
||
mode, configured_mode, inherit_house_mode,
|
||
preset, preset_override,
|
||
current_temperature, target_temperature, device_setpoint,
|
||
desired_power, desired_mode,
|
||
actual_power, actual_mode, actual_setpoint,
|
||
demand, control_source,
|
||
manual_override_until,
|
||
local_thermostat_power, local_thermostat_resume_at,
|
||
device_manual_override, device_manual_override_until,
|
||
control_owner, control_command_source, control_since, resume_at, control_reason,
|
||
blocked_reason, lockout_until,
|
||
current_schedule_id, current_schedule_name,
|
||
next_events[]
|
||
```
|
||
|
||
This endpoint is the best way for another client to understand **desired vs actual state**, who owns control, and why a zone is blocked/paused.
|
||
|
||
---
|
||
|
||
## Events and retention
|
||
|
||
### `GET /api/events?limit=100`
|
||
|
||
Response:
|
||
|
||
```json
|
||
{
|
||
"events": [
|
||
{
|
||
"id": 1,
|
||
"timestamp": "...",
|
||
"level": "info",
|
||
"kind": "device.updated",
|
||
"message": "...",
|
||
"metadata": {}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### `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
|
||
|
||
### `GET /api/settings`
|
||
|
||
Returns a public-safe settings document. Secrets are blanked and accompanied by `*_configured` booleans where relevant.
|
||
|
||
Shape:
|
||
|
||
```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": {}
|
||
}
|
||
```
|
||
|
||
#### Home Assistant settings
|
||
|
||
```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"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### InfluxDB settings
|
||
|
||
```json
|
||
{
|
||
"enabled": true,
|
||
"version": "2",
|
||
"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.
|
||
|
||
#### Notification settings
|
||
|
||
```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,
|
||
"target_timeout_minutes": 60,
|
||
"alert_types": {
|
||
"stale_sensor": true,
|
||
"sensor_errors": true,
|
||
"communication": true,
|
||
"target_timeout": true,
|
||
"automation": true,
|
||
"control_errors": true,
|
||
"important_events": true,
|
||
"other": true
|
||
}
|
||
}
|
||
```
|
||
|
||
Modes: `problems`, `important`. Providers: `pushover`, `slack`, `discord`.
|
||
|
||
### `PUT /api/settings`
|
||
|
||
Accepts the complete `RuntimeSettings` document. Important behavior:
|
||
|
||
- `house_mode` and `house_power_enabled` cannot be changed here; use House Control API.
|
||
- 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`.
|
||
|
||
Returns the safe public settings form.
|
||
|
||
### `GET /api/settings/export`
|
||
|
||
Returns configuration format version `1`:
|
||
|
||
```text
|
||
format_version
|
||
exported_at
|
||
settings
|
||
devices[]
|
||
zones[]
|
||
groups[]
|
||
schedules[]
|
||
automations[]
|
||
```
|
||
|
||
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.
|
||
|
||
### `POST /api/settings/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.
|
||
|
||
Metric/event history and generated access-token records are preserved.
|
||
|
||
Response:
|
||
|
||
```json
|
||
{
|
||
"ok": true
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 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`
|
||
|
||
```json
|
||
{
|
||
"entity_id": "sensor.room_temperature"
|
||
}
|
||
```
|
||
|
||
`entity_id` is optional; controller defaults/aliases are resolved. Response:
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"temperature_c": 23.4,
|
||
"entity_id": "sensor.room_temperature"
|
||
}
|
||
```
|
||
|
||
### `POST /api/integrations/notifications/test`
|
||
|
||
Accepts a `NotificationSettings` object. Blank secret/webhook fields reuse saved secrets for the test.
|
||
|
||
Response:
|
||
|
||
```json
|
||
{
|
||
"ok": true
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## Access tokens
|
||
|
||
### `GET /api/access-tokens`
|
||
|
||
Returns:
|
||
|
||
```json
|
||
[
|
||
{
|
||
"id": "uuid",
|
||
"name": "Home Assistant",
|
||
"token_prefix": "gree_controller_abc...",
|
||
"created_at": "..."
|
||
}
|
||
]
|
||
```
|
||
|
||
### `POST /api/access-tokens`
|
||
|
||
```json
|
||
{
|
||
"name": "Home Assistant"
|
||
}
|
||
```
|
||
|
||
Name length: `1..80`. If omitted, default is `Home Assistant`.
|
||
|
||
Response `201 Created`:
|
||
|
||
```json
|
||
{
|
||
"token": "gree_controller_FULL_SECRET_SHOWN_ONCE",
|
||
"item": {
|
||
"id": "uuid",
|
||
"name": "Home Assistant",
|
||
"token_prefix": "gree_controller_...",
|
||
"created_at": "..."
|
||
}
|
||
}
|
||
```
|
||
|
||
### `DELETE /api/access-tokens/{id}`
|
||
|
||
Revokes token and returns `204`.
|
||
|
||
---
|
||
|
||
## Restricted Home Assistant API
|
||
|
||
These routes always require a generated token or the administrator app token.
|
||
|
||
### `GET /api/integrations/home-assistant/devices`
|
||
|
||
Returns `Device[]`.
|
||
|
||
### `POST /api/integrations/home-assistant/devices/{id}/command`
|
||
|
||
Accepts `DeviceCommand`. A direct command is rejected if the device belongs to a disabled thermostat zone; re-enable the zone for normal HA/controller ownership or use the administrator technical device endpoint deliberately.
|
||
|
||
### `GET /api/integrations/home-assistant/control-plan`
|
||
|
||
Same payload as administrator `GET /api/control-plan`.
|
||
|
||
### `GET /api/integrations/home-assistant/groups`
|
||
|
||
Returns an HA-oriented derived group list. Each object includes:
|
||
|
||
```text
|
||
id, name, zone_ids, zone_names,
|
||
power_enabled, effective_power,
|
||
mode, preset, house_mode,
|
||
zone_count, enabled_zones, active_zones, demanding_zones,
|
||
device_count, online_devices, current_temperature,
|
||
members[], next_events[]
|
||
```
|
||
|
||
Member rows include zone/device identity, configured/effective enable state, mode/preset, room/target temperature, demand, source, schedule and current manual/local ownership markers.
|
||
|
||
### `POST /api/integrations/home-assistant/groups/{id}/control`
|
||
|
||
Same body/semantics as normal group control.
|
||
|
||
### `POST /api/integrations/home-assistant/house/control`
|
||
|
||
Same `{ "mode": "cool|heat|off" }` semantics as administrator house mode.
|
||
|
||
### `POST /api/integrations/home-assistant/house/preset`
|
||
|
||
Same `{ "preset": "auto|comfort|sleep|away" }` semantics.
|
||
|
||
### `POST /api/integrations/home-assistant/house/power`
|
||
|
||
Same `{ "power": true|false }` semantics.
|
||
|
||
### `POST /api/integrations/home-assistant/zones/{id}/control`
|
||
|
||
Same `ZoneControlPatch` thermostat semantics as the normal zone control endpoint. The internal source is recorded as Home Assistant thermostat control.
|
||
|
||
---
|
||
|
||
## WebSocket
|
||
|
||
### Connection
|
||
|
||
Without administrator authentication:
|
||
|
||
```text
|
||
ws://HOST:8787/ws
|
||
```
|
||
|
||
When `GREE_CONTROLLER_APP_TOKEN` is configured:
|
||
|
||
```text
|
||
ws://HOST:8787/ws?token=APP_TOKEN
|
||
```
|
||
|
||
Generated restricted HA tokens are not WebSocket administrator tokens.
|
||
|
||
### Message envelope
|
||
|
||
Every server event uses:
|
||
|
||
```json
|
||
{
|
||
"event": "device.updated",
|
||
"timestamp": "2026-08-30T06:54:00Z",
|
||
"data": {}
|
||
}
|
||
```
|
||
|
||
The first frame is always `bootstrap` with the same payload as `GET /api/bootstrap`, unless bootstrap generation itself fails.
|
||
|
||
Common live events include:
|
||
|
||
```text
|
||
bootstrap
|
||
device.created
|
||
device.updated
|
||
device.deleted
|
||
devices.discovered
|
||
zone.created
|
||
zone.updated
|
||
zone.deleted
|
||
group.created
|
||
group.updated
|
||
group.deleted
|
||
schedule.created
|
||
schedule.updated
|
||
schedule.deleted
|
||
schedule.template_applied
|
||
automation.created
|
||
automation.updated
|
||
automation.deleted
|
||
settings.updated
|
||
configuration.imported
|
||
debug.settings
|
||
api.request
|
||
gree.frame
|
||
log.created
|
||
```
|
||
|
||
Additional engine/integration events may be introduced without changing the envelope.
|
||
|
||
`api.request` data:
|
||
|
||
```json
|
||
{
|
||
"method": "GET",
|
||
"path": "/api/system/info",
|
||
"status": 200,
|
||
"duration_ms": 2
|
||
}
|
||
```
|
||
|
||
GREE debug events are emitted only when enabled and are intended for diagnostics, not as a stable protocol API.
|
||
|
||
---
|
||
|
||
## Localization endpoints
|
||
|
||
Language files are public so the UI can localize before administrator authentication.
|
||
|
||
### `GET /lang/index.json`
|
||
|
||
Returns the generated catalog of embedded packs.
|
||
|
||
### `GET /lang/{code}.json`
|
||
|
||
Returns one embedded language pack, e.g.:
|
||
|
||
```text
|
||
GET /lang/en.json
|
||
GET /lang/pl.json
|
||
```
|
||
|
||
---
|
||
|
||
## Practical API examples
|
||
|
||
Assume:
|
||
|
||
```bash
|
||
BASE='http://127.0.0.1:8787'
|
||
AUTH='Authorization: Bearer APP_TOKEN'
|
||
```
|
||
|
||
Discover devices:
|
||
|
||
```bash
|
||
curl -X POST "$BASE/api/discovery" -H "$AUTH" -H 'Content-Type: application/json' \
|
||
-d '{"protocol_version":0,"passes":3}'
|
||
```
|
||
|
||
Directly poll a device:
|
||
|
||
```bash
|
||
curl -X POST "$BASE/api/devices/DEVICE_ID/poll" -H "$AUTH"
|
||
```
|
||
|
||
Set a zone target:
|
||
|
||
```bash
|
||
curl -X POST "$BASE/api/zones/ZONE_ID/control" -H "$AUTH" -H 'Content-Type: application/json' \
|
||
-d '{"setpoint":22.5}'
|
||
```
|
||
|
||
Return zone to automatic scheduling:
|
||
|
||
```bash
|
||
curl -X POST "$BASE/api/zones/ZONE_ID/control" -H "$AUTH" -H 'Content-Type: application/json' \
|
||
-d '{"preset":"auto","clear_local_thermostat_override":true}'
|
||
```
|
||
|
||
Turn the whole managed house off:
|
||
|
||
```bash
|
||
curl -X POST "$BASE/api/house/power" -H "$AUTH" -H 'Content-Type: application/json' \
|
||
-d '{"power":false}'
|
||
```
|
||
|
||
Read current ownership/desired-vs-actual state:
|
||
|
||
```bash
|
||
curl "$BASE/api/control-plan" -H "$AUTH"
|
||
```
|
||
|
||
Read 90 days of zone history:
|
||
|
||
```bash
|
||
curl "$BASE/api/history?scope=zones&zone_id=ZONE_ID&hours=2160" -H "$AUTH"
|
||
```
|
||
|
||
Create a restricted Home Assistant token:
|
||
|
||
```bash
|
||
curl -X POST "$BASE/api/access-tokens" -H "$AUTH" -H 'Content-Type: application/json' \
|
||
-d '{"name":"Home Assistant"}'
|
||
```
|
||
|
||
Use that token:
|
||
|
||
```bash
|
||
curl -H 'Authorization: Bearer gree_controller_RESTRICTED_TOKEN' \
|
||
"$BASE/api/integrations/home-assistant/control-plan"
|
||
```
|