From 7de006e8412c416c3726207fd7247f62cdb066ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Mon, 24 Aug 2026 23:20:06 +0200 Subject: [PATCH] v0.6.1 --- BUILD_REPORT.md | 10 ++++++++-- Cargo.lock | 2 +- Cargo.toml | 2 +- FILE_MANIFEST.sha256 | 18 +++++++++--------- README.md | 4 ++-- .../gree_controller/manifest.json | 2 +- src/engine.rs | 8 +++++--- src/notifications.rs | 10 +++++----- web/styles.css | 2 +- web/sw.js | 2 +- 10 files changed, 34 insertions(+), 26 deletions(-) diff --git a/BUILD_REPORT.md b/BUILD_REPORT.md index e18e109..8f2e3a1 100644 --- a/BUILD_REPORT.md +++ b/BUILD_REPORT.md @@ -1,8 +1,8 @@ -# GREE Controller v0.5.5 - build and validation report +# GREE Controller v0.6.1 - build and validation report ## Scope -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. +Version 0.6.1 includes the notification, reverse-proxy, mobile decimal-input, log filtering and thermostat-copy changes described below, plus a Rust type-safety hotfix for communication-failure notifications. ## Implemented changes @@ -42,6 +42,12 @@ Version 0.5.5 builds on 0.5.4 with dedicated Night mode and Home Assistant/Senso - The dashboard renders the control plan as blocks with current targets/demand and upcoming actions. - Home Assistant integration now also exposes whole-house/per-zone plan sensors, writable per-zone target-temperature `number` entities and per-zone enable `switch` entities via the restricted integration API. +## 0.6.1 compile hotfix + +- Fixed `u8`/`u32` mismatches in communication-failure threshold handling without changing the persisted `Device.communication_failures` type or notification-settings schema. +- Removed the unused `AppState` parameter from Slack/Discord webhook delivery. +- Bumped application, Cargo lock root package, Home Assistant custom-component and PWA cache versions to `0.6.1`. + ## Validation performed in packaging environment - `node --check web/app.js`. diff --git a/Cargo.lock b/Cargo.lock index 85b96e0..842dd57 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -633,7 +633,7 @@ dependencies = [ [[package]] name = "gree-controller" -version = "0.5.5" +version = "0.6.1" dependencies = [ "aes", "aes-gcm", diff --git a/Cargo.toml b/Cargo.toml index 7d46a4e..16f01fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gree-controller" -version = "0.5.5" +version = "0.6.1" 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 09346bc..7117c20 100644 --- a/FILE_MANIFEST.sha256 +++ b/FILE_MANIFEST.sha256 @@ -1,10 +1,10 @@ 623bd769512ef75f51e9bf7fb685d4d59ec84d7ccc75c826fe72c5538be737c5 ./.env.example a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore -b26651d11ad5156406250dd7eb3061c5d47fa0c999a6899ea13a97aa6f295178 ./BUILD_REPORT.md -4202057467ffdc3f53ef250c3e7852a929be788bb0af03fbd2366a57ce42b79e ./Cargo.lock -9edc867d716d9d8ce2c54cdf17e16628f9c2b338ee36f88e0bb0fcb4f7884b57 ./Cargo.toml +110e07efa26849462b6f5064f9bbadfc477301390b2303a2ff3dd205f41ef973 ./BUILD_REPORT.md +24efad1c04de0afd647ddb9a6a7d70b3c1e31b91de28dc8643d6be688a5db5e6 ./Cargo.lock +4d03ac4ec8bdf303f4b58c02576fe71f1a1cca8a23f383c08a2a3dcdfc4d2176 ./Cargo.toml 19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE -44675b0d5d9e6e89dd0bae8eff3ab76a190a3b1bdd6507e7402957bbd92cac36 ./README.md +39a7ebd7b27b4b1b026ed56becbccfb524822234ecfa68423b68a3bc5659d768 ./README.md f2c8eb28fedb26bb8f5636e1805e7a782cc472b87d882f6752d520f16216a248 ./build.rs 674f8cf1ab9f1a49188e20b8e3977f1e2b7e9b8ef975315266730c44a55bbb48 ./docs/API.md 234dd200e380a13ecd3e61b4ea455f6f08d64ce89382077dee80684acadb9703 ./docs/HOME_ASSISTANT_MIGRATION.md @@ -23,7 +23,7 @@ b0314469ddb7c69ee4a96c677815af30cb97713e93911a05597f2fdc3d10f489 ./home-assista 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/logo.png -f79cc14c65131fa86a5bf41d55f49b60a3aa71a6d15de98027de830e3b11b2a1 ./home-assistant/custom_components/gree_controller/manifest.json +d1873870df2388f43f9cfd8a2e617ca394eac53d93e2eb8cb85df4d3b6a9caa2 ./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 @@ -48,13 +48,13 @@ b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/upda 87b985ba7095a3b165928fe6d051acf34c34d2b48ce882b2b2c89c486f3f2ad3 ./src/api.rs 0f50b30a0088b6ae8289ecf42be1938cbcd95f672d370cff7e5446e7e1f02b83 ./src/config.rs a89bc49e359715109149130a10ac60abd26bfd2bc18c5ee5142e01696d9f9cdd ./src/db.rs -614bc52f203f2de657266a74fa93933a8b30a4a631b208282c88813687a0db37 ./src/engine.rs +4a74955d2f5f830bae4758ed078157b3fb1a54c67f338e48ea1f2765efbd980f ./src/engine.rs ae3b496749a3fd723b243d9bea92e5d76249f52814c80359ad9bac53abacb074 ./src/error.rs 081f6909e95839c7da8c40b866af9de237e0540f3e65e1ce739ce70a6fa94846 ./src/home_assistant.rs 190b0a33431539676e5dd7796698077f16c179d42eae4501ca96a91bf797cbf8 ./src/influxdb.rs 31d56301834ffe4afa7d8092feb033643c39c65040c62b73d4bd38ddd34407f0 ./src/main.rs 6be14e8e3286c9ce5bd921ccaa39431bb2d3cd882d2945fa8b17b2f00bf5a8fb ./src/models.rs -30e9dd984027405a726c3f281673c28ae4d48c0fb8af823b3c0e4c5706505263 ./src/notifications.rs +ea4bd7f20759101c2525600a1f342d2fc0946e2f0b3208b03cc5a415b6947c10 ./src/notifications.rs 7fc31fbf8841a073a1544b8c7a6390f1a15b56087486ca0596a8418340fa232a ./src/protocol/crypto.rs 37bd46ac7c50d1674463eddcf2ee9c85cdbf8fe0829cef13a3f5fe857d3d0f55 ./src/protocol/gree.rs a910bd9432a393740c0f6fab52bfcb551f0ea756718d66d290fd2610767cf07c ./src/protocol/mod.rs @@ -65,6 +65,6 @@ ef02fe53df75af12cb957e15b945543eeba937a13154a1fc6c5234ee6f25b435 ./web/app.js e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg 002c172392a00006a5128fc4cb881b0361a2d3e76298dbd80c0a013f4e1f9dde ./web/index.html fd26156e9f1d6713d3def564ad000553d9a16a24376059701db2ee762c99ee6c ./web/manifest.webmanifest -648630cb390be4ef7654053caa4010760e5f963ea9d67ccec4e6b07a5e2545f7 ./web/styles.css -87d25648f24b853c94b39e31e93fe737cae524c74402f287a586d0b5718ca39e ./web/sw.js +87148c295a8d6ab7017d10dde25528f2d3bcbc50ca15dc2e0869307e0b1604de ./web/styles.css +64355a48ea25c86b6fceae31f9d1e79a7f71cde35a055a001133c91f220b939f ./web/sw.js d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js diff --git a/README.md b/README.md index 82b3ac3..f4707be 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.5**. +Current version: **0.6.1**. ## 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.5.zip +unzip gree-controller-v0.6.1.zip cd gree-controller chmod +x scripts/*.sh ./scripts/dev.sh diff --git a/home-assistant/custom_components/gree_controller/manifest.json b/home-assistant/custom_components/gree_controller/manifest.json index de8d109..c5249d3 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.5", + "version": "0.6.1", "config_flow": true, "integration_type": "hub", "iot_class": "local_polling", diff --git a/src/engine.rs b/src/engine.rs index 6347a67..96c3396 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -230,13 +230,15 @@ async fn poll_device(state: &AppState, device: &mut Device) { log_poll_health_transition(state, device, previous_failures).await; } -async fn log_poll_health_transition(state: &AppState, device: &Device, previous_failures: u32) { +async fn log_poll_health_transition(state: &AppState, device: &Device, previous_failures: u8) { let threshold = state.settings.read().await.notifications.communication_failure_threshold.max(2); - if device.communication_failures >= threshold && previous_failures < threshold { + let current_failures = u32::from(device.communication_failures); + let previous_failures = u32::from(previous_failures); + if current_failures >= threshold && previous_failures < threshold { state.log("warn", "device.offline", &format!("{} did not respond {} times in a row", device.name, device.communication_failures), json!({ "device_id": device.id, "consecutive_failures": device.communication_failures, "threshold": threshold })); - } else if device.communication_failures == 0 && previous_failures >= threshold { + } else if current_failures == 0 && previous_failures >= threshold { state.log("info", "device.recovered", &format!("{} is responding again", device.name), json!({"device_id": device.id})); } } diff --git a/src/notifications.rs b/src/notifications.rs index 9ffa0ee..bd4f136 100644 --- a/src/notifications.rs +++ b/src/notifications.rs @@ -42,8 +42,8 @@ pub async fn dispatch(state: AppState, level: String, kind: String, message: Str let title = format!("GREE Controller - {}", if level == "error" { "error" } else if level == "warn" { "warning" } else { "event" }); let result = match cfg.provider.as_str() { "pushover" => send_pushover(&state, &cfg, &title, &message).await, - "slack" => send_webhook(&state, &cfg.slack_webhook_url, json!({"text": format!("*{}*\\n{}", title, message)})).await, - "discord" => send_webhook(&state, &cfg.discord_webhook_url, json!({"content": format!("**{}**\\n{}", title, message)})).await, + "slack" => send_webhook(&cfg.slack_webhook_url, json!({"text": format!("*{}*\\n{}", title, message)})).await, + "discord" => send_webhook(&cfg.discord_webhook_url, json!({"content": format!("**{}**\\n{}", title, message)})).await, _ => Err("unsupported notification provider".into()), }; if let Err(err) = result { @@ -59,7 +59,7 @@ async fn send_pushover(state: &AppState, cfg: &NotificationSettings, title: &str if response.status().is_success() { Ok(()) } else { Err(format!("Pushover HTTP {}", response.status())) } } -async fn send_webhook(state: &AppState, url: &str, body: Value) -> Result<(), String> { +async fn send_webhook(url: &str, body: Value) -> Result<(), String> { let parsed = url::Url::parse(url).map_err(|_| "invalid webhook URL".to_string())?; if parsed.scheme() != "https" { return Err("webhook URL must use HTTPS".into()); } let host = parsed.host_str().unwrap_or_default().to_ascii_lowercase(); @@ -76,8 +76,8 @@ async fn send_webhook(state: &AppState, url: &str, body: Value) -> Result<(), St pub async fn test(state: &AppState, cfg: NotificationSettings) -> Result<(), String> { match cfg.provider.as_str() { "pushover" => send_pushover(state, &cfg, "GREE Controller", "Test notification").await, - "slack" => send_webhook(state, &cfg.slack_webhook_url, json!({"text":"GREE Controller - test notification"})).await, - "discord" => send_webhook(state, &cfg.discord_webhook_url, json!({"content":"GREE Controller - test notification"})).await, + "slack" => send_webhook(&cfg.slack_webhook_url, json!({"text":"GREE Controller - test notification"})).await, + "discord" => send_webhook(&cfg.discord_webhook_url, json!({"content":"GREE Controller - test notification"})).await, _ => Err("unsupported notification provider".into()), } } diff --git a/web/styles.css b/web/styles.css index 900e8df..2d09922 100644 --- a/web/styles.css +++ b/web/styles.css @@ -613,7 +613,7 @@ html[data-theme='light'] .simulation-metrics > div, html[data-theme='light'] .si .device-capability-buttons button { min-height:34px; padding:7px 11px; border:1px solid var(--line); border-radius:11px; background:var(--surface-muted); color:var(--text); } .device-capability-buttons button.active { border-color:var(--accent); color:var(--accent); } -/* v0.5.5: compact, centered unit-feature controls */ +/* v0.6.1: compact, centered unit-feature controls */ .device-capability-panel { justify-items:center; text-align:center; padding:11px 0 3px; } .device-capability-panel > small { text-align:center; } .device-capability-buttons { justify-content:center; align-items:center; gap:6px; max-width:100%; } diff --git a/web/sw.js b/web/sw.js index 10127ad..72b8695 100644 --- a/web/sw.js +++ b/web/sw.js @@ -1,4 +1,4 @@ -const CACHE = 'gree-controller-v060'; +const CACHE = 'gree-controller-v061'; const SCOPE = new URL(self.registration.scope).pathname.replace(/\/$/, ''); 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')];