409 lines
17 KiB
Markdown
409 lines
17 KiB
Markdown
# GREE Controller
|
||
|
||
Self-hosted controller for GREE-compatible air conditioners with a local Web UI, thermostat zones, schedules, Home Assistant integration, history, notifications and a documented HTTP/WebSocket API.
|
||
|
||
**Current release: 0.9.1**
|
||
|
||
> [Full API reference](docs/API.md) — authentication, every endpoint, request bodies, response models, WebSocket events and examples.
|
||
|
||
## What it does
|
||
|
||
- Discovers and binds GREE Wi-Fi units on the LAN, including mixed protocol generations.
|
||
- Provides direct technical device control and a separate thermostat layer built around zones.
|
||
- Supports cooling/heating profiles: Comfort, Sleep, Away and custom quick targets.
|
||
- Coordinates house, group and per-zone control without silently fighting physical/manual overrides.
|
||
- Supports schedules, automations, night mode and temporary Quick Thermostat sessions.
|
||
- Can use GREE sensors, Home Assistant room sensors or a weighted combination.
|
||
- Stores recent history in SQLite and can archive/query long-term history in InfluxDB 1.x or 2.x.
|
||
- Exposes native Home Assistant entities through the bundled custom integration.
|
||
- Includes PWA-capable responsive UI, Polish/English localization and live diagnostics.
|
||
- Can run in Simulation mode without physical air conditioners. A large warning is shown whenever simulation is enabled.
|
||
|
||
## UI overview
|
||
|
||
The interface is intentionally split by responsibility:
|
||
|
||
| Area | Purpose |
|
||
| --- | --- |
|
||
| Dashboard | Whole-house summary and Quick Thermostat controls. |
|
||
| Devices | Discovery, binding and direct/technical GREE device control. |
|
||
| Zones | Thermostat configuration, profiles, sensors and control ownership. |
|
||
| Groups | Climate group membership plus optional group-level mode/preset/custom-temperature control. Group ON activates member thermostat control; Group OFF powers member units down and releases group ownership so individual thermostats are not left group-blocked. |
|
||
| Schedules | Weekly thermostat schedules and ready-made templates. |
|
||
| Automations | Time/temperature triggered device or group actions. |
|
||
| History | Overview, zones, devices and HA sensors with precise chart tooltips and zoom. |
|
||
| Simulation | Simulated units for safe testing. |
|
||
| Night mode | Quiet/Sleep/fan limits during an overnight window. |
|
||
| Home Assistant | Sensor connection, aliases and restricted integration tokens. |
|
||
| Settings → Application | Simulation, notifications, metrics/logs, InfluxDB, debug and backup. |
|
||
| Settings → GREE | Controller identity, polling/discovery, GREE commands and live GREE traffic. |
|
||
| Events | Operational event log and diagnostics. |
|
||
|
||
The top bar uses the same compact language and theme controls on desktop and mobile. The live debug overlay can be filtered to **All**, **Requests** or **GREE** frames.
|
||
|
||
## Quick start for development
|
||
|
||
Requirements are installed automatically on supported Debian/Ubuntu environments unless `--no-install` is used.
|
||
|
||
```bash
|
||
cp .env.example .env
|
||
./scripts/dev.sh
|
||
```
|
||
|
||
Useful development commands:
|
||
|
||
```bash
|
||
./scripts/dev.sh --check # format, tests, build and HTTP smoke test
|
||
./scripts/dev.sh --release # optimized local build
|
||
./scripts/dev.sh --reset # recreate the local SQLite database
|
||
./scripts/smoke.sh # API smoke test against an isolated simulated instance
|
||
```
|
||
|
||
The default panel is available at `http://127.0.0.1:8787` when the process is bound locally.
|
||
|
||
## LXC / systemd installation
|
||
|
||
The production scripts target Debian/Ubuntu systemd hosts and LXC containers.
|
||
|
||
### First installation
|
||
|
||
```bash
|
||
sudo ./scripts/install.sh
|
||
```
|
||
|
||
Optional flags:
|
||
|
||
```bash
|
||
sudo ./scripts/install.sh --skip-tests
|
||
sudo ./scripts/install.sh --no-start
|
||
```
|
||
|
||
Installed layout:
|
||
|
||
| Path | Purpose |
|
||
| --- | --- |
|
||
| `/opt/gree-controller/gree-controller` | Release binary. |
|
||
| `/etc/gree-controller.env` | Environment configuration; mode `0600`. |
|
||
| `/var/lib/gree-controller/gree-controller.db` | SQLite database. |
|
||
| `/etc/systemd/system/gree-controller.service` | systemd unit. |
|
||
| `/var/backups/gree-controller/` | Update backups used for rollback. |
|
||
|
||
### Update
|
||
|
||
Run from the extracted source tree of the new release:
|
||
|
||
```bash
|
||
sudo ./scripts/update.sh
|
||
```
|
||
|
||
The updater builds/tests first, stops the old service, backs up the binary/unit/environment/database, installs the release, checks `/api/health` and rolls back automatically if startup fails.
|
||
|
||
### Service helper
|
||
|
||
```bash
|
||
./scripts/service.sh status
|
||
./scripts/service.sh health
|
||
./scripts/service.sh logs
|
||
sudo ./scripts/service.sh restart
|
||
```
|
||
|
||
`./scripts/install-lxc.sh` remains as a compatibility alias to `install.sh`.
|
||
|
||
## Configuration
|
||
|
||
Copy `.env.example` for the full supported example. Command-line arguments exist for the core `Config` options, while most day-to-day runtime settings are also editable in the Web UI and persisted in SQLite.
|
||
|
||
Environment values explicitly supplied for supported runtime overrides win over the persisted value after restart.
|
||
|
||
### Core variables
|
||
|
||
| Variable | Default | Description |
|
||
| --- | --- | --- |
|
||
| `GREE_CONTROLLER_BIND` | `0.0.0.0:8787` | HTTP/WebSocket listen address. |
|
||
| `GREE_CONTROLLER_DATABASE` | `./data/gree-controller.db` | SQLite database path. |
|
||
| `GREE_CONTROLLER_APP_TOKEN` | empty | Optional administrator API/Web UI token. Empty means trusted-LAN mode. |
|
||
| `GREE_CONTROLLER_BASE_PATH` | empty | Optional reverse-proxy prefix such as `/gree`. |
|
||
| `GREE_CONTROLLER_ID` | `gree-controller` | GREE client/controller identifier. |
|
||
| `GREE_CONTROLLER_SIMULATE` | `false` | Initial Simulation mode. |
|
||
| `GREE_CONTROLLER_AUTO_SEED` | `false` | Seed simulated sample data when applicable. |
|
||
| `GREE_CONTROLLER_POLL_INTERVAL_SECONDS` | `15` | Device polling interval. |
|
||
| `GREE_CONTROLLER_ZONE_INTERVAL_SECONDS` | `5` | Thermostat control interval. |
|
||
| `GREE_CONTROLLER_DISCOVERY_TIMEOUT_MS` | `3000` | Discovery timeout. |
|
||
| `GREE_CONTROLLER_DISCOVERY_BROADCAST` | `255.255.255.255:7000` | GREE discovery target. |
|
||
| `GREE_CONTROLLER_GREE_INTERFACE` | auto | Optional interface name or local IP used for GREE UDP traffic. |
|
||
| `GREE_CONTROLLER_COMPRESSOR_PROTECTION_ENABLED` | `true` | Enable controller-side compressor restart/mode-change protection. |
|
||
| `GREE_CONTROLLER_COMPRESSOR_PROTECTION_SECONDS` | `180` | Compressor protection window (30–1800 seconds; 180 seconds recommended). |
|
||
|
||
Additional environment variables cover history retention, debug, night mode, Home Assistant and InfluxDB. See [`.env.example`](.env.example).
|
||
|
||
## Connecting physical GREE units
|
||
|
||
1. Place the controller host on a network that can reach the air-conditioner Wi-Fi modules by UDP.
|
||
2. Open **Devices** and start discovery.
|
||
3. Auto protocol mode is recommended; the controller accepts both supported GREE encryption generations.
|
||
4. Newly discovered devices are bound automatically when possible. Manual bind is also available.
|
||
5. Create a thermostat zone for each unit you want the thermostat engine to own.
|
||
|
||
Discovery uses UDP broadcast, so routed/VLAN networks must explicitly permit or relay the required traffic.
|
||
|
||
### Multi-NIC / dedicated GREE interface
|
||
|
||
For a host with separate management and GREE networks, set for example:
|
||
|
||
```bash
|
||
GREE_CONTROLLER_GREE_INTERFACE=eth1
|
||
```
|
||
|
||
or a local address:
|
||
|
||
```bash
|
||
GREE_CONTROLLER_GREE_INTERFACE=192.168.50.2
|
||
```
|
||
|
||
The controller will use that interface for GREE UDP traffic while keeping the HTTP UI on `GREE_CONTROLLER_BIND`.
|
||
|
||
Diagnostics:
|
||
|
||
```bash
|
||
sudo ./scripts/configure-gree-network.sh
|
||
./scripts/network-debug.sh
|
||
```
|
||
|
||
The hardened systemd unit allows `AF_NETLINK`, which is required for interface discovery on multi-NIC Linux/LXC systems.
|
||
|
||
## Thermostat model
|
||
|
||
### Devices vs zones
|
||
|
||
A **Device** is the physical GREE unit. Device commands are direct/technical commands.
|
||
|
||
A **Zone** is the thermostat owner for a device. It decides demand from room temperature, setpoint, hysteresis, schedules, house master state, manual ownership and safety lockouts. Group control can temporarily apply shared settings. Turning a group OFF powers its member units down and releases group ownership; each thermostat can then be switched back on independently without an OFF group acting as a membership block.
|
||
|
||
### Compressor protection
|
||
|
||
Controller-side compressor protection is enabled by default and uses a 3-minute window. The switch and duration are available under **Settings → GREE**. Thermostat, group and whole-house starts or Heat/Cool reversals that fall inside the window are kept as visible pending tasks instead of being discarded. The pending task is shown on both the thermostat and its device card. A permanent **Queue** button above Thermostats opens a global modal sorted by execution time, with device/zone, command, owner, protection deadline, live countdown, per-task cancellation and **Cancel all**. Safety OFF commands remain immediate.
|
||
|
||
This distinction is important: direct device control intentionally behaves differently from thermostat control.
|
||
|
||
### Control ownership
|
||
|
||
The zone state exposes who currently owns control (`control_owner`, `control_source`, timestamps and reason). Physical remote/direct device actions can create a manual-device takeover so normal schedules do not immediately overwrite the user. Explicit zone thermostat control hands ownership back to the thermostat engine when appropriate.
|
||
|
||
Whole-house master OFF remains authoritative and powers managed devices down.
|
||
|
||
### Profiles and schedules
|
||
|
||
Each zone stores separate cooling and heating temperatures for:
|
||
|
||
- Comfort
|
||
- Sleep
|
||
- Away
|
||
- Custom/manual target
|
||
|
||
Schedules select profiles or a custom target for selected ISO weekdays (`1=Monday`, `7=Sunday`). Overnight windows are supported. Overlapping enabled schedules for the same zone are rejected.
|
||
|
||
Quick preset/setpoint overrides normally hand control back at the next schedule boundary. Temporary Quick Thermostat adds explicit start/finish rules such as duration, exact time, temperature reached/stable or next schedule boundary.
|
||
|
||
## Home Assistant
|
||
|
||
There are two independent Home Assistant directions.
|
||
|
||
### 1. Home Assistant as a temperature source
|
||
|
||
Configure **Home Assistant / Sensors** in the Web UI or use:
|
||
|
||
```text
|
||
HA_URL=
|
||
HA_TOKEN=
|
||
HA_ENTITY_ID=
|
||
HA_OUTDOOR_ENTITY_ID=
|
||
HA_SENSOR_STALE_AFTER_SECONDS=300
|
||
HA_ALLOW_INVALID_TLS=false
|
||
```
|
||
|
||
Per zone, `sensor_source` can be:
|
||
|
||
- `device` — GREE indoor sensor,
|
||
- `home_assistant` — configured HA room sensor,
|
||
- `combined` — weighted GREE + HA value.
|
||
|
||
Stale/unavailable external data falls back to the GREE sensor when possible. The optional outdoor sensor is only an assist signal; it never replaces room temperature.
|
||
|
||
### 2. GREE Controller entities inside Home Assistant
|
||
|
||
Bundled integration directory:
|
||
|
||
```text
|
||
home-assistant/custom_components/gree_controller/
|
||
```
|
||
|
||
Copy `gree_controller` to Home Assistant's `custom_components` directory, restart Home Assistant and add **GREE Controller** from Integrations.
|
||
|
||
Create a restricted token in **Home Assistant / Sensors → Access tokens**. The token secret is displayed only once and the database stores only its SHA-256 hash. The integration uses a restricted `/api/integrations/home-assistant/*` surface rather than administrator endpoints.
|
||
|
||
The integration exposes physical device climate controls, thermostat zone climate entities, whole-house controls, groups and optional unit capabilities. Prefer zone thermostat entities for normal comfort control; physical device entities are direct/manual controls.
|
||
|
||
For entity-ID migration tooling:
|
||
|
||
```bash
|
||
python3 scripts/generate_ha_migration.py --help
|
||
```
|
||
|
||
The generated mapping example is under `home-assistant/generated/`.
|
||
|
||
## History and InfluxDB
|
||
|
||
SQLite is the local hot store. History compaction reduces older local sample density while preserving the resolutions needed by charts. Retention is configurable from the UI or environment.
|
||
|
||
Optional InfluxDB writes samples in parallel and can serve the older part of long history queries:
|
||
|
||
- InfluxDB 1.x: URL, database, optional username/password.
|
||
- InfluxDB 2.x: URL, organization, bucket and token.
|
||
|
||
If an Influx query fails, the API returns available SQLite data and can include a `storage_warning` rather than discarding the whole history response.
|
||
|
||
See [`GET /api/history`](docs/API.md#history-and-readings) for scopes and bucket behavior.
|
||
|
||
## Notifications
|
||
|
||
Optional notifications support:
|
||
|
||
- Pushover
|
||
- Slack webhook
|
||
- Discord webhook
|
||
|
||
Modes can report problems only or problems plus important state changes. Individual categories include sensor freshness/errors, communication failures, target timeout, automation/control errors and other warnings. Cooldown and failure thresholds are configurable.
|
||
|
||
## Debugging
|
||
|
||
Enable **Settings → Application → On-screen debug**.
|
||
|
||
The overlay has three filters:
|
||
|
||
- **All** — request diagnostics, application events and GREE frames,
|
||
- **Requests** — HTTP method/path/status/duration,
|
||
- **GREE** — sanitized protocol frames when GREE frame logging is enabled.
|
||
|
||
Binding/encryption keys are not intentionally exposed in GREE debug frames.
|
||
|
||
For Linux/network issues also use:
|
||
|
||
```bash
|
||
./scripts/network-debug.sh
|
||
./scripts/service.sh logs
|
||
```
|
||
|
||
## Backup and restore
|
||
|
||
**Settings → Application → Configuration backup** exports settings, devices, zones, groups, schedules and automations.
|
||
|
||
The export intentionally does **not** contain metric history, event history or generated API-token records. It **does contain** GREE binding keys and configured integration secrets, so store it like a credential file.
|
||
|
||
Import replaces application configuration while preserving local metric/event history and generated access-token records. Runtime ownership/timers are sanitized and live device state is re-polled before automatic control resumes.
|
||
|
||
## Reverse proxy and sub-path deployment
|
||
|
||
For a root deployment, proxy HTTP and WebSocket traffic to the controller normally.
|
||
|
||
For a sub-path, configure:
|
||
|
||
```bash
|
||
GREE_CONTROLLER_BASE_PATH=/gree
|
||
```
|
||
|
||
Then serve the application under `/gree/`. The proxy must preserve WebSocket upgrade headers. A typical nginx location is:
|
||
|
||
```nginx
|
||
location /gree/ {
|
||
proxy_pass http://127.0.0.1:8787/gree/;
|
||
proxy_http_version 1.1;
|
||
proxy_set_header Upgrade $http_upgrade;
|
||
proxy_set_header Connection "upgrade";
|
||
proxy_set_header Host $host;
|
||
}
|
||
```
|
||
|
||
If your proxy strips the prefix, keep its upstream/base-path handling consistent. Do not publish the controller directly to an untrusted network without authentication and TLS at the proxy/VPN layer.
|
||
|
||
## Security
|
||
|
||
The default empty `GREE_CONTROLLER_APP_TOKEN` is intended for a trusted LAN only. Set a long random token when the interface is reachable by other networks.
|
||
|
||
Implemented safeguards include:
|
||
|
||
- optional bearer administrator authentication,
|
||
- separate restricted generated tokens for Home Assistant,
|
||
- hashed generated-token storage,
|
||
- secrets omitted from normal settings responses,
|
||
- restrictive security headers and no permissive CORS,
|
||
- API responses marked `no-store`,
|
||
- hardened systemd service,
|
||
- safe device power-off behavior when thermostat ownership is removed,
|
||
- startup synchronization before the thermostat engine begins issuing commands.
|
||
|
||
For remote access, prefer a VPN or authenticated TLS reverse proxy. Treat configuration exports and `/etc/gree-controller.env` as secrets.
|
||
|
||
## Localization
|
||
|
||
Language packs are JSON files under `lang/`. The build validates/embeds them and generates the public language catalog.
|
||
|
||
To add a language:
|
||
|
||
1. Copy `lang/en.json` to `lang/<code>.json`.
|
||
2. Update `meta.code`, names and locale.
|
||
3. Keep the same translation keys as the reference pack.
|
||
4. Rebuild the Rust binary.
|
||
|
||
Runtime assets are available at `/lang/index.json` and `/lang/<code>.json`.
|
||
|
||
## API
|
||
|
||
The HTTP API is the same backend used by the Web UI. It includes devices, zones, groups, house control, schedules, automations, history, control plan, events, settings, backup/restore, debug, tokens and integration tests.
|
||
|
||
Start here:
|
||
|
||
**[docs/API.md — complete API reference](docs/API.md)**
|
||
|
||
Public health check:
|
||
|
||
```bash
|
||
curl http://127.0.0.1:8787/api/health
|
||
```
|
||
|
||
Authenticated example when an app token is configured:
|
||
|
||
```bash
|
||
curl -H 'Authorization: Bearer YOUR_TOKEN' \
|
||
http://127.0.0.1:8787/api/system/info
|
||
```
|
||
|
||
## Project layout
|
||
|
||
```text
|
||
src/ Rust backend, GREE protocol and thermostat engine
|
||
web/ Embedded Web UI / PWA
|
||
web/js/ Frontend JS source modules bundled by build.rs
|
||
lang/ Runtime language packs
|
||
home-assistant/ Home Assistant custom integration and migration output
|
||
scripts/ Development, install, update, service and diagnostics
|
||
systemd/ Production service unit
|
||
docs/API.md Complete API documentation
|
||
.env.example Environment reference
|
||
```
|
||
|
||
The application is intentionally self-contained: static assets and language packs are embedded into the binary at build time; SQLite is the default data store; no external frontend build chain is required. `build.rs` concatenates the ordered files from `web/js/` into one generated application bundle and exposes it under a content-hashed URL.
|
||
|
||
## Validation before release
|
||
|
||
Recommended full check on a host with Rust installed:
|
||
|
||
```bash
|
||
./scripts/dev.sh --check
|
||
```
|
||
|
||
This runs formatting checks, Rust tests, a build and an isolated simulated API smoke test.
|
||
|
||
## License
|
||
|
||
See [LICENSE](LICENSE).
|