first commit

This commit is contained in:
Mateusz Gruszczyński
2026-08-23 21:34:07 +02:00
commit 1d3dcba1a9
62 changed files with 12456 additions and 0 deletions
+299
View File
@@ -0,0 +1,299 @@
# GREE Controller
> Identifier convention: project-owned namespace identifiers use `gree_controller`. Home Assistant uses `gree_controller`, UI storage uses `gree_controller_*`, and environment variables use `GREE_CONTROLLER_*`.
Standalone local GREE air-conditioner controller written in Rust. It runs on a regular Linux host or an LXC container and provides a mobile-first web interface without depending on the vendor cloud.
Current version: **0.3.3**.
## Highlights
- local GREE discovery over UDP/7000,
- V1 bind/status/command transport using AES-128-ECB,
- V2 AES-128-GCM envelope support,
- power, HVAC mode, target temperature, fan, vertical/horizontal swing, quiet, turbo and display light,
- SQLite state/history/event storage,
- temperature zones with hysteresis and minimum ON/OFF protection,
- weekly schedules including ranges that cross midnight,
- temperature/time automations,
- per-zone optional Home Assistant room-temperature sensors with GREE fallback,
- combined zone temperature using configurable GREE/external sensor weighting and discrepancy protection,
- REST API and WebSocket updates,
- responsive PWA optimized for phones,
- JSON-based UI localization loaded from embedded `lang/*.json` language packs,
- light, dark and system appearance modes stored in a browser cookie,
- optional Bearer-token authentication,
- simulator mode for development without physical hardware,
- Debian/Ubuntu LXC systemd installer,
- Home Assistant custom integration that proxies `climate` commands through this controller,
- migration mapping generator for retaining existing HA entity IDs such as `climate.klima_salon`.
See [`BUILD_REPORT.md`](BUILD_REPORT.md) for package validation details and [`docs/LXC.md`](docs/LXC.md) for the LXC deployment/update workflow.
## Quick start
On Debian, Ubuntu or an LXC container:
```bash
unzip gree-controller-v0.3.3.zip
cd gree-controller
chmod +x scripts/*.sh
./scripts/dev.sh
```
`scripts/dev.sh` installs missing build tools when possible, installs stable Rust with `rustup` when required, creates `.env`, builds the application and starts the web panel.
Default address:
```text
http://HOST_ADDRESS:8787
```
The first empty database can be seeded with **Living Room (simulator)** so the UI, history, zones and automations can be tested without an AC.
### Development commands
```bash
./scripts/dev.sh --check
./scripts/dev.sh --release
./scripts/dev.sh --reset
./scripts/dev.sh --host 0.0.0.0 --port 8787
./scripts/dev.sh --no-install
```
## Web interface
The UI is mobile-first and uses no external CDN.
Language selector:
- English is the required default/fallback language,
- Polish is included,
- additional languages are discovered automatically from `lang/*.json` at build time.
The selected language is stored in the `gree_controller_language` cookie. The UI contains no hard-coded list of supported languages. To add a language, copy `lang/en.json`, translate the `translations` values, set the `meta` fields, save it as `<code>.json`, and rebuild. For example, `lang/de.json` becomes an additional language after `cargo build` / `./scripts/dev.sh`. Missing translation keys fall back to English.
See [`docs/LOCALIZATION.md`](docs/LOCALIZATION.md) for the language-pack format and validation rules.
Appearance selector:
- System,
- Light,
- Dark.
The selected appearance is stored in the `gree_controller_theme` cookie. The interface uses flat surfaces and borders; decorative UI shadows were removed in v0.2.0.
## Connecting a physical GREE device
1. Put the controller and AC in a network where UDP/7000 traffic is allowed.
2. Open the web interface and select **Discover**.
3. Use **Bind** or send a command so the controller can obtain/use the device key.
4. If LXC/VLAN broadcast does not pass, add the unit manually with IP and MAC/CID.
Some GREE firmware families use protocol variations. V1 covers common Wi-Fi units. V2 implements the standard AES-GCM envelope but unusual firmware may require protocol-specific adaptation.
## LXC/systemd installation and updates
All operator scripts are under `scripts/`. On a clean Debian/Ubuntu LXC container:
```bash
chmod +x scripts/*.sh
sudo ./scripts/install.sh
```
The installer installs build dependencies/Rust when required, runs the Rust tests, builds a release binary, creates the `gree-controller` service account, stores runtime data in `/var/lib/gree-controller`, installs the binary under `/opt/gree-controller`, creates `/etc/gree-controller.env`, generates an administrator token and enables the systemd service. Existing `/etc/gree-controller.env` is preserved.
For a later release, unpack the new source archive and run:
```bash
sudo ./scripts/update.sh
```
The update is designed for LXC testing and production-style upgrades: compilation/tests happen before the running service is stopped; then the script backs up the installed binary, service unit, environment file and stopped SQLite database under `/var/backups/gree-controller/<timestamp>/`. After replacement it checks `/api/health`. A failed startup triggers automatic rollback to the previous binary, unit and database backup.
Service helpers:
```bash
./scripts/service.sh status
sudo ./scripts/service.sh restart
./scripts/service.sh logs
./scripts/service.sh health
```
Use `--skip-tests` with `install.sh` or `update.sh` only when you explicitly want to skip `cargo test --all-targets`. `scripts/install-lxc.sh` remains as a compatibility alias to `scripts/install.sh`.
## Environment configuration
| Variable | Default | Purpose |
|---|---:|---|
| `GREE_CONTROLLER_BIND` | `0.0.0.0:8787` | HTTP/WebSocket bind address |
| `GREE_CONTROLLER_DATABASE` | `./data/gree-controller.db` | SQLite file |
| `GREE_CONTROLLER_APP_TOKEN` | empty | Bearer token; empty disables API authentication |
| `GREE_CONTROLLER_SIMULATE` | `true` | Enables simulator support |
| `GREE_CONTROLLER_AUTO_SEED` | `true` | Seeds a simulator into an empty database |
| `GREE_CONTROLLER_POLL_INTERVAL_SECONDS` | `15` | Device polling interval |
| `GREE_CONTROLLER_ZONE_INTERVAL_SECONDS` | `5` | Zone-control interval |
| `GREE_CONTROLLER_DISCOVERY_TIMEOUT_MS` | `3000` | UDP discovery timeout |
| `GREE_CONTROLLER_DISCOVERY_BROADCAST` | `255.255.255.255:7000` | Discovery broadcast target |
| `GREE_CONTROLLER_ID` | `gree-controller` | GREE protocol client CID |
| `HA_URL` | empty | Optional Home Assistant URL |
| `HA_TOKEN` | empty | Optional Home Assistant Long-Lived Access Token |
| `HA_ENTITY_ID` | empty | Optional default HA temperature sensor |
Settings changed from the web panel are stored in SQLite. `GREE_CONTROLLER_APP_TOKEN` is loaded at process startup.
## Per-zone room temperature sensors
Each control zone can pair one GREE indoor unit with its own optional room sensor from Home Assistant. This is intentionally configured per zone, so rooms do not share a global temperature source.
Example:
```text
Living room -> GREE Living Room + sensor.living_room_temperature
Bedroom -> GREE Bedroom + sensor.bedroom_temperature
Office -> GREE Office + sensor.office_temperature
```
Zone temperature strategies:
- **GREE only** — use the AC internal sensor.
- **GREE + room sensor** — recommended; calculate a weighted control temperature from both sensors. The default room-sensor weight is 40%.
- **Room sensor only** — use the assigned HA room sensor, with automatic fallback to GREE if HA or the entity becomes unavailable.
For combined control, `max_sensor_difference` protects against an obviously incorrect external measurement. If the two sensors differ by more than the configured threshold (default `3.0°C`), the zone uses the GREE temperature and logs a sensor-discrepancy event.
The zone API exposes `device_temperature`, `external_temperature`, `current_temperature` (the actual control temperature) and `control_temperature_source` for diagnostics. Existing SQLite zone records remain compatible because the new fields have defaults and are stored in the existing JSON payload.
## Home Assistant
There are two independent HA directions:
1. **HA as an optional sensor source**: the Rust controller can read a selected HA sensor and use it for a zone.
2. **HA as a client of GREE Controller**: the included custom integration creates `climate` entities whose commands are sent to this Rust application.
For the HA client connection, open **Settings -> Home Assistant integration access** in GREE Controller and press **Create new token**. The secret is shown once. Paste that token into the Home Assistant `GREE Controller` integration together with the controller URL. Managed HA tokens are stored as SHA-256 hashes and are scoped to the dedicated HA device/command API; they cannot change controller settings or manage other tokens.
The second option is designed to replace the built-in/default GREE integration without changing automation/dashboard references.
Example migration target:
```text
old: climate.klima_salon -> built-in GREE integration
new: climate.klima_salon -> GREE Controller custom integration -> Rust API -> AC
```
Generate an entity mapping:
```bash
./scripts/generate_ha_migration.py \
--entity climate.klima_salon \
--device gree-aabbccddeeff
```
Or validate against the controller and automatically use its only device:
```bash
./scripts/generate_ha_migration.py \
--entity climate.klima_salon \
--controller-url http://192.168.1.20:8787 \
--controller-token YOUR_CONTROLLER_TOKEN
```
The generated file must be copied to:
```text
/config/gree_controller_entities.json
```
Full installation and safe takeover procedure: [`home-assistant/README.md`](home-assistant/README.md) and [`docs/HOME_ASSISTANT_MIGRATION.md`](docs/HOME_ASSISTANT_MIGRATION.md).
## API
Important endpoints:
```text
GET /api/health
GET /api/bootstrap
POST /api/discovery
GET /api/devices
POST /api/devices
GET /api/devices/:id
PATCH /api/devices/:id
POST /api/devices/:id/bind
POST /api/devices/:id/poll
POST /api/devices/:id/command
GET /api/zones
POST /api/zones
GET /api/schedules
POST /api/schedules
GET /api/automations
POST /api/automations
GET /api/readings
GET /api/events
GET /api/settings
PUT /api/settings
GET /api/access-tokens
POST /api/access-tokens
DELETE /api/access-tokens/{id}
POST /api/integrations/home-assistant/test
GET /api/integrations/home-assistant/devices
POST /api/integrations/home-assistant/devices/{id}/command
WS /ws
```
Example command:
```bash
curl -X POST http://127.0.0.1:8787/api/devices/sim-salon/command \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer YOUR_TOKEN' \
-d '{"power":true,"mode":"cool","target_temperature":22,"fan_speed":3}'
```
`/api/health` is public. The normal controller API and Web UI require `GREE_CONTROLLER_APP_TOKEN` only when that administrator token is configured. The dedicated `/api/integrations/home-assistant/*` client endpoints always require either a generated HA access token or the administrator token. WebSocket accepts only the administrator token using `?token=...`.
More examples: [`docs/API.md`](docs/API.md).
## Security
- The application does not terminate TLS. Use HTTPS reverse proxy or VPN on untrusted networks.
- Do not expose port 8787 directly to the public Internet.
- Use a long random `GREE_CONTROLLER_APP_TOKEN`.
- Protect `.env`, `/etc/gree-controller.env`, SQLite data and HA tokens.
- The controller sends device commands only to configured local-network devices.
## Backup
For a systemd installation:
```bash
systemctl stop gree-controller
cp /var/lib/gree-controller/gree-controller.db /safe/backup/location/
systemctl start gree-controller
```
Development data is stored under `data/` by default.
## Project layout
```text
src/api.rs HTTP API, WebSocket, embedded web assets
src/db.rs SQLite persistence and row/domain mapping
src/queries.rs all SQLite schema and SQL statements
src/engine.rs polling, zones, schedules and automations
src/protocol/ GREE UDP/AES discovery, bind, status, command
src/home_assistant.rs optional HA sensor client
web/ mobile-first bilingual PWA
home-assistant/custom_components/ HA custom integration
scripts/install.sh first LXC/systemd installation
scripts/update.sh safe LXC/systemd update with backup/rollback
scripts/service.sh service status/start/stop/restart/logs/health
scripts/dev.sh development build/run/check workflow
scripts/generate_ha_migration.py legacy HA entity-ID mapping generator
scripts/smoke.sh API smoke test
systemd/ systemd service unit
```
## License
MIT. This project uses a community-reconstructed local device protocol and is not an official product of GREE Electric Appliances Inc.