v0.8.5
This commit is contained in:
+18
-42
@@ -1,53 +1,29 @@
|
|||||||
# GREE Controller v0.8.4 - build and validation report
|
# GREE Controller v0.8.5 - build and validation report
|
||||||
|
|
||||||
## 0.8.4 Scheduled Temporary Quick Thermostat start and ownership hardening
|
## 0.8.5 Temporary temperature-condition activation fix
|
||||||
|
|
||||||
Source baseline: v0.8.3.
|
Source baseline: v0.8.4.
|
||||||
|
|
||||||
### Changes
|
### Fix
|
||||||
|
|
||||||
- Added independent Temporary Quick Thermostat start rules: immediately, after a delay, or at an absolute date/time.
|
- Corrected Temporary Quick Thermostat temperature-condition activation detection.
|
||||||
- Delayed sessions are persisted without taking local thermostat ownership before `started_at`; the controller wakes at the scheduled start and activates the saved target then.
|
- `activated_at` now correctly marks a session as active for `temperature_reached` and `temperature_stable` evaluation.
|
||||||
- Duration, absolute finish validation, safety timeout and next-schedule-boundary calculations are anchored to the effective start time.
|
- Existing `local_thermostat_power == true` remains a compatibility/recovery marker for sessions persisted by earlier releases.
|
||||||
- Added pending-session countdown/status to the Quick Thermostat button and modal; after activation the same control switches to the existing finish countdown/status.
|
- Future delayed sessions still cannot evaluate or complete their temperature condition before `started_at`.
|
||||||
- Active Temporary Quick Thermostat targets keep priority over schedule transitions and schedule edits.
|
- The change directly addresses the v0.8.4 updater failures:
|
||||||
- Direct device automations remain blocked by local thermostat ownership while the temporary session is active; group climate mode/preset actions are deferred for an actively owned zone, while group power state may change underneath and becomes effective after hand-back.
|
- `temporary_stable_condition_requires_continuous_hold_time`
|
||||||
- Before a delayed start, normal schedule/automation ownership is unchanged unless another pre-existing local/manual override already owns the zone.
|
- `temporary_stable_condition_resets_when_temperature_leaves_range`
|
||||||
- Local Quick Thermostat ON can use the zone's last Heat/Cool mode when inherited house climate mode is `off`; whole-house master power remains authoritative.
|
|
||||||
- Cancelling a pending session does not clear unrelated manual quick-control state.
|
|
||||||
- Added Rust regression tests for delayed-session ownership, pre-start temperature conditions, schedule target priority and local Quick Thermostat operation with inherited house mode `off`.
|
|
||||||
- Bumped controller and Home Assistant integration version to 0.8.4 and rotated the PWA service-worker cache key.
|
|
||||||
|
|
||||||
### Ownership/priority scenarios reviewed
|
|
||||||
|
|
||||||
| Scenario | Expected result |
|
|
||||||
| --- | --- |
|
|
||||||
| Delayed session before start | Normal schedule and automations continue; pending session owns nothing yet. |
|
|
||||||
| Start time reached | Session acquires local thermostat ownership, enables the zone if needed and applies its saved target. |
|
|
||||||
| Schedule transitions while active | Schedule may advance internally, but `manual_setpoint` from Temporary Quick Thermostat remains effective. |
|
|
||||||
| Schedule edited while active | Generic schedule-boundary override timer is not re-armed, so the temporary target is not cleared. |
|
|
||||||
| Direct-device automation while active | Suppressed by local thermostat ownership. |
|
|
||||||
| Group mode/preset automation while active | Climate change is deferred for the owned zone; it cannot clear/change the temporary target. |
|
|
||||||
| Group power automation while active | Group gate can change underneath, but local temporary ownership keeps the zone running; the gate applies after hand-back. |
|
|
||||||
| Temporary finish | Local ownership is cleared and the currently applicable schedule/group/house state is recalculated. |
|
|
||||||
| Session started from disabled zone | Zone is temporarily enabled, then restored to disabled and its unit is stopped after hand-back. |
|
|
||||||
|
|
||||||
### Validation executed in this environment
|
### Validation executed in this environment
|
||||||
|
|
||||||
- `node --check web/app.js`
|
- JavaScript syntax checks for `web/app.js`, `web/theme-init.js`, `web/sw.js`
|
||||||
- `node --check web/theme-init.js`
|
- JSON parsing for project JSON files
|
||||||
- `node --check web/sw.js`
|
- Python syntax compilation for Python sources
|
||||||
- parsed all JSON files, including PL/EN language packs and Home Assistant manifest
|
- shell syntax checks for `scripts/*.sh`
|
||||||
- checked duplicate HTML IDs
|
- version consistency checks
|
||||||
- checked that newly referenced PL/EN translation keys exist
|
|
||||||
- `python3 -m compileall -q home-assistant scripts make_zip.py`
|
|
||||||
- `bash -n scripts/*.sh`
|
|
||||||
- checked version consistency across Cargo.toml, Cargo.lock, README and Home Assistant manifest
|
|
||||||
- regenerated and verified `FILE_MANIFEST.sha256`
|
- regenerated and verified `FILE_MANIFEST.sha256`
|
||||||
- tested the final ZIP with `unzip -t`
|
- final ZIP integrity check
|
||||||
|
|
||||||
### Rust toolchain note
|
### Rust toolchain note
|
||||||
|
|
||||||
This execution environment does not contain `cargo`, `rustc` or `rustfmt`, so the Rust regression tests and full compilation cannot be executed here. The tests are included in `src/engine.rs`, and the installer/updater still runs `cargo test --all-targets` before replacing the running service.
|
This environment does not contain `cargo`, `rustc` or `rustfmt`, so Rust tests cannot be executed here. The supplied deployment log confirms v0.8.4 compiled and 46/48 tests passed; this hotfix changes the activation predicate responsible for the two failures. `scripts/update.sh` will run the full Rust test suite before replacing the service.
|
||||||
|
|
||||||
---
|
|
||||||
|
|||||||
Generated
+1
-1
@@ -633,7 +633,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gree-controller"
|
name = "gree-controller"
|
||||||
version = "0.8.4"
|
version = "0.8.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gree-controller"
|
name = "gree-controller"
|
||||||
version = "0.8.4"
|
version = "0.8.5"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["GREE Controller contributors"]
|
authors = ["GREE Controller contributors"]
|
||||||
description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support"
|
description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
d67af429e4da9ce08e9d2f2a8472849ffbd70d135b1c5da535a076026794d04c ./.env.example
|
d67af429e4da9ce08e9d2f2a8472849ffbd70d135b1c5da535a076026794d04c ./.env.example
|
||||||
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
|
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
|
||||||
23209d6e3c3ba681d5e414aa85840b019c5e4c4ac3fe86afab8590eccbfb8315 ./BUILD_REPORT.md
|
04ab15fbace991a367ab08543d17cd7c8f3aed06465e905f179ac6ca47b58359 ./BUILD_REPORT.md
|
||||||
450f637f06e0ca0e516bd144c3000ad707db51a343a095994bfc657ffcdf130a ./Cargo.lock
|
bd7d9b714ad9096d7ecde66df3b97ae9a73c4caddcbbbd338e4fd3af5c09dd03 ./Cargo.lock
|
||||||
a9d33234e320683b0d6413dfa9098435d17213b8058639a849cc64a5f0ca25fa ./Cargo.toml
|
310dd2cd0f8be29268d31c4b969ef01e956265614df1c899f3291ed639452bc7 ./Cargo.toml
|
||||||
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
||||||
87c67cc28db5426d89cdbd4369a05016f0b058331273688bc52e286088b1b5dc ./README.md
|
ff399e8c70e10e8622ad08beba55c253fa5eb9627719aa2023147a91139b74b4 ./README.md
|
||||||
91c826e2f8c974bdb7b15e01e9b20487f06ff887247ecd9600f1263c11a61b96 ./build.rs
|
91c826e2f8c974bdb7b15e01e9b20487f06ff887247ecd9600f1263c11a61b96 ./build.rs
|
||||||
d458a3b1ed381c885d7c4b7e38f306f3e66838d27480551436f1e340995ea6e2 ./docs/API.md
|
d458a3b1ed381c885d7c4b7e38f306f3e66838d27480551436f1e340995ea6e2 ./docs/API.md
|
||||||
234dd200e380a13ecd3e61b4ea455f6f08d64ce89382077dee80684acadb9703 ./docs/HOME_ASSISTANT_MIGRATION.md
|
234dd200e380a13ecd3e61b4ea455f6f08d64ce89382077dee80684acadb9703 ./docs/HOME_ASSISTANT_MIGRATION.md
|
||||||
@@ -24,7 +24,7 @@ ab08fbe40e9bb48ebcbfff98760aaa0c9434b61b705aaaadea0c09c255d99b0e ./home-assista
|
|||||||
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./home-assistant/custom_components/gree_controller/entity_map.py
|
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./home-assistant/custom_components/gree_controller/entity_map.py
|
||||||
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./home-assistant/custom_components/gree_controller/icon.png
|
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./home-assistant/custom_components/gree_controller/icon.png
|
||||||
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./home-assistant/custom_components/gree_controller/logo.png
|
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./home-assistant/custom_components/gree_controller/logo.png
|
||||||
59c5239f76835e0a1c8326b2525f4cc1528a1a3021b7e197a216308e2b1421e5 ./home-assistant/custom_components/gree_controller/manifest.json
|
f3b837e006c0696928fa0140b42e0d69d44bbe4083460db71a62b4629f42ba84 ./home-assistant/custom_components/gree_controller/manifest.json
|
||||||
38d659d0273c0d1428679e44574a2666c605d1b3796d323b626baa40560788cf ./home-assistant/custom_components/gree_controller/number.py
|
38d659d0273c0d1428679e44574a2666c605d1b3796d323b626baa40560788cf ./home-assistant/custom_components/gree_controller/number.py
|
||||||
39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./home-assistant/custom_components/gree_controller/select.py
|
39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./home-assistant/custom_components/gree_controller/select.py
|
||||||
1cae12876eb81085910907cf1fcf340a18dcba4f8c967ef222c9496325057849 ./home-assistant/custom_components/gree_controller/sensor.py
|
1cae12876eb81085910907cf1fcf340a18dcba4f8c967ef222c9496325057849 ./home-assistant/custom_components/gree_controller/sensor.py
|
||||||
@@ -50,7 +50,7 @@ b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/upda
|
|||||||
e1153953e3217380ed4f4559e85236d3e26d6dd6168683a721f053252426c454 ./src/api.rs
|
e1153953e3217380ed4f4559e85236d3e26d6dd6168683a721f053252426c454 ./src/api.rs
|
||||||
9040e8cb6647c76a875148b7591abcccfe4e2d4708ef462a1e5d25dd4ccac911 ./src/config.rs
|
9040e8cb6647c76a875148b7591abcccfe4e2d4708ef462a1e5d25dd4ccac911 ./src/config.rs
|
||||||
5dfda2f4dc540c502885b0cd7017dc77768684588acf528f01d1fd88f1af4aec ./src/db.rs
|
5dfda2f4dc540c502885b0cd7017dc77768684588acf528f01d1fd88f1af4aec ./src/db.rs
|
||||||
ffb8abf8e7d092c01e75940744a747debcb2ecc35d417f73bb4c094842ed1607 ./src/engine.rs
|
da12b76d1de2f6394829720805c0a82f88cbda05d7e32e55915d18a648b6685f ./src/engine.rs
|
||||||
4b271b6fc365b1078c01d6178eb563841b2ecaed5d8639196f58e1312d2236fe ./src/error.rs
|
4b271b6fc365b1078c01d6178eb563841b2ecaed5d8639196f58e1312d2236fe ./src/error.rs
|
||||||
c6ff66da9ad08506f839ec56a869ead3abc824b5311e0ea9244517d11f7f4207 ./src/home_assistant.rs
|
c6ff66da9ad08506f839ec56a869ead3abc824b5311e0ea9244517d11f7f4207 ./src/home_assistant.rs
|
||||||
190b0a33431539676e5dd7796698077f16c179d42eae4501ca96a91bf797cbf8 ./src/influxdb.rs
|
190b0a33431539676e5dd7796698077f16c179d42eae4501ca96a91bf797cbf8 ./src/influxdb.rs
|
||||||
@@ -68,5 +68,5 @@ e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.
|
|||||||
ee64c273b334c2d0f9747408b6142a8d506021cbf2107178c2213ca4e4a17c8c ./web/index.html
|
ee64c273b334c2d0f9747408b6142a8d506021cbf2107178c2213ca4e4a17c8c ./web/index.html
|
||||||
fd26156e9f1d6713d3def564ad000553d9a16a24376059701db2ee762c99ee6c ./web/manifest.webmanifest
|
fd26156e9f1d6713d3def564ad000553d9a16a24376059701db2ee762c99ee6c ./web/manifest.webmanifest
|
||||||
6aa06f52e4c6391a43016a6a585b7422e3de319744db40a9b233beb27e57412d ./web/styles.css
|
6aa06f52e4c6391a43016a6a585b7422e3de319744db40a9b233beb27e57412d ./web/styles.css
|
||||||
c93bacaf417610558881bdfd0a3eae324c5d783a0a34c1b7527a145abb469ce1 ./web/sw.js
|
bd2fe227d905b0cd5fb00ca9e92fb94c0d6c4402a9ae3ee51c68f6c1848fb67b ./web/sw.js
|
||||||
d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js
|
d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js
|
||||||
|
|||||||
@@ -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.
|
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.8.4**.
|
Current version: **0.8.5**.
|
||||||
|
|
||||||
## Highlights
|
## Highlights
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ See [`BUILD_REPORT.md`](BUILD_REPORT.md) for package validation details and [`do
|
|||||||
On Debian, Ubuntu or an LXC container:
|
On Debian, Ubuntu or an LXC container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
unzip gree-controller-v0.8.4.zip
|
unzip gree-controller-v0.8.5.zip
|
||||||
cd gree-controller
|
cd gree-controller
|
||||||
chmod +x scripts/*.sh
|
chmod +x scripts/*.sh
|
||||||
./scripts/dev.sh
|
./scripts/dev.sh
|
||||||
@@ -480,6 +480,13 @@ Zones now use setpoint modulation, global seasonal house mode, cooling/heating C
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## 0.8.5 Temporary temperature-condition activation fix
|
||||||
|
|
||||||
|
- Fixed `temperature_stable` / `temperature_reached` evaluation for sessions already marked active through `activated_at`.
|
||||||
|
- Kept delayed sessions protected from evaluating or completing before their scheduled start.
|
||||||
|
- Preserved migration compatibility with active v0.8.3 sessions by also accepting existing local Quick Thermostat ownership as an activation marker.
|
||||||
|
- Fixes the two v0.8.4 regression tests that stopped `scripts/update.sh` before service replacement.
|
||||||
|
|
||||||
## 0.8.4 Scheduled Temporary Quick Thermostat start and ownership hardening
|
## 0.8.4 Scheduled Temporary Quick Thermostat start and ownership hardening
|
||||||
|
|
||||||
- Temporary Quick Thermostat can start immediately, after a configurable delay, or at a specific local date/time.
|
- Temporary Quick Thermostat can start immediately, after a configurable delay, or at a specific local date/time.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"domain": "gree_controller",
|
"domain": "gree_controller",
|
||||||
"name": "GREE Controller",
|
"name": "GREE Controller",
|
||||||
"version": "0.8.4",
|
"version": "0.8.5",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"integration_type": "hub",
|
"integration_type": "hub",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
|
|||||||
+27
-1
@@ -762,7 +762,16 @@ fn temporary_temperature_condition_met(zone: &Zone, session: &TemporaryQuickTher
|
|||||||
/// Update a temperature-based temporary session from the freshly selected room sensor.
|
/// Update a temperature-based temporary session from the freshly selected room sensor.
|
||||||
/// Returns a completion reason when ownership should be handed back immediately.
|
/// Returns a completion reason when ownership should be handed back immediately.
|
||||||
fn evaluate_temporary_quick_thermostat_condition(zone: &mut Zone, now: DateTime<Utc>) -> Option<String> {
|
fn evaluate_temporary_quick_thermostat_condition(zone: &mut Zone, now: DateTime<Utc>) -> Option<String> {
|
||||||
if zone.local_thermostat_power != Some(true) { return None; }
|
// `activated_at` is the primary marker that a scheduled Temporary Quick Thermostat
|
||||||
|
// actually started. `local_thermostat_power == Some(true)` is retained as a legacy/
|
||||||
|
// recovery marker for sessions persisted before `activated_at` existed. A future
|
||||||
|
// scheduled session must never start or finish a temperature condition early.
|
||||||
|
let session_active = zone.temporary_quick_thermostat.as_ref().map(|session| {
|
||||||
|
session.activated_at.as_ref().map(|at| at <= &now).unwrap_or(false)
|
||||||
|
|| (zone.local_thermostat_power == Some(true) && session.started_at <= now)
|
||||||
|
}).unwrap_or(false);
|
||||||
|
if !session_active { return None; }
|
||||||
|
|
||||||
let met = zone.temporary_quick_thermostat.as_ref()
|
let met = zone.temporary_quick_thermostat.as_ref()
|
||||||
.filter(|session| matches!(session.finish_kind.as_str(), "temperature_reached" | "temperature_stable"))
|
.filter(|session| matches!(session.finish_kind.as_str(), "temperature_reached" | "temperature_stable"))
|
||||||
.map(|session| temporary_temperature_condition_met(zone, session))?;
|
.map(|session| temporary_temperature_condition_met(zone, session))?;
|
||||||
@@ -2901,6 +2910,23 @@ mod tests {
|
|||||||
assert!(zone.temporary_quick_thermostat.as_ref().unwrap().condition_started_at.is_none());
|
assert!(zone.temporary_quick_thermostat.as_ref().unwrap().condition_started_at.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn legacy_active_temporary_session_without_activated_at_still_evaluates_condition() {
|
||||||
|
let now = Utc::now();
|
||||||
|
let mut zone = test_zone("device");
|
||||||
|
zone.current_temperature = Some(23.0);
|
||||||
|
zone.local_thermostat_power = Some(true);
|
||||||
|
let mut session = temporary_session(now.clone());
|
||||||
|
session.activated_at = None;
|
||||||
|
session.condition_started_at = Some(now.clone() - chrono::Duration::hours(1));
|
||||||
|
zone.temporary_quick_thermostat = Some(session);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
evaluate_temporary_quick_thermostat_condition(&mut zone, now),
|
||||||
|
Some("temperature_stable".into())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn temporary_setpoint_keeps_priority_over_active_schedule() {
|
fn temporary_setpoint_keeps_priority_over_active_schedule() {
|
||||||
let mut zone = test_zone("device");
|
let mut zone = test_zone("device");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'gree-controller-v084-scheduled-temporary-quick-thermostat';
|
const CACHE = 'gree-controller-v085-temporary-condition-activation-fix';
|
||||||
const SCOPE = new URL(self.registration.scope).pathname.replace(/\/$/, '');
|
const SCOPE = new URL(self.registration.scope).pathname.replace(/\/$/, '');
|
||||||
const path = value => `${SCOPE}${value.startsWith('/') ? value : `/${value}`}` || '/';
|
const path = value => `${SCOPE}${value.startsWith('/') ? value : `/${value}`}` || '/';
|
||||||
const ASSETS = [path('/'), path('/styles.css'), path('/app.js'), path('/theme-init.js'), path('/favicon.svg'), path('/manifest.webmanifest'), path('/lang/index.json'), path('/lang/en.json')];
|
const ASSETS = [path('/'), path('/styles.css'), path('/app.js'), path('/theme-init.js'), path('/favicon.svg'), path('/manifest.webmanifest'), path('/lang/index.json'), path('/lang/en.json')];
|
||||||
|
|||||||
Reference in New Issue
Block a user