# 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 ``` These two endpoints always require `Authorization: Bearer ` (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. ## 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` 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/.json` returns the corresponding language pack. Add a valid `lang/.json` file and rebuild to expose a new language. ### `GET /api/history` The history API exposes three independent data families and a combined overview. Common parameters are `hours=6|24|168|720` and `limit` up to 20,000 rows. Downsampling is performed in SQLite: 30-second buckets up to 6 hours, 2-minute buckets up to 24 hours, 10-minute buckets up to 7 days, and 30-minute buckets for longer ranges. ```text GET /api/history?scope=overview&hours=24 GET /api/history?scope=devices&device_id=DEVICE_ID&hours=24 GET /api/history?scope=zones&zone_id=ZONE_ID&hours=24 GET /api/history?scope=sensors&entity_id=sensor.room_temperature&hours=24 ``` `scope=overview` returns: ```json { "scope": "overview", "bucket_seconds": 120, "zones": [], "devices": [], "sensors": [], "counts": {"devices": 0, "zones": 0, "ha": 0} } ``` Device rows come from the existing `readings` table and contain `indoor_temperature`, optional GREE `outdoor_temperature`, `target_temperature`, `power`, and `source`. This makes old device history immediately available after an upgrade. Zone rows contain `gree_temperature`, `external_temperature` (HA room sensor), `control_temperature`, `target_temperature`, `device_setpoint`, `outdoor_temperature`, `power`, `mode`, `fan_speed`, `demand`, `control_source`, and `active_preset`. If a zone has no rich samples yet, the API falls back to that zone's existing GREE device readings instead of returning an empty timeline. Sensor rows contain `entity_id`, optional `zone_id`, `kind` (`room` or `outdoor`), `timestamp`, and `temperature`. New HA samples start being collected after the upgrade; where older rich zone samples contain the same HA values, the API can expose them as compatibility history.