This commit is contained in:
Mateusz Gruszczyński
2026-08-24 23:20:06 +02:00
parent 76a6f050ae
commit 7de006e841
10 changed files with 34 additions and 26 deletions
+8 -2
View File
@@ -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`.
Generated
+1 -1
View File
@@ -633,7 +633,7 @@ dependencies = [
[[package]]
name = "gree-controller"
version = "0.5.5"
version = "0.6.1"
dependencies = [
"aes",
"aes-gcm",
+1 -1
View File
@@ -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"
+9 -9
View File
@@ -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
+2 -2
View File
@@ -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
@@ -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",
+5 -3
View File
@@ -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}));
}
}
+5 -5
View File
@@ -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()),
}
}
+1 -1
View File
@@ -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%; }
+1 -1
View File
@@ -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')];