v0.6.1
This commit is contained in:
+8
-2
@@ -1,8 +1,8 @@
|
|||||||
# GREE Controller v0.5.5 - build and validation report
|
# GREE Controller v0.6.1 - build and validation report
|
||||||
|
|
||||||
## Scope
|
## 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
|
## 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.
|
- 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.
|
- 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
|
## Validation performed in packaging environment
|
||||||
|
|
||||||
- `node --check web/app.js`.
|
- `node --check web/app.js`.
|
||||||
|
|||||||
Generated
+1
-1
@@ -633,7 +633,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gree-controller"
|
name = "gree-controller"
|
||||||
version = "0.5.5"
|
version = "0.6.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gree-controller"
|
name = "gree-controller"
|
||||||
version = "0.5.5"
|
version = "0.6.1"
|
||||||
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 @@
|
|||||||
623bd769512ef75f51e9bf7fb685d4d59ec84d7ccc75c826fe72c5538be737c5 ./.env.example
|
623bd769512ef75f51e9bf7fb685d4d59ec84d7ccc75c826fe72c5538be737c5 ./.env.example
|
||||||
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
|
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
|
||||||
b26651d11ad5156406250dd7eb3061c5d47fa0c999a6899ea13a97aa6f295178 ./BUILD_REPORT.md
|
110e07efa26849462b6f5064f9bbadfc477301390b2303a2ff3dd205f41ef973 ./BUILD_REPORT.md
|
||||||
4202057467ffdc3f53ef250c3e7852a929be788bb0af03fbd2366a57ce42b79e ./Cargo.lock
|
24efad1c04de0afd647ddb9a6a7d70b3c1e31b91de28dc8643d6be688a5db5e6 ./Cargo.lock
|
||||||
9edc867d716d9d8ce2c54cdf17e16628f9c2b338ee36f88e0bb0fcb4f7884b57 ./Cargo.toml
|
4d03ac4ec8bdf303f4b58c02576fe71f1a1cca8a23f383c08a2a3dcdfc4d2176 ./Cargo.toml
|
||||||
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
||||||
44675b0d5d9e6e89dd0bae8eff3ab76a190a3b1bdd6507e7402957bbd92cac36 ./README.md
|
39a7ebd7b27b4b1b026ed56becbccfb524822234ecfa68423b68a3bc5659d768 ./README.md
|
||||||
f2c8eb28fedb26bb8f5636e1805e7a782cc472b87d882f6752d520f16216a248 ./build.rs
|
f2c8eb28fedb26bb8f5636e1805e7a782cc472b87d882f6752d520f16216a248 ./build.rs
|
||||||
674f8cf1ab9f1a49188e20b8e3977f1e2b7e9b8ef975315266730c44a55bbb48 ./docs/API.md
|
674f8cf1ab9f1a49188e20b8e3977f1e2b7e9b8ef975315266730c44a55bbb48 ./docs/API.md
|
||||||
234dd200e380a13ecd3e61b4ea455f6f08d64ce89382077dee80684acadb9703 ./docs/HOME_ASSISTANT_MIGRATION.md
|
234dd200e380a13ecd3e61b4ea455f6f08d64ce89382077dee80684acadb9703 ./docs/HOME_ASSISTANT_MIGRATION.md
|
||||||
@@ -23,7 +23,7 @@ b0314469ddb7c69ee4a96c677815af30cb97713e93911a05597f2fdc3d10f489 ./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
|
||||||
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
|
d0206766d76f70ea1c75a618e41bf1e8e8c0429f42ee97f40daac1ea12f16658 ./home-assistant/custom_components/gree_controller/number.py
|
||||||
5c914c2faa18a9cb9eb442dc111c9416f89a630578f820beb021d5381aa1b2d0 ./home-assistant/custom_components/gree_controller/sensor.py
|
5c914c2faa18a9cb9eb442dc111c9416f89a630578f820beb021d5381aa1b2d0 ./home-assistant/custom_components/gree_controller/sensor.py
|
||||||
7c23374d1c82e4b361089386ff89265322b80def0f4db9d3fd2c039867033105 ./home-assistant/custom_components/gree_controller/switch.py
|
7c23374d1c82e4b361089386ff89265322b80def0f4db9d3fd2c039867033105 ./home-assistant/custom_components/gree_controller/switch.py
|
||||||
@@ -48,13 +48,13 @@ b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/upda
|
|||||||
87b985ba7095a3b165928fe6d051acf34c34d2b48ce882b2b2c89c486f3f2ad3 ./src/api.rs
|
87b985ba7095a3b165928fe6d051acf34c34d2b48ce882b2b2c89c486f3f2ad3 ./src/api.rs
|
||||||
0f50b30a0088b6ae8289ecf42be1938cbcd95f672d370cff7e5446e7e1f02b83 ./src/config.rs
|
0f50b30a0088b6ae8289ecf42be1938cbcd95f672d370cff7e5446e7e1f02b83 ./src/config.rs
|
||||||
a89bc49e359715109149130a10ac60abd26bfd2bc18c5ee5142e01696d9f9cdd ./src/db.rs
|
a89bc49e359715109149130a10ac60abd26bfd2bc18c5ee5142e01696d9f9cdd ./src/db.rs
|
||||||
614bc52f203f2de657266a74fa93933a8b30a4a631b208282c88813687a0db37 ./src/engine.rs
|
4a74955d2f5f830bae4758ed078157b3fb1a54c67f338e48ea1f2765efbd980f ./src/engine.rs
|
||||||
ae3b496749a3fd723b243d9bea92e5d76249f52814c80359ad9bac53abacb074 ./src/error.rs
|
ae3b496749a3fd723b243d9bea92e5d76249f52814c80359ad9bac53abacb074 ./src/error.rs
|
||||||
081f6909e95839c7da8c40b866af9de237e0540f3e65e1ce739ce70a6fa94846 ./src/home_assistant.rs
|
081f6909e95839c7da8c40b866af9de237e0540f3e65e1ce739ce70a6fa94846 ./src/home_assistant.rs
|
||||||
190b0a33431539676e5dd7796698077f16c179d42eae4501ca96a91bf797cbf8 ./src/influxdb.rs
|
190b0a33431539676e5dd7796698077f16c179d42eae4501ca96a91bf797cbf8 ./src/influxdb.rs
|
||||||
31d56301834ffe4afa7d8092feb033643c39c65040c62b73d4bd38ddd34407f0 ./src/main.rs
|
31d56301834ffe4afa7d8092feb033643c39c65040c62b73d4bd38ddd34407f0 ./src/main.rs
|
||||||
6be14e8e3286c9ce5bd921ccaa39431bb2d3cd882d2945fa8b17b2f00bf5a8fb ./src/models.rs
|
6be14e8e3286c9ce5bd921ccaa39431bb2d3cd882d2945fa8b17b2f00bf5a8fb ./src/models.rs
|
||||||
30e9dd984027405a726c3f281673c28ae4d48c0fb8af823b3c0e4c5706505263 ./src/notifications.rs
|
ea4bd7f20759101c2525600a1f342d2fc0946e2f0b3208b03cc5a415b6947c10 ./src/notifications.rs
|
||||||
7fc31fbf8841a073a1544b8c7a6390f1a15b56087486ca0596a8418340fa232a ./src/protocol/crypto.rs
|
7fc31fbf8841a073a1544b8c7a6390f1a15b56087486ca0596a8418340fa232a ./src/protocol/crypto.rs
|
||||||
37bd46ac7c50d1674463eddcf2ee9c85cdbf8fe0829cef13a3f5fe857d3d0f55 ./src/protocol/gree.rs
|
37bd46ac7c50d1674463eddcf2ee9c85cdbf8fe0829cef13a3f5fe857d3d0f55 ./src/protocol/gree.rs
|
||||||
a910bd9432a393740c0f6fab52bfcb551f0ea756718d66d290fd2610767cf07c ./src/protocol/mod.rs
|
a910bd9432a393740c0f6fab52bfcb551f0ea756718d66d290fd2610767cf07c ./src/protocol/mod.rs
|
||||||
@@ -65,6 +65,6 @@ ef02fe53df75af12cb957e15b945543eeba937a13154a1fc6c5234ee6f25b435 ./web/app.js
|
|||||||
e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg
|
e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg
|
||||||
002c172392a00006a5128fc4cb881b0361a2d3e76298dbd80c0a013f4e1f9dde ./web/index.html
|
002c172392a00006a5128fc4cb881b0361a2d3e76298dbd80c0a013f4e1f9dde ./web/index.html
|
||||||
fd26156e9f1d6713d3def564ad000553d9a16a24376059701db2ee762c99ee6c ./web/manifest.webmanifest
|
fd26156e9f1d6713d3def564ad000553d9a16a24376059701db2ee762c99ee6c ./web/manifest.webmanifest
|
||||||
648630cb390be4ef7654053caa4010760e5f963ea9d67ccec4e6b07a5e2545f7 ./web/styles.css
|
87148c295a8d6ab7017d10dde25528f2d3bcbc50ca15dc2e0869307e0b1604de ./web/styles.css
|
||||||
87d25648f24b853c94b39e31e93fe737cae524c74402f287a586d0b5718ca39e ./web/sw.js
|
64355a48ea25c86b6fceae31f9d1e79a7f71cde35a055a001133c91f220b939f ./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.5.5**.
|
Current version: **0.6.1**.
|
||||||
|
|
||||||
## Highlights
|
## 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:
|
On Debian, Ubuntu or an LXC container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
unzip gree-controller-v0.5.5.zip
|
unzip gree-controller-v0.6.1.zip
|
||||||
cd gree-controller
|
cd gree-controller
|
||||||
chmod +x scripts/*.sh
|
chmod +x scripts/*.sh
|
||||||
./scripts/dev.sh
|
./scripts/dev.sh
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"domain": "gree_controller",
|
"domain": "gree_controller",
|
||||||
"name": "GREE Controller",
|
"name": "GREE Controller",
|
||||||
"version": "0.5.5",
|
"version": "0.6.1",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"integration_type": "hub",
|
"integration_type": "hub",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
|
|||||||
+5
-3
@@ -230,13 +230,15 @@ async fn poll_device(state: &AppState, device: &mut Device) {
|
|||||||
log_poll_health_transition(state, device, previous_failures).await;
|
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);
|
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!({
|
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
|
"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}));
|
state.log("info", "device.recovered", &format!("{} is responding again", device.name), json!({"device_id": device.id}));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 title = format!("GREE Controller - {}", if level == "error" { "error" } else if level == "warn" { "warning" } else { "event" });
|
||||||
let result = match cfg.provider.as_str() {
|
let result = match cfg.provider.as_str() {
|
||||||
"pushover" => send_pushover(&state, &cfg, &title, &message).await,
|
"pushover" => send_pushover(&state, &cfg, &title, &message).await,
|
||||||
"slack" => send_webhook(&state, &cfg.slack_webhook_url, json!({"text": format!("*{}*\\n{}", title, message)})).await,
|
"slack" => send_webhook(&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,
|
"discord" => send_webhook(&cfg.discord_webhook_url, json!({"content": format!("**{}**\\n{}", title, message)})).await,
|
||||||
_ => Err("unsupported notification provider".into()),
|
_ => Err("unsupported notification provider".into()),
|
||||||
};
|
};
|
||||||
if let Err(err) = result {
|
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())) }
|
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())?;
|
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()); }
|
if parsed.scheme() != "https" { return Err("webhook URL must use HTTPS".into()); }
|
||||||
let host = parsed.host_str().unwrap_or_default().to_ascii_lowercase();
|
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> {
|
pub async fn test(state: &AppState, cfg: NotificationSettings) -> Result<(), String> {
|
||||||
match cfg.provider.as_str() {
|
match cfg.provider.as_str() {
|
||||||
"pushover" => send_pushover(state, &cfg, "GREE Controller", "Test notification").await,
|
"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,
|
"slack" => send_webhook(&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,
|
"discord" => send_webhook(&cfg.discord_webhook_url, json!({"content":"GREE Controller - test notification"})).await,
|
||||||
_ => Err("unsupported notification provider".into()),
|
_ => Err("unsupported notification provider".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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 { 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); }
|
.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 { justify-items:center; text-align:center; padding:11px 0 3px; }
|
||||||
.device-capability-panel > small { text-align:center; }
|
.device-capability-panel > small { text-align:center; }
|
||||||
.device-capability-buttons { justify-content:center; align-items:center; gap:6px; max-width:100%; }
|
.device-capability-buttons { justify-content:center; align-items:center; gap:6px; max-width:100%; }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'gree-controller-v060';
|
const CACHE = 'gree-controller-v061';
|
||||||
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