v0.8.13
This commit is contained in:
+1359
-219
File diff suppressed because it is too large
Load Diff
@@ -1,67 +0,0 @@
|
||||
# Home Assistant entity-ID migration
|
||||
|
||||
## Goal
|
||||
|
||||
Replace an existing GREE climate entity while preserving its `entity_id`.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
Before: climate.klima_salon -> default GREE integration -> AC
|
||||
After: climate.klima_salon -> GREE Controller integration -> Rust controller -> AC
|
||||
```
|
||||
|
||||
Keeping the same entity ID allows existing dashboards, scripts, scenes and automations that reference the entity by ID to continue working.
|
||||
|
||||
## Why a takeover step is required
|
||||
|
||||
Home Assistant's entity registry reserves entity IDs. A second integration cannot create another active `climate.klima_salon` while the original entity still exists. The new integration therefore checks for conflicts and stops setup rather than allowing HA to generate a suffixed name such as `climate.klima_salon_2`.
|
||||
|
||||
## Generate the mapping
|
||||
|
||||
For one entity:
|
||||
|
||||
```bash
|
||||
./scripts/generate_ha_migration.py \
|
||||
--entity climate.klima_salon \
|
||||
--device gree-aabbccddeeff
|
||||
```
|
||||
|
||||
For several:
|
||||
|
||||
```bash
|
||||
./scripts/generate_ha_migration.py \
|
||||
--map climate.klima_salon=gree-aabbccddeeff \
|
||||
--map climate.klima_sypialnia=gree-112233445566
|
||||
```
|
||||
|
||||
Generated structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": 1,
|
||||
"entities": [
|
||||
{
|
||||
"entity_id": "climate.klima_salon",
|
||||
"device_id": "gree-aabbccddeeff"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Copy it to `/config/gree_controller_entities.json` on the Home Assistant host.
|
||||
|
||||
## Migration sequence
|
||||
|
||||
1. Add the physical AC to the standalone Rust application.
|
||||
2. Test power, mode and target temperature from its web UI.
|
||||
3. Generate the HA entity mapping.
|
||||
4. Copy the custom component to `/config/custom_components/gree_controller/`.
|
||||
5. Disable/remove the previous GREE integration in HA so it no longer controls or publishes the old climate entity.
|
||||
6. Remove any stale entity registry entry only after the old integration is unloaded.
|
||||
7. Add the **GREE Controller** integration and provide its URL/token.
|
||||
8. Confirm the exact old entity ID is present again.
|
||||
9. Test `climate.set_temperature`, HVAC modes and power from HA.
|
||||
10. Verify automations and dashboards that use the preserved entity ID.
|
||||
|
||||
The standalone controller remains available during the HA migration, so the AC can still be controlled from its own web UI if HA is restarting.
|
||||
@@ -1,71 +0,0 @@
|
||||
# Localization
|
||||
|
||||
The web interface uses JSON language packs from `lang/`. Language files are discovered at Rust build time and embedded in the application binary.
|
||||
|
||||
English (`lang/en.json`) is required and is always the fallback language. Polish (`lang/pl.json`) is included by default.
|
||||
|
||||
## Add a language
|
||||
|
||||
1. Copy `lang/en.json` to a file named with the new language code, for example `lang/de.json`.
|
||||
2. Update the `meta` object.
|
||||
3. Translate values inside `translations`. Do not rename translation keys.
|
||||
4. Run `./scripts/dev.sh --check` or build the project again.
|
||||
5. Start the rebuilt binary. The new language appears automatically in the language selector.
|
||||
|
||||
Example structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"meta": {
|
||||
"code": "de",
|
||||
"name": "German",
|
||||
"native_name": "Deutsch",
|
||||
"locale": "de-DE"
|
||||
},
|
||||
"translations": {
|
||||
"controls.language": "Sprache",
|
||||
"controls.theme": "Darstellung"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The filename and `meta.code` must match (`de.json` -> `"code": "de"`). File names may contain ASCII letters, digits, `-` and `_` only.
|
||||
|
||||
## Fallback behavior
|
||||
|
||||
A language pack does not have to duplicate every English key while it is being developed. If a key is missing from the selected language, the UI uses the value from `en.json`. If a key is also missing from English, the translation key itself is shown, which makes incomplete strings visible during development.
|
||||
|
||||
## Build-time validation
|
||||
|
||||
`build.rs` checks that:
|
||||
|
||||
- at least one JSON language file exists,
|
||||
- `en.json` exists,
|
||||
- every language file contains valid JSON,
|
||||
- every file has `meta.code`, `meta.name`, `meta.native_name` and `meta.locale`,
|
||||
- `meta.code` matches the filename,
|
||||
- `translations` is a JSON object.
|
||||
|
||||
A malformed language pack fails the Rust build instead of producing a broken selector at runtime.
|
||||
|
||||
## Runtime endpoints
|
||||
|
||||
The embedded language catalog is available at:
|
||||
|
||||
```text
|
||||
GET /lang/index.json
|
||||
```
|
||||
|
||||
Individual embedded packs are available at:
|
||||
|
||||
```text
|
||||
GET /lang/en.json
|
||||
GET /lang/pl.json
|
||||
GET /lang/<code>.json
|
||||
```
|
||||
|
||||
These endpoints are intentionally public so that localization also works before API authentication is completed.
|
||||
|
||||
## Browser preference
|
||||
|
||||
The selected language code is stored for one year in the `gree_controller_language` cookie. If the stored language is no longer present in a later build, the UI falls back to English.
|
||||
-177
@@ -1,177 +0,0 @@
|
||||
# LXC installation and update
|
||||
|
||||
This document describes the supported Debian/Ubuntu systemd deployment used for LXC testing.
|
||||
|
||||
## First installation
|
||||
|
||||
Unpack the source archive inside the container and run:
|
||||
|
||||
```bash
|
||||
cd gree-controller
|
||||
chmod +x scripts/*.sh
|
||||
sudo ./scripts/install.sh
|
||||
```
|
||||
|
||||
The installer:
|
||||
|
||||
1. installs required build packages when missing,
|
||||
2. installs stable Rust with rustup when Cargo is unavailable,
|
||||
3. runs `cargo test --all-targets`,
|
||||
4. builds `target/release/gree-controller`,
|
||||
5. creates the `gree-controller` system user/group,
|
||||
6. creates `/var/lib/gree-controller`, `/opt/gree-controller` and `/var/backups/gree-controller`,
|
||||
7. installs the systemd unit,
|
||||
8. creates `/etc/gree-controller.env` only when it does not already exist,
|
||||
9. enables/restarts the service,
|
||||
10. verifies `GET /api/health`.
|
||||
|
||||
Installed state is intentionally outside the extracted source directory:
|
||||
|
||||
```text
|
||||
/opt/gree-controller/gree-controller installed binary
|
||||
/etc/gree-controller.env persistent configuration/secrets
|
||||
/var/lib/gree-controller/gree-controller.db persistent SQLite database
|
||||
/var/backups/gree-controller/ update backups
|
||||
/etc/systemd/system/gree-controller.service systemd service
|
||||
```
|
||||
|
||||
The default installation starts in simulator mode. Change `GREE_CONTROLLER_SIMULATE=false` and `GREE_CONTROLLER_AUTO_SEED=false` in `/etc/gree-controller.env` when moving to physical units, then restart the service.
|
||||
|
||||
## Update
|
||||
|
||||
Unpack a newer source archive and run from that new directory:
|
||||
|
||||
```bash
|
||||
sudo ./scripts/update.sh
|
||||
```
|
||||
|
||||
The update workflow is designed to minimize downtime and preserve the database:
|
||||
|
||||
1. build dependencies/Rust are checked,
|
||||
2. tests run while the currently installed controller stays online,
|
||||
3. the new release binary is built while the old service stays online,
|
||||
4. the service is stopped,
|
||||
5. the installed binary, service unit, environment file and SQLite database are copied to `/var/backups/gree-controller/<UTC timestamp>/`,
|
||||
6. the new binary/unit is installed,
|
||||
7. systemd starts the new version,
|
||||
8. `/api/health` is checked,
|
||||
9. on failure the old binary, unit and database are restored automatically.
|
||||
|
||||
The updater does not overwrite `/etc/gree-controller.env` during a successful update.
|
||||
|
||||
Use `--skip-tests` only for deliberate fast testing:
|
||||
|
||||
```bash
|
||||
sudo ./scripts/update.sh --skip-tests
|
||||
```
|
||||
|
||||
## Service helper
|
||||
|
||||
```bash
|
||||
./scripts/service.sh status
|
||||
./scripts/service.sh health
|
||||
./scripts/service.sh logs
|
||||
sudo ./scripts/service.sh restart
|
||||
sudo ./scripts/service.sh stop
|
||||
sudo ./scripts/service.sh start
|
||||
```
|
||||
|
||||
Equivalent native commands remain available:
|
||||
|
||||
```bash
|
||||
systemctl status gree-controller
|
||||
journalctl -u gree-controller -f
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Edit:
|
||||
|
||||
```text
|
||||
/etc/gree-controller.env
|
||||
```
|
||||
|
||||
and restart:
|
||||
|
||||
```bash
|
||||
sudo ./scripts/service.sh restart
|
||||
```
|
||||
|
||||
Do not store controller or Home Assistant secrets in the source tree.
|
||||
|
||||
## Database and SQL layout
|
||||
|
||||
Runtime persistence uses SQLite. All schema definitions and SQL statements in the Rust application are centralized in:
|
||||
|
||||
```text
|
||||
src/queries.rs
|
||||
```
|
||||
|
||||
`src/db.rs` contains connection/transaction logic and maps database rows to Rust domain models, but it does not embed SQL statements.
|
||||
|
||||
|
||||
## Two network interfaces
|
||||
|
||||
When the LXC has a management interface and a dedicated GREE network, configure the service environment explicitly. Example for `eth1` on `10.87.65.0/25`:
|
||||
|
||||
```env
|
||||
GREE_CONTROLLER_GREE_INTERFACE=eth1
|
||||
GREE_CONTROLLER_DISCOVERY_BROADCAST=auto
|
||||
|
||||
This explicit interface configuration is recommended for predictable LXC deployments. Version 0.3.7 also automatically selects the directly connected local IPv4 address for a GREE device when the interface variable is omitted; for example, a target in `10.87.65.0/25` selects the local address on that subnet.
|
||||
GREE_CONTROLLER_SIMULATE=false
|
||||
GREE_CONTROLLER_AUTO_SEED=false
|
||||
```
|
||||
|
||||
Restart the service after editing `/etc/gree-controller.env`:
|
||||
|
||||
```bash
|
||||
systemctl restart gree-controller
|
||||
journalctl -u gree-controller -n 100 --no-pager
|
||||
```
|
||||
|
||||
During discovery the log should contain a line similar to:
|
||||
|
||||
```text
|
||||
Starting GREE discovery target=10.87.65.127:7000 local=10.87.65.27:<ephemeral> interface=eth1
|
||||
```
|
||||
|
||||
Use `scripts/network-debug.sh` for routing diagnostics.
|
||||
|
||||
|
||||
## Mixed GREE model generations
|
||||
|
||||
Version 0.3.7 can discover both AES-ECB and AES-GCM modules. In the Web UI choose **Discover -> Auto (V1 + V2)** and use 3-5 scan passes. If a family is still missing, repeat with V1-only and V2-only to see which protocol its Wi-Fi module answers with.
|
||||
|
||||
A single command/status timeout no longer immediately flips a device offline; offline requires three consecutive communication failures.
|
||||
|
||||
## Multi-NIC LXC and AF_NETLINK
|
||||
|
||||
When `GREE_CONTROLLER_GREE_INTERFACE` is set, the controller enumerates IPv4 addresses with Linux `getifaddrs()`. On Linux this requires a Netlink socket. The systemd sandbox therefore allows `AF_NETLINK` in addition to `AF_UNIX`, `AF_INET`, and `AF_INET6`.
|
||||
|
||||
If an older unit reports:
|
||||
|
||||
```text
|
||||
getifaddrs failed
|
||||
Address family not supported by protocol (os error 97)
|
||||
```
|
||||
|
||||
update the systemd unit or add `AF_NETLINK` to `RestrictAddressFamilies`, then run:
|
||||
|
||||
```bash
|
||||
systemctl daemon-reload
|
||||
systemctl restart gree-controller
|
||||
```
|
||||
|
||||
For a dedicated GREE NIC such as `eth1`, the expected startup/bind log should identify the IPv4 address of that interface instead of `0.0.0.0`.
|
||||
|
||||
### Legacy V1 devices discovered but not binding
|
||||
|
||||
Version 0.3.8 sends the GREE protocol `tcid` and inner `mac` identifiers in canonical lowercase hexadecimal. If an older `502cc6...` device is discovered on UDP/7000 but stays offline after bind timeouts, update to v0.3.8 before changing routing or firewall settings. With debug logging, `Sending GREE request` should show `wire_mac=502cc6...` in lowercase.
|
||||
|
||||
|
||||
## Home Assistant HTTPS with a self-signed certificate
|
||||
|
||||
The optional outbound HA sensor client validates TLS certificates by default. For a trusted local endpoint such as `https://10.87.65.2` that uses a self-signed, expired or hostname-mismatched certificate, enable **Settings -> Allow invalid/self-signed HTTPS certificate** and save. The same initial setting can be supplied as `HA_ALLOW_INVALID_TLS=true`.
|
||||
|
||||
This opt-in affects only controller -> Home Assistant sensor requests. It does not change the GREE UDP transport and it does not add HTTPS termination to the controller itself.
|
||||
@@ -1,196 +0,0 @@
|
||||
# GREE Controller project specification
|
||||
|
||||
## Product goal
|
||||
|
||||
Build an autonomous local GREE HVAC controller running primarily as a Rust service in a dedicated Linux/LXC environment. Home Assistant is optional: it can provide external sensor data and can consume controller devices through a thin custom integration, but it must not contain the core GREE protocol or heating logic.
|
||||
|
||||
## Architecture
|
||||
|
||||
```text
|
||||
Home Assistant / Web UI / REST clients
|
||||
|
|
||||
REST + WebSocket
|
||||
|
|
||||
GREE Controller (Rust)
|
||||
+--------------------------------+
|
||||
| Device/state manager |
|
||||
| GREE protocol UDP/AES |
|
||||
| Zone/heating engine |
|
||||
| Scheduler |
|
||||
| Automation engine |
|
||||
| SQLite |
|
||||
| Mobile-first web UI |
|
||||
+--------------------------------+
|
||||
|
|
||||
UDP/7000
|
||||
|
|
||||
GREE AC
|
||||
```
|
||||
|
||||
## Independence requirements
|
||||
|
||||
- GREE control must work when Home Assistant is stopped.
|
||||
- Local schedules and automations must continue without HA.
|
||||
- HA sensor failures must never remove basic access to the AC.
|
||||
- Device state is persisted by the controller and can be restored to clients after reconnect/restart.
|
||||
|
||||
## GREE protocol layer
|
||||
|
||||
The protocol implementation is isolated from application logic and covers:
|
||||
|
||||
- discovery,
|
||||
- packet encoding/decoding,
|
||||
- AES-128-ECB support,
|
||||
- AES-128-GCM envelope support,
|
||||
- bind/key acquisition,
|
||||
- status polling,
|
||||
- command transport,
|
||||
- reconnect/offline handling.
|
||||
|
||||
The rest of the application works with generic device state and commands rather than raw protocol packets.
|
||||
|
||||
## Device model
|
||||
|
||||
Each device stores:
|
||||
|
||||
- stable controller ID,
|
||||
- MAC/CID,
|
||||
- name,
|
||||
- IP/port,
|
||||
- protocol version,
|
||||
- model/firmware when available,
|
||||
- encryption key when bound,
|
||||
- enabled/simulated flags,
|
||||
- power and HVAC mode,
|
||||
- target/current/outdoor temperature,
|
||||
- fan, swing, quiet, turbo, light,
|
||||
- online/last-seen/error state.
|
||||
|
||||
## Smart thermostat, zones and schedules
|
||||
|
||||
The primary user model is a fast thermostat, not raw device automation. A global climate mode selects the season (`cool`, `heat`, `off`). Zones follow it by default and can optionally override Heat/Cool. The UI labels this as **Mode policy**: keep **Follow global mode** when the zone should inherit the mode selected globally in GREE Controller; the fixed Cooling/Heating policies are explicit overrides. House `off` is a **do not control** state for inherited zones: manual device operation is left untouched, while a zone explicitly switched to Heat/Cool can operate independently. Whole-house power on/off is a separate master state. Master Off is authoritative for zones and controller automations but does not modify the selected house thermostat mode.
|
||||
|
||||
During normal heating/cooling the controller minimizes unit power cycling. It keeps the indoor unit powered and uses **setpoint modulation**:
|
||||
|
||||
- when the zone requires conditioning, use the active target (optionally assisted slightly by outdoor weather),
|
||||
- when the zone is satisfied, move the device setpoint to the non-demand side of the room target so the inverter/compressor can stop naturally,
|
||||
- use hysteresis and a minimum adjustment interval to avoid command chatter,
|
||||
- optionally adjust fan speed based on room error and outdoor extremes; with Smart fan enabled, a satisfied zone uses Low fan together with the standby setpoint and requests Quiet mode in the same frame when the unit supports it. Unsupported Quiet commands automatically fall back to Low fan without breaking thermostat control.
|
||||
|
||||
Each zone has separate seasonal profile temperatures:
|
||||
|
||||
- Cooling: Comfort / Sleep / Away,
|
||||
- Heating: Comfort / Sleep / Away.
|
||||
|
||||
The zone can use the GREE internal sensor, its own Home Assistant room sensor, or a weighted combination. External room sensors are configured per zone; loss/discrepancy falls back safely to the GREE sensor.
|
||||
|
||||
Weekly schedules reference profiles instead of duplicating temperatures. Ready-made Family, Child room, Bedroom, Workday and Always-comfort templates create ordinary schedule rows that remain fully editable. A manual **Sleep**, Comfort, Away or custom-temperature override ends automatically at the next schedule boundary; if no future transition exists, it remains active until explicitly cleared. Whole-house preset actions apply the same temporary policy to every zone.
|
||||
|
||||
Automations remain available for advanced exceptions. Daily comfort should be implemented with zones/profiles/schedules so direct-device automation commands do not compete with the thermostat engine.
|
||||
|
||||
Climate groups are named collections of thermostat zones (for example Upstairs/Downstairs). Group commands can independently set power, Heat/Cool/house-follow mode and Auto/Comfort/Sleep/Away profile for only their member zones. Automation actions may target either a direct device or a climate group.
|
||||
|
||||
### Outdoor temperature assist
|
||||
|
||||
A configured Home Assistant outdoor-temperature entity is optional auxiliary context. It never replaces the room-control temperature. Under strong heat/cold the engine may slightly bias the active AC target and increase Smart Fan airflow. If HA is unavailable, the smart thermostat continues without outdoor assistance.
|
||||
|
||||
## Scheduler and automations
|
||||
|
||||
Schedules are weekly time windows and may cross midnight. Equal start/end times mean a 24-hour block for each selected weekday. Enabled schedules for one zone may not overlap. Schedules can select Comfort/Sleep/Away or a custom setpoint. Automations support time or temperature triggers and device commands with cooldown protection; a failed command also observes the cooldown instead of retrying every control cycle. They are intended for exceptions rather than the normal daily thermostat cycle.
|
||||
|
||||
The automation engine runs in Rust and does not require Home Assistant YAML automation logic.
|
||||
|
||||
## API
|
||||
|
||||
The controller exposes REST for configuration/commands and WebSocket for live state updates. The HA integration and web UI use the same controller API.
|
||||
|
||||
## Home Assistant direction 1: external sensor input
|
||||
|
||||
The Rust application can read a specifically configured HA entity using a Long-Lived Access Token. This input is optional and is not a prerequisite for GREE control.
|
||||
|
||||
## Home Assistant direction 2: native climate entities
|
||||
|
||||
A custom integration creates HA climate entities and translates HA service calls to controller API commands. It does not communicate with GREE directly.
|
||||
|
||||
For migrations from the default GREE integration, a mapping file can request an existing entity ID such as `climate.klima_salon`. The previous integration must release that ID before takeover.
|
||||
|
||||
## Web UI
|
||||
|
||||
Primary use is from a phone. Requirements:
|
||||
|
||||
- responsive mobile-first layout,
|
||||
- touch-friendly controls,
|
||||
- live state updates,
|
||||
- device, zone, schedule, automation, history and diagnostics screens,
|
||||
- JSON-based language packs from `lang/*.json`, with English as the required default/fallback and Polish included,
|
||||
- automatic language discovery at build time, so a new valid `<code>.json` file adds a language without JavaScript changes,
|
||||
- language stored in the `gree_controller_language` cookie,
|
||||
- system/light/dark appearance modes,
|
||||
- appearance stored in a cookie,
|
||||
- flat visual design without decorative shadows,
|
||||
- no letter-logo badge next to the application name.
|
||||
|
||||
## Storage
|
||||
|
||||
SQLite stores configuration, state, readings and events. PostgreSQL or other external database services are not required for the single-node deployment target.
|
||||
|
||||
## Deployment
|
||||
|
||||
Primary target:
|
||||
|
||||
```text
|
||||
LXC / Debian or Ubuntu
|
||||
/opt/gree-controller/gree-controller
|
||||
/etc/gree-controller.env
|
||||
/var/lib/gree-controller/gree-controller.db
|
||||
systemd: gree-controller.service
|
||||
```
|
||||
|
||||
A development script prepares dependencies/build/runtime configuration, and a separate installer creates the systemd deployment.
|
||||
|
||||
## Security
|
||||
|
||||
- optional administrator Bearer token for the controller Web/API,
|
||||
- separately generated, revocable Home Assistant client tokens stored only as SHA-256 hashes,
|
||||
- Home Assistant client tokens are restricted to device read/control endpoints,
|
||||
- secrets kept outside source control,
|
||||
- no direct public Internet exposure,
|
||||
- TLS delegated to a trusted reverse proxy/VPN when required,
|
||||
- local device keys and HA token protected in environment/database files,
|
||||
- invalid/self-signed HA HTTPS certificates are rejected by default; bypass is an explicit trusted-LAN opt-in.
|
||||
|
||||
|
||||
## Per-zone room sensors
|
||||
|
||||
A zone represents one room and normally maps one GREE indoor unit to one optional external room-temperature sensor. External sensors are not global. For example, Living Room can use `sensor.living_room_temperature` while Bedroom independently uses `sensor.bedroom_temperature`.
|
||||
|
||||
The zone controller supports `device`, `combined`, and `home_assistant` temperature strategies. Combined mode uses a configurable external-sensor weight (40% by default), validates the difference between sensors, and falls back to the GREE sensor when the external source is missing or outside the configured discrepancy limit. The local GREE measurement therefore remains available even when Home Assistant is offline.
|
||||
|
||||
|
||||
## Operational packaging conventions
|
||||
|
||||
- All operator-facing shell/Python utilities live under `scripts/`.
|
||||
- `scripts/install.sh` performs the first systemd/LXC installation.
|
||||
- `scripts/update.sh` performs an in-place update with a stopped SQLite backup, health check and automatic rollback.
|
||||
- `scripts/service.sh` provides common systemd operations.
|
||||
- Cargo's `build.rs` stays at the package root because Cargo requires that location.
|
||||
- Every SQLite statement and schema definition is centralized in `src/queries.rs`; database/domain code must not embed SQL strings elsewhere.
|
||||
|
||||
|
||||
## Web UI design system (v0.4.4)
|
||||
|
||||
The embedded UI uses the classic GREE Controller visual language: large rounded surfaces, circular thermostat controls, comfortable spacing, compact desktop navigation and mobile bottom navigation. Light, Dark and System themes use neutral surfaces with a restrained green accent.
|
||||
|
||||
The UI ships as a normal static `web/styles.css` file embedded into the Rust binary. There is no frontend package manager, CDN, or CSS build pipeline.
|
||||
|
||||
### Rich zone history
|
||||
|
||||
Zone history stores GREE temperature, optional Home Assistant room temperature, calculated control temperature, profile target, actual device setpoint, outdoor temperature assist, power, mode, fan speed, demand, active preset and control source. The UI can compare all zones on common temperature/target charts or inspect one zone in detail.
|
||||
|
||||
### History information architecture (v0.4.4)
|
||||
|
||||
History is not a single long page. It is split into URL-addressable views: Overview, Zones, GREE devices, HA sensors and Custom chart. Device history exists independently from zones, HA sensors have their own history stream, and zone history adds the thermostat/control context. A compatibility fallback maps existing GREE device readings into a zone timeline when the richer zone table is still empty.
|
||||
|
||||
The custom chart composer can mix GREE indoor/outdoor/target values, zone GREE/HA/control/target/device-setpoint/outdoor values, and HA temperature entities. Saved definitions persist in browser storage and a chart definition can be serialized into the `/history/custom?chart=...` URL for direct sharing/bookmarking.
|
||||
|
||||
Quick thermostat temperature nudges are optimistic in the browser and stored separately from the selected Comfort/Sleep/Away/Auto preset. Changing `+/-` therefore does not silently leave Auto mode.
|
||||
@@ -1,32 +0,0 @@
|
||||
# Reverse proxy
|
||||
|
||||
The web UI supports HTTPS/WSS and sub-path deployments. The server honors `GREE_CONTROLLER_BASE_PATH` and also understands `X-Forwarded-Prefix` when a proxy strips the prefix before forwarding.
|
||||
|
||||
## Root deployment
|
||||
|
||||
Proxy `/` to `http://127.0.0.1:8787` and forward WebSocket upgrade headers. No controller setting is required.
|
||||
|
||||
## Sub-path deployment
|
||||
|
||||
For a public path such as `/gree`, either:
|
||||
|
||||
- set `GREE_CONTROLLER_BASE_PATH=/gree` and proxy `/gree` to the controller without stripping the path, or
|
||||
- strip `/gree` in the proxy and send `X-Forwarded-Prefix: /gree`.
|
||||
|
||||
Static assets, language packs, browser routes, API requests, PWA scope and WebSocket URLs use the effective base path.
|
||||
|
||||
### nginx example (prefix stripped)
|
||||
|
||||
```nginx
|
||||
location /gree/ {
|
||||
proxy_pass http://127.0.0.1:8787/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Prefix /gree;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
}
|
||||
```
|
||||
|
||||
For an Internet-facing endpoint, add TLS and proxy authentication. If the application token is enabled, avoid access-log formats that record query strings because the browser WebSocket connection includes the token in its URL.
|
||||
@@ -1,31 +0,0 @@
|
||||
# Security notes
|
||||
|
||||
The controller is designed primarily for a trusted LAN. This release adds safe defaults without forcing authentication on existing installations.
|
||||
|
||||
## Implemented safeguards
|
||||
|
||||
- `GREE_CONTROLLER_APP_TOKEN=` remains supported. Authentication is optional and existing installations are compatible.
|
||||
- Permissive CORS was removed. The web UI and API are same-origin by default.
|
||||
- Responses include `X-Content-Type-Options`, `X-Frame-Options`, `Referrer-Policy`, `Content-Security-Policy` and a restrictive `Permissions-Policy`; API responses are marked `no-store`.
|
||||
- Runtime secrets for Home Assistant, InfluxDB and notifications are stored server-side and never returned to the browser. Empty secret fields keep the previously stored value.
|
||||
- Slack and Discord notification webhooks require HTTPS and are restricted to the official webhook hosts. Redirect following is disabled for these outbound webhook requests. Pushover uses its fixed official API endpoint.
|
||||
- API access tokens are stored hashed. Administrator token behavior is unchanged for backwards compatibility.
|
||||
- History/event API limits and SQLite indexes bound common read paths. History retention/compaction is configurable.
|
||||
|
||||
## Remaining risks / recommendations
|
||||
|
||||
1. With an empty application token, every client that can reach the controller HTTP port can operate the air conditioners and change configuration. Keep port 8787 on a trusted VLAN or put authentication in the reverse proxy.
|
||||
2. The WebSocket administrator token is still passed in its query string because browser WebSocket APIs cannot set an Authorization header. Avoid logging query strings at the proxy and prefer HTTPS/WSS when a token is enabled.
|
||||
3. The application does not terminate TLS. Use a reverse proxy or VPN for traffic crossing an untrusted network.
|
||||
4. Home Assistant `allow_invalid_tls` should be used only with a known local instance; keep it disabled otherwise.
|
||||
5. Configuration exports contain device keys and may contain integration secrets. Treat backup files as secrets.
|
||||
6. There is no per-client API rate limiter. For exposure beyond a trusted LAN, configure rate limiting at the reverse proxy.
|
||||
7. No CSRF token is used. Same-origin operation, removal of permissive CORS and bearer-token authentication reduce the risk, but an authenticated public deployment should also use proxy-level origin/access controls.
|
||||
|
||||
## Suggested reverse-proxy hardening
|
||||
|
||||
- TLS only; redirect HTTP to HTTPS.
|
||||
- Do not log URL query strings if administrator authentication is enabled.
|
||||
- Pass WebSocket upgrades for `/ws`.
|
||||
- Add authentication at the proxy when `GREE_CONTROLLER_APP_TOKEN` is empty and the service is reachable outside the trusted LAN.
|
||||
- Limit request body sizes and add basic request-rate limiting.
|
||||
Reference in New Issue
Block a user