7867 lines
207 KiB
JSON
7867 lines
207 KiB
JSON
{
|
|
"openapi": "3.1.0",
|
|
"info": {
|
|
"title": "GREE Controller API",
|
|
"version": "0.13.5",
|
|
"summary": "Local HTTP/WebSocket API for GREE HVAC control",
|
|
"description": "Self-hosted API used by the GREE Controller Web UI and Home Assistant integration.\n\n### Authentication\nNormal administrator endpoints accept `Authorization: Bearer <APP_TOKEN>` or `x-api-token: <APP_TOKEN>` when `GREE_CONTROLLER_APP_TOKEN` is configured. If the app token is empty, those endpoints intentionally run in trusted-LAN mode without authentication.\n\nThe restricted `/api/integrations/home-assistant/*` control surface always requires either a generated access token or the administrator app token. Generated tokens do **not** grant normal administrator API access.\n\nIn Swagger UI use **Authorize** and enter the token in either the bearer field or `x-api-token` field.\n\n### Control ownership\nThermostat zones, groups, house rules, direct device control, schedules and visual Flows share an ownership/arbitration model. Prefer zone/group/house endpoints for thermostat intent; direct device commands are technical/manual control and can deliberately take ownership.\n\n### 0.12.0 breaking API\nRuntime settings are split into functional `/api/settings/*` resources. The former `/api/settings`, `/api/debug`, `/api/events/retention`, `/api/settings/export` and `/api/settings/import` endpoints were removed without compatibility aliases.\n\n### 0.13.0\n`control-plan` keeps its existing HTTP response shape but is materialized in memory and pushed to WebSocket clients as `control_plan.updated`; HTTP remains the fallback/resync path. A restricted Home Assistant snapshot endpoint combines devices, groups and the control plan.\n\n### 0.13.1\nRuntime WebSocket churn is reduced without changing contracts: no-op zone regulator heartbeats are deduplicated and device heartbeat polls only invalidate the materialized control plan when plan-relevant device state changes.\n\n### 0.13.2\nCompletes live WebSocket synchronization for entity creation, schedules, automations, configuration imports and runtime device/automation state while preserving the existing HTTP API contracts and control-plan fallback behavior.\n\n### 0.13.3\nLogical thermostat targets are normalized to 0.1 C consistently, including Temporary Quick Thermostat and thermostat-managed automation/Flow actions. The bundled Web UI accepts comma or dot decimal input for the temporary thermostat target; physical GREE setpoint rounding is unchanged.\n\n### 0.13.4\nDisabled-zone thermostat controls remain visually active in the bundled Web UI because explicit temporary/manual thermostat and direct manual control remain available while zone automation is disabled. HTTP and WebSocket contracts are unchanged.\n\n### 0.13.5\nThe zone settings dialog now explains directly beside the enabled/disabled option that disabling a zone stops automation but does not block manual thermostat, temporary thermostat or direct manual control. HTTP and WebSocket contracts remain unchanged.",
|
|
"license": {
|
|
"name": "MIT"
|
|
}
|
|
},
|
|
"servers": [
|
|
{
|
|
"url": "/",
|
|
"description": "This GREE Controller instance"
|
|
}
|
|
],
|
|
"tags": [
|
|
{
|
|
"name": "System",
|
|
"description": "Health, bootstrap and runtime diagnostics."
|
|
},
|
|
{
|
|
"name": "Devices",
|
|
"description": "GREE discovery, binding, polling and direct technical device control."
|
|
},
|
|
{
|
|
"name": "Zones",
|
|
"description": "Thermostat configuration, Quick Thermostat and ownership hand-back."
|
|
},
|
|
{
|
|
"name": "Compressor protection",
|
|
"description": "Pending compressor-protection queue inspection/cancellation actions."
|
|
},
|
|
{
|
|
"name": "Groups",
|
|
"description": "Scoped multi-zone thermostat groups."
|
|
},
|
|
{
|
|
"name": "House",
|
|
"description": "Whole-house thermostat mode, profile and bulk power actions."
|
|
},
|
|
{
|
|
"name": "Schedules",
|
|
"description": "Native weekly zone schedules and built-in templates."
|
|
},
|
|
{
|
|
"name": "Automations",
|
|
"description": "Legacy temperature/time automations and Flow-generated runtime records."
|
|
},
|
|
{
|
|
"name": "Flows",
|
|
"description": "Visual source graphs, atomic compilation, portability, dry-run and diagnostics."
|
|
},
|
|
{
|
|
"name": "History",
|
|
"description": "Readings, chart history and resolved control plan."
|
|
},
|
|
{
|
|
"name": "Events",
|
|
"description": "Event log."
|
|
},
|
|
{
|
|
"name": "Settings",
|
|
"description": "Functional runtime settings resources. Each endpoint reads/writes only one settings section."
|
|
},
|
|
{
|
|
"name": "Configuration",
|
|
"description": "Versioned full configuration backup and restore. Backups contain secrets."
|
|
},
|
|
{
|
|
"name": "Diagnostics",
|
|
"description": "Integration connection tests and diagnostics."
|
|
},
|
|
{
|
|
"name": "Access tokens",
|
|
"description": "Generated restricted tokens for Home Assistant."
|
|
},
|
|
{
|
|
"name": "Home Assistant",
|
|
"description": "Always-authenticated restricted integration control surface."
|
|
},
|
|
{
|
|
"name": "WebSocket",
|
|
"description": "Live event stream."
|
|
},
|
|
{
|
|
"name": "Catalogs",
|
|
"description": "Public embedded language and Flow-preset catalogs."
|
|
}
|
|
],
|
|
"paths": {
|
|
"/api/health": {
|
|
"get": {
|
|
"tags": [
|
|
"System"
|
|
],
|
|
"summary": "Health check",
|
|
"description": "Public lightweight process and control-engine health check. `control_ready=false` means the process is alive but initial physical device synchronization has not completed.",
|
|
"operationId": "health",
|
|
"security": [],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Controller health",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Health"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/bootstrap": {
|
|
"get": {
|
|
"tags": [
|
|
"System"
|
|
],
|
|
"summary": "Get application bootstrap",
|
|
"description": "Returns the initial Web UI entity snapshot: devices, zones, groups, schedules, automations, Flows, access-token metadata, house mode, outdoor temperature, the latest materialized control plan with its revision, and system diagnostics. Runtime settings are loaded from the functional `/api/settings/*` resources.",
|
|
"operationId": "bootstrap",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Initial application snapshot",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/system/info": {
|
|
"get": {
|
|
"tags": [
|
|
"System"
|
|
],
|
|
"summary": "Get system diagnostics",
|
|
"description": "Returns the same system diagnostic object exposed inside bootstrap, including version, uptime, authentication mode, database/bind information and GREE frame counters.",
|
|
"operationId": "systemInfo",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "System diagnostics",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/discovery": {
|
|
"post": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Discover GREE devices",
|
|
"description": "Broadcasts GREE discovery, merges known devices, attempts binding for devices without a key, persists results and reports newly discovered controller IDs.",
|
|
"operationId": "discoverDevices",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/DiscoveryRequest"
|
|
},
|
|
"example": {
|
|
"timeout_ms": 6000,
|
|
"broadcast": "255.255.255.255:7000",
|
|
"protocol_version": 0,
|
|
"passes": 3
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Discovery result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/DiscoveryResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/devices": {
|
|
"get": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "List devices",
|
|
"description": "Lists all known physical and simulated GREE devices with their latest persisted/runtime state.",
|
|
"operationId": "listDevices",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Device list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Add device manually",
|
|
"description": "Registers a device without broadcast discovery. MAC addresses are normalized and duplicate MACs are rejected.",
|
|
"operationId": "addDevice",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ManualDeviceRequest"
|
|
},
|
|
"example": {
|
|
"name": "Living room",
|
|
"mac": "AABBCCDDEEFF",
|
|
"ip": "192.168.50.30",
|
|
"port": 7000,
|
|
"protocol_version": 1,
|
|
"key": null,
|
|
"simulated": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created device",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/devices/{id}": {
|
|
"get": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Get device",
|
|
"description": "Returns one device by controller ID.",
|
|
"operationId": "getDevice",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Device ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Device",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"patch": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Patch device configuration",
|
|
"description": "Updates technical device fields. Changing protocol version clears the binding key/capability cache. Disabling a device follows the controller's safe-disable path.",
|
|
"operationId": "patchDevice",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Device ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/DevicePatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated device",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Delete device",
|
|
"description": "Deletes a device only after thermostat/automation safety checks. Referenced or unsafely owned devices are rejected.",
|
|
"operationId": "deleteDevice",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Device ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Device deleted"
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/devices/{id}/bind": {
|
|
"post": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Bind or re-bind device",
|
|
"description": "Performs GREE binding and returns the updated device. Simulated devices are returned unchanged.",
|
|
"operationId": "bindDevice",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Device ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Bound device",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/devices/{id}/poll": {
|
|
"post": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Poll device now",
|
|
"description": "Immediately polls a unit and persists/returns its refreshed state.",
|
|
"operationId": "pollDevice",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Device ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated device",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/devices/{id}/probe": {
|
|
"post": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Probe device latency",
|
|
"description": "Performs a minimal non-mutating GREE status round-trip. It does not update online/error counters, readings, capabilities, thermostat ownership or persisted state.",
|
|
"operationId": "probeDevice",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Device ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Probe result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"device_id": {
|
|
"type": "string"
|
|
},
|
|
"response_time_ms": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"ok": {
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"required": [
|
|
"device_id",
|
|
"response_time_ms",
|
|
"ok"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"example": {
|
|
"device_id": "gree-aabbccddeeff",
|
|
"response_time_ms": 18,
|
|
"ok": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/devices/{id}/command": {
|
|
"post": {
|
|
"tags": [
|
|
"Devices"
|
|
],
|
|
"summary": "Send direct device command",
|
|
"description": "Administrator manual/direct control. Only changed fields are sent. Climate-relevant direct commands may take thermostat ownership so automation does not immediately fight the user. A disabled thermostat zone requires explicit `manual_override=true`.",
|
|
"operationId": "commandDevice",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Device ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ManualDeviceCommand"
|
|
},
|
|
"example": {
|
|
"power": true,
|
|
"mode": "cool",
|
|
"target_temperature": 22,
|
|
"fan_speed": 3,
|
|
"manual_override": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated device",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/zones": {
|
|
"get": {
|
|
"tags": [
|
|
"Zones"
|
|
],
|
|
"summary": "List thermostat zones",
|
|
"description": "Returns all thermostat zones including live sensor, demand, ownership, lockout and override state.",
|
|
"operationId": "listZones",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Zone list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Zone"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"Zones"
|
|
],
|
|
"summary": "Create thermostat zone",
|
|
"description": "Creates a thermostat zone after validating temperature ranges, sensor source and one-zone-per-device ownership.",
|
|
"operationId": "createZone",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ZoneInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created zone",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Zone"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/zones/{id}": {
|
|
"get": {
|
|
"tags": [
|
|
"Zones"
|
|
],
|
|
"summary": "Get thermostat zone",
|
|
"description": "Returns one thermostat zone.",
|
|
"operationId": "getZone",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Zone ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Zone",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Zone"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Zones"
|
|
],
|
|
"summary": "Replace zone configuration",
|
|
"description": "Replaces editable zone configuration while preserving and reconciling runtime safety/ownership state. If `revision` is supplied, stale updates can return 409.",
|
|
"operationId": "updateZone",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Zone ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ZoneInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated zone",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Zone"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"Zones"
|
|
],
|
|
"summary": "Delete thermostat zone",
|
|
"description": "Safely powers the owned device off before detaching thermostat ownership, then removes related group membership when safe.",
|
|
"operationId": "deleteZone",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Zone ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Zone deleted"
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/zones/{id}/control": {
|
|
"post": {
|
|
"tags": [
|
|
"Zones"
|
|
],
|
|
"summary": "Control thermostat zone",
|
|
"description": "Quick Thermostat API for setpoint/preset/mode/power and ownership hand-back. It can also start or cancel persisted Temporary Quick Thermostat sessions. Manual setpoints retain 0.1 C precision; the physical GREE setpoint is still rounded to protocol resolution.",
|
|
"operationId": "controlZone",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Zone ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ZoneControlPatch"
|
|
},
|
|
"example": {
|
|
"setpoint": 22.5,
|
|
"power": true,
|
|
"mode": "house",
|
|
"preset": "comfort",
|
|
"clear_override": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated zone",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Zone"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/zones/{id}/schedule-template": {
|
|
"post": {
|
|
"tags": [
|
|
"Schedules"
|
|
],
|
|
"summary": "Apply built-in schedule template",
|
|
"description": "Replaces schedules for one zone with a built-in family/child/bedroom/workday/always template after overlap validation.",
|
|
"operationId": "applyScheduleTemplate",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Zone ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ScheduleTemplateRequest"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Zone and generated schedules",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"zone": {
|
|
"$ref": "#/components/schemas/Zone"
|
|
},
|
|
"schedules": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Schedule"
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"zone",
|
|
"schedules"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/zones/{id}/compressor-queue/cancel": {
|
|
"post": {
|
|
"tags": [
|
|
"Compressor protection"
|
|
],
|
|
"summary": "Cancel zone compressor queue",
|
|
"description": "Cancels the currently pending compressor-protection task for one zone. The same intent stays suppressed until a new explicit control request or changed target/mode re-arms it.",
|
|
"operationId": "cancelZoneCompressorQueue",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Zone ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Cancellation result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/compressor-queue/cancel-all": {
|
|
"post": {
|
|
"tags": [
|
|
"Compressor protection"
|
|
],
|
|
"summary": "Cancel all compressor queues",
|
|
"description": "Cancels every currently pending compressor-protection task. Safety OFF commands are never delayed by compressor protection.",
|
|
"operationId": "cancelAllCompressorQueues",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Cancellation summary",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/groups": {
|
|
"get": {
|
|
"tags": [
|
|
"Groups"
|
|
],
|
|
"summary": "List climate groups",
|
|
"description": "Returns configured climate groups.",
|
|
"operationId": "listGroups",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Group list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ClimateGroup"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"Groups"
|
|
],
|
|
"summary": "Create climate group",
|
|
"description": "Creates a group containing one or more existing zones. Duplicate IDs are normalized away.",
|
|
"operationId": "createGroup",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GroupInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created group",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ClimateGroup"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/groups/{id}": {
|
|
"get": {
|
|
"tags": [
|
|
"Groups"
|
|
],
|
|
"summary": "Get climate group",
|
|
"description": "Returns one climate group.",
|
|
"operationId": "getGroup",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Group ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Group",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ClimateGroup"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Groups"
|
|
],
|
|
"summary": "Replace climate group",
|
|
"description": "Replaces group name/member zones/control state after validating references.",
|
|
"operationId": "updateGroup",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Group ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GroupInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated group",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ClimateGroup"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"Groups"
|
|
],
|
|
"summary": "Delete climate group",
|
|
"description": "Deletes a climate group and releases scoped group ownership. Returns 204 on success.",
|
|
"operationId": "deleteGroup",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Group ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Group deleted"
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/groups/{id}/control": {
|
|
"post": {
|
|
"tags": [
|
|
"Groups"
|
|
],
|
|
"summary": "Control climate group",
|
|
"description": "Applies scoped group power/mode/preset/custom setpoint to member zones. Group OFF stores members as individually-off thermostats rather than creating a persistent global gate.",
|
|
"operationId": "controlGroup",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Group ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GroupControlPatch"
|
|
},
|
|
"example": {
|
|
"power": true,
|
|
"mode": "house",
|
|
"preset": "custom",
|
|
"setpoint": 22.3
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Group control result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/house/control": {
|
|
"post": {
|
|
"tags": [
|
|
"House"
|
|
],
|
|
"summary": "Set house thermostat mode",
|
|
"description": "Sets the house rule (`cool`, `heat`, `off`) used by free zones that inherit global mode. Explicit local/group/direct ownership is preserved.",
|
|
"operationId": "controlHouse",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HouseControlPatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Public runtime settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/RuntimeSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/house/power": {
|
|
"post": {
|
|
"tags": [
|
|
"House"
|
|
],
|
|
"summary": "Bulk house power",
|
|
"description": "One-shot whole-house thermostat ON/OFF. OFF stores every thermostat as indefinite local OFF before sending device OFF so normal demand cannot immediately restart it. ON releases those local OFF markers and sends ON.",
|
|
"operationId": "powerHouse",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HousePowerPatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Bulk power result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/house/preset": {
|
|
"post": {
|
|
"tags": [
|
|
"House"
|
|
],
|
|
"summary": "Apply house preset",
|
|
"description": "Applies `auto`, `comfort`, `sleep` or `away` to eligible free house-controlled zones. Scoped local/group/direct ownership is not overwritten.",
|
|
"operationId": "presetHouse",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HousePresetPatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "House preset result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/schedules": {
|
|
"get": {
|
|
"tags": [
|
|
"Schedules"
|
|
],
|
|
"summary": "List schedules",
|
|
"description": "Lists legacy/native thermostat schedules, including Flow ownership metadata when generated from a visual Flow.",
|
|
"operationId": "listSchedules",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Schedule list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Schedule"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"Schedules"
|
|
],
|
|
"summary": "Create schedule",
|
|
"description": "Creates a weekly schedule. Times are local HH:MM, midnight crossing is supported and enabled schedules for the same zone may not overlap.",
|
|
"operationId": "createSchedule",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ScheduleInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created schedule",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Schedule"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/schedules/{id}": {
|
|
"get": {
|
|
"tags": [
|
|
"Schedules"
|
|
],
|
|
"summary": "Get schedule",
|
|
"description": "Returns one schedule.",
|
|
"operationId": "getSchedule",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Schedule ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Schedule",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Schedule"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Schedules"
|
|
],
|
|
"summary": "Replace schedule",
|
|
"description": "Replaces a legacy/native schedule after validation. Flow-generated schedules are read-only here; edit the owning Flow.",
|
|
"operationId": "updateSchedule",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Schedule ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ScheduleInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated schedule",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Schedule"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"Schedules"
|
|
],
|
|
"summary": "Delete schedule",
|
|
"description": "Deletes a legacy/native schedule. Flow-generated schedules must be changed by editing/deleting the Flow.",
|
|
"operationId": "deleteSchedule",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Schedule ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Schedule deleted"
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/automations": {
|
|
"get": {
|
|
"tags": [
|
|
"Automations"
|
|
],
|
|
"summary": "List automations",
|
|
"description": "Lists legacy automations and Flow-generated automations with source ownership metadata.",
|
|
"operationId": "listAutomations",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Automation list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Automation"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"Automations"
|
|
],
|
|
"summary": "Create automation",
|
|
"description": "Creates a temperature/time automation targeting either a direct device or a climate group.",
|
|
"operationId": "createAutomation",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/AutomationInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created automation",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Automation"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/automations/{id}": {
|
|
"get": {
|
|
"tags": [
|
|
"Automations"
|
|
],
|
|
"summary": "Get automation",
|
|
"description": "Returns one automation.",
|
|
"operationId": "getAutomation",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Automation ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Automation",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Automation"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Automations"
|
|
],
|
|
"summary": "Replace automation",
|
|
"description": "Replaces a legacy automation. Flow-generated automations are read-only here; edit the owning Flow.",
|
|
"operationId": "updateAutomation",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Automation ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/AutomationInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated automation",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Automation"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"Automations"
|
|
],
|
|
"summary": "Delete automation",
|
|
"description": "Deletes a legacy automation. Flow-generated automations must be changed by editing/deleting the Flow.",
|
|
"operationId": "deleteAutomation",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Automation ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Automation deleted"
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/flows": {
|
|
"get": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "List visual Flows",
|
|
"description": "Lists visual Flow source graphs and compiled-output metadata.",
|
|
"operationId": "listFlows",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Flow list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Flow"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "Create visual Flow",
|
|
"description": "Creates a Flow source graph. Executable Flows validate the DAG and atomically compile native schedules/automations; draft Flows are forced disabled and compile no outputs.",
|
|
"operationId": "createFlow",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/FlowInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created Flow",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Flow"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/flows/{id}": {
|
|
"get": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "Get visual Flow",
|
|
"description": "Returns one Flow source graph plus compiled-output metadata.",
|
|
"operationId": "getFlow",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Flow ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Flow",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Flow"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "Update visual Flow",
|
|
"description": "Updates a Flow atomically. `expected_revision` is required; a mismatch returns 409 so stale editor tabs cannot overwrite newer graphs.",
|
|
"operationId": "updateFlow",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Flow ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/FlowInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated Flow",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Flow"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"delete": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "Delete visual Flow",
|
|
"description": "Deletes the Flow and its generated schedules/automations atomically.",
|
|
"operationId": "deleteFlow",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Flow ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Flow deleted"
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/flows/{id}/export": {
|
|
"get": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "Export Flow source",
|
|
"description": "Exports a versioned `gree-controller-flow` document containing only the source graph, never generated schedules/automations.",
|
|
"operationId": "exportFlow",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Flow ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Portable Flow document",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/FlowExport"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/flows/import": {
|
|
"post": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "Import Flow source",
|
|
"description": "Imports either a `gree-controller-flow` envelope or a direct Flow source payload. A new Flow ID/revision is created; executable imports are validated and recompiled, drafts remain disabled.",
|
|
"operationId": "importFlow",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/FlowExport"
|
|
},
|
|
{
|
|
"$ref": "#/components/schemas/FlowInput"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Imported Flow",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Flow"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"409": {
|
|
"$ref": "#/components/responses/Conflict"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/flows/simulate": {
|
|
"post": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "Dry-run Flow",
|
|
"description": "Validates, compiles and evaluates a Flow at an optional RFC3339 time with per-node overrides. Returns trace, match status, `would_execute` and `blocked_reason`. Never mutates thermostat/device/group/schedule/automation state.",
|
|
"operationId": "simulateFlow",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/FlowSimulationInput"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Dry-run result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/FlowSimulationResult"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/flows/{id}/logs": {
|
|
"get": {
|
|
"tags": [
|
|
"Flows"
|
|
],
|
|
"summary": "Get Flow-related events",
|
|
"description": "Returns recent events associated with the Flow or its generated automations. Limit defaults to 100 and is clamped to 1..250.",
|
|
"operationId": "flowLogs",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Flow ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
},
|
|
{
|
|
"name": "limit",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Maximum returned events",
|
|
"schema": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 250
|
|
},
|
|
"example": 100
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Flow event list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"events": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/EventLog"
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"events"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/readings": {
|
|
"get": {
|
|
"tags": [
|
|
"History"
|
|
],
|
|
"summary": "Get device readings",
|
|
"description": "Legacy/lightweight device history. `hours` defaults to 24 and is clamped to 10 years; `limit` defaults to 1500.",
|
|
"operationId": "readings",
|
|
"parameters": [
|
|
{
|
|
"name": "device_id",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Optional device filter",
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "hours",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Lookback window in hours",
|
|
"schema": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 87600
|
|
},
|
|
"example": 24
|
|
},
|
|
{
|
|
"name": "limit",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Row limit",
|
|
"schema": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"example": 1500
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Device readings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"readings": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Reading"
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"readings"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/history": {
|
|
"get": {
|
|
"tags": [
|
|
"History"
|
|
],
|
|
"summary": "Get rich history",
|
|
"description": "Chart/history API for overview, zones, devices or Home Assistant sensors. Rows are bucketed by lookback window. When InfluxDB is enabled, older data may be merged with SQLite; an Influx failure falls back to available SQLite and may return `storage_warning`.",
|
|
"operationId": "history",
|
|
"parameters": [
|
|
{
|
|
"name": "scope",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "History family; defaults to zones",
|
|
"schema": {
|
|
"type": "string",
|
|
"enum": [
|
|
"overview",
|
|
"zones",
|
|
"zone",
|
|
"devices",
|
|
"sensors"
|
|
]
|
|
},
|
|
"example": "zones"
|
|
},
|
|
{
|
|
"name": "zone_id",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Zone filter",
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "device_id",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Device filter",
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "entity_id",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Home Assistant entity filter",
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
{
|
|
"name": "hours",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Lookback window",
|
|
"schema": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 87600
|
|
},
|
|
"example": 24
|
|
},
|
|
{
|
|
"name": "limit",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Maximum rows",
|
|
"schema": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 20000
|
|
},
|
|
"example": 12000
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "History payload",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/control-plan": {
|
|
"get": {
|
|
"tags": [
|
|
"History"
|
|
],
|
|
"summary": "Get resolved control plan",
|
|
"description": "Machine-readable desired-vs-actual thermostat plan with ownership, blocking reasons, schedules, next events and per-zone control decisions. The response shape is unchanged; the bundled Web UI receives plan changes through WebSocket and uses this endpoint as a fallback/resynchronization surface.",
|
|
"operationId": "controlPlan",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Resolved control plan",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/events": {
|
|
"get": {
|
|
"tags": [
|
|
"Events"
|
|
],
|
|
"summary": "List event log",
|
|
"description": "Returns recent controller event rows. Limit defaults to 100.",
|
|
"operationId": "events",
|
|
"parameters": [
|
|
{
|
|
"name": "limit",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Maximum events",
|
|
"schema": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"example": 100
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Event list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"events": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/EventLog"
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"events"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/test": {
|
|
"post": {
|
|
"tags": [
|
|
"Diagnostics"
|
|
],
|
|
"summary": "Test Home Assistant temperature",
|
|
"description": "Tests the configured Home Assistant connection and resolves a temperature from the supplied entity or controller default/alias.",
|
|
"operationId": "testHomeAssistant",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HaTestRequest"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Test result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"ok": {
|
|
"type": "boolean"
|
|
},
|
|
"temperature_c": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"entity_id": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"required": [
|
|
"ok",
|
|
"entity_id"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"example": {
|
|
"ok": true,
|
|
"temperature_c": 23.4,
|
|
"entity_id": "sensor.room_temperature"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/entity": {
|
|
"post": {
|
|
"tags": [
|
|
"Diagnostics"
|
|
],
|
|
"summary": "Inspect Home Assistant entity",
|
|
"description": "Reads the raw current Home Assistant entity document used by Flow shared-input diagnostics, including availability, attributes and timestamps.",
|
|
"operationId": "inspectHomeAssistantEntity",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HaEntityRequest"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Entity state",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
},
|
|
"example": {
|
|
"ok": true,
|
|
"entity_id": "climate.gas_boiler",
|
|
"state": "heat",
|
|
"available": true,
|
|
"attributes": {
|
|
"hvac_action": "heating"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/notifications/test": {
|
|
"post": {
|
|
"tags": [
|
|
"Diagnostics"
|
|
],
|
|
"summary": "Send notification test",
|
|
"description": "Tests the selected notification provider. Blank secret/webhook fields reuse saved secrets instead of clearing them.",
|
|
"operationId": "testNotifications",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NotificationSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Notification test result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"properties": {
|
|
"ok": {
|
|
"type": "boolean",
|
|
"example": true
|
|
}
|
|
},
|
|
"required": [
|
|
"ok"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/access-tokens": {
|
|
"get": {
|
|
"tags": [
|
|
"Access tokens"
|
|
],
|
|
"summary": "List restricted access tokens",
|
|
"description": "Lists metadata for generated restricted Home Assistant tokens. Full token secrets are never returned after creation.",
|
|
"operationId": "listAccessTokens",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Token metadata",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ApiTokenInfo"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"post": {
|
|
"tags": [
|
|
"Access tokens"
|
|
],
|
|
"summary": "Create restricted access token",
|
|
"description": "Creates a restricted Home Assistant API token. The full secret is returned once; only its SHA-256 hash and display prefix are stored.",
|
|
"operationId": "createAccessToken",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CreateAccessTokenRequest"
|
|
},
|
|
"example": {
|
|
"name": "Home Assistant"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"201": {
|
|
"description": "Created token",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/CreateAccessTokenResponse"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/access-tokens/{id}": {
|
|
"delete": {
|
|
"tags": [
|
|
"Access tokens"
|
|
],
|
|
"summary": "Revoke restricted access token",
|
|
"description": "Revokes a generated restricted token by ID.",
|
|
"operationId": "deleteAccessToken",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Access token ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"204": {
|
|
"description": "Token revoked"
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/devices": {
|
|
"get": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "List devices for Home Assistant",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Returns Device[].",
|
|
"operationId": "haListDevices",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Device list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/devices/{id}/command": {
|
|
"post": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "Control device from Home Assistant",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Accepts DeviceCommand. Direct control is rejected when the device belongs to a disabled thermostat zone; the restricted surface cannot bypass that safety rule.",
|
|
"operationId": "haCommandDevice",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Device ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/DeviceCommand"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated device",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/control-plan": {
|
|
"get": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "Get control plan for Home Assistant",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Returns the same latest materialized machine-readable control plan as the administrator endpoint.",
|
|
"operationId": "haControlPlan",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Resolved control plan",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/groups": {
|
|
"get": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "List derived climate groups",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Returns HA-oriented group objects with effective power/mode/preset, temperatures, member detail and next events.",
|
|
"operationId": "haListGroups",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Derived group list",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/groups/{id}/control": {
|
|
"post": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "Control climate group from Home Assistant",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Uses the same scoped group thermostat semantics as the administrator group-control endpoint.",
|
|
"operationId": "haControlGroup",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Group ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GroupControlPatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Group control result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/house/control": {
|
|
"post": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "Set house mode from Home Assistant",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Uses the same cool/heat/off house-mode semantics as the administrator endpoint.",
|
|
"operationId": "haControlHouse",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HouseControlPatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Public runtime settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/RuntimeSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/house/preset": {
|
|
"post": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "Set house preset from Home Assistant",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Uses the same auto/comfort/sleep/away semantics as the administrator endpoint.",
|
|
"operationId": "haPresetHouse",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HousePresetPatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "House preset result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/house/power": {
|
|
"post": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "Bulk house power from Home Assistant",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Uses the same one-shot whole-house thermostat ON/OFF semantics as the administrator endpoint.",
|
|
"operationId": "haPowerHouse",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HousePowerPatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Bulk power result",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/zones/{id}/control": {
|
|
"post": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "Control thermostat zone from Home Assistant",
|
|
"description": "This restricted Home Assistant surface always requires either a generated controller access token or the administrator app token. Generated tokens are intentionally not accepted by normal administrator endpoints. Uses the same ZoneControlPatch semantics as the administrator Quick Thermostat endpoint and records Home Assistant as the control source.",
|
|
"operationId": "haControlZone",
|
|
"parameters": [
|
|
{
|
|
"name": "id",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Zone ID",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ZoneControlPatch"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated zone",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Zone"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"404": {
|
|
"$ref": "#/components/responses/NotFound"
|
|
},
|
|
"502": {
|
|
"$ref": "#/components/responses/BadGateway"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/ws": {
|
|
"get": {
|
|
"tags": [
|
|
"WebSocket"
|
|
],
|
|
"summary": "Open live event stream",
|
|
"description": "Upgrades to WebSocket. The first server frame is `bootstrap`; later frames use `{event,timestamp,data}`. When an administrator app token is configured, pass it as the `token` query parameter. Generated restricted Home Assistant tokens are not accepted here.",
|
|
"operationId": "websocket",
|
|
"parameters": [
|
|
{
|
|
"name": "token",
|
|
"in": "query",
|
|
"required": false,
|
|
"description": "Administrator app token when authentication is enabled",
|
|
"schema": {
|
|
"type": "string"
|
|
}
|
|
}
|
|
],
|
|
"security": [
|
|
{
|
|
"WebSocketQueryToken": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"101": {
|
|
"description": "Switching Protocols"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/lang/index.json": {
|
|
"get": {
|
|
"tags": [
|
|
"Catalogs"
|
|
],
|
|
"summary": "List embedded language packs",
|
|
"description": "Public catalog used by the Web UI before authentication.",
|
|
"operationId": "languageIndex",
|
|
"security": [],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Language catalog",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/lang/{file}": {
|
|
"get": {
|
|
"tags": [
|
|
"Catalogs"
|
|
],
|
|
"summary": "Get embedded language pack",
|
|
"description": "Returns one embedded JSON language pack such as `en.json` or `pl.json`.",
|
|
"operationId": "languageFile",
|
|
"parameters": [
|
|
{
|
|
"name": "file",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Language file name, e.g. en.json",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Language pack",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Language pack not found"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/presets/index.json": {
|
|
"get": {
|
|
"tags": [
|
|
"Catalogs"
|
|
],
|
|
"summary": "List Flow presets",
|
|
"description": "Public catalog of embedded visual Flow templates/presets.",
|
|
"operationId": "presetIndex",
|
|
"security": [],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Preset catalog",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/presets/{file}": {
|
|
"get": {
|
|
"tags": [
|
|
"Catalogs"
|
|
],
|
|
"summary": "Get Flow preset",
|
|
"description": "Returns one embedded Flow preset JSON document.",
|
|
"operationId": "presetFile",
|
|
"parameters": [
|
|
{
|
|
"name": "file",
|
|
"in": "path",
|
|
"required": true,
|
|
"description": "Preset file name",
|
|
"schema": {
|
|
"type": "string"
|
|
},
|
|
"example": "uuid"
|
|
}
|
|
],
|
|
"security": [],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Flow preset",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"404": {
|
|
"description": "Preset not found"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/settings/application": {
|
|
"get": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Get application settings",
|
|
"description": "Application-level runtime switches.",
|
|
"operationId": "getApplicationSettings",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "application settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ApplicationSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Update application settings",
|
|
"description": "Application-level runtime switches.",
|
|
"operationId": "updateApplicationSettings",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ApplicationSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated application settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ApplicationSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/settings/gree": {
|
|
"get": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Get GREE settings",
|
|
"description": "Controller identity, polling/discovery and GREE command safety settings.",
|
|
"operationId": "getGREESettings",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "GREE settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GreeSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Update GREE settings",
|
|
"description": "Controller identity, polling/discovery and GREE command safety settings.",
|
|
"operationId": "updateGREESettings",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GreeSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated GREE settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/GreeSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/settings/history": {
|
|
"get": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Get history settings",
|
|
"description": "Metric and event-log retention settings. Updating event retention prunes expired event rows immediately.",
|
|
"operationId": "getHistorySettings",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "history settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HistorySettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Update history settings",
|
|
"description": "Metric and event-log retention settings. Updating event retention prunes expired event rows immediately.",
|
|
"operationId": "updateHistorySettings",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HistorySettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated history settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HistorySettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/settings/influxdb": {
|
|
"get": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Get InfluxDB settings",
|
|
"description": "InfluxDB history configuration. GET never returns password/token values.",
|
|
"operationId": "getInfluxDBSettings",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "InfluxDB settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/InfluxDbSettingsView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Update InfluxDB settings",
|
|
"description": "Updates only InfluxDB settings. Omit `password` or `token` to keep the stored secret; send an explicit empty string to clear it.",
|
|
"operationId": "updateInfluxDBSettings",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/InfluxDbSettingsUpdate"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated InfluxDB settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/InfluxDbSettingsView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/settings/notifications": {
|
|
"get": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Get notification settings",
|
|
"description": "Notification behavior and provider status. GET never returns provider secrets.",
|
|
"operationId": "getNotificationSettings",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "notification settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NotificationSettingsView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Update notification settings",
|
|
"description": "Updates only notification settings. Omit secret/webhook fields to keep stored values; send an explicit empty string to clear a value.",
|
|
"operationId": "updateNotificationSettings",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NotificationSettingsUpdate"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated notification settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NotificationSettingsView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/settings/night": {
|
|
"get": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Get night mode settings",
|
|
"description": "Night-mode schedule and fan/quiet behavior.",
|
|
"operationId": "getNightModeSettings",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "night mode settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NightModeSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Update night mode settings",
|
|
"description": "Night-mode schedule and fan/quiet behavior.",
|
|
"operationId": "updateNightModeSettings",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NightModeSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated night mode settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/NightModeSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/settings/home-assistant": {
|
|
"get": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Get Home Assistant settings",
|
|
"description": "Home Assistant connection, sensor aliases, shared Flow inputs and outdoor-assist switch. GET never returns the token.",
|
|
"operationId": "getHomeAssistantSettings",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Home Assistant settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HomeAssistantSettingsView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Update Home Assistant settings",
|
|
"description": "Updates only Home Assistant settings. Omit `token` to keep the stored token; send an explicit empty string to clear it.",
|
|
"operationId": "updateHomeAssistantSettings",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HomeAssistantSettingsUpdate"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated Home Assistant settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/HomeAssistantSettingsView"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/settings/debug": {
|
|
"get": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Get debug settings",
|
|
"description": "Live Web UI/API/GREE debug switches.",
|
|
"operationId": "getDebugSettings",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "debug settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/DebugSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
},
|
|
"put": {
|
|
"tags": [
|
|
"Settings"
|
|
],
|
|
"summary": "Update debug settings",
|
|
"description": "Live Web UI/API/GREE debug switches.",
|
|
"operationId": "updateDebugSettings",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/DebugSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Updated debug settings",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/DebugSettings"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/configuration/export": {
|
|
"get": {
|
|
"tags": [
|
|
"Configuration"
|
|
],
|
|
"summary": "Export configuration",
|
|
"description": "Exports format v3 full controller configuration including device binding keys and integration credentials. Metric history, event rows and generated access-token records are excluded. Treat this response as a secret backup.",
|
|
"operationId": "exportConfiguration",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Configuration backup",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ConfigurationExport"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/configuration/import": {
|
|
"post": {
|
|
"tags": [
|
|
"Configuration"
|
|
],
|
|
"summary": "Import configuration",
|
|
"description": "Validates and atomically replaces controller configuration from format v3 using the setpoint control strategy required by 0.12.0. Shared Flow input references are resolved against resources inside the backup. Runtime device/zone ownership and telemetry state are sanitized during import.",
|
|
"operationId": "importConfiguration",
|
|
"requestBody": {
|
|
"required": true,
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/ConfigurationExport"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Imported configuration summary",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"400": {
|
|
"$ref": "#/components/responses/BadRequest"
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"/api/integrations/home-assistant/snapshot": {
|
|
"get": {
|
|
"tags": [
|
|
"Home Assistant"
|
|
],
|
|
"summary": "Get Home Assistant integration snapshot",
|
|
"description": "Returns devices, derived groups, the latest materialized control plan and its revision in one restricted request. Existing per-resource Home Assistant endpoints remain available for compatibility.",
|
|
"operationId": "haSnapshot",
|
|
"security": [
|
|
{
|
|
"BearerToken": []
|
|
},
|
|
{
|
|
"ApiTokenHeader": []
|
|
}
|
|
],
|
|
"responses": {
|
|
"200": {
|
|
"description": "Home Assistant integration snapshot",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"401": {
|
|
"$ref": "#/components/responses/Unauthorized"
|
|
},
|
|
"500": {
|
|
"$ref": "#/components/responses/InternalError"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"components": {
|
|
"securitySchemes": {
|
|
"BearerToken": {
|
|
"type": "http",
|
|
"scheme": "bearer",
|
|
"bearerFormat": "token",
|
|
"description": "Administrator app token on normal API routes. On restricted Home Assistant routes, either the administrator token or a generated restricted token is accepted."
|
|
},
|
|
"ApiTokenHeader": {
|
|
"type": "apiKey",
|
|
"in": "header",
|
|
"name": "x-api-token",
|
|
"description": "Alternative to the Bearer header. Token permissions are identical to the same token sent as Bearer."
|
|
},
|
|
"WebSocketQueryToken": {
|
|
"type": "apiKey",
|
|
"in": "query",
|
|
"name": "token",
|
|
"description": "Administrator app token for `/ws` when app authentication is enabled. Restricted Home Assistant tokens are not accepted."
|
|
}
|
|
},
|
|
"schemas": {
|
|
"Error": {
|
|
"type": "object",
|
|
"properties": {
|
|
"error": {
|
|
"type": "string",
|
|
"description": "Human-readable error message",
|
|
"example": "invalid request: unsupported mode"
|
|
}
|
|
},
|
|
"required": [
|
|
"error"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"Health": {
|
|
"type": "object",
|
|
"properties": {
|
|
"status": {
|
|
"type": "string",
|
|
"description": "Process health",
|
|
"enum": [
|
|
"ok"
|
|
],
|
|
"example": "ok"
|
|
},
|
|
"name": {
|
|
"type": "string",
|
|
"example": "gree-controller"
|
|
},
|
|
"version": {
|
|
"type": "string",
|
|
"example": "0.13.5"
|
|
},
|
|
"uptime_seconds": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"example": 1234
|
|
},
|
|
"control_ready": {
|
|
"type": "boolean",
|
|
"description": "True after initial physical device synchronization",
|
|
"example": true
|
|
},
|
|
"time": {
|
|
"type": "string",
|
|
"example": "2026-09-03T09:30:00Z",
|
|
"format": "date-time"
|
|
}
|
|
},
|
|
"required": [
|
|
"status",
|
|
"name",
|
|
"version",
|
|
"uptime_seconds",
|
|
"control_ready",
|
|
"time"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"DeviceCommand": {
|
|
"type": "object",
|
|
"description": "Sparse direct-device command. Only supplied fields are changed.",
|
|
"properties": {
|
|
"power": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
],
|
|
"description": "Power state"
|
|
},
|
|
"mode": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "GREE mode",
|
|
"enum": [
|
|
"auto",
|
|
"cool",
|
|
"dry",
|
|
"fan",
|
|
"heat",
|
|
null
|
|
]
|
|
},
|
|
"target_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"description": "Target temperature in Celsius; normalized to 8..30",
|
|
"minimum": 8,
|
|
"maximum": 30
|
|
},
|
|
"fan_speed": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"description": "0=Auto, 1..5 fixed speed",
|
|
"minimum": 0,
|
|
"maximum": 5
|
|
},
|
|
"swing_vertical": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"swing_horizontal": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"quiet": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"turbo": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"light": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"air": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"xfan": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"health": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"sleep": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"ManualDeviceCommand": {
|
|
"type": "object",
|
|
"description": "Administrator direct-device command. `manual_override` is a safety acknowledgement for disabled thermostat zones.",
|
|
"properties": {
|
|
"power": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
],
|
|
"description": "Power state"
|
|
},
|
|
"mode": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "GREE mode",
|
|
"enum": [
|
|
"auto",
|
|
"cool",
|
|
"dry",
|
|
"fan",
|
|
"heat",
|
|
null
|
|
]
|
|
},
|
|
"target_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"description": "Target temperature in Celsius; normalized to 8..30",
|
|
"minimum": 8,
|
|
"maximum": 30
|
|
},
|
|
"fan_speed": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"description": "0=Auto, 1..5 fixed speed",
|
|
"minimum": 0,
|
|
"maximum": 5
|
|
},
|
|
"swing_vertical": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"swing_horizontal": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"quiet": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"turbo": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"light": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"air": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"xfan": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"health": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"sleep": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"manual_override": {
|
|
"type": "boolean",
|
|
"description": "Required as true for deliberate direct control of a device owned by a disabled thermostat zone.",
|
|
"example": false
|
|
}
|
|
}
|
|
},
|
|
"DevicePatch": {
|
|
"type": "object",
|
|
"description": "Editable technical device fields.",
|
|
"properties": {
|
|
"name": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"ip": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"example": "192.168.50.31"
|
|
},
|
|
"port": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 1,
|
|
"maximum": 65535,
|
|
"example": 7000
|
|
},
|
|
"protocol_version": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"description": "0=auto/unknown, 1=AES-ECB, 2=AES-GCM",
|
|
"minimum": 0,
|
|
"maximum": 2
|
|
},
|
|
"key": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Binding key. JSON null clears the saved key."
|
|
},
|
|
"enabled": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"ManualDeviceRequest": {
|
|
"type": "object",
|
|
"description": "Manual device registration request. Port defaults to 7000, protocol to 1, simulated to false.",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Living room"
|
|
},
|
|
"mac": {
|
|
"type": "string",
|
|
"example": "AABBCCDDEEFF"
|
|
},
|
|
"ip": {
|
|
"type": "string",
|
|
"example": "192.168.50.30"
|
|
},
|
|
"port": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 65535,
|
|
"example": 7000
|
|
},
|
|
"protocol_version": {
|
|
"type": "integer",
|
|
"description": "1=legacy AES-ECB, 2=AES-GCM",
|
|
"minimum": 1,
|
|
"maximum": 2,
|
|
"example": 1
|
|
},
|
|
"key": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"simulated": {
|
|
"type": "boolean",
|
|
"example": false
|
|
}
|
|
},
|
|
"required": [
|
|
"name",
|
|
"mac",
|
|
"ip"
|
|
]
|
|
},
|
|
"Device": {
|
|
"type": "object",
|
|
"description": "Physical or simulated GREE unit plus latest communication/state snapshot.",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"description": "Stable controller ID",
|
|
"example": "gree-aabbccddeeff"
|
|
},
|
|
"mac": {
|
|
"type": "string",
|
|
"example": "AABBCCDDEEFF"
|
|
},
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Living room"
|
|
},
|
|
"ip": {
|
|
"type": "string",
|
|
"example": "192.168.50.30"
|
|
},
|
|
"port": {
|
|
"type": "integer",
|
|
"example": 7000
|
|
},
|
|
"protocol_version": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"maximum": 2,
|
|
"example": 2
|
|
},
|
|
"model": {
|
|
"type": "string",
|
|
"example": "GREE"
|
|
},
|
|
"firmware": {
|
|
"type": "string"
|
|
},
|
|
"key": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "GREE binding key; treat as secret"
|
|
},
|
|
"cid": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"simulated": {
|
|
"type": "boolean"
|
|
},
|
|
"power": {
|
|
"type": "boolean"
|
|
},
|
|
"mode": {
|
|
"type": "string",
|
|
"enum": [
|
|
"auto",
|
|
"cool",
|
|
"dry",
|
|
"fan",
|
|
"heat"
|
|
]
|
|
},
|
|
"target_temperature": {
|
|
"type": "number",
|
|
"minimum": 8,
|
|
"maximum": 30
|
|
},
|
|
"fan_speed": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"maximum": 5
|
|
},
|
|
"swing_vertical": {
|
|
"type": "boolean"
|
|
},
|
|
"swing_horizontal": {
|
|
"type": "boolean"
|
|
},
|
|
"quiet": {
|
|
"type": "boolean"
|
|
},
|
|
"turbo": {
|
|
"type": "boolean"
|
|
},
|
|
"light": {
|
|
"type": "boolean"
|
|
},
|
|
"air": {
|
|
"type": "boolean"
|
|
},
|
|
"xfan": {
|
|
"type": "boolean"
|
|
},
|
|
"health": {
|
|
"type": "boolean"
|
|
},
|
|
"sleep": {
|
|
"type": "boolean"
|
|
},
|
|
"current_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"outdoor_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"online": {
|
|
"type": "boolean"
|
|
},
|
|
"response_time_ms": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
]
|
|
},
|
|
"last_seen": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"last_error": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"communication_failures": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"created_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"updated_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"mac",
|
|
"name",
|
|
"ip",
|
|
"port",
|
|
"enabled",
|
|
"power",
|
|
"mode",
|
|
"target_temperature",
|
|
"online",
|
|
"created_at",
|
|
"updated_at"
|
|
]
|
|
},
|
|
"DiscoveryRequest": {
|
|
"type": "object",
|
|
"description": "All fields optional. Missing values use runtime GREE settings.",
|
|
"properties": {
|
|
"timeout_ms": {
|
|
"type": "integer",
|
|
"description": "Effective range 500..30000 ms",
|
|
"minimum": 500,
|
|
"maximum": 30000,
|
|
"example": 6000
|
|
},
|
|
"broadcast": {
|
|
"type": "string",
|
|
"description": "IPv4 socket address; omitted values use runtime settings",
|
|
"example": "255.255.255.255:7000"
|
|
},
|
|
"protocol_version": {
|
|
"type": "integer",
|
|
"description": "0=auto/both, 1=AES-ECB, 2=AES-GCM",
|
|
"minimum": 0,
|
|
"maximum": 2,
|
|
"example": 0
|
|
},
|
|
"passes": {
|
|
"type": "integer",
|
|
"description": "Discovery passes",
|
|
"minimum": 1,
|
|
"maximum": 10,
|
|
"example": 3
|
|
}
|
|
}
|
|
},
|
|
"DiscoveryResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"count": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"example": 1
|
|
},
|
|
"devices": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
},
|
|
"new_device_ids": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"example": [
|
|
"gree-aabbccddeeff"
|
|
]
|
|
}
|
|
},
|
|
"required": [
|
|
"count",
|
|
"devices",
|
|
"new_device_ids"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"TemporaryQuickThermostatRequest": {
|
|
"type": "object",
|
|
"description": "Persisted temporary thermostat session with delayed/absolute start and several finish rules.",
|
|
"properties": {
|
|
"start_kind": {
|
|
"type": "string",
|
|
"enum": [
|
|
"now",
|
|
"delay",
|
|
"at"
|
|
],
|
|
"example": "now"
|
|
},
|
|
"start_delay_minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 1
|
|
},
|
|
"start_at": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"finish_kind": {
|
|
"type": "string",
|
|
"enum": [
|
|
"duration",
|
|
"until",
|
|
"temperature_reached",
|
|
"temperature_stable",
|
|
"schedule_boundary"
|
|
],
|
|
"example": "duration"
|
|
},
|
|
"duration_minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 1,
|
|
"example": 90
|
|
},
|
|
"until": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"target_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 24.2,
|
|
"description": "Logical thermostat target in C. Values are normalized to 0.1 C by the controller."
|
|
},
|
|
"temperature_operator": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"enum": [
|
|
"within",
|
|
"at_or_below",
|
|
"at_or_above",
|
|
null
|
|
],
|
|
"example": "within"
|
|
},
|
|
"tolerance_c": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"minimum": 0,
|
|
"example": 0.3
|
|
},
|
|
"hold_minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"minimum": 1
|
|
},
|
|
"max_duration_minutes": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"description": "Optional fail-safe for temperature-based sessions",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"required": [
|
|
"start_kind",
|
|
"finish_kind"
|
|
]
|
|
},
|
|
"ZoneControlPatch": {
|
|
"type": "object",
|
|
"description": "Quick thermostat control. Fields may be combined; clear flags hand ownership back to automation at different layers.",
|
|
"properties": {
|
|
"setpoint": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"description": "Quick custom target; kept at 0.1 C precision",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 22.5
|
|
},
|
|
"power": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
],
|
|
"description": "Local Quick Thermostat power ownership"
|
|
},
|
|
"mode": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"enum": [
|
|
"house",
|
|
"cool",
|
|
"heat",
|
|
null
|
|
]
|
|
},
|
|
"enabled": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"preset": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"enum": [
|
|
"auto",
|
|
"comfort",
|
|
"sleep",
|
|
"away",
|
|
"custom",
|
|
null
|
|
]
|
|
},
|
|
"clear_override": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"clear_device_manual_override": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"clear_local_thermostat_override": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"temporary_quick_thermostat": {
|
|
"oneOf": [
|
|
{
|
|
"$ref": "#/components/schemas/TemporaryQuickThermostatRequest"
|
|
},
|
|
{
|
|
"type": "null"
|
|
}
|
|
]
|
|
},
|
|
"clear_temporary_quick_thermostat": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
}
|
|
}
|
|
},
|
|
"ZoneInput": {
|
|
"type": "object",
|
|
"description": "Editable thermostat-zone configuration. Runtime ownership/demand/lockout fields are returned separately on `Zone`.",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Living room"
|
|
},
|
|
"device_id": {
|
|
"type": "string",
|
|
"example": "gree-aabbccddeeff"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"mode": {
|
|
"type": "string",
|
|
"enum": [
|
|
"cool",
|
|
"heat"
|
|
],
|
|
"example": "cool"
|
|
},
|
|
"inherit_house_mode": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"setpoint": {
|
|
"type": "number",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 23.0
|
|
},
|
|
"cool_comfort_setpoint": {
|
|
"type": "number",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 23.0
|
|
},
|
|
"cool_sleep_setpoint": {
|
|
"type": "number",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 24.5
|
|
},
|
|
"cool_away_setpoint": {
|
|
"type": "number",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 27.0
|
|
},
|
|
"heat_comfort_setpoint": {
|
|
"type": "number",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 21.0
|
|
},
|
|
"heat_sleep_setpoint": {
|
|
"type": "number",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 19.0
|
|
},
|
|
"heat_away_setpoint": {
|
|
"type": "number",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 17.0
|
|
},
|
|
"hysteresis": {
|
|
"type": "number",
|
|
"minimum": 0.1,
|
|
"maximum": 5,
|
|
"example": 0.6
|
|
},
|
|
"separate_hysteresis": {
|
|
"type": "boolean",
|
|
"example": false
|
|
},
|
|
"cool_hysteresis": {
|
|
"type": "number",
|
|
"minimum": 0.1,
|
|
"maximum": 5,
|
|
"example": 0.6
|
|
},
|
|
"heat_hysteresis": {
|
|
"type": "number",
|
|
"minimum": 0.1,
|
|
"maximum": 5,
|
|
"example": 0.6
|
|
},
|
|
"min_on_seconds": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"example": 180
|
|
},
|
|
"min_off_seconds": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"example": 180
|
|
},
|
|
"min_adjust_seconds": {
|
|
"type": "integer",
|
|
"minimum": 0,
|
|
"example": 120
|
|
},
|
|
"standby_offset_c": {
|
|
"type": "number",
|
|
"minimum": 0.5,
|
|
"maximum": 8,
|
|
"example": 2.0
|
|
},
|
|
"smart_fan": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"sensor_source": {
|
|
"type": "string",
|
|
"enum": [
|
|
"device",
|
|
"home_assistant",
|
|
"combined"
|
|
],
|
|
"example": "combined"
|
|
},
|
|
"ha_entity_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"example": "sensor.living_room_temperature"
|
|
},
|
|
"external_sensor_weight": {
|
|
"type": "number",
|
|
"minimum": 0,
|
|
"maximum": 1,
|
|
"example": 0.4
|
|
},
|
|
"max_sensor_difference": {
|
|
"type": "number",
|
|
"minimum": 0.1,
|
|
"maximum": 20,
|
|
"example": 3.0
|
|
},
|
|
"sensor_stale_after_seconds": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"example": 300
|
|
},
|
|
"revision": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"description": "Optimistic concurrency revision when updating",
|
|
"minimum": 1,
|
|
"example": 12
|
|
}
|
|
},
|
|
"required": [
|
|
"name",
|
|
"device_id"
|
|
]
|
|
},
|
|
"Zone": {
|
|
"type": "object",
|
|
"description": "Thermostat zone. In addition to editable configuration it exposes live sensors, resolved target, demand, ownership, temporary/manual overrides and compressor protection state.",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"example": "zone-1"
|
|
},
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Living room"
|
|
},
|
|
"device_id": {
|
|
"type": "string",
|
|
"example": "gree-aabbccddeeff"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"mode": {
|
|
"type": "string",
|
|
"enum": [
|
|
"cool",
|
|
"heat"
|
|
]
|
|
},
|
|
"inherit_house_mode": {
|
|
"type": "boolean"
|
|
},
|
|
"setpoint": {
|
|
"type": "number"
|
|
},
|
|
"active_preset": {
|
|
"type": "string",
|
|
"example": "comfort"
|
|
},
|
|
"manual_preset": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"manual_setpoint": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"current_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"device_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"external_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"effective_mode": {
|
|
"type": "string"
|
|
},
|
|
"effective_setpoint": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"device_setpoint": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"demand": {
|
|
"type": "boolean"
|
|
},
|
|
"local_thermostat_power": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"local_thermostat_resume_at": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"device_manual_override": {
|
|
"type": "boolean"
|
|
},
|
|
"device_manual_override_since": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"control_owner": {
|
|
"type": "string",
|
|
"example": "automation"
|
|
},
|
|
"control_source": {
|
|
"type": "string"
|
|
},
|
|
"control_reason": {
|
|
"type": "string"
|
|
},
|
|
"control_resume_at": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"lockout_until": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"lockout_reason": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"compressor_pending_action": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"compressor_pending_since": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"compressor_pending_until": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"revision": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"created_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"updated_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"device_id",
|
|
"enabled",
|
|
"mode",
|
|
"revision",
|
|
"created_at",
|
|
"updated_at"
|
|
]
|
|
},
|
|
"GroupInput": {
|
|
"type": "object",
|
|
"description": "Climate group definition. Every zone ID must exist.",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Bedrooms"
|
|
},
|
|
"zone_ids": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
},
|
|
"minItems": 1,
|
|
"example": [
|
|
"zone-1",
|
|
"zone-2"
|
|
]
|
|
},
|
|
"power_enabled": {
|
|
"type": "boolean",
|
|
"description": "Initial group control state",
|
|
"example": true
|
|
}
|
|
},
|
|
"required": [
|
|
"name",
|
|
"zone_ids"
|
|
]
|
|
},
|
|
"ClimateGroup": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"example": "uuid"
|
|
},
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Bedrooms"
|
|
},
|
|
"zone_ids": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"power_enabled": {
|
|
"type": "boolean",
|
|
"description": "Group bulk-power/control state; not a permanent device power gate."
|
|
},
|
|
"created_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"updated_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"zone_ids",
|
|
"power_enabled",
|
|
"created_at",
|
|
"updated_at"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"GroupControlPatch": {
|
|
"type": "object",
|
|
"description": "Scoped group thermostat control. Group OFF stores members as individually-off thermostats; individual zones can later be re-enabled independently.",
|
|
"properties": {
|
|
"power": {
|
|
"type": [
|
|
"boolean",
|
|
"null"
|
|
]
|
|
},
|
|
"mode": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"enum": [
|
|
"house",
|
|
"cool",
|
|
"heat",
|
|
null
|
|
]
|
|
},
|
|
"preset": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"enum": [
|
|
"auto",
|
|
"comfort",
|
|
"sleep",
|
|
"away",
|
|
"custom",
|
|
null
|
|
]
|
|
},
|
|
"setpoint": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"description": "Requires preset=custom",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 22.3
|
|
}
|
|
}
|
|
},
|
|
"HouseControlPatch": {
|
|
"type": "object",
|
|
"properties": {
|
|
"mode": {
|
|
"type": "string",
|
|
"enum": [
|
|
"cool",
|
|
"heat",
|
|
"off"
|
|
],
|
|
"example": "cool"
|
|
}
|
|
},
|
|
"required": [
|
|
"mode"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"HousePowerPatch": {
|
|
"type": "object",
|
|
"properties": {
|
|
"power": {
|
|
"type": "boolean",
|
|
"example": false
|
|
}
|
|
},
|
|
"required": [
|
|
"power"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"HousePresetPatch": {
|
|
"type": "object",
|
|
"properties": {
|
|
"preset": {
|
|
"type": "string",
|
|
"enum": [
|
|
"auto",
|
|
"comfort",
|
|
"sleep",
|
|
"away"
|
|
],
|
|
"example": "sleep"
|
|
}
|
|
},
|
|
"required": [
|
|
"preset"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"ScheduleTemplateRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"template": {
|
|
"type": "string",
|
|
"enum": [
|
|
"family",
|
|
"child",
|
|
"bedroom",
|
|
"workday",
|
|
"always"
|
|
],
|
|
"example": "family"
|
|
}
|
|
},
|
|
"required": [
|
|
"template"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"ScheduleInput": {
|
|
"type": "object",
|
|
"description": "Weekly thermostat schedule. Enabled schedules for the same zone cannot overlap.",
|
|
"properties": {
|
|
"zone_id": {
|
|
"type": "string",
|
|
"example": "zone-1"
|
|
},
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Night"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"weekdays": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 7
|
|
},
|
|
"minItems": 1,
|
|
"example": [
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7
|
|
]
|
|
},
|
|
"start_time": {
|
|
"type": "string",
|
|
"description": "Local HH:MM",
|
|
"example": "22:30",
|
|
"pattern": "^[0-2][0-9]:[0-5][0-9]$"
|
|
},
|
|
"end_time": {
|
|
"type": "string",
|
|
"description": "Local HH:MM; crossing midnight is supported",
|
|
"example": "06:30",
|
|
"pattern": "^[0-2][0-9]:[0-5][0-9]$"
|
|
},
|
|
"preset": {
|
|
"type": "string",
|
|
"enum": [
|
|
"comfort",
|
|
"sleep",
|
|
"away",
|
|
"custom"
|
|
],
|
|
"example": "sleep"
|
|
},
|
|
"setpoint": {
|
|
"type": "number",
|
|
"description": "Used directly only for custom preset",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 24.5
|
|
}
|
|
},
|
|
"required": [
|
|
"zone_id",
|
|
"name",
|
|
"weekdays",
|
|
"start_time",
|
|
"end_time",
|
|
"setpoint"
|
|
]
|
|
},
|
|
"Schedule": {
|
|
"type": "object",
|
|
"properties": {
|
|
"zone_id": {
|
|
"type": "string",
|
|
"example": "zone-1"
|
|
},
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Night"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"weekdays": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 7
|
|
},
|
|
"minItems": 1,
|
|
"example": [
|
|
1,
|
|
2,
|
|
3,
|
|
4,
|
|
5,
|
|
6,
|
|
7
|
|
]
|
|
},
|
|
"start_time": {
|
|
"type": "string",
|
|
"description": "Local HH:MM",
|
|
"example": "22:30",
|
|
"pattern": "^[0-2][0-9]:[0-5][0-9]$"
|
|
},
|
|
"end_time": {
|
|
"type": "string",
|
|
"description": "Local HH:MM; crossing midnight is supported",
|
|
"example": "06:30",
|
|
"pattern": "^[0-2][0-9]:[0-5][0-9]$"
|
|
},
|
|
"preset": {
|
|
"type": "string",
|
|
"enum": [
|
|
"comfort",
|
|
"sleep",
|
|
"away",
|
|
"custom"
|
|
],
|
|
"example": "sleep"
|
|
},
|
|
"setpoint": {
|
|
"type": "number",
|
|
"description": "Used directly only for custom preset",
|
|
"minimum": 8,
|
|
"maximum": 30,
|
|
"example": 24.5
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"example": "uuid"
|
|
},
|
|
"created_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"updated_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"flow_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Present when generated by a visual Flow; then edit the Flow instead of the legacy schedule endpoint."
|
|
},
|
|
"flow_node_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"zone_id",
|
|
"name",
|
|
"weekdays",
|
|
"start_time",
|
|
"end_time",
|
|
"preset",
|
|
"setpoint",
|
|
"created_at",
|
|
"updated_at"
|
|
]
|
|
},
|
|
"AutomationInput": {
|
|
"type": "object",
|
|
"description": "Legacy automation request. Action target is either a direct device or a group.",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Hot room"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"trigger_kind": {
|
|
"type": "string",
|
|
"enum": [
|
|
"temperature_above",
|
|
"temperature_below",
|
|
"time"
|
|
],
|
|
"example": "temperature_above"
|
|
},
|
|
"trigger_device_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"example": "gree-aabbccddeeff"
|
|
},
|
|
"threshold": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"example": 27.0
|
|
},
|
|
"at_time": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"example": "20:30"
|
|
},
|
|
"action_device_id": {
|
|
"type": "string",
|
|
"description": "Direct-device target; leave empty for group action",
|
|
"example": "gree-aabbccddeeff"
|
|
},
|
|
"action_group_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"action_preset": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"enum": [
|
|
"auto",
|
|
"comfort",
|
|
"sleep",
|
|
"away",
|
|
null
|
|
]
|
|
},
|
|
"action": {
|
|
"$ref": "#/components/schemas/DeviceCommand"
|
|
},
|
|
"cooldown_seconds": {
|
|
"type": "integer",
|
|
"minimum": 30,
|
|
"example": 300
|
|
}
|
|
},
|
|
"required": [
|
|
"name",
|
|
"trigger_kind"
|
|
]
|
|
},
|
|
"Automation": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Hot room"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"trigger_kind": {
|
|
"type": "string",
|
|
"enum": [
|
|
"temperature_above",
|
|
"temperature_below",
|
|
"time"
|
|
],
|
|
"example": "temperature_above"
|
|
},
|
|
"trigger_device_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"example": "gree-aabbccddeeff"
|
|
},
|
|
"threshold": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
],
|
|
"example": 27.0
|
|
},
|
|
"at_time": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"example": "20:30"
|
|
},
|
|
"action_device_id": {
|
|
"type": "string",
|
|
"description": "Direct-device target; leave empty for group action",
|
|
"example": "gree-aabbccddeeff"
|
|
},
|
|
"action_group_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"action_preset": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"enum": [
|
|
"auto",
|
|
"comfort",
|
|
"sleep",
|
|
"away",
|
|
null
|
|
]
|
|
},
|
|
"action": {
|
|
"$ref": "#/components/schemas/DeviceCommand"
|
|
},
|
|
"cooldown_seconds": {
|
|
"type": "integer",
|
|
"minimum": 30,
|
|
"example": 300
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"example": "uuid"
|
|
},
|
|
"last_fired_at": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"format": "date-time"
|
|
},
|
|
"flow_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Present for Flow-generated automations; edit the Flow instead."
|
|
},
|
|
"flow_node_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"created_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"updated_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"trigger_kind",
|
|
"action",
|
|
"cooldown_seconds",
|
|
"created_at",
|
|
"updated_at"
|
|
]
|
|
},
|
|
"FlowNode": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"example": "condition"
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"description": "Condition, logic or action block kind",
|
|
"example": "constant"
|
|
},
|
|
"x": {
|
|
"type": "number",
|
|
"example": 20
|
|
},
|
|
"y": {
|
|
"type": "number",
|
|
"example": 20
|
|
},
|
|
"config": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"description": "Block-specific configuration"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"kind",
|
|
"config"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"FlowEdge": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"example": "edge-1"
|
|
},
|
|
"from": {
|
|
"type": "string",
|
|
"example": "condition"
|
|
},
|
|
"to": {
|
|
"type": "string",
|
|
"example": "action"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"from",
|
|
"to"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"FlowInput": {
|
|
"type": "object",
|
|
"description": "Visual Flow source graph. Executable saves validate the DAG and atomically compile schedules/automations.",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Comfort Flow"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"draft": {
|
|
"type": "boolean",
|
|
"description": "Drafts are forced disabled and compile no outputs",
|
|
"example": false
|
|
},
|
|
"description": {
|
|
"type": "string",
|
|
"example": "Comfort when occupied"
|
|
},
|
|
"nodes": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/FlowNode"
|
|
}
|
|
},
|
|
"edges": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/FlowEdge"
|
|
}
|
|
},
|
|
"expected_revision": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"description": "Required for updates to prevent stale editor tabs overwriting newer graphs",
|
|
"minimum": 1
|
|
}
|
|
},
|
|
"required": [
|
|
"name"
|
|
]
|
|
},
|
|
"Flow": {
|
|
"type": "object",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Comfort Flow"
|
|
},
|
|
"enabled": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"draft": {
|
|
"type": "boolean",
|
|
"description": "Drafts are forced disabled and compile no outputs",
|
|
"example": false
|
|
},
|
|
"description": {
|
|
"type": "string",
|
|
"example": "Comfort when occupied"
|
|
},
|
|
"nodes": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/FlowNode"
|
|
}
|
|
},
|
|
"edges": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/FlowEdge"
|
|
}
|
|
},
|
|
"expected_revision": {
|
|
"type": [
|
|
"integer",
|
|
"null"
|
|
],
|
|
"description": "Required for updates to prevent stale editor tabs overwriting newer graphs",
|
|
"minimum": 1
|
|
},
|
|
"id": {
|
|
"type": "string",
|
|
"example": "uuid"
|
|
},
|
|
"summary": {
|
|
"type": "string"
|
|
},
|
|
"compiled_schedule_ids": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"compiled_automation_ids": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"revision": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"example": 1
|
|
},
|
|
"created_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"updated_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"enabled",
|
|
"draft",
|
|
"nodes",
|
|
"edges",
|
|
"revision",
|
|
"created_at",
|
|
"updated_at"
|
|
]
|
|
},
|
|
"FlowExport": {
|
|
"type": "object",
|
|
"properties": {
|
|
"format": {
|
|
"type": "string",
|
|
"enum": [
|
|
"gree-controller-flow"
|
|
],
|
|
"example": "gree-controller-flow"
|
|
},
|
|
"version": {
|
|
"type": "integer",
|
|
"example": 1
|
|
},
|
|
"exported_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"flow": {
|
|
"$ref": "#/components/schemas/FlowInput"
|
|
}
|
|
},
|
|
"required": [
|
|
"format",
|
|
"version",
|
|
"exported_at",
|
|
"flow"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"FlowSimulationInput": {
|
|
"type": "object",
|
|
"description": "Dry-run input. Simulation validates/compiles/evaluates the graph but never mutates controller state.",
|
|
"properties": {
|
|
"flow": {
|
|
"$ref": "#/components/schemas/FlowInput"
|
|
},
|
|
"flow_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"at": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "RFC3339 simulation time",
|
|
"format": "date-time"
|
|
},
|
|
"overrides": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"description": "Map of Flow node IDs to simulated values"
|
|
},
|
|
"log": {
|
|
"type": "boolean",
|
|
"example": true
|
|
}
|
|
},
|
|
"required": [
|
|
"flow"
|
|
]
|
|
},
|
|
"FlowSimulationResult": {
|
|
"type": "object",
|
|
"properties": {
|
|
"dry_run": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"flow_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"summary": {
|
|
"type": "string"
|
|
},
|
|
"compiled": {
|
|
"type": "object",
|
|
"properties": {
|
|
"schedules": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
},
|
|
"automations": {
|
|
"type": "integer",
|
|
"minimum": 0
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
},
|
|
"actions": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"properties": {
|
|
"node_id": {
|
|
"type": "string"
|
|
},
|
|
"kind": {
|
|
"type": "string"
|
|
},
|
|
"matched": {
|
|
"type": "boolean"
|
|
},
|
|
"would_execute": {
|
|
"type": "boolean"
|
|
},
|
|
"blocked_reason": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
]
|
|
},
|
|
"config": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
},
|
|
"trace": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"note": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"required": [
|
|
"dry_run",
|
|
"at",
|
|
"actions"
|
|
]
|
|
},
|
|
"Reading": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"device_id": {
|
|
"type": "string"
|
|
},
|
|
"timestamp": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"indoor_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"outdoor_temperature": {
|
|
"type": [
|
|
"number",
|
|
"null"
|
|
]
|
|
},
|
|
"target_temperature": {
|
|
"type": "number"
|
|
},
|
|
"power": {
|
|
"type": "boolean"
|
|
},
|
|
"source": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"device_id",
|
|
"timestamp",
|
|
"target_temperature",
|
|
"power",
|
|
"source"
|
|
]
|
|
},
|
|
"EventLog": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "integer",
|
|
"minimum": 1
|
|
},
|
|
"timestamp": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"level": {
|
|
"type": "string",
|
|
"example": "info"
|
|
},
|
|
"kind": {
|
|
"type": "string",
|
|
"example": "device.updated"
|
|
},
|
|
"message": {
|
|
"type": "string"
|
|
},
|
|
"metadata": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"timestamp",
|
|
"level",
|
|
"kind",
|
|
"message",
|
|
"metadata"
|
|
]
|
|
},
|
|
"DebugSettings": {
|
|
"type": "object",
|
|
"properties": {
|
|
"overlay_enabled": {
|
|
"type": "boolean",
|
|
"example": true
|
|
},
|
|
"gree_frames": {
|
|
"type": "boolean",
|
|
"example": false
|
|
}
|
|
},
|
|
"required": [
|
|
"overlay_enabled",
|
|
"gree_frames"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"RuntimeSettings": {
|
|
"type": "object",
|
|
"description": "Internal full runtime-settings representation embedded in ConfigurationExport. Unlike `/api/settings/*` views, this backup object may contain integration secrets.",
|
|
"properties": {
|
|
"controller_id": {
|
|
"type": "string",
|
|
"example": "gree-controller"
|
|
},
|
|
"simulator_enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"poll_interval_seconds": {
|
|
"type": "integer",
|
|
"minimum": 2,
|
|
"maximum": 3600,
|
|
"example": 15
|
|
},
|
|
"zone_interval_seconds": {
|
|
"type": "integer",
|
|
"minimum": 2,
|
|
"maximum": 3600,
|
|
"example": 5
|
|
},
|
|
"discovery_timeout_ms": {
|
|
"type": "integer",
|
|
"minimum": 300,
|
|
"maximum": 30000,
|
|
"example": 3000
|
|
},
|
|
"discovery_broadcast": {
|
|
"type": "string",
|
|
"example": "255.255.255.255:7000"
|
|
},
|
|
"house_mode": {
|
|
"type": "string",
|
|
"enum": [
|
|
"cool",
|
|
"heat",
|
|
"off"
|
|
]
|
|
},
|
|
"control_strategy": {
|
|
"type": "string",
|
|
"enum": [
|
|
"setpoint"
|
|
]
|
|
},
|
|
"history_retention_days": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 3650
|
|
},
|
|
"event_log_retention_days": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 3650
|
|
},
|
|
"compressor_protection_enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"compressor_protection_seconds": {
|
|
"type": "integer",
|
|
"minimum": 30,
|
|
"maximum": 1800,
|
|
"example": 180
|
|
},
|
|
"debug": {
|
|
"$ref": "#/components/schemas/DebugSettings"
|
|
},
|
|
"night_mode": {
|
|
"$ref": "#/components/schemas/NightModeSettings"
|
|
},
|
|
"notifications": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"description": "Full notification settings including secrets in configuration backups."
|
|
},
|
|
"influxdb": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"description": "Full InfluxDB settings including secrets in configuration backups."
|
|
},
|
|
"home_assistant": {
|
|
"type": "object",
|
|
"additionalProperties": true,
|
|
"description": "Full Home Assistant settings including token in configuration backups."
|
|
},
|
|
"outdoor_assist_enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"history_compaction_enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"suppress_device_beep": {
|
|
"type": "boolean"
|
|
}
|
|
}
|
|
},
|
|
"ConfigurationExport": {
|
|
"type": "object",
|
|
"description": "Full configuration backup. Contains binding keys and integration credentials; treat as a secret.",
|
|
"properties": {
|
|
"format_version": {
|
|
"type": "integer",
|
|
"enum": [
|
|
3
|
|
],
|
|
"example": 3
|
|
},
|
|
"exported_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
},
|
|
"settings": {
|
|
"$ref": "#/components/schemas/RuntimeSettings"
|
|
},
|
|
"devices": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Device"
|
|
}
|
|
},
|
|
"zones": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Zone"
|
|
}
|
|
},
|
|
"groups": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/ClimateGroup"
|
|
}
|
|
},
|
|
"schedules": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Schedule"
|
|
}
|
|
},
|
|
"automations": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Automation"
|
|
}
|
|
},
|
|
"flows": {
|
|
"type": "array",
|
|
"items": {
|
|
"$ref": "#/components/schemas/Flow"
|
|
}
|
|
}
|
|
},
|
|
"required": [
|
|
"format_version",
|
|
"exported_at",
|
|
"settings",
|
|
"devices",
|
|
"zones",
|
|
"groups",
|
|
"schedules",
|
|
"automations",
|
|
"flows"
|
|
]
|
|
},
|
|
"ApiTokenInfo": {
|
|
"type": "object",
|
|
"properties": {
|
|
"id": {
|
|
"type": "string",
|
|
"example": "uuid"
|
|
},
|
|
"name": {
|
|
"type": "string",
|
|
"example": "Home Assistant"
|
|
},
|
|
"token_prefix": {
|
|
"type": "string",
|
|
"example": "gree_controller_abc..."
|
|
},
|
|
"created_at": {
|
|
"type": "string",
|
|
"format": "date-time"
|
|
}
|
|
},
|
|
"required": [
|
|
"id",
|
|
"name",
|
|
"token_prefix",
|
|
"created_at"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"CreateAccessTokenRequest": {
|
|
"type": "object",
|
|
"description": "If name is omitted, `Home Assistant` is used.",
|
|
"properties": {
|
|
"name": {
|
|
"type": "string",
|
|
"description": "Optional 1..80 character display name",
|
|
"example": "Home Assistant"
|
|
}
|
|
}
|
|
},
|
|
"CreateAccessTokenResponse": {
|
|
"type": "object",
|
|
"properties": {
|
|
"token": {
|
|
"type": "string",
|
|
"description": "Full generated secret. Returned exactly once; only its SHA-256 hash is stored.",
|
|
"example": "gree_controller_FULL_SECRET_SHOWN_ONCE"
|
|
},
|
|
"item": {
|
|
"$ref": "#/components/schemas/ApiTokenInfo"
|
|
}
|
|
},
|
|
"required": [
|
|
"token",
|
|
"item"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"HaTestRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"entity_id": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Optional. Defaults/aliases are resolved when omitted.",
|
|
"example": "sensor.room_temperature"
|
|
}
|
|
}
|
|
},
|
|
"HaEntityRequest": {
|
|
"type": "object",
|
|
"properties": {
|
|
"entity_id": {
|
|
"type": "string",
|
|
"example": "climate.gas_boiler"
|
|
}
|
|
},
|
|
"required": [
|
|
"entity_id"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"NotificationSettings": {
|
|
"type": "object",
|
|
"description": "Notification test/settings shape. Provider secrets/webhook fields are also accepted; blank secret fields reuse saved secrets during a test.",
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"mode": {
|
|
"type": "string",
|
|
"enum": [
|
|
"problems",
|
|
"important"
|
|
]
|
|
},
|
|
"provider": {
|
|
"type": "string",
|
|
"enum": [
|
|
"pushover",
|
|
"slack",
|
|
"discord"
|
|
]
|
|
},
|
|
"cooldown_seconds": {
|
|
"type": "integer",
|
|
"minimum": 30,
|
|
"maximum": 86400
|
|
},
|
|
"communication_failure_threshold": {
|
|
"type": "integer",
|
|
"minimum": 2,
|
|
"maximum": 100
|
|
},
|
|
"target_timeout_minutes": {
|
|
"type": "integer",
|
|
"minimum": 5,
|
|
"maximum": 1440
|
|
}
|
|
}
|
|
},
|
|
"ApplicationSettings": {
|
|
"type": "object",
|
|
"properties": {
|
|
"simulator_enabled": {
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"required": [
|
|
"simulator_enabled"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"GreeSettings": {
|
|
"type": "object",
|
|
"properties": {
|
|
"controller_id": {
|
|
"type": "string",
|
|
"minLength": 1,
|
|
"example": "gree-controller"
|
|
},
|
|
"poll_interval_seconds": {
|
|
"type": "integer",
|
|
"minimum": 2,
|
|
"maximum": 3600
|
|
},
|
|
"zone_interval_seconds": {
|
|
"type": "integer",
|
|
"minimum": 2,
|
|
"maximum": 3600
|
|
},
|
|
"discovery_timeout_ms": {
|
|
"type": "integer",
|
|
"minimum": 300,
|
|
"maximum": 30000
|
|
},
|
|
"discovery_broadcast": {
|
|
"type": "string",
|
|
"example": "255.255.255.255:7000"
|
|
},
|
|
"suppress_device_beep": {
|
|
"type": "boolean"
|
|
},
|
|
"compressor_protection_enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"compressor_protection_seconds": {
|
|
"type": "integer",
|
|
"minimum": 30,
|
|
"maximum": 1800
|
|
}
|
|
},
|
|
"required": [
|
|
"controller_id",
|
|
"poll_interval_seconds",
|
|
"zone_interval_seconds",
|
|
"discovery_timeout_ms",
|
|
"discovery_broadcast",
|
|
"suppress_device_beep",
|
|
"compressor_protection_enabled",
|
|
"compressor_protection_seconds"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"HistorySettings": {
|
|
"type": "object",
|
|
"properties": {
|
|
"retention_days": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 3650
|
|
},
|
|
"compaction_enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"event_retention_days": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 3650
|
|
}
|
|
},
|
|
"required": [
|
|
"retention_days",
|
|
"compaction_enabled",
|
|
"event_retention_days"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"InfluxDbSettingsView": {
|
|
"type": "object",
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"version": {
|
|
"type": "string",
|
|
"enum": [
|
|
"1",
|
|
"2"
|
|
]
|
|
},
|
|
"url": {
|
|
"type": "string"
|
|
},
|
|
"database": {
|
|
"type": "string"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
},
|
|
"org": {
|
|
"type": "string"
|
|
},
|
|
"bucket": {
|
|
"type": "string"
|
|
},
|
|
"history_threshold_days": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 3650
|
|
},
|
|
"password_configured": {
|
|
"type": "boolean"
|
|
},
|
|
"token_configured": {
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"required": [
|
|
"enabled",
|
|
"version",
|
|
"url",
|
|
"database",
|
|
"username",
|
|
"org",
|
|
"bucket",
|
|
"history_threshold_days",
|
|
"password_configured",
|
|
"token_configured"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"InfluxDbSettingsUpdate": {
|
|
"type": "object",
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"version": {
|
|
"type": "string",
|
|
"enum": [
|
|
"1",
|
|
"2"
|
|
]
|
|
},
|
|
"url": {
|
|
"type": "string"
|
|
},
|
|
"database": {
|
|
"type": "string"
|
|
},
|
|
"username": {
|
|
"type": "string"
|
|
},
|
|
"org": {
|
|
"type": "string"
|
|
},
|
|
"bucket": {
|
|
"type": "string"
|
|
},
|
|
"history_threshold_days": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 3650
|
|
},
|
|
"password": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Omit/null to preserve the stored value; empty string clears it."
|
|
},
|
|
"token": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Omit/null to preserve the stored value; empty string clears it."
|
|
}
|
|
},
|
|
"required": [
|
|
"enabled",
|
|
"version",
|
|
"url",
|
|
"database",
|
|
"username",
|
|
"org",
|
|
"bucket",
|
|
"history_threshold_days"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"NotificationAlertTypes": {
|
|
"type": "object",
|
|
"properties": {
|
|
"stale_sensor": {
|
|
"type": "boolean"
|
|
},
|
|
"sensor_errors": {
|
|
"type": "boolean"
|
|
},
|
|
"communication": {
|
|
"type": "boolean"
|
|
},
|
|
"target_timeout": {
|
|
"type": "boolean"
|
|
},
|
|
"automation": {
|
|
"type": "boolean"
|
|
},
|
|
"control_errors": {
|
|
"type": "boolean"
|
|
},
|
|
"important_events": {
|
|
"type": "boolean"
|
|
},
|
|
"other": {
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"required": [
|
|
"stale_sensor",
|
|
"sensor_errors",
|
|
"communication",
|
|
"target_timeout",
|
|
"automation",
|
|
"control_errors",
|
|
"important_events",
|
|
"other"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"NotificationSettingsView": {
|
|
"type": "object",
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"mode": {
|
|
"type": "string",
|
|
"enum": [
|
|
"problems",
|
|
"important"
|
|
]
|
|
},
|
|
"provider": {
|
|
"type": "string",
|
|
"enum": [
|
|
"pushover",
|
|
"slack",
|
|
"discord"
|
|
]
|
|
},
|
|
"cooldown_seconds": {
|
|
"type": "integer",
|
|
"minimum": 30,
|
|
"maximum": 86400
|
|
},
|
|
"communication_failure_threshold": {
|
|
"type": "integer",
|
|
"minimum": 2,
|
|
"maximum": 100
|
|
},
|
|
"target_timeout_minutes": {
|
|
"type": "integer",
|
|
"minimum": 5,
|
|
"maximum": 1440
|
|
},
|
|
"alert_types": {
|
|
"$ref": "#/components/schemas/NotificationAlertTypes"
|
|
},
|
|
"pushover_configured": {
|
|
"type": "boolean"
|
|
},
|
|
"slack_configured": {
|
|
"type": "boolean"
|
|
},
|
|
"discord_configured": {
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"required": [
|
|
"enabled",
|
|
"mode",
|
|
"provider",
|
|
"cooldown_seconds",
|
|
"communication_failure_threshold",
|
|
"target_timeout_minutes",
|
|
"alert_types",
|
|
"pushover_configured",
|
|
"slack_configured",
|
|
"discord_configured"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"NotificationSettingsUpdate": {
|
|
"type": "object",
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"mode": {
|
|
"type": "string",
|
|
"enum": [
|
|
"problems",
|
|
"important"
|
|
]
|
|
},
|
|
"provider": {
|
|
"type": "string",
|
|
"enum": [
|
|
"pushover",
|
|
"slack",
|
|
"discord"
|
|
]
|
|
},
|
|
"cooldown_seconds": {
|
|
"type": "integer",
|
|
"minimum": 30,
|
|
"maximum": 86400
|
|
},
|
|
"communication_failure_threshold": {
|
|
"type": "integer",
|
|
"minimum": 2,
|
|
"maximum": 100
|
|
},
|
|
"target_timeout_minutes": {
|
|
"type": "integer",
|
|
"minimum": 5,
|
|
"maximum": 1440
|
|
},
|
|
"alert_types": {
|
|
"$ref": "#/components/schemas/NotificationAlertTypes"
|
|
},
|
|
"pushover_app_token": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Omit/null to preserve the stored secret; empty string clears it."
|
|
},
|
|
"pushover_user_key": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Omit/null to preserve the stored secret; empty string clears it."
|
|
},
|
|
"slack_webhook_url": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Omit/null to preserve the stored secret; empty string clears it."
|
|
},
|
|
"discord_webhook_url": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Omit/null to preserve the stored secret; empty string clears it."
|
|
}
|
|
},
|
|
"required": [
|
|
"enabled",
|
|
"mode",
|
|
"provider",
|
|
"cooldown_seconds",
|
|
"communication_failure_threshold",
|
|
"target_timeout_minutes",
|
|
"alert_types"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"NightModeSettings": {
|
|
"type": "object",
|
|
"properties": {
|
|
"enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"start_time": {
|
|
"type": "string",
|
|
"pattern": "^[0-2][0-9]:[0-5][0-9]$"
|
|
},
|
|
"end_time": {
|
|
"type": "string",
|
|
"pattern": "^[0-2][0-9]:[0-5][0-9]$"
|
|
},
|
|
"max_fan_speed": {
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
"maximum": 5
|
|
},
|
|
"force_quiet": {
|
|
"type": "boolean"
|
|
},
|
|
"use_native_sleep": {
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"required": [
|
|
"enabled",
|
|
"start_time",
|
|
"end_time",
|
|
"max_fan_speed",
|
|
"force_quiet",
|
|
"use_native_sleep"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"HomeAssistantSettingsView": {
|
|
"type": "object",
|
|
"properties": {
|
|
"url": {
|
|
"type": "string"
|
|
},
|
|
"default_entity_id": {
|
|
"type": "string"
|
|
},
|
|
"outdoor_entity_id": {
|
|
"type": "string"
|
|
},
|
|
"sensor_stale_after_seconds": {
|
|
"type": "integer"
|
|
},
|
|
"allow_invalid_tls": {
|
|
"type": "boolean"
|
|
},
|
|
"sensor_aliases": {
|
|
"type": "object",
|
|
"additionalProperties": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"flow_inputs": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"outdoor_assist_enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"token_configured": {
|
|
"type": "boolean"
|
|
}
|
|
},
|
|
"required": [
|
|
"url",
|
|
"default_entity_id",
|
|
"outdoor_entity_id",
|
|
"sensor_stale_after_seconds",
|
|
"allow_invalid_tls",
|
|
"sensor_aliases",
|
|
"flow_inputs",
|
|
"outdoor_assist_enabled",
|
|
"token_configured"
|
|
],
|
|
"additionalProperties": false
|
|
},
|
|
"HomeAssistantSettingsUpdate": {
|
|
"type": "object",
|
|
"properties": {
|
|
"url": {
|
|
"type": "string"
|
|
},
|
|
"default_entity_id": {
|
|
"type": "string"
|
|
},
|
|
"outdoor_entity_id": {
|
|
"type": "string"
|
|
},
|
|
"sensor_stale_after_seconds": {
|
|
"type": "integer"
|
|
},
|
|
"allow_invalid_tls": {
|
|
"type": "boolean"
|
|
},
|
|
"sensor_aliases": {
|
|
"type": "object",
|
|
"additionalProperties": {
|
|
"type": "string"
|
|
}
|
|
},
|
|
"flow_inputs": {
|
|
"type": "array",
|
|
"items": {
|
|
"type": "object",
|
|
"additionalProperties": true
|
|
}
|
|
},
|
|
"outdoor_assist_enabled": {
|
|
"type": "boolean"
|
|
},
|
|
"token": {
|
|
"type": [
|
|
"string",
|
|
"null"
|
|
],
|
|
"description": "Omit/null to preserve the stored token; empty string clears it."
|
|
}
|
|
},
|
|
"required": [
|
|
"url",
|
|
"default_entity_id",
|
|
"outdoor_entity_id",
|
|
"sensor_stale_after_seconds",
|
|
"allow_invalid_tls",
|
|
"sensor_aliases",
|
|
"flow_inputs",
|
|
"outdoor_assist_enabled"
|
|
],
|
|
"additionalProperties": false
|
|
}
|
|
},
|
|
"responses": {
|
|
"BadRequest": {
|
|
"description": "Validation error or unsafe/invalid operation",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Unauthorized": {
|
|
"description": "Missing or incorrect token",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
},
|
|
"example": {
|
|
"error": "unauthorized"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"NotFound": {
|
|
"description": "Resource ID does not exist",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"Conflict": {
|
|
"description": "Revision/concurrency conflict or conflicting resource state",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"BadGateway": {
|
|
"description": "GREE/Home Assistant/integration communication failure",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"InternalError": {
|
|
"description": "Unexpected server or storage error",
|
|
"content": {
|
|
"application/json": {
|
|
"schema": {
|
|
"$ref": "#/components/schemas/Error"
|
|
},
|
|
"example": {
|
|
"error": "internal server error"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|