diff --git a/BUILD_REPORT.md b/BUILD_REPORT.md
index 5835244..cdc3fe4 100644
--- a/BUILD_REPORT.md
+++ b/BUILD_REPORT.md
@@ -1,11 +1,16 @@
-# GREE Controller v0.5.4 - build and validation report
+# GREE Controller v0.5.5 - build and validation report
## Scope
-Version 0.5.4 builds on 0.5.3 with Home Assistant sensor-read fixes, full zone climate mode control, GREE capability discovery and native Sleep support during night mode.
+Version 0.5.5 builds on 0.5.4 with dedicated Night mode and Home Assistant/Sensors pages, compact unit-feature controls, and room-temperature refresh for disabled zones.
## Implemented changes
+- Night-mode settings moved out of application Settings into a dedicated **Night mode** page.
+- Home Assistant connection, sensor aliases and integration access tokens moved to a dedicated **Home Assistant / Sensors** page.
+- Settings now contains application/technical settings only.
+- Unit-feature controls on device cards are smaller, centered and visually aligned with the other compact device controls.
+- Disabled thermostat zones continue refreshing and showing room temperature while control commands remain disabled.
- Home Assistant sensor aliases are now presentation-only end-to-end: backend reads resolve aliases back to the original `entity_id`, settings are canonicalized, and zone/outdoor polling records the real entity ID.
- Outdoor temperature now falls back to the median outdoor reading from online GREE units when the configured Home Assistant outdoor sensor is unavailable.
- GREE optional capabilities are discovered from status properties (`Lig`, `Quiet`, `Tur`, `Air`, `Blo`, `Health`, `SwhSlp`) and persisted with each device.
diff --git a/Cargo.lock b/Cargo.lock
index e0eb817..85b96e0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -633,7 +633,7 @@ dependencies = [
[[package]]
name = "gree-controller"
-version = "0.5.4"
+version = "0.5.5"
dependencies = [
"aes",
"aes-gcm",
diff --git a/Cargo.toml b/Cargo.toml
index 763d324..7d46a4e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "gree-controller"
-version = "0.5.4"
+version = "0.5.5"
edition = "2021"
authors = ["GREE Controller contributors"]
description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support"
diff --git a/FILE_MANIFEST.sha256 b/FILE_MANIFEST.sha256
index 70dd9f6..686fa92 100644
--- a/FILE_MANIFEST.sha256
+++ b/FILE_MANIFEST.sha256
@@ -1,17 +1,17 @@
e027a3bf37a7917e249ebffb980d43b5e18c70e5931113271975cbeda81a88bd ./.env.example
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
-7e0bbddcccea0726bdbf7c93a0fa3a892c1d60279b6da8d992a55a7183522b01 ./BUILD_REPORT.md
-ce1d4a2d05be90ffecc39af85cdf5383b08484c3a27482e02f387030075db17e ./Cargo.lock
-d9e0c071ee11f26bd8e804e6cff976339982ebca45dad2f03614e147c35df327 ./Cargo.toml
+52c2c492893ce42e68dac763533a5070170c21b18d67b302a4e1380a4d4cc4ab ./BUILD_REPORT.md
+4202057467ffdc3f53ef250c3e7852a929be788bb0af03fbd2366a57ce42b79e ./Cargo.lock
+9edc867d716d9d8ce2c54cdf17e16628f9c2b338ee36f88e0bb0fcb4f7884b57 ./Cargo.toml
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
-e7b879527c9d1eb7d6bbd054813e709026777e4a79e62b4c8912d2d5aa5e7ff3 ./README.md
+44675b0d5d9e6e89dd0bae8eff3ab76a190a3b1bdd6507e7402957bbd92cac36 ./README.md
a4fa9bfee9735ed8ed95ea31456e0cce503d82502ae3f550108ffca51b0f0c3d ./build.rs
-f00f7475d690694c837e29a618c7737199515bd7a64a5a3be5f44291fe73df0c ./docs/API.md
+674f8cf1ab9f1a49188e20b8e3977f1e2b7e9b8ef975315266730c44a55bbb48 ./docs/API.md
234dd200e380a13ecd3e61b4ea455f6f08d64ce89382077dee80684acadb9703 ./docs/HOME_ASSISTANT_MIGRATION.md
7a88d6e76fda21e5d34ab351e26bc10dc1f8f7b3055505aefad1df7c56d65ae4 ./docs/LOCALIZATION.md
10a0722e1100fb4a05e3067daeb67dc47b0c0a096b43b1cbf2bf002967ce7d98 ./docs/LXC.md
47e18e6b1723f1f6eb2516be6d83bbebd31b8155d9d3cdfccc0973177f3d8441 ./docs/PROJECT_SPEC.md
-cf889651576a0860c3dc383c255aa011306f82d6287533617c523bcc41caca21 ./home-assistant/README.md
+925ffa324b1b2cfad7ca40354e8255548f70627f95c4bb345b957d3f7e53694c ./home-assistant/README.md
f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./home-assistant/custom_components/gree_controller/__init__.py
b8e7c0dd722bfac1d1d8d5c2a4b5ff6b2d6fa89525b9ff5c121ee1d09623a7fd ./home-assistant/custom_components/gree_controller/api.py
b0314469ddb7c69ee4a96c677815af30cb97713e93911a05597f2fdc3d10f489 ./home-assistant/custom_components/gree_controller/climate.py
@@ -19,7 +19,7 @@ b0314469ddb7c69ee4a96c677815af30cb97713e93911a05597f2fdc3d10f489 ./home-assista
071f721b75af2ed68812c9be3a62b7ae63771e56e567a569f59ca976f8ff42f1 ./home-assistant/custom_components/gree_controller/const.py
8dd51322798cad28d4d19938fe459aa2a4d3b64b075532149f3c8b62049a6c8b ./home-assistant/custom_components/gree_controller/coordinator.py
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./home-assistant/custom_components/gree_controller/entity_map.py
-b3ac1d74c2f8decdc0dcb9689d3a62bea803a9533164929c09d97922c08c605a ./home-assistant/custom_components/gree_controller/manifest.json
+f79cc14c65131fa86a5bf41d55f49b60a3aa71a6d15de98027de830e3b11b2a1 ./home-assistant/custom_components/gree_controller/manifest.json
d0206766d76f70ea1c75a618e41bf1e8e8c0429f42ee97f40daac1ea12f16658 ./home-assistant/custom_components/gree_controller/number.py
5c914c2faa18a9cb9eb442dc111c9416f89a630578f820beb021d5381aa1b2d0 ./home-assistant/custom_components/gree_controller/sensor.py
7c23374d1c82e4b361089386ff89265322b80def0f4db9d3fd2c039867033105 ./home-assistant/custom_components/gree_controller/switch.py
@@ -27,8 +27,8 @@ d0206766d76f70ea1c75a618e41bf1e8e8c0429f42ee97f40daac1ea12f16658 ./home-assista
13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./home-assistant/custom_components/gree_controller/translations/pl.json
4513070521d3dda0efb0d974a86ba674494cfb2b66fe9e5cac5b1b0430dede97 ./home-assistant/generated/gree_controller_entities.example.json
253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md
-e824a016cff1fa0411ab456b74f3cfe597546072c9e334ef92de69f86a868f48 ./lang/en.json
-93d26be77deb820dbce29484db8f2ef6c56b5b05a451c4e9d57013e43aa88395 ./lang/pl.json
+eb5370fbee1a8edc11a536ff0e68dba2152767734feb2976fef3cb7cc8c885f4 ./lang/en.json
+9e4f43dd809f2d92aca8ce6813e843dbf7e2f38adcfd9cdae584a94e22197fa3 ./lang/pl.json
028e1f16e9fbaed57cadb88eff04e65b4bd67722c50b4d6b1fb525f5a2f39abf ./make_zip.py
bb89bac237e750e9b1bf73761d7df97a6b81853091615878c03f13d7b6399aa7 ./scripts/README.md
3640e34a1ed5a93be3e96610848b16b8e748d5ca95975ac7e95d38cbf32695a8 ./scripts/common.sh
@@ -44,7 +44,7 @@ b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/upda
ca63498714f3e154fd98c0c2157ab355bf36fc2208d7b3f82c201e153749fb04 ./src/api.rs
31ef3ddbc096e580e9212486683e4db86998322ee87190c61b0cab5ae6bc8fc9 ./src/config.rs
a89bc49e359715109149130a10ac60abd26bfd2bc18c5ee5142e01696d9f9cdd ./src/db.rs
-c2ac8e8b4acc2bd15e9c41af5a003b7ced4424346617946e387ec57ce9cb2583 ./src/engine.rs
+9dfea316b39da6ded85cb9c7ec6f6a61e0cd9a51f40469145782d5766c9cf7a4 ./src/engine.rs
ae3b496749a3fd723b243d9bea92e5d76249f52814c80359ad9bac53abacb074 ./src/error.rs
081f6909e95839c7da8c40b866af9de237e0540f3e65e1ce739ce70a6fa94846 ./src/home_assistant.rs
190b0a33431539676e5dd7796698077f16c179d42eae4501ca96a91bf797cbf8 ./src/influxdb.rs
@@ -56,9 +56,9 @@ a910bd9432a393740c0f6fab52bfcb551f0ea756718d66d290fd2610767cf07c ./src/protocol
d1cba5e55c77d44c75a9c9897ae76c327fd96bdf9c01ad27e34322b689348487 ./src/queries.rs
e3c02b232bd9d632ca1d3b6ad69a7cc61dc2e51954765d9e963d713d135f7dca ./src/state.rs
b92a6cb158b494fe145b43c7641e65f6fafff47201d7d76edbec2cfd8b94835c ./systemd/gree-controller.service
-e82ff244991b968a3dd69f117ce9feeeee6e21c00a257d1d42273283b2d7ff99 ./web/app.js
+17342e3aa40a55285f5d056502b232e6aeed41a64ff3e1fdf94c0d8278385ffe ./web/app.js
e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg
-3a7b734e25955f148c5ef0518f6b4abbb04c0a1e660cd58270292fba3bee149f ./web/index.html
+1474d31bf8266f6b6dc2dc47225644394259dc6e0afc8e09f0eaddfa93db1d82 ./web/index.html
c0e628423a82c5037b6d650aad5e8befe30945492c8cb0a5d94433db7b58c77b ./web/manifest.webmanifest
-2d20ba68af2b67b1c57104f0fbb67a0144e2f6aeb12ed8fc9b616a32baa89a3e ./web/styles.css
-f75381d719eb299730a85406eb86a58f56fd2ec9bd566bcb3cb84ae6a2d38f87 ./web/sw.js
+b8a3cecbde31f9aa4ed3afb5755c62cf98ad90a12faf0a616835170ee889e252 ./web/styles.css
+f8bda0083c138828a037469d3db189559190d4b893bcff764a6f9bfd9030b265 ./web/sw.js
diff --git a/README.md b/README.md
index 5d6ec6b..82b3ac3 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
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.5.4**.
+Current version: **0.5.5**.
## Highlights
@@ -46,7 +46,7 @@ See [`BUILD_REPORT.md`](BUILD_REPORT.md) for package validation details and [`do
On Debian, Ubuntu or an LXC container:
```bash
-unzip gree-controller-v0.5.4.zip
+unzip gree-controller-v0.5.5.zip
cd gree-controller
chmod +x scripts/*.sh
./scripts/dev.sh
@@ -177,6 +177,8 @@ Use `--skip-tests` with `install.sh` or `update.sh` only when you explicitly wan
Settings changed from the web panel are stored in SQLite. Explicit history/debug/Influx environment variables override their persisted values at process startup. Supplying an Influx URL enables the archive unless `GREE_CONTROLLER_INFLUX_ENABLED=false` is explicitly set. `GREE_CONTROLLER_APP_TOKEN` is loaded at process startup.
+Web UI organization: **Settings** contains controller/application and technical storage/debug options, while **Night mode** and **Home Assistant / Sensors** are separate pages under More. Disabled zones continue reporting room temperature even though thermostat control is stopped.
+
## Climate history
History is collected independently for physical GREE devices, control zones, and configured Home Assistant temperature sensors. Device samples continue to use the long-standing `readings` table, so upgrading does not require waiting for a new zone-history table to fill. When rich `zone_readings` are not available yet, the API automatically reconstructs a compatible zone timeline from existing device readings.
@@ -234,9 +236,9 @@ 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/control-plan/zone-control API; they cannot change controller settings or manage other tokens.
+For the HA client connection, open **More -> Home Assistant / Sensors** 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/control-plan/zone-control API; they cannot change controller settings or manage other tokens.
-The outbound HA sensor client also supports local HTTPS endpoints such as `https://10.87.65.2`. If the server uses a self-signed, expired or hostname-mismatched certificate, enable **Settings -> Allow invalid/self-signed HTTPS certificate**. This disables certificate/hostname validation only for the controller's outbound Home Assistant sensor client and should only be used on a trusted LAN.
+The outbound HA sensor client also supports local HTTPS endpoints such as `https://192.168.50.25`. If the server uses a self-signed, expired or hostname-mismatched certificate, enable **Home Assistant / Sensors -> Allow invalid/self-signed HTTPS certificate**. This disables certificate/hostname validation only for the controller's outbound Home Assistant sensor client and should only be used on a trusted LAN.
The second option is designed to replace the built-in/default GREE integration without changing automation/dashboard references.
diff --git a/docs/API.md b/docs/API.md
index 6e91453..414eb29 100644
--- a/docs/API.md
+++ b/docs/API.md
@@ -10,7 +10,7 @@ BASE='http://127.0.0.1:8787'
## Home Assistant access tokens
-Create and revoke integration tokens from the controller Web UI under **Settings -> Home Assistant integration access**. The clear-text secret is returned only once and the SQLite database stores only its SHA-256 hash.
+Create and revoke integration tokens from the controller Web UI under **More -> Home Assistant / Sensors**. The clear-text secret is returned only once and the SQLite database stores only its SHA-256 hash.
Administrator endpoints:
diff --git a/home-assistant/README.md b/home-assistant/README.md
index 0722e3a..02c90a1 100644
--- a/home-assistant/README.md
+++ b/home-assistant/README.md
@@ -27,7 +27,7 @@ Copy the directory into your HA configuration:
/config/custom_components/gree_controller/
```
-Before adding the integration, open the standalone controller Web UI and go to **Settings -> Home Assistant integration access -> Create new token**. Copy the generated secret; it is shown only once.
+Before adding the integration, open the standalone controller Web UI and go to **More -> Home Assistant / Sensors -> Create new token**. Copy the generated secret; it is shown only once.
Restart Home Assistant, then open **Settings -> Devices & services -> Add integration -> GREE Controller** and enter only:
diff --git a/home-assistant/custom_components/gree_controller/manifest.json b/home-assistant/custom_components/gree_controller/manifest.json
index 123b3c3..de8d109 100644
--- a/home-assistant/custom_components/gree_controller/manifest.json
+++ b/home-assistant/custom_components/gree_controller/manifest.json
@@ -1,7 +1,7 @@
{
"domain": "gree_controller",
"name": "GREE Controller",
- "version": "0.5.4",
+ "version": "0.5.5",
"config_flow": true,
"integration_type": "hub",
"iot_class": "local_polling",
diff --git a/lang/en.json b/lang/en.json
index 5aaaf5b..a094df6 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -490,6 +490,14 @@
"devices.xfan": "X-FAN",
"devices.health": "Health",
"devices.air": "Air",
- "devices.sleep": "Sleep"
+ "devices.sleep": "Sleep",
+ "nav.nightMode": "Night mode",
+ "nav.homeAssistant": "Home Assistant / Sensors",
+ "night.eyebrow": "Comfort",
+ "night.description": "Configure quieter thermostat behavior for sleeping hours without mixing it with application settings.",
+ "night.saveHint": "Save night-mode changes.",
+ "homeAssistant.eyebrow": "Integration",
+ "homeAssistant.description": "Connection, temperature sensors, friendly aliases and access tokens for the Home Assistant integration.",
+ "homeAssistant.saveHint": "Save Home Assistant and sensor changes."
}
}
diff --git a/lang/pl.json b/lang/pl.json
index c41ae9a..284fe5c 100644
--- a/lang/pl.json
+++ b/lang/pl.json
@@ -490,6 +490,14 @@
"devices.xfan": "X-FAN",
"devices.health": "Health",
"devices.air": "Air",
- "devices.sleep": "Sleep"
+ "devices.sleep": "Sleep",
+ "nav.nightMode": "Tryb nocny",
+ "nav.homeAssistant": "Home Assistant / Czujniki",
+ "night.eyebrow": "Komfort",
+ "night.description": "Ustaw cichszą pracę termostatu w godzinach nocnych bez mieszania tych opcji z ustawieniami aplikacji.",
+ "night.saveHint": "Zapisz zmiany trybu nocnego.",
+ "homeAssistant.eyebrow": "Integracja",
+ "homeAssistant.description": "Połączenie, czujniki temperatury, przyjazne aliasy i tokeny dostępu dla integracji Home Assistant.",
+ "homeAssistant.saveHint": "Zapisz ustawienia Home Assistant i czujników."
}
}
diff --git a/src/engine.rs b/src/engine.rs
index abf8a92..3a2b044 100644
--- a/src/engine.rs
+++ b/src/engine.rs
@@ -354,8 +354,6 @@ async fn control_zones(state: &AppState) -> Result<()> {
let night_active = night_mode_active(&settings.night_mode, Local::now().time());
for mut zone in state.db.list_zones()? {
- if !zone.enabled { continue; }
-
if zone.manual_override_until.map(|until| until <= Utc::now()).unwrap_or(false) {
zone.manual_preset = None;
zone.manual_setpoint = None;
@@ -419,6 +417,17 @@ async fn control_zones(state: &AppState) -> Result<()> {
}));
}
+ // Disabled zones still refresh and publish their room temperature. Disabling a
+ // thermostat stops control actions, but it must not make the room sensor disappear
+ // from the dashboard or zone view.
+ if !zone.enabled {
+ zone.demand = false;
+ record_zone_history(state, &zone, outdoor_temperature, settings.poll_interval_seconds);
+ state.db.save_zone(&zone)?;
+ state.broadcast("zone.updated", serde_json::to_value(&zone)?);
+ continue;
+ }
+
// Global Off is the only normal path that intentionally powers units down.
if effective_mode == "off" {
zone.active_preset = "off".into();
diff --git a/web/app.js b/web/app.js
index 19b9756..cfd4900 100644
--- a/web/app.js
+++ b/web/app.js
@@ -213,6 +213,8 @@ function renderAll() {
renderAccessTokens();
fillSelects();
renderSettings();
+ renderNightSettings();
+ renderHomeAssistantSettings();
renderDebugOverlay();
}
@@ -565,6 +567,7 @@ function zoneCard(zone, detailed = true) {
const sensorDetails = zone.sensor_source === 'device'
? `${tr('zones.greeTemp')}: ${fmtTemp(zone.device_temperature ?? device?.current_temperature)}`
: `${tr('zones.greeTemp')}: ${fmtTemp(zone.device_temperature)} · ${tr('zones.externalTemp')}: ${fmtTemp(zone.external_temperature)} · ${tr('zones.usedSource')}: ${zoneControlSourceLabel(zone.control_temperature_source)}`;
+ const roomTemperature = zone.current_temperature ?? zone.device_temperature ?? device?.current_temperature;
const target = Number(zone.effective_setpoint ?? zone.setpoint);
const manual = zone.manual_preset || 'auto';
const mode = zone.inherit_house_mode ? 'house' : zone.mode;
@@ -574,7 +577,7 @@ function zoneCard(zone, detailed = true) {
: ``;
return `
Configure quieter thermostat behavior for sleeping hours without mixing it with application settings.
+
+
+
+
+
Integration
Home Assistant / Sensors
+
Connection, temperature sensors, friendly aliases and access tokens for the Home Assistant integration.
+
+
+
System
Settings
-
-
Night mode
During selected hours the thermostat limits fan speed and can request Quiet on supported units.
-
-
-
-
-
-
-
-
-
+
Metrics and logs
SQLite keeps recent data locally and compacts older samples to the resolution used by charts.
@@ -204,29 +244,9 @@
-
-
Home Assistant sensor input
Optional. Used when a room zone reads an external Home Assistant temperature sensor.
-
-
-
-
-
-
-
-
Use only for a trusted local Home Assistant server, for example https://192.168.50.25.
-
-
Sensor aliasesFriendly names are used in charts and selectors; the original entity_id remains unchanged.
-
-
-
-
-
-
+
-
-
Home Assistant integration access
Create a controller token and paste it into the GREE Controller integration in Home Assistant.
-
-
+
Configuration backup
Export/import application configuration. Exported files can contain GREE device keys plus Home Assistant and InfluxDB secrets; metrics and API access tokens are not included.