From 3ffb02595e621f6c61d7e7bf73e780414e780f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Fri, 18 Sep 2026 10:27:39 +0200 Subject: [PATCH] v0.15.4 --- Cargo.lock | 690 ++++++++++-------- Cargo.toml | 58 +- FILE_MANIFEST.sha256 | 53 +- README.md | 5 +- SOURCE_MANIFEST.sha256 | 51 +- docs/API.md | 6 +- docs/openapi.json | 8 +- ha-addon/.env.example | 2 +- ha-addon/Dockerfile | 8 +- ha-addon/README.md | 6 +- ha-addon/build.sh | 22 +- ha-addon/home-assistant/README.md | 2 + .../gree_controller/manifest.json | 2 +- .../repository/gree-controller/CHANGELOG.md | 13 + ha-addon/repository/gree-controller/DOCS.md | 8 + ha-addon/repository/gree-controller/README.md | 4 +- .../repository/gree-controller/config.yaml | 4 +- scripts/api_dev_test.py | 6 +- src/api.rs | 57 +- src/api/auth.rs | 3 +- src/api/history.rs | 3 +- src/api/openapi.rs | 6 +- src/api/websocket.rs | 6 +- src/home_assistant.rs | 4 +- src/main.rs | 8 + src/protocol/crypto.rs | 27 +- src/protocol/gree_cloud.rs | 7 +- src/provider.rs | 21 +- 28 files changed, 610 insertions(+), 480 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 87e5e00..55f0d7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,49 +10,37 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" -version = "0.5.2" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" dependencies = [ - "crypto-common 0.1.7", - "generic-array", + "crypto-common 0.2.2", + "inout", ] [[package]] name = "aes" -version = "0.8.4" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +checksum = "35f0f96ce78e38c3dc6d8948aa8163d06385be74000f3c7a95bf1eef35d3ea32" dependencies = [ - "cfg-if", "cipher", - "cpufeatures 0.2.17", + "cpubits", + "cpufeatures 0.3.0", ] [[package]] name = "aes-gcm" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +checksum = "7f2b8006a0c83f52b62ba44a97b58bf76fe2f70a329e588f67f89691d93d498f" dependencies = [ "aead", "aes", "cipher", "ctr", + "ctutils", "ghash", - "subtle", -] - -[[package]] -name = "ahash" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", ] [[package]] @@ -150,17 +138,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "async-trait" -version = "0.1.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" -dependencies = [ - "proc-macro2", - "quote", - "syn 3.0.3", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -175,15 +152,15 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "axum" -version = "0.7.9" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" +checksum = "31b698c5f9a010f6573133b09e0de5408834d0c82f8d7475a89fc1867a71cd90" dependencies = [ - "async-trait", "axum-core", "axum-macros", - "base64", + "base64 0.22.1", "bytes", + "form_urlencoded", "futures-util", "http", "http-body", @@ -196,8 +173,7 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustversion", - "serde", + "serde_core", "serde_json", "serde_path_to_error", "serde_urlencoded", @@ -213,19 +189,17 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ - "async-trait", "bytes", - "futures-util", + "futures-core", "http", "http-body", "http-body-util", "mime", "pin-project-lite", - "rustversion", "sync_wrapper", "tower-layer", "tower-service", @@ -234,9 +208,9 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce" +checksum = "7aa268c23bfbbd2c4363b9cd302a4f504fb2a9dfe7e3451d66f35dd392e20aca" dependencies = [ "proc-macro2", "quote", @@ -249,6 +223,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "bitflags" version = "2.13.1" @@ -279,12 +259,6 @@ version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.12.1" @@ -307,12 +281,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" -[[package]] -name = "cfg_aliases" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" - [[package]] name = "chacha20" version = "0.10.1" @@ -340,19 +308,20 @@ dependencies = [ [[package]] name = "cipher" -version = "0.4.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ - "crypto-common 0.1.7", + "block-buffer 0.12.1", + "crypto-common 0.2.2", "inout", ] [[package]] name = "clap" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", "clap_derive", @@ -360,9 +329,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstream", "anstyle", @@ -372,9 +341,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.4" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" dependencies = [ "heck", "proc-macro2", @@ -388,12 +357,28 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "cmov" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c9ea0ac24bc397ab3c98583a3c9ba74fa56b09a4449bbe172b9b1ddb016027a" + [[package]] name = "colorchoice" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" +[[package]] +name = "combine" +version = "4.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfc320937d09e6de266b31b9afb480f197d7a861be86be7cb2ea7e5d1bfffc5e" +dependencies = [ + "bytes", + "memchr", +] + [[package]] name = "compression-codecs" version = "0.4.38" @@ -417,12 +402,28 @@ version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + [[package]] name = "cpufeatures" version = "0.2.17" @@ -450,12 +451,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossbeam-utils" -version = "0.8.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" - [[package]] name = "crypto-common" version = "0.1.7" @@ -463,7 +458,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", - "rand_core 0.6.4", "typenum", ] @@ -473,18 +467,29 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ + "getrandom 0.4.3", "hybrid-array", + "rand_core 0.10.1", ] [[package]] name = "ctr" -version = "0.9.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +checksum = "baaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21" dependencies = [ "cipher", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "data-encoding" version = "2.11.1" @@ -588,8 +593,15 @@ checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", + "zlib-rs", ] +[[package]] +name = "foldhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" + [[package]] name = "form_urlencoded" version = "1.2.2" @@ -668,10 +680,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi", - "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi 5.3.0", + "wasip2", ] [[package]] @@ -681,48 +703,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ "cfg-if", - "js-sys", "libc", - "r-efi", + "r-efi 6.0.0", "rand_core 0.10.1", - "wasm-bindgen", ] [[package]] name = "ghash" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +checksum = "2eecf2d5dc9b66b732b97707a0210906b1d30523eb773193ab777c0c84b3e8d5" dependencies = [ - "opaque-debug", "polyval", ] [[package]] name = "gree-controller" -version = "0.15.2" +version = "0.15.4" dependencies = [ "aes", "aes-gcm", "anyhow", "axum", - "base64", + "base64 0.23.1", "chrono", "clap", "dotenvy", "futures-util", "libc", - "rand 0.8.7", + "rand 0.10.2", "reqwest", "rusqlite", "serde", "serde_json", - "sha2 0.10.9", + "sha2", "tempfile", - "thiserror 2.0.20", + "thiserror", "tokio", "tokio-rustls", - "tower-http", + "tower-http 0.7.1", "tracing", "tracing-subscriber", "url", @@ -733,11 +752,11 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "ahash", + "foldhash", ] [[package]] @@ -745,14 +764,17 @@ name = "hashbrown" version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" +dependencies = [ + "foldhash", +] [[package]] name = "hashlink" -version = "0.9.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +checksum = "a596f1b20ed2cc5ecac41a164aaebc7258057060f06c0cf7a2ba3991ee7990fb" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.17.1", ] [[package]] @@ -849,7 +871,6 @@ dependencies = [ "tokio", "tokio-rustls", "tower-service", - "webpki-roots", ] [[package]] @@ -858,7 +879,7 @@ version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64", + "base64 0.22.1", "bytes", "futures-channel", "futures-util", @@ -1017,11 +1038,11 @@ dependencies = [ [[package]] name = "inout" -version = "0.1.4" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] @@ -1042,6 +1063,55 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +[[package]] +name = "jni" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498" +dependencies = [ + "cfg-if", + "combine", + "jni-macros", + "jni-sys", + "log", + "simd_cesu8", + "thiserror", + "walkdir", + "windows-link", +] + +[[package]] +name = "jni-macros" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "simd_cesu8", + "syn 2.0.119", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.119", +] + [[package]] name = "js-sys" version = "0.3.104" @@ -1067,9 +1137,9 @@ checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libsqlite3-sys" -version = "0.30.1" +version = "0.38.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +checksum = "f1d20bef17f513b9b3004532233187769cd072d790971f4e4da0e346eb6401e8" dependencies = [ "cc", "pkg-config", @@ -1103,12 +1173,6 @@ version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" -[[package]] -name = "lru-slab" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" - [[package]] name = "matchers" version = "0.2.0" @@ -1120,9 +1184,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.7.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" [[package]] name = "memchr" @@ -1198,10 +1262,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] -name = "opaque-debug" -version = "0.3.1" +name = "openssl-probe" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "parking_lot" @@ -1246,13 +1310,12 @@ checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "polyval" -version = "0.6.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +checksum = "f0fa31d631f2b2cb2a544d0aa321ce847a94764d701ca2becc411138b93d49cd" dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "opaque-debug", + "cpubits", + "cpufeatures 0.3.0", "universal-hash", ] @@ -1283,62 +1346,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quinn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" -dependencies = [ - "bytes", - "cfg_aliases", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls", - "socket2", - "thiserror 2.0.20", - "tokio", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-proto" -version = "0.11.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04759210543be93709136e28212294a659ef5001836ff4eab4d663e4529bba83" -dependencies = [ - "bytes", - "getrandom 0.4.3", - "lru-slab", - "rand 0.10.2", - "rand_pcg", - "ring", - "rustc-hash", - "rustls", - "rustls-pki-types", - "slab", - "thiserror 2.0.20", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.61.2", -] - [[package]] name = "quote" version = "1.0.47" @@ -1348,6 +1355,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "r-efi" version = "6.0.0" @@ -1356,13 +1369,12 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.7" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" +checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "libc", "rand_chacha", - "rand_core 0.6.4", + "rand_core 0.9.5", ] [[package]] @@ -1378,21 +1390,21 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.6.4", + "rand_core 0.9.5", ] [[package]] name = "rand_core" -version = "0.6.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.3.4", ] [[package]] @@ -1401,15 +1413,6 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" -[[package]] -name = "rand_pcg" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" -dependencies = [ - "rand_core 0.10.1", -] - [[package]] name = "redox_syscall" version = "0.5.18" @@ -1450,11 +1453,11 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "reqwest" -version = "0.12.28" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" +checksum = "16a1cfa75cc186dd73d5818e510e042e40927bccc9c236b061cea97e1eb08029" dependencies = [ - "base64", + "base64 0.23.1", "bytes", "futures-core", "http", @@ -1467,9 +1470,9 @@ dependencies = [ "log", "percent-encoding", "pin-project-lite", - "quinn", "rustls", "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", "serde_urlencoded", @@ -1477,13 +1480,12 @@ dependencies = [ "tokio", "tokio-rustls", "tower", - "tower-http", + "tower-http 0.6.11", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", ] [[package]] @@ -1501,10 +1503,20 @@ dependencies = [ ] [[package]] -name = "rusqlite" -version = "0.32.1" +name = "rsqlite-vfs" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +checksum = "c51c9ae4df8a7fba42103df5c621fa3c37eccf3a3c650879e90fc48b11cc192c" +dependencies = [ + "hashbrown 0.16.1", + "thiserror", +] + +[[package]] +name = "rusqlite" +version = "0.40.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f2a97da3e3873c73cb2a2e71b35c40ff95e0b1eefa8d72d8499a6928c3b5b3" dependencies = [ "bitflags", "fallible-iterator", @@ -1512,6 +1524,7 @@ dependencies = [ "hashlink", "libsqlite3-sys", "smallvec", + "sqlite-wasm-rs", ] [[package]] @@ -1545,15 +1558,18 @@ version = "8.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ffa149f6aa81b58a5b3011d01a857c4ed12c7a732d2c51947a4c7c692185f0" dependencies = [ - "sha2 0.11.0", + "sha2", "walkdir", ] [[package]] -name = "rustc-hash" -version = "2.1.3" +name = "rustc_version" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] [[package]] name = "rustix" @@ -1583,16 +1599,54 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pki-types" version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ - "web-time", "zeroize", ] +[[package]] +name = "rustls-platform-verifier" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.103.15" @@ -1625,12 +1679,50 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "schannel" +version = "0.1.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "security-framework" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + [[package]] name = "serde" version = "1.0.229" @@ -1708,17 +1800,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha2" -version = "0.10.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" -dependencies = [ - "cfg-if", - "cpufeatures 0.2.17", - "digest 0.10.7", -] - [[package]] name = "sha2" version = "0.11.0" @@ -1761,6 +1842,22 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" +[[package]] +name = "simd_cesu8" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" +dependencies = [ + "rustc_version", + "simdutf8", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + [[package]] name = "slab" version = "0.4.12" @@ -1783,6 +1880,18 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "sqlite-wasm-rs" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc3efc0da82635d7e1ced0053bbbfa8c7ab9645d0bf36ceb4f7127bb85315d75" +dependencies = [ + "cc", + "js-sys", + "rsqlite-vfs", + "wasm-bindgen", +] + [[package]] name = "stable_deref_trait" version = "1.2.1" @@ -1856,33 +1965,13 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "thiserror" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" -dependencies = [ - "thiserror-impl 1.0.69", -] - [[package]] name = "thiserror" version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.20", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.69" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.119", + "thiserror-impl", ] [[package]] @@ -1915,21 +2004,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "tinyvec" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "tokio" version = "1.53.1" @@ -1960,9 +2034,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.4" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +checksum = "b0c85f2c3ef0b1cd58b36682f4b17aaa995f0e5db534d85692b4903abce21f67" dependencies = [ "rustls", "tokio", @@ -1970,9 +2044,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.24.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +checksum = "8f72a05e828585856dacd553fba484c242c46e391fb0e58917c942ee9202915c" dependencies = [ "futures-util", "log", @@ -2015,23 +2089,39 @@ version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ - "async-compression", "bitflags", "bytes", - "futures-core", "futures-util", "http", "http-body", "pin-project-lite", - "tokio", - "tokio-util", "tower", "tower-layer", "tower-service", - "tracing", "url", ] +[[package]] +name = "tower-http" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a05a66a4fdd61cbbe0a1d755ffe0ca6aba159dd4820936a0ff8a8278245b9c" +dependencies = [ + "async-compression", + "bitflags", + "bytes", + "futures-core", + "http", + "http-body", + "percent-encoding", + "pin-project-lite", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -2114,20 +2204,18 @@ checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.24.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +checksum = "6c01152af293afb9c7c2a57e4b559c5620b421f6d133261c60dd2d0cdb38e6b8" dependencies = [ - "byteorder", "bytes", "data-encoding", "http", "httparse", "log", - "rand 0.8.7", + "rand 0.9.5", "sha1", - "thiserror 1.0.69", - "utf-8", + "thiserror", ] [[package]] @@ -2150,12 +2238,12 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "universal-hash" -version = "0.5.1" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +checksum = "f4987bdc12753382e0bec4a65c50738ffaabc998b9cdd1f952fb5f39b0048a96" dependencies = [ - "crypto-common 0.1.7", - "subtle", + "crypto-common 0.2.2", + "ctutils", ] [[package]] @@ -2176,12 +2264,6 @@ dependencies = [ "serde", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -2219,11 +2301,12 @@ dependencies = [ [[package]] name = "utoipa-swagger-ui" -version = "8.0.3" +version = "9.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5c80b4dd79ea382e8374d67dcce22b5c6663fa13a82ad3886441d1bbede5e35" +checksum = "d047458f1b5b65237c2f6dc6db136945667f40a7668627b3490b9513a3d43a55" dependencies = [ "axum", + "base64 0.22.1", "mime_guess", "regex", "rust-embed", @@ -2242,9 +2325,9 @@ checksum = "e2eebbbfe4093922c2b6734d7c679ebfebd704a0d7e56dfcb0d05818ce28977d" [[package]] name = "uuid" -version = "1.25.0" +version = "1.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f053576934f05a761a402421fbbe3d425d9366f75f978806a037b3ca481abecc" +checksum = "2ef6dac1e96601b4fb3acccccff2139741fcb757cb9a36089bf5be91cfb285ce" dependencies = [ "getrandom 0.4.3", "js-sys", @@ -2295,6 +2378,15 @@ version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" +[[package]] +name = "wasip2" +version = "1.0.4+wasi-0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.127" @@ -2361,13 +2453,12 @@ dependencies = [ ] [[package]] -name = "web-time" -version = "1.1.0" +name = "webpki-root-certs" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b" dependencies = [ - "js-sys", - "wasm-bindgen", + "rustls-pki-types", ] [[package]] @@ -2529,6 +2620,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "wit-bindgen" +version = "0.57.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" + [[package]] name = "writeable" version = "0.6.4" @@ -2640,21 +2737,24 @@ dependencies = [ [[package]] name = "zip" -version = "2.4.2" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50" +checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308" dependencies = [ "arbitrary", "crc32fast", - "crossbeam-utils", - "displaydoc", "flate2", "indexmap", "memchr", - "thiserror 2.0.20", "zopfli", ] +[[package]] +name = "zlib-rs" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b268e58e7c693d7c271f93ffc4ba3b380412554231c85bf61ca7af91042a4112" + [[package]] name = "zmij" version = "1.0.23" diff --git a/Cargo.toml b/Cargo.toml index f554c90..1002ee0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,44 +1,44 @@ [package] name = "gree-controller" -version = "0.15.2" +version = "0.15.4" edition = "2021" authors = ["GREE Controller contributors"] description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support" license = "MIT" [dependencies] -aes = "0.8" -aes-gcm = "0.10" -anyhow = "1" -axum = { version = "0.7", features = ["macros", "ws"] } -base64 = "0.22" -chrono = { version = "0.4", features = ["serde", "clock"] } -clap = { version = "4", features = ["derive", "env"] } -dotenvy = "0.15" -futures-util = "0.3" -libc = "0.2" -rand = "0.8" -reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } -rusqlite = { version = "0.32", features = ["bundled"] } -webpki-roots = "1" -tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12", "logging"] } -serde = { version = "1", features = ["derive"] } -serde_json = "1" -sha2 = "0.10" -thiserror = "2" -tokio = { version = "1", features = ["full"] } -tower-http = { version = "0.6", features = ["compression-gzip", "cors", "trace"] } -tracing = "0.1" -tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt"] } -utoipa-swagger-ui = { version = "=8.0.3", default-features = false, features = ["axum", "debug-embed", "vendored"] } -url = "2" -uuid = { version = "1", features = ["v4", "serde"] } +aes = "=0.9.3" +aes-gcm = "=0.11.1" +anyhow = "=1.0.104" +axum = { version = "=0.8.9", features = ["macros", "ws"] } +base64 = "=0.23.1" +chrono = { version = "=0.4.45", features = ["serde", "clock"] } +clap = { version = "=4.6.7", features = ["derive", "env"] } +dotenvy = "=0.15.7" +futures-util = "=0.3.34" +libc = "=0.2.189" +rand = "=0.10.2" +reqwest = { version = "=0.13.5", default-features = false, features = ["json", "query", "form", "rustls-no-provider"] } +rusqlite = { version = "=0.40.2", features = ["bundled"] } +webpki-roots = "=1.0.9" +tokio-rustls = { version = "=0.26.5", default-features = false, features = ["ring", "tls12", "logging"] } +serde = { version = "=1.0.229", features = ["derive"] } +serde_json = "=1.0.151" +sha2 = "=0.11.0" +thiserror = "=2.0.20" +tokio = { version = "=1.53.1", features = ["full"] } +tower-http = { version = "=0.7.1", features = ["compression-gzip", "cors", "trace"] } +tracing = "=0.1.44" +tracing-subscriber = { version = "=0.3.23", features = ["env-filter", "fmt"] } +utoipa-swagger-ui = { version = "=9.0.2", default-features = false, features = ["axum", "debug-embed", "vendored"] } +url = "=2.5.8" +uuid = { version = "=1.26.1", features = ["v4", "serde"] } [build-dependencies] -serde_json = "1" +serde_json = "=1.0.151" [dev-dependencies] -tempfile = "3" +tempfile = "=3.27.0" [profile.release] strip = true diff --git a/FILE_MANIFEST.sha256 b/FILE_MANIFEST.sha256 index 4063ca2..bdd694c 100644 --- a/FILE_MANIFEST.sha256 +++ b/FILE_MANIFEST.sha256 @@ -1,19 +1,18 @@ de0793949cf01d27d903653226ecc9b5f72523d8711f20bcab022cf42c4c4ed0 ./.env.example a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore -82bb41f94fdf5c66ebd9e6caa92e0f1794431067298e0a27c95c8e5bfd68de89 ./Cargo.lock -39bdb16196253559e3487aa912ff770c09c7b08cdfbb21e9db1d8af1304ea7e0 ./Cargo.toml +37e255dd094e4720f96b74e501a179cf81c838ff327cbc1924b8fc4b5ea555fa ./Cargo.toml 19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE -84a0803bc75dc3199e23ef56c11c6950e8bd888c686ecda7cc369829e8e3073f ./README.md -f21732756af313565bfe0788230e45cc11c384cee1187f006d426c5463183c0c ./SOURCE_MANIFEST.sha256 +c1cac4ca532e73d64e5b090ad410a2161e9790b8d77fc6732adf52c248fb3472 ./README.md +8dc1f42dd20c98873fcd0a979475560f9ec79e098f01375de47f8fd96ef6e80d ./SOURCE_MANIFEST.sha256 29e9821e5ed216ea3565dd6d8bc0b174ed3cf9fa72c4ccebbfa99e98db3ad8f9 ./build.rs -604a795dec077dd7e4f3462a564fdda68e8084aef07da0fcf3dfb6053a46cc58 ./docs/API.md +0da3db314314e19a00c08700f94495075fecd1e54a5b188f6a62cb237307e96f ./docs/API.md a881ba0808dd3f189d92038f6163c39d6b6208f6dbff5c32c0ea1a2628f3fbb4 ./docs/FLOW.md -8babaa6830fa70b2d3d8208ef51808e79c9d68c4e007b9ba1537fe582ba03b3d ./docs/openapi.json -c65aa543d2e99f8f7d52736307b07ebd182597d80124661d53a16bb23f6f1118 ./ha-addon/.env.example -0993076ca45b6d31859680835204cdc111b3f9bdbf460d50b4efec56cd5e685b ./ha-addon/Dockerfile -adf7ff248d782a3b1cba82b8789c57b6849ddaaaf5fbc108af75e18b1534a885 ./ha-addon/README.md -dd9291b12afade6fc20d66e80a5513251270e18e4c265260b2bbbe393a5a94c4 ./ha-addon/build.sh -4061846cec4d829e4101b4021df7f07dc2e0293ccfd11e91589f49733ec7c5b4 ./ha-addon/home-assistant/README.md +55ffdcc5b0a43d930823cea7c94235990dbbc4a35b60832b9adca1faf606d036 ./docs/openapi.json +77b8becf7a2c16a384ea85721d878b76e2d520549cb4455d9aa806e57e5a2ecd ./ha-addon/.env.example +0ca6e58170c2b8925194431ebbdb55f0c8b377fec5cd422cd2bd257e2d9328e3 ./ha-addon/Dockerfile +0951696a2c2e66d4d969f8e7f8641184e3012f261583b31074bc38a7a1c0cc1a ./ha-addon/README.md +a4596a70e50acfe698a8ae1dcb9bebd04adba95b69781218fca7add82c17703e ./ha-addon/build.sh +7dd2534a6f8405e640e28b7cb0e94270cc5f01fad8a972193ec254befe8a96b9 ./ha-addon/home-assistant/README.md f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./ha-addon/home-assistant/custom_components/gree_controller/__init__.py 3f6ef15ef58456376ac53fde7cace1ef359d6a6f7a64c5b575ad77ea6e55ccc4 ./ha-addon/home-assistant/custom_components/gree_controller/api.py da2a0a9390ab75cef150cd281bc329fa409d0d28f51382b36bd8de3a73325c16 ./ha-addon/home-assistant/custom_components/gree_controller/climate.py @@ -22,7 +21,7 @@ b7f0873109c52be9d7f09bea3dffc416103c50085e1f0680d11661a969479898 ./ha-addon/hom 6509286c7b7de638dcc5d40ce53181e65d1eddc5dc36a13306dc6d87220fedbb ./ha-addon/home-assistant/custom_components/gree_controller/coordinator.py 5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./ha-addon/home-assistant/custom_components/gree_controller/entity_map.py c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./ha-addon/home-assistant/custom_components/gree_controller/icon.png -d467809d894b8cb9e8e04a2cc279e0cec3227c1d1c689098bdc3c0380aa9043e ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json +d1ec103c9a167382e33877183b6df221a5cced5db58cf5d6eefd2eb24ab16077 ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json c52a484b671ce738ecc00228a1db19a5d703f69ab27530c2896a5c2ae3b4a96f ./ha-addon/home-assistant/custom_components/gree_controller/number.py 39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./ha-addon/home-assistant/custom_components/gree_controller/select.py cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/home-assistant/custom_components/gree_controller/sensor.py @@ -30,10 +29,10 @@ cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/hom a745cc458c235158d5d70b6a33d8000fd8b40ff93bfe2f2796af0f4b3a9eef9b ./ha-addon/home-assistant/custom_components/gree_controller/translations/en.json 50b7d6fe6329ad4ea6bee9612ab141c2f73f8382fcc2af0bb076a8e8d4dd4465 ./ha-addon/home-assistant/custom_components/gree_controller/translations/pl.json c5fc5c87273d82d2834a0a5a365c821a416413ed509613441e24e4dc3507c4d2 ./ha-addon/home-assistant/generated/gree_controller_entities.example.json -e3a227ffe23368b152d0ba4a4e81a95b70d35e9870b2a8dc7b2048d6901a7f05 ./ha-addon/repository/gree-controller/CHANGELOG.md -1b5599195329cc3e643c23aa1caadcec80f133e8e515eec7d92b9f3cbda5b80b ./ha-addon/repository/gree-controller/DOCS.md -c3db302f38d26dc9f8caf37a1a8a07a1334cc07ae301d452f2940a5ec5915719 ./ha-addon/repository/gree-controller/README.md -21b82216d0d84cc66ecbed69457caf61174fa9304528fe051c98e8ef7c634025 ./ha-addon/repository/gree-controller/config.yaml +1d1508e247b67487e6aac52b532adec2842494ec2e60144491c5144967a4f8f3 ./ha-addon/repository/gree-controller/CHANGELOG.md +50b8ba050c6b4919e4d057f7b38c1e23d3913b5b7c87552626452e9695d37251 ./ha-addon/repository/gree-controller/DOCS.md +e3834bf712d4cd2acc715d8c85db96dd6e2fb3fbb758dac537f6034c337b3745 ./ha-addon/repository/gree-controller/README.md +d060ee39cdea4de68bd9ededaebb7b81d974821e418b69e00c39cbdebd61f801 ./ha-addon/repository/gree-controller/config.yaml 3aae6cdae4c3aaab7786a9575e7093b7e2c5b69288167075f4b7475611691a6b ./ha-addon/repository/gree-controller/topologia-ha-vlan-gree-pl.png 0d0b42a7639b128946eec379175436fa1f150294f39d2dfd169077bfa87fd14d ./ha-addon/repository/gree-controller/topology-ha-vlan-gree-en.png 2272740b185e9520e948f74b8f45cf98b8b5fd28c93bdee760da626f91fe5c2a ./ha-addon/repository/gree-controller/translations/en.yaml @@ -85,7 +84,7 @@ fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/wind 804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json fd7390d64a2378352c09382accf6efff43903d952d111b22a982f06c5b2a3b4b ./regenerate-sha.sh c64b1c6deeb24f20af662bfce7fa3683703914987241107ce664fa2f6d1a9dcb ./scripts/README.md -81f2d3f512f21d167c6d18bd2bda9d9e1557c0b234aa7826148ea557d726ddc2 ./scripts/api_dev_test.py +b9bd0f1db6bf879ca3778c4969dd56d3c35b7bdd137df517dbd2cd2e11856080 ./scripts/api_dev_test.py 5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh 6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh 1d6e14e26e49aa9d3527f30a23668bf8d9c48b67e6628ef686c3155c012155de ./scripts/dev.sh @@ -98,9 +97,9 @@ e00d211e3885e30d7fed1e43b44e6fdad40a67019060156c0641816a93e3365f ./scripts/netw 81345b6a0b51736bdbc98fd23199b62e4c721b4e7437e02dab7ea79b97dff29a ./scripts/service.sh bd703ef841f9763f13367aaa5764381b9c59ee87210e806c24617f3cc0739a9b ./scripts/smoke.sh b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/update.sh -bd7e0455c6a1501f761f0d4c00ff74833eecbd75078af9168235f90a2d9485b3 ./src/api.rs +f4ace9a1104ab1d0016db1d34c3ac2c4010fc1a5534af5fbf02d2042d5815d8c ./src/api.rs 0db0d81da4b8161004ddcbed2096812c285ecec9d944771670e6c8edf0775175 ./src/api/assets.rs -b24092f34a46626d64628b510eba82193f0b203fd097f6a621b91af5d91eb571 ./src/api/auth.rs +1139dacbd3f6ff94bf721eb5a60d469016fb935ddcf484d71bfeb249b72c833a ./src/api/auth.rs 9e4fc675306e111ed3db7af9822e2925d88109c31b9e309851665a975c0bd83c ./src/api/automations.rs 27a788efe385ad7180cb7fc7ec66c34ebd5e6062d9cdf35b32fb461e52a42863 ./src/api/configuration.rs 19bc141286a336ad67e99079496eb0ae5126f986ab28be62b5f97758e5f6969c ./src/api/debug_tokens.rs @@ -110,16 +109,16 @@ ca21f6d5a407e2e3532899d53ba4e8682c2fe961a46d8cd870ddc459721513ef ./src/api/devi 2ef2f64b77886e2abd6b410adf8de91a2333d3ebdb8fcee8376ba566e5bba029 ./src/api/flows.rs 82c02fa135132ea3ebdb4d88dd1210dc536d22f987151d7f82595ee3d3d03440 ./src/api/gree_cloud.rs b61b0b4f196c5e72e47cf06ca0c14df3cf8eedbdef0242a9d2af33623663489f ./src/api/groups.rs -3cc64b9c992805f3fbf01c0785cf29ce3121750bf30bd6420ed6e5cf2f8df422 ./src/api/history.rs +b6d586bc42b166ac05648f3da7d9aeb88efde2e9eaab5642685eb4d9cf15f95a ./src/api/history.rs e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs 8495967c3df72110f591c744975984c78cafc8181b2d430e7fd5b9baf57eba95 ./src/api/integrations.rs 7658111f7d125db55a6e23f88157339b110b2cd1ed13ceabd8f860b42dba5101 ./src/api/middleware.rs -45e34a447ff384d99a3c42c489ca9fa75849c74d4d246caa91c63d927de17396 ./src/api/openapi.rs +c01b8b942e64a46dac19ce08346aa844df7e9ac7147c0ad6d0f2cfd90e071ec0 ./src/api/openapi.rs b777e7fbeccef699e11ffd16bb18633843c99afecacce2221280e54b09f6d2da ./src/api/public_settings.rs 5b29f2e5aa2c422c5829ef89c7b59cf753883aa7f60661c95ab0f95cf676fa3f ./src/api/schedules.rs fd08162d0f9287700196028ad0ca2aec7c242238056b0a228ca5bdcb319ece4e ./src/api/settings.rs bb57f4b28df75ba350c9706719650fff3a689afee0cb6979c1fcae79396ac0cf ./src/api/system.rs -94d3845def693aafe15fa6e8b390881c46c3c236b62f247ddfdc055d9226ed22 ./src/api/websocket.rs +3b0124a76dbc654584bcf186d43f89d20b6e7fd980ce0ffbf5a9e8eced5ec7f6 ./src/api/websocket.rs ddd1bfc8625b66f6e5f3d24b3122ac86c25f89b0af527e3dfce9102551a8f142 ./src/api/zones.rs 0b7d2ace2e8cb1dd0cb59aa6ca3e80cec14078e93530fd7b58081798585cd833 ./src/config.rs de0ce7807aebe4c0e325fbef01855e7fc1cfd117529f53f04a416fda3997673a ./src/db.rs @@ -156,12 +155,12 @@ af4edaf12faf294f44a8992d120a99b09edd1cbdd66981390e027d13fd6b6790 ./src/engine/t c89ff36c6a67bf4fbf68c43e18aa0a556de2dc69263fd79db376363afc741a4f ./src/engine/zone_actions.rs fb169bcc20f95abe9892367df6dd3a683584bdbc721792d6ffb9311b81ca30d9 ./src/engine/zone_control.rs bfac95cec87f0df6ce562153cd3cfe6731359d703e6c592d2c2f7ba01ea62d99 ./src/error.rs -c55d32f288fe95869fc288d47817b8e289fbe284be4219e81b1e7493ff5e3a57 ./src/home_assistant.rs +a9768150162a010579d40060417e276703e8756c139fcf57dddab9fffc98d840 ./src/home_assistant.rs bcd14e4d1af3ca580f3b95bcd86164c40f762511e1b8e2501cb8a598a6d8adf4 ./src/influxdb.rs da4068295f37c23222bb13bebac022d88ba7729604a49ad25438c55e45458a49 ./src/influxdb/codec.rs 2d36405912646b30b1a1a37a7a4e18c2104ab22e865b593316a609dda884aec2 ./src/influxdb/query.rs 67e42a92295480d2f1d364958f184654cfb5d4b77e7e1df47f588bdec18868a0 ./src/influxdb/write.rs -1982ce54737a8780d1404b105d53db59cd5bee3d1c426f9a881d26cef7059bf5 ./src/main.rs +62f9da6ef4f5fd92701d0857773f9f6236ef25356f21b9b42236abab6ba7da53 ./src/main.rs 23688a5cb68efded89471ce959328d27adff370d451bd9f378a283ab51437e76 ./src/models.rs 920e028d96a14cca9f74a964bb296e68a109cfead314d3164c180201e606d151 ./src/models/automation.rs fc5f2802a073a175a8985e56bcb87eb1ff481226d5b4eeabad73dbba1839fc45 ./src/models/control_plan.rs @@ -175,7 +174,7 @@ f1359b68f1d041cd441f80429e77893eeb6f6194613b58fd3e7a212fb511db3e ./src/models/r c4de6101de85d9d7e6814b2504b87d9216561e3d9e274054f081f505fb152140 ./src/models/temporary_thermostat.rs bc2818ce8d0dae1edfb1b98e5d1c00b193f03eeaa28e343d3532f6023288738c ./src/models/zone.rs 4c1f676eaf0b6da45b4d4b090ae3ac862fb97c1f9e53284a1640767ae9591d8f ./src/notifications.rs -cca742bb2b500eb9269f69385fcf88053cd08aabf6a98b7669b8a7a2fd67df13 ./src/protocol/crypto.rs +7746bca683809b82529ed152272ae5c0cd3971758a02e076def58f770e7adf10 ./src/protocol/crypto.rs daca14e9a4dd65394add7c7753c8ae5e7e43e991323a5ca23d8788aae4428925 ./src/protocol/gree.rs 7907c33e6396c7e0d61705b735b21c84d6ed784012fb61022b872c6745540f1d ./src/protocol/gree/binding.rs 91d82c3ecae21615e4edad31b7ea95dca9b578650348666a2b61475b5a644669 ./src/protocol/gree/commands.rs @@ -186,10 +185,10 @@ ff33db623f8f1bf30015b4a00e1f247a99de713da3d297c672e42c0795ec845c ./src/protocol 1076cb80950be00ca19f9e2370c73040902d1483b0e80c0ca349c7830d38c9f7 ./src/protocol/gree/polling.rs e0555fac67d1dd0129ecfea6d1fd2fbeb1a73ac89ad95d1b74a7094e50e29ae4 ./src/protocol/gree/tests.rs 3c93e5b254a2a40a07854532cb5fc07e493ad65d9ba2cf28093cff4a4a4e451c ./src/protocol/gree/transport.rs -297983059c915057869fbb4f6bcfe752f3d5bd1e93c3a2651a1bf883c739ed29 ./src/protocol/gree_cloud.rs +b4e285f499dd787b75259777a14e3a51a1a071c7d176bcf30c1de0933920e0dc ./src/protocol/gree_cloud.rs b4b1bad9cad889dd69681b2afc3e6a09ef19e19b2a1f2900fd417c4b1f55ec2c ./src/protocol/gree_cloud_mqtt.rs 6258ee3888a5f9a4f8bb6cfbbac97f2621de07f9da6bcb2fa596d452f47f2e49 ./src/protocol/mod.rs -2a08099b456847f24a828d711c4a0aba3fc372936d9a53f0be931f6706226cc5 ./src/provider.rs +a677ce61d3d0f4cf358055ddbc343e73b452c68daed80798499147370819615e ./src/provider.rs 830621fa75265da7288b8135704c0ce27e0687f87d55abf3cdbe40a6e2f3d2b1 ./src/queries.rs 7fac65a9dcbcecee09816f5447c7792dc94f736b1efb66ac85629db75f6280be ./src/queries/device_history.rs 580917b91441fe9b3276cf0cfc31536ba7954b6a86f4080347b93f9367a5b1ac ./src/queries/entities.rs diff --git a/README.md b/README.md index 717437b..58a647e 100644 --- a/README.md +++ b/README.md @@ -2,11 +2,12 @@ Self-hosted controller for GREE-compatible air conditioners with a local Web UI, thermostat zones, schedules, Home Assistant integration, history, notifications and a documented HTTP/WebSocket API. -**Version: 0.15.2** +**Version: 0.15.4** -Version 0.15.2 adds granular single-function unit actions to Visual Flow and exposes fan/Quiet/Turbo/Panel Light/Air/X-Fan/Health/Sleep controls in legacy automations, so automations can change one unit feature without touching unrelated settings. +Version 0.15.4 refreshes the Rust dependency stack, including Axum 0.8, Reqwest 0.13, Rusqlite 0.40, Rand 0.10, RustCrypto AES/AES-GCM and utoipa-swagger-ui 9, with the required compatibility migrations. > [Full API reference](docs/API.md) — authentication, every endpoint, request bodies, response models, WebSocket events and examples. +> Built-in API: `/api/*` and `/ws`; interactive Swagger docs: `/api-docs`; OpenAPI JSON: `/api-docs/openapi.json`. ## What it does diff --git a/SOURCE_MANIFEST.sha256 b/SOURCE_MANIFEST.sha256 index 8692991..0f4947c 100644 --- a/SOURCE_MANIFEST.sha256 +++ b/SOURCE_MANIFEST.sha256 @@ -1,18 +1,17 @@ de0793949cf01d27d903653226ecc9b5f72523d8711f20bcab022cf42c4c4ed0 ./.env.example a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore -82bb41f94fdf5c66ebd9e6caa92e0f1794431067298e0a27c95c8e5bfd68de89 ./Cargo.lock -39bdb16196253559e3487aa912ff770c09c7b08cdfbb21e9db1d8af1304ea7e0 ./Cargo.toml +37e255dd094e4720f96b74e501a179cf81c838ff327cbc1924b8fc4b5ea555fa ./Cargo.toml 19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE -84a0803bc75dc3199e23ef56c11c6950e8bd888c686ecda7cc369829e8e3073f ./README.md +c1cac4ca532e73d64e5b090ad410a2161e9790b8d77fc6732adf52c248fb3472 ./README.md 29e9821e5ed216ea3565dd6d8bc0b174ed3cf9fa72c4ccebbfa99e98db3ad8f9 ./build.rs -604a795dec077dd7e4f3462a564fdda68e8084aef07da0fcf3dfb6053a46cc58 ./docs/API.md +0da3db314314e19a00c08700f94495075fecd1e54a5b188f6a62cb237307e96f ./docs/API.md a881ba0808dd3f189d92038f6163c39d6b6208f6dbff5c32c0ea1a2628f3fbb4 ./docs/FLOW.md -8babaa6830fa70b2d3d8208ef51808e79c9d68c4e007b9ba1537fe582ba03b3d ./docs/openapi.json -c65aa543d2e99f8f7d52736307b07ebd182597d80124661d53a16bb23f6f1118 ./ha-addon/.env.example -0993076ca45b6d31859680835204cdc111b3f9bdbf460d50b4efec56cd5e685b ./ha-addon/Dockerfile -adf7ff248d782a3b1cba82b8789c57b6849ddaaaf5fbc108af75e18b1534a885 ./ha-addon/README.md -dd9291b12afade6fc20d66e80a5513251270e18e4c265260b2bbbe393a5a94c4 ./ha-addon/build.sh -4061846cec4d829e4101b4021df7f07dc2e0293ccfd11e91589f49733ec7c5b4 ./ha-addon/home-assistant/README.md +55ffdcc5b0a43d930823cea7c94235990dbbc4a35b60832b9adca1faf606d036 ./docs/openapi.json +77b8becf7a2c16a384ea85721d878b76e2d520549cb4455d9aa806e57e5a2ecd ./ha-addon/.env.example +0ca6e58170c2b8925194431ebbdb55f0c8b377fec5cd422cd2bd257e2d9328e3 ./ha-addon/Dockerfile +0951696a2c2e66d4d969f8e7f8641184e3012f261583b31074bc38a7a1c0cc1a ./ha-addon/README.md +a4596a70e50acfe698a8ae1dcb9bebd04adba95b69781218fca7add82c17703e ./ha-addon/build.sh +7dd2534a6f8405e640e28b7cb0e94270cc5f01fad8a972193ec254befe8a96b9 ./ha-addon/home-assistant/README.md f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./ha-addon/home-assistant/custom_components/gree_controller/__init__.py 3f6ef15ef58456376ac53fde7cace1ef359d6a6f7a64c5b575ad77ea6e55ccc4 ./ha-addon/home-assistant/custom_components/gree_controller/api.py da2a0a9390ab75cef150cd281bc329fa409d0d28f51382b36bd8de3a73325c16 ./ha-addon/home-assistant/custom_components/gree_controller/climate.py @@ -21,7 +20,7 @@ b7f0873109c52be9d7f09bea3dffc416103c50085e1f0680d11661a969479898 ./ha-addon/hom 6509286c7b7de638dcc5d40ce53181e65d1eddc5dc36a13306dc6d87220fedbb ./ha-addon/home-assistant/custom_components/gree_controller/coordinator.py 5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./ha-addon/home-assistant/custom_components/gree_controller/entity_map.py c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./ha-addon/home-assistant/custom_components/gree_controller/icon.png -d467809d894b8cb9e8e04a2cc279e0cec3227c1d1c689098bdc3c0380aa9043e ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json +d1ec103c9a167382e33877183b6df221a5cced5db58cf5d6eefd2eb24ab16077 ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json c52a484b671ce738ecc00228a1db19a5d703f69ab27530c2896a5c2ae3b4a96f ./ha-addon/home-assistant/custom_components/gree_controller/number.py 39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./ha-addon/home-assistant/custom_components/gree_controller/select.py cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/home-assistant/custom_components/gree_controller/sensor.py @@ -29,10 +28,10 @@ cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/hom a745cc458c235158d5d70b6a33d8000fd8b40ff93bfe2f2796af0f4b3a9eef9b ./ha-addon/home-assistant/custom_components/gree_controller/translations/en.json 50b7d6fe6329ad4ea6bee9612ab141c2f73f8382fcc2af0bb076a8e8d4dd4465 ./ha-addon/home-assistant/custom_components/gree_controller/translations/pl.json c5fc5c87273d82d2834a0a5a365c821a416413ed509613441e24e4dc3507c4d2 ./ha-addon/home-assistant/generated/gree_controller_entities.example.json -e3a227ffe23368b152d0ba4a4e81a95b70d35e9870b2a8dc7b2048d6901a7f05 ./ha-addon/repository/gree-controller/CHANGELOG.md -1b5599195329cc3e643c23aa1caadcec80f133e8e515eec7d92b9f3cbda5b80b ./ha-addon/repository/gree-controller/DOCS.md -c3db302f38d26dc9f8caf37a1a8a07a1334cc07ae301d452f2940a5ec5915719 ./ha-addon/repository/gree-controller/README.md -21b82216d0d84cc66ecbed69457caf61174fa9304528fe051c98e8ef7c634025 ./ha-addon/repository/gree-controller/config.yaml +1d1508e247b67487e6aac52b532adec2842494ec2e60144491c5144967a4f8f3 ./ha-addon/repository/gree-controller/CHANGELOG.md +50b8ba050c6b4919e4d057f7b38c1e23d3913b5b7c87552626452e9695d37251 ./ha-addon/repository/gree-controller/DOCS.md +e3834bf712d4cd2acc715d8c85db96dd6e2fb3fbb758dac537f6034c337b3745 ./ha-addon/repository/gree-controller/README.md +d060ee39cdea4de68bd9ededaebb7b81d974821e418b69e00c39cbdebd61f801 ./ha-addon/repository/gree-controller/config.yaml 3aae6cdae4c3aaab7786a9575e7093b7e2c5b69288167075f4b7475611691a6b ./ha-addon/repository/gree-controller/topologia-ha-vlan-gree-pl.png 0d0b42a7639b128946eec379175436fa1f150294f39d2dfd169077bfa87fd14d ./ha-addon/repository/gree-controller/topology-ha-vlan-gree-en.png 2272740b185e9520e948f74b8f45cf98b8b5fd28c93bdee760da626f91fe5c2a ./ha-addon/repository/gree-controller/translations/en.yaml @@ -84,7 +83,7 @@ fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/wind 804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json fd7390d64a2378352c09382accf6efff43903d952d111b22a982f06c5b2a3b4b ./regenerate-sha.sh c64b1c6deeb24f20af662bfce7fa3683703914987241107ce664fa2f6d1a9dcb ./scripts/README.md -81f2d3f512f21d167c6d18bd2bda9d9e1557c0b234aa7826148ea557d726ddc2 ./scripts/api_dev_test.py +b9bd0f1db6bf879ca3778c4969dd56d3c35b7bdd137df517dbd2cd2e11856080 ./scripts/api_dev_test.py 5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh 6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh 1d6e14e26e49aa9d3527f30a23668bf8d9c48b67e6628ef686c3155c012155de ./scripts/dev.sh @@ -97,9 +96,9 @@ e00d211e3885e30d7fed1e43b44e6fdad40a67019060156c0641816a93e3365f ./scripts/netw 81345b6a0b51736bdbc98fd23199b62e4c721b4e7437e02dab7ea79b97dff29a ./scripts/service.sh bd703ef841f9763f13367aaa5764381b9c59ee87210e806c24617f3cc0739a9b ./scripts/smoke.sh b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/update.sh -bd7e0455c6a1501f761f0d4c00ff74833eecbd75078af9168235f90a2d9485b3 ./src/api.rs +f4ace9a1104ab1d0016db1d34c3ac2c4010fc1a5534af5fbf02d2042d5815d8c ./src/api.rs 0db0d81da4b8161004ddcbed2096812c285ecec9d944771670e6c8edf0775175 ./src/api/assets.rs -b24092f34a46626d64628b510eba82193f0b203fd097f6a621b91af5d91eb571 ./src/api/auth.rs +1139dacbd3f6ff94bf721eb5a60d469016fb935ddcf484d71bfeb249b72c833a ./src/api/auth.rs 9e4fc675306e111ed3db7af9822e2925d88109c31b9e309851665a975c0bd83c ./src/api/automations.rs 27a788efe385ad7180cb7fc7ec66c34ebd5e6062d9cdf35b32fb461e52a42863 ./src/api/configuration.rs 19bc141286a336ad67e99079496eb0ae5126f986ab28be62b5f97758e5f6969c ./src/api/debug_tokens.rs @@ -109,16 +108,16 @@ ca21f6d5a407e2e3532899d53ba4e8682c2fe961a46d8cd870ddc459721513ef ./src/api/devi 2ef2f64b77886e2abd6b410adf8de91a2333d3ebdb8fcee8376ba566e5bba029 ./src/api/flows.rs 82c02fa135132ea3ebdb4d88dd1210dc536d22f987151d7f82595ee3d3d03440 ./src/api/gree_cloud.rs b61b0b4f196c5e72e47cf06ca0c14df3cf8eedbdef0242a9d2af33623663489f ./src/api/groups.rs -3cc64b9c992805f3fbf01c0785cf29ce3121750bf30bd6420ed6e5cf2f8df422 ./src/api/history.rs +b6d586bc42b166ac05648f3da7d9aeb88efde2e9eaab5642685eb4d9cf15f95a ./src/api/history.rs e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs 8495967c3df72110f591c744975984c78cafc8181b2d430e7fd5b9baf57eba95 ./src/api/integrations.rs 7658111f7d125db55a6e23f88157339b110b2cd1ed13ceabd8f860b42dba5101 ./src/api/middleware.rs -45e34a447ff384d99a3c42c489ca9fa75849c74d4d246caa91c63d927de17396 ./src/api/openapi.rs +c01b8b942e64a46dac19ce08346aa844df7e9ac7147c0ad6d0f2cfd90e071ec0 ./src/api/openapi.rs b777e7fbeccef699e11ffd16bb18633843c99afecacce2221280e54b09f6d2da ./src/api/public_settings.rs 5b29f2e5aa2c422c5829ef89c7b59cf753883aa7f60661c95ab0f95cf676fa3f ./src/api/schedules.rs fd08162d0f9287700196028ad0ca2aec7c242238056b0a228ca5bdcb319ece4e ./src/api/settings.rs bb57f4b28df75ba350c9706719650fff3a689afee0cb6979c1fcae79396ac0cf ./src/api/system.rs -94d3845def693aafe15fa6e8b390881c46c3c236b62f247ddfdc055d9226ed22 ./src/api/websocket.rs +3b0124a76dbc654584bcf186d43f89d20b6e7fd980ce0ffbf5a9e8eced5ec7f6 ./src/api/websocket.rs ddd1bfc8625b66f6e5f3d24b3122ac86c25f89b0af527e3dfce9102551a8f142 ./src/api/zones.rs 0b7d2ace2e8cb1dd0cb59aa6ca3e80cec14078e93530fd7b58081798585cd833 ./src/config.rs de0ce7807aebe4c0e325fbef01855e7fc1cfd117529f53f04a416fda3997673a ./src/db.rs @@ -155,12 +154,12 @@ af4edaf12faf294f44a8992d120a99b09edd1cbdd66981390e027d13fd6b6790 ./src/engine/t c89ff36c6a67bf4fbf68c43e18aa0a556de2dc69263fd79db376363afc741a4f ./src/engine/zone_actions.rs fb169bcc20f95abe9892367df6dd3a683584bdbc721792d6ffb9311b81ca30d9 ./src/engine/zone_control.rs bfac95cec87f0df6ce562153cd3cfe6731359d703e6c592d2c2f7ba01ea62d99 ./src/error.rs -c55d32f288fe95869fc288d47817b8e289fbe284be4219e81b1e7493ff5e3a57 ./src/home_assistant.rs +a9768150162a010579d40060417e276703e8756c139fcf57dddab9fffc98d840 ./src/home_assistant.rs bcd14e4d1af3ca580f3b95bcd86164c40f762511e1b8e2501cb8a598a6d8adf4 ./src/influxdb.rs da4068295f37c23222bb13bebac022d88ba7729604a49ad25438c55e45458a49 ./src/influxdb/codec.rs 2d36405912646b30b1a1a37a7a4e18c2104ab22e865b593316a609dda884aec2 ./src/influxdb/query.rs 67e42a92295480d2f1d364958f184654cfb5d4b77e7e1df47f588bdec18868a0 ./src/influxdb/write.rs -1982ce54737a8780d1404b105d53db59cd5bee3d1c426f9a881d26cef7059bf5 ./src/main.rs +62f9da6ef4f5fd92701d0857773f9f6236ef25356f21b9b42236abab6ba7da53 ./src/main.rs 23688a5cb68efded89471ce959328d27adff370d451bd9f378a283ab51437e76 ./src/models.rs 920e028d96a14cca9f74a964bb296e68a109cfead314d3164c180201e606d151 ./src/models/automation.rs fc5f2802a073a175a8985e56bcb87eb1ff481226d5b4eeabad73dbba1839fc45 ./src/models/control_plan.rs @@ -174,7 +173,7 @@ f1359b68f1d041cd441f80429e77893eeb6f6194613b58fd3e7a212fb511db3e ./src/models/r c4de6101de85d9d7e6814b2504b87d9216561e3d9e274054f081f505fb152140 ./src/models/temporary_thermostat.rs bc2818ce8d0dae1edfb1b98e5d1c00b193f03eeaa28e343d3532f6023288738c ./src/models/zone.rs 4c1f676eaf0b6da45b4d4b090ae3ac862fb97c1f9e53284a1640767ae9591d8f ./src/notifications.rs -cca742bb2b500eb9269f69385fcf88053cd08aabf6a98b7669b8a7a2fd67df13 ./src/protocol/crypto.rs +7746bca683809b82529ed152272ae5c0cd3971758a02e076def58f770e7adf10 ./src/protocol/crypto.rs daca14e9a4dd65394add7c7753c8ae5e7e43e991323a5ca23d8788aae4428925 ./src/protocol/gree.rs 7907c33e6396c7e0d61705b735b21c84d6ed784012fb61022b872c6745540f1d ./src/protocol/gree/binding.rs 91d82c3ecae21615e4edad31b7ea95dca9b578650348666a2b61475b5a644669 ./src/protocol/gree/commands.rs @@ -185,10 +184,10 @@ ff33db623f8f1bf30015b4a00e1f247a99de713da3d297c672e42c0795ec845c ./src/protocol 1076cb80950be00ca19f9e2370c73040902d1483b0e80c0ca349c7830d38c9f7 ./src/protocol/gree/polling.rs e0555fac67d1dd0129ecfea6d1fd2fbeb1a73ac89ad95d1b74a7094e50e29ae4 ./src/protocol/gree/tests.rs 3c93e5b254a2a40a07854532cb5fc07e493ad65d9ba2cf28093cff4a4a4e451c ./src/protocol/gree/transport.rs -297983059c915057869fbb4f6bcfe752f3d5bd1e93c3a2651a1bf883c739ed29 ./src/protocol/gree_cloud.rs +b4e285f499dd787b75259777a14e3a51a1a071c7d176bcf30c1de0933920e0dc ./src/protocol/gree_cloud.rs b4b1bad9cad889dd69681b2afc3e6a09ef19e19b2a1f2900fd417c4b1f55ec2c ./src/protocol/gree_cloud_mqtt.rs 6258ee3888a5f9a4f8bb6cfbbac97f2621de07f9da6bcb2fa596d452f47f2e49 ./src/protocol/mod.rs -2a08099b456847f24a828d711c4a0aba3fc372936d9a53f0be931f6706226cc5 ./src/provider.rs +a677ce61d3d0f4cf358055ddbc343e73b452c68daed80798499147370819615e ./src/provider.rs 830621fa75265da7288b8135704c0ce27e0687f87d55abf3cdbe40a6e2f3d2b1 ./src/queries.rs 7fac65a9dcbcecee09816f5447c7792dc94f736b1efb66ac85629db75f6280be ./src/queries/device_history.rs 580917b91441fe9b3276cf0cfc31536ba7954b6a86f4080347b93f9367a5b1ac ./src/queries/entities.rs diff --git a/docs/API.md b/docs/API.md index 6a5b596..e5fa901 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,6 +1,6 @@ # GREE Controller API reference -HTTP and WebSocket API for GREE Controller **0.15.2**. +HTTP and WebSocket API for GREE Controller **0.15.4**. [← Main documentation](../README.md) @@ -240,7 +240,7 @@ Response: { "status": "ok", "name": "gree-controller", - "version": "0.15.2", + "version": "0.15.4", "uptime_seconds": 1234, "control_ready": true, "time": "2026-08-30T06:54:00Z" @@ -303,7 +303,7 @@ Returns the initial Web UI snapshot: "control_plan": {"generated_at": "2026-09-04T08:00:00Z", "zones": [], "rules": []}, "control_plan_revision": 42, "system": { - "version": "0.15.2", + "version": "0.15.4", "uptime_seconds": 1234, "auth_required": false, "control_ready": true, diff --git a/docs/openapi.json b/docs/openapi.json index 4b17fda..48de255 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -2,9 +2,9 @@ "openapi": "3.1.0", "info": { "title": "GREE Controller API", - "version": "0.15.2", - "summary": "Local HTTP/WebSocket API for GREE HVAC control", - "description": "Self-hosted API used by the GREE Controller Web UI and Home Assistant integration.\n\n### Authentication\nAdministrator endpoints accept `Authorization: Bearer ` or `x-api-token: ` when configured. Restricted Home Assistant control endpoints also accept generated integration tokens.\n\n### Local and GREE Cloud\nDevices use one API model and one command surface. `connection_type=local` is dispatched only to the existing LAN/UDP provider; `connection_type=gree_cloud` is dispatched only to the GREE Cloud provider. No automatic transport fallback is performed.\n\n### GREE Cloud security\nCloud passwords, REST/MQTT tokens, Authorization values and device cipher keys are never returned in normal API responses or Cloud diagnostics. MQTT uses TLS with certificate and hostname validation.\n\n### Energy\nGREE Cloud `ElcAll` and selected Home Assistant cumulative energy sensors are normalized to kWh and converted to consumption deltas before aggregation. Raw cumulative values are retained only as meter samples/baselines.\n\n### 0.15.2\nAdds a dedicated Visual Flow single-function GREE action and optional fan/Quiet/Turbo/Panel Light/Air/X-Fan/Health/Sleep fields to legacy device automations, allowing one unit function to change without touching unrelated settings.\n\n### 0.15.1\nImproves Web UI WebSocket state handling: temporary disconnects show a reconnecting state, persistent failures escalate after 15 seconds, and successful reconnects restore the connected state while the existing HTTP fallback remains active.\n\n### 0.15.0\nAdds granular vertical/horizontal louver positions across direct control, thermostat views, legacy automations, Visual Flow and the bundled Home Assistant integration. Legacy boolean swing command payloads remain accepted. Direct add-on access now shows an invalid-token error only after an explicit token submission.\n\n### 0.14.24\nPublic Custom Charts now fetch chart metadata before language assets, use English for missing-chart errors, support pinch-to-zoom/panning and clickable metric legends, and include the related missing-ID, favicon and Access Token UX fixes.\n\n### 0.14.23\nCode cleanup and small UX changes.\n\n### 0.14.22\nCode cleanup and small UX changes.\n\n### 0.14.21\nCode cleanup and small UX changes.\n\n### 0.14.20\nFixes the ARM cross-build bootstrap by removing the invalid xx-cargo version probe, prepares the target Rust standard library in a cacheable pre-source layer, shares dependency fetching across target architectures, and isolates compiled target caches per architecture while preserving DISTRO-selected Alpine/musl and Debian Trixie/glibc runtimes.\n\n### 0.14.19\nHome Assistant OCI builds now compile Rust for amd64/arm64 on the native build platform through xx cross-compilation, keep Cargo registry/target caches between builds, and send a smaller Docker context while preserving the selected Alpine (musl) or Debian Trixie (glibc) runtime. The Web UI also deduplicates the initial GREE Cloud runtime-status GET across the HTTP and WebSocket bootstrap renders.\n\n### 0.14.18\nShared Web UI CSS now uses generic reusable class names for segmented tabs, configuration layouts, chart cards, enable toggles, diagram primitives and Flow block categories; behavior and visual styling are unchanged.\n\n### 0.14.17\nHistory navigation now reuses the same segmented tab component as Flow / Schedules / Automations, with redundant History-specific tab CSS removed.\n\n### 0.14.16\nCustom Charts now expose saved-chart editing in the Web UI, public chart pages can switch history range through an optional hours override, and the standalone chart layout fits the viewport without vertical page scrolling.\n\n### 0.14.15\nHome Assistant add-on Custom Chart links now resolve the primary HA host IPv4 through Supervisor, support an explicit public_chart_base_url override, and enforce the fixed 8787 ingress/application port contract at startup and build time. Standalone bind/port behavior remains configurable.\n\n### 0.14.14\nShared Flow input Home Assistant sources now expose a dedicated entity search box separate from the selected entity_id, making large live entity catalogs easy to filter by name, ID and state.\n\n### 0.14.13\nHome Assistant add-on authentication is now hidden behind an automatic Supervisor status, manual URL/token fallback is unlocked only after a failed HA test, connection tests return a live sample entity reading, and Shared Flow input HA sources include searchable live entity suggestions.\n\n### 0.14.12\nThe Home Assistant add-on now uses the Supervisor Core API proxy and runtime SUPERVISOR_TOKEN automatically; standalone Home Assistant URL/token configuration is unchanged.\n\n### 0.14.11\nWeb UI icons now use a shared inline SVG set instead of font-dependent Unicode glyphs across navigation, dialogs, Flow, charts, controls and event categories for consistent cross-platform rendering.\n\n\n### 0.14.10\nNight mode and Home Assistant / Sensors standalone settings now use the full available page width, matching the other Web UI sections.\n\n### 0.14.9\nPower controls use an embedded SVG icon instead of a font-dependent Unicode glyph. Home Assistant room-sensor stale/error events identify the affected entity and zone, and historical event rows can recover that context from metadata.\n\n### 0.14.8\nRemaining Home Assistant and notification diagnostic errors no longer use device-transport 502 responses. Missing/invalid integration configuration returns 400, configured external dependency failures return 424, and 502 is reserved for Local/LAN GREE device communication.\n\n### 0.14.7\nHome Assistant energy-sensor discovery now returns an empty optional result when HA is not configured, uses 424 for configured external-dependency failures, and custom select popovers use their rendered height when positioning above a field.\n\n\n### 0.14.6\nFixes dynamic custom-select duplication in History → Energy and hides Energy history controls when no energy source is configured.\n\n### 0.14.5\nWeb UI single-choice controls now use one consistent custom dropdown, language packs are loaded on demand, and the dashboard outdoor temperature opens a 24-hour history modal.\n\n### 0.14.4\nHome Assistant connection tests validate only the configured server/API token and require no entity. `outdoor_entity_id` is the global Home Assistant outdoor-temperature sensor; zones can override it with `ha_outdoor_entity_id`. Room-temperature Home Assistant sensors remain configured per zone with `ha_entity_id`. Global/per-zone outdoor sensors are integrated with aliases, metrics/history and Visual Flow entity suggestions.\n\n### 0.14.2\nAdds independent vertical/horizontal swing controls across manual device control, thermostat zones, legacy automations, Visual Flow and Home Assistant zone climates. Swing is treated as an auxiliary one-shot unit setting and does not replace thermostat ownership.\n\n### 0.14.1\nAdds split/multisplit installation groups with shared energy and outdoor-temperature sources, multi-target energy charts with period comparison, cleaner Cloud status/alerts and safe MQTT cleanup after the last Cloud device is removed.\n\n### 0.14.0\nAdds first-class GREE Cloud MQTT status/control, reconnect/resubscribe lifecycle, Cloud diagnostics, per-device capabilities, Cloud/HA energy sources and energy-history aggregation while preserving the LAN transport contract.", + "version": "0.15.4", + "summary": "Local HTTP/WebSocket API for GREE Controller", + "description": "Local API used by the GREE Controller Web UI and Home Assistant integration.", "license": { "name": "MIT" } @@ -5900,7 +5900,7 @@ }, "version": { "type": "string", - "example": "0.15.2" + "example": "0.15.4" }, "uptime_seconds": { "type": "integer", diff --git a/ha-addon/.env.example b/ha-addon/.env.example index 592c7bb..ef844f9 100644 --- a/ha-addon/.env.example +++ b/ha-addon/.env.example @@ -2,7 +2,7 @@ REGISTRY=repo.example.com IMAGE_NAME=gree-controller DISTRO=alpine -RUST_VERSION=1.89 +RUST_VERSION=1.98.1 BUILD_PLATFORMS=linux/amd64,linux/arm64 BUILDER=gree-controller-multiarch BUILDER_CONFIG= diff --git a/ha-addon/Dockerfile b/ha-addon/Dockerfile index 256a10b..3606f50 100644 --- a/ha-addon/Dockerfile +++ b/ha-addon/Dockerfile @@ -1,5 +1,5 @@ # syntax=docker/dockerfile:1.7 -ARG RUST_VERSION=1.89 +ARG RUST_VERSION=1.98.1 ARG XX_VERSION=1.9.0 # Cross-compilation helpers. Builder stages always run on BUILDPLATFORM, so an @@ -16,11 +16,12 @@ RUN apt-get update \ # Fetch Rust dependencies before TARGETPLATFORM enters the cache chain, so the # same registry/git cache is reused by amd64 and arm64 builds. -COPY Cargo.toml Cargo.lock ./ +COPY Cargo.toml ./ RUN --mount=type=cache,id=gree-controller-cargo-registry,target=/usr/local/cargo/registry \ --mount=type=cache,id=gree-controller-cargo-git,target=/usr/local/cargo/git \ mkdir -p src \ && printf 'fn main() {}\n' > src/main.rs \ + && cargo generate-lockfile \ && cargo fetch --locked \ && rm -rf src @@ -56,11 +57,12 @@ WORKDIR /src RUN apk add --no-cache clang lld llvm file pkgconf # Keep dependency fetching architecture-independent here as well. -COPY Cargo.toml Cargo.lock ./ +COPY Cargo.toml ./ RUN --mount=type=cache,id=gree-controller-cargo-registry,target=/usr/local/cargo/registry \ --mount=type=cache,id=gree-controller-cargo-git,target=/usr/local/cargo/git \ mkdir -p src \ && printf 'fn main() {}\n' > src/main.rs \ + && cargo generate-lockfile \ && cargo fetch --locked \ && rm -rf src diff --git a/ha-addon/README.md b/ha-addon/README.md index 3f002c4..73f4260 100644 --- a/ha-addon/README.md +++ b/ha-addon/README.md @@ -2,6 +2,8 @@ This directory contains the OCI build, Home Assistant add-on repository source, custom integration and repository synchronization tooling. +The packaged controller includes its HTTP/WebSocket API and built-in Swagger documentation at `/api-docs` (`/api-docs/openapi.json` for OpenAPI 3.1). + ## Configuration Create the local build/repository configuration once: @@ -20,7 +22,7 @@ Important variables: REGISTRY=repo.example.com IMAGE_NAME=gree-controller DISTRO=alpine -RUST_VERSION=1.89 +RUST_VERSION=1.98.1 BUILD_PLATFORMS=linux/amd64,linux/arm64 BUILDER=gree-controller-multiarch BUILDER_CONFIG= @@ -40,7 +42,7 @@ INTEGRATION_DOMAIN=gree_controller ./build.sh push ``` -The project version comes only from root `Cargo.toml`. `render` synchronizes it to `Cargo.lock`, add-on `config.yaml` and the custom integration `manifest.json`, and sets the OCI image from `.env`. +The project version comes only from root `Cargo.toml`. `render` synchronizes it to add-on `config.yaml` and the custom integration `manifest.json`, and sets the OCI image from `.env`. The container build generates `Cargo.lock` from the exact direct dependency versions in `Cargo.toml` before fetching and compiling dependencies. For the Home Assistant package, TCP `8787` is an intentional fixed host-network/ingress port contract. `build.sh render` verifies `config.yaml`, `run.sh`, the watchdog URL and Docker image metadata stay consistent. The runtime also compares the Supervisor-reported ingress port before starting. Standalone installations remain free to use any `GREE_CONTROLLER_BIND` port. diff --git a/ha-addon/build.sh b/ha-addon/build.sh index 273f53b..522eb3a 100755 --- a/ha-addon/build.sh +++ b/ha-addon/build.sh @@ -32,7 +32,6 @@ VERSION="$(awk -F '"' '/^version = "/ {print $2; exit}' "$PROJECT_ROOT/Cargo.tom IMAGE_REPO="${REGISTRY%/}/${IMAGE_NAME#/}" IMAGE_TAG="${IMAGE_REPO}:${VERSION}" CONFIG="$SCRIPT_DIR/repository/$ADDON_DIR/config.yaml" -LOCKFILE="$PROJECT_ROOT/Cargo.lock" INTEGRATION_MANIFEST="$SCRIPT_DIR/home-assistant/custom_components/$INTEGRATION_DOMAIN/manifest.json" REPOSITORY_CONFIG="$SCRIPT_DIR/repository/repository.yaml" RUN_SCRIPT="$SCRIPT_DIR/run.sh" @@ -44,18 +43,16 @@ DOCKERFILE="$SCRIPT_DIR/Dockerfile" render_metadata() { command -v python3 >/dev/null 2>&1 || { echo "python3 is required" >&2; exit 1; } - python3 - "$CONFIG" "$LOCKFILE" "$INTEGRATION_MANIFEST" "$REPOSITORY_CONFIG" "$VERSION" "$IMAGE_REPO" "$HA_REPO_URL" <<'PY' + python3 - "$CONFIG" "$INTEGRATION_MANIFEST" "$REPOSITORY_CONFIG" "$VERSION" "$IMAGE_REPO" "$HA_REPO_URL" <<'PY' from pathlib import Path -import re import sys config = Path(sys.argv[1]) -lockfile = Path(sys.argv[2]) -manifest = Path(sys.argv[3]) -repository = Path(sys.argv[4]) -version = sys.argv[5] -image = sys.argv[6] -repo_url = sys.argv[7] +manifest = Path(sys.argv[2]) +repository = Path(sys.argv[3]) +version = sys.argv[4] +image = sys.argv[5] +repo_url = sys.argv[6] lines = config.read_text(encoding="utf-8").splitlines() out = [] @@ -70,13 +67,6 @@ for line in lines: out.append(line) config.write_text("\n".join(out) + "\n", encoding="utf-8") -lock = lockfile.read_text(encoding="utf-8") -pattern = r'(\[\[package\]\]\nname = "gree-controller"\nversion = ")[^"]+("\n)' -updated, count = re.subn(pattern, rf'\g<1>{version}\g<2>', lock, count=1) -if count != 1: - raise SystemExit("Could not find gree-controller package version in Cargo.lock") -lockfile.write_text(updated, encoding="utf-8") - import json data = json.loads(manifest.read_text(encoding="utf-8")) data["version"] = version diff --git a/ha-addon/home-assistant/README.md b/ha-addon/home-assistant/README.md index 169eebf..59f3958 100644 --- a/ha-addon/home-assistant/README.md +++ b/ha-addon/home-assistant/README.md @@ -8,6 +8,8 @@ ha-addon/home-assistant/custom_components/gree_controller/ It creates HA entities for physical units, thermostat zones, whole-house controls and climate groups, while sending every command to the standalone Rust controller. Home Assistant therefore remains a client and UDP/AES GREE communication stays outside HA. +The controller exposes the API used by the integration and Web UI under `/api/*` and `/ws`; interactive Swagger documentation is available at `/api-docs`, with OpenAPI JSON at `/api-docs/openapi.json`. + The climate proxy supports power/turn on/off, HVAC modes, target temperature, fan mode, granular vertical louver positions and granular horizontal louver positions. `off`/`on` remain the first two swing modes for compatibility, followed by fixed positions and the supported vertical partial-swing ranges. The card UI translates those modes using the Home Assistant language while the underlying mode IDs (for example `fixed_upper`) remain unchanged for services, scripts and automations. Automation plan: diff --git a/ha-addon/home-assistant/custom_components/gree_controller/manifest.json b/ha-addon/home-assistant/custom_components/gree_controller/manifest.json index 7a788b5..466a331 100644 --- a/ha-addon/home-assistant/custom_components/gree_controller/manifest.json +++ b/ha-addon/home-assistant/custom_components/gree_controller/manifest.json @@ -1,7 +1,7 @@ { "domain": "gree_controller", "name": "GREE Controller", - "version": "0.15.2", + "version": "0.15.4", "config_flow": true, "integration_type": "hub", "iot_class": "local_polling", diff --git a/ha-addon/repository/gree-controller/CHANGELOG.md b/ha-addon/repository/gree-controller/CHANGELOG.md index bed02e9..715baa6 100644 --- a/ha-addon/repository/gree-controller/CHANGELOG.md +++ b/ha-addon/repository/gree-controller/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 0.15.4 + +- Updates the Rust dependency stack to current major/minor releases, including Axum 0.8, Reqwest 0.13, Rusqlite 0.40, Rand 0.10, AES 0.9, AES-GCM 0.11, Base64 0.23, SHA-2 0.11, Tower HTTP 0.7 and utoipa-swagger-ui 9. +- Migrates Axum route parameters and WebSocket text frames, Rand APIs, RustCrypto AES/AES-GCM APIs and Reqwest TLS configuration for the new dependency versions. +- Updates the Home Assistant add-on Rust builder to Rust 1.98.1. +- Pins direct Rust dependencies to exact updated releases; container builds generate a fresh lockfile before fetching and compiling with `--locked`. +- Uses `ring` as the single Rustls crypto provider across Reqwest and the direct MQTT TLS client, avoiding the Rustls provider ambiguity introduced by Reqwest 0.13. + +## 0.15.3 + +- Simplifies the built-in Swagger API documentation: removes the embedded release-history changelog, starts with all endpoint groups collapsed and hides the global Schemas section. +- Documents the HTTP/WebSocket API, Swagger UI (`/api-docs`) and OpenAPI document (`/api-docs/openapi.json`) in the main documentation and Home Assistant add-on package. + ## 0.15.2 - Adds a dedicated Visual Flow action for changing exactly one GREE unit function without modifying unrelated settings. diff --git a/ha-addon/repository/gree-controller/DOCS.md b/ha-addon/repository/gree-controller/DOCS.md index 0dc0bec..d22da09 100644 --- a/ha-addon/repository/gree-controller/DOCS.md +++ b/ha-addon/repository/gree-controller/DOCS.md @@ -59,6 +59,10 @@ Broadcast zwykle nie przechodzi przez router. Sterowanie unicast może działać | `public_chart_base_url` | opcjonalny bazowy URL publicznych linków Custom Chart; puste = automatyczne główne IPv4 hosta HA + `:8787` | | `log_level` | `error`, `warn`, `info`, `debug`, `trace` | +### API i dokumentacja API + +Aplikacja udostępnia HTTP API pod `/api/*` oraz WebSocket pod `/ws`. Interaktywna dokumentacja Swagger jest dostępna pod `/api-docs`, a dokument OpenAPI 3.1 pod `/api-docs/openapi.json`. Te same ścieżki działają przez ingress Home Assistant; bezpośredni dostęp na porcie `8787` podlega regułom `app_token`. + ### Home Assistant API Dodatek korzysta automatycznie z wewnętrznego proxy Home Assistant Core (`http://supervisor/core/api/`) i tokenu `SUPERVISOR_TOKEN` przekazywanego przez Supervisor. Gdy token jest wykryty, UI pokazuje automatyczną autoryzację i ukrywa ręczne pola URL/token. Dopiero nieudany `Test HA` odblokowuje awaryjny ręczny fallback. Token Supervisor jest używany tylko w pamięci procesu i nie jest zapisywany w SQLite. @@ -125,6 +129,10 @@ Broadcast normally does not cross routers. Unicast control may work through rout | `public_chart_base_url` | optional base URL for public Custom Chart links; empty = primary HA host IPv4 + `:8787` automatically | | `log_level` | `error`, `warn`, `info`, `debug`, `trace` | +### API and API documentation + +The application exposes its HTTP API under `/api/*` and WebSocket under `/ws`. Interactive Swagger documentation is available at `/api-docs`, with the OpenAPI 3.1 document at `/api-docs/openapi.json`. The same paths work through Home Assistant ingress; direct access on port `8787` follows the configured `app_token` rules. + ### Home Assistant API The add-on automatically uses the internal Home Assistant Core proxy (`http://supervisor/core/api/`) and the runtime `SUPERVISOR_TOKEN` provided by Supervisor. When the token is detected, the UI shows automatic authorization and hides manual URL/token fields. A failed `Test HA` unlocks the optional manual fallback. The Supervisor token is used only at runtime and is not stored in SQLite. diff --git a/ha-addon/repository/gree-controller/README.md b/ha-addon/repository/gree-controller/README.md index f67375f..80a1425 100644 --- a/ha-addon/repository/gree-controller/README.md +++ b/ha-addon/repository/gree-controller/README.md @@ -1,6 +1,6 @@ # GREE Controller -Local GREE HVAC controller packaged as a Home Assistant add-on, with Web UI, local API, UDP discovery/control, `amd64` and `aarch64` support, ingress, and database backup from `/data/gree-controller.db`. +Local GREE HVAC controller packaged as a Home Assistant add-on, with Web UI, HTTP/WebSocket API, built-in Swagger API documentation, UDP discovery/control, `amd64` and `aarch64` support, ingress, and database backup from `/data/gree-controller.db`. ![Home Assistant OS + GREE + VLAN topology](https://git.linuxiarz.pl/gru/gree-controller-ha-addon/raw/branch/master/gree-controller/topology-ha-vlan-gree-en.png) @@ -8,6 +8,8 @@ For VLAN deployments, configure VLAN interfaces on the Home Assistant OS host. T Full documentation: [DOCS.md](./DOCS.md). +The controller exposes `/api/*` and `/ws`. Interactive API documentation is available at `/api-docs`, with the OpenAPI 3.1 document at `/api-docs/openapi.json`. The same paths work through Home Assistant ingress; direct access on port `8787` follows the configured `app_token` rules. + The same Git repository also contains the optional `custom_components/gree_controller` integration. It is distributed with the repository but is not installed automatically with the add-on. Repository: https://git.linuxiarz.pl/gru/gree-controller-ha-addon/ diff --git a/ha-addon/repository/gree-controller/config.yaml b/ha-addon/repository/gree-controller/config.yaml index 523dec3..047f1d8 100644 --- a/ha-addon/repository/gree-controller/config.yaml +++ b/ha-addon/repository/gree-controller/config.yaml @@ -1,7 +1,7 @@ name: "GREE Controller" -version: "0.15.2" +version: "0.15.4" slug: "gree_controller" -description: "Local GREE HVAC controller with Web UI and Home Assistant integration" +description: "Local GREE HVAC controller with Web UI, API, Swagger API docs and Home Assistant integration" url: "https://git.linuxiarz.pl/gru/gree-controller-ha-addon/" arch: - amd64 diff --git a/scripts/api_dev_test.py b/scripts/api_dev_test.py index 9cfeb1a..1d88eeb 100644 --- a/scripts/api_dev_test.py +++ b/scripts/api_dev_test.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Developer smoke/integration tests for GREE Controller API 0.14.18. +"""Developer smoke/integration tests for GREE Controller API 0.15.4. Default mode is read-only and safe to run against a real controller. Use --settings-write to additionally round-trip all split settings resources and @@ -26,7 +26,7 @@ from typing import Any, Callable, Iterable, Optional DEFAULT_BASE_URL = os.environ.get("GREE_API_URL", "http://127.0.0.1:8787") DEFAULT_TOKEN = os.environ.get("GREE_API_TOKEN", "") -DEFAULT_EXPECTED_VERSION = "0.14.18" +DEFAULT_EXPECTED_VERSION = "0.15.4" SETTINGS_PATHS: dict[str, set[str]] = { "/api/settings/application": {"simulator_enabled"}, @@ -593,7 +593,7 @@ def run_suite(args: argparse.Namespace) -> int: print(f"Settings write tests: {'ENABLED' if args.settings_write else 'disabled'}\n") runner.run("public health", lambda: test_health(client, args.expected_version)) - runner.run("OpenAPI 0.14.18 contract", lambda: test_openapi(client, args.expected_version)) + runner.run("OpenAPI 0.15.4 contract", lambda: test_openapi(client, args.expected_version)) runner.run("bootstrap snapshot contract", lambda: test_bootstrap_contract(client)) runner.run("protected API requires auth", lambda: test_protected_auth(client)) diff --git a/src/api.rs b/src/api.rs index 90ee360..56e7a2b 100644 --- a/src/api.rs +++ b/src/api.rs @@ -34,7 +34,6 @@ use axum::{ use base64::{engine::general_purpose::URL_SAFE_NO_PAD, Engine as _}; use chrono::{Duration as ChronoDuration, NaiveTime, Utc}; use futures_util::StreamExt; -use rand::{rngs::OsRng, RngCore}; use serde::Deserialize; use serde_json::{json, Value}; use sha2::{Digest, Sha256}; @@ -91,31 +90,31 @@ pub fn router(state: AppState) -> Router { .route("/api/discovery", post(discover)) .route("/api/devices", get(list_devices).post(add_device)) .route( - "/api/devices/:id", + "/api/devices/{id}", get(get_device).patch(patch_device).delete(delete_device), ) - .route("/api/devices/:id/bind", post(bind_device)) - .route("/api/devices/:id/poll", post(poll_device)) - .route("/api/devices/:id/probe", post(probe_device)) - .route("/api/devices/:id/command", post(command_device)) + .route("/api/devices/{id}/bind", post(bind_device)) + .route("/api/devices/{id}/poll", post(poll_device)) + .route("/api/devices/{id}/probe", post(probe_device)) + .route("/api/devices/{id}/command", post(command_device)) .route( "/api/device-groups", get(list_device_groups).post(create_device_group), ) .route( - "/api/device-groups/:id", + "/api/device-groups/{id}", get(get_device_group) .put(update_device_group) .delete(delete_device_group), ) .route("/api/zones", get(list_zones).post(create_zone)) .route( - "/api/zones/:id", + "/api/zones/{id}", get(get_zone).put(update_zone).delete(delete_zone), ) - .route("/api/zones/:id/control", post(update_zone_control)) + .route("/api/zones/{id}/control", post(update_zone_control)) .route( - "/api/zones/:id/compressor-queue/cancel", + "/api/zones/{id}/compressor-queue/cancel", post(cancel_zone_compressor_queue), ) .route( @@ -123,21 +122,21 @@ pub fn router(state: AppState) -> Router { post(cancel_all_compressor_queues), ) .route( - "/api/zones/:id/schedule-template", + "/api/zones/{id}/schedule-template", post(apply_schedule_template), ) .route("/api/groups", get(list_groups).post(create_group)) .route( - "/api/groups/:id", + "/api/groups/{id}", get(get_group).put(update_group).delete(delete_group), ) - .route("/api/groups/:id/control", post(update_group_control)) + .route("/api/groups/{id}/control", post(update_group_control)) .route("/api/house/control", post(update_house_control)) .route("/api/house/power", post(update_house_power)) .route("/api/house/preset", post(update_house_preset)) .route("/api/schedules", get(list_schedules).post(create_schedule)) .route( - "/api/schedules/:id", + "/api/schedules/{id}", get(get_schedule) .put(update_schedule) .delete(delete_schedule), @@ -147,7 +146,7 @@ pub fn router(state: AppState) -> Router { get(list_automations).post(create_automation), ) .route( - "/api/automations/:id", + "/api/automations/{id}", get(get_automation) .put(update_automation) .delete(delete_automation), @@ -155,10 +154,10 @@ pub fn router(state: AppState) -> Router { .route("/api/flows", get(list_flows).post(create_flow)) .route("/api/flows/import", post(import_flow)) .route("/api/flows/simulate", post(simulate_flow)) - .route("/api/flows/:id/export", get(export_flow)) - .route("/api/flows/:id/logs", get(flow_logs)) + .route("/api/flows/{id}/export", get(export_flow)) + .route("/api/flows/{id}/logs", get(flow_logs)) .route( - "/api/flows/:id", + "/api/flows/{id}", get(get_flow).put(update_flow).delete(delete_flow), ) .route("/api/readings", get(readings)) @@ -215,7 +214,7 @@ pub fn router(state: AppState) -> Router { get(list_access_tokens).post(create_access_token), ) .route( - "/api/access-tokens/:id", + "/api/access-tokens/{id}", axum::routing::delete(delete_access_token), ) .route("/api/integrations/gree-cloud/test", post(test_gree_cloud)) @@ -224,7 +223,7 @@ pub fn router(state: AppState) -> Router { get(discover_gree_cloud_devices), ) .route( - "/api/integrations/gree-cloud/devices/:cloud_id/add", + "/api/integrations/gree-cloud/devices/{cloud_id}/add", post(add_gree_cloud_device), ) .route( @@ -236,7 +235,7 @@ pub fn router(state: AppState) -> Router { post(reconnect_gree_cloud), ) .route( - "/api/devices/:id/cloud-diagnostics", + "/api/devices/{id}/cloud-diagnostics", get(cloud_device_diagnostics), ) .route( @@ -271,7 +270,7 @@ pub fn router(state: AppState) -> Router { get(list_devices), ) .route( - "/api/integrations/home-assistant/devices/:id/command", + "/api/integrations/home-assistant/devices/{id}/command", post(command_home_assistant_device), ) .route( @@ -283,7 +282,7 @@ pub fn router(state: AppState) -> Router { get(list_home_assistant_groups), ) .route( - "/api/integrations/home-assistant/groups/:id/control", + "/api/integrations/home-assistant/groups/{id}/control", post(update_home_assistant_group_control), ) .route( @@ -299,7 +298,7 @@ pub fn router(state: AppState) -> Router { post(update_house_power), ) .route( - "/api/integrations/home-assistant/zones/:id/control", + "/api/integrations/home-assistant/zones/{id}/control", post(update_home_assistant_zone_control), ) .route_layer(middleware::from_fn_with_state( @@ -309,8 +308,8 @@ pub fn router(state: AppState) -> Router { let mut app = Router::new() .route("/api/health", get(health)) - .route("/api/public/charts/custom/:token", get(public_custom_chart)) - .route("/charts/custom/:token", get(custom_chart_page)) + .route("/api/public/charts/custom/{token}", get(public_custom_chart)) + .route("/charts/custom/{token}", get(custom_chart_page)) .route("/custom-chart.js", get(custom_chart_js)) .route("/ws", get(websocket)) .route("/", get(index)) @@ -322,11 +321,11 @@ pub fn router(state: AppState) -> Router { .route("/manifest.webmanifest", get(manifest)) .route("/sw.js", get(service_worker)) .route("/favicon.svg", get(favicon)) - .route("/flows/:id", get(index)) + .route("/flows/{id}", get(index)) .route("/lang/index.json", get(language_index)) - .route("/lang/:file", get(language_file)) + .route("/lang/{file}", get(language_file)) .route("/presets/index.json", get(preset_index)) - .route("/presets/:file", get(preset_file)) + .route("/presets/{file}", get(preset_file)) .merge(openapi::swagger_ui(&state.config.base_path)) .merge(protected) .merge(home_assistant_api); diff --git a/src/api/auth.rs b/src/api/auth.rs index 0a8f83d..a0a93bd 100644 --- a/src/api/auth.rs +++ b/src/api/auth.rs @@ -99,7 +99,6 @@ fn hash_token(token: &str) -> String { fn generate_access_token() -> String { let mut bytes = [0u8; 32]; - let mut rng = OsRng; - rng.fill_bytes(&mut bytes); + rand::fill(&mut bytes); format!("gree_controller_{}", URL_SAFE_NO_PAD.encode(bytes)) } diff --git a/src/api/history.rs b/src/api/history.rs index 536bc33..a611b21 100644 --- a/src/api/history.rs +++ b/src/api/history.rs @@ -550,8 +550,7 @@ fn validate_public_chart_spec(series: &[String]) -> Result<(), AppError> { fn generate_public_chart_token() -> String { let mut bytes = [0u8; 32]; - let mut rng = OsRng; - rng.fill_bytes(&mut bytes); + rand::fill(&mut bytes); format!("chart_{}", URL_SAFE_NO_PAD.encode(bytes)) } diff --git a/src/api/openapi.rs b/src/api/openapi.rs index ca9339b..86278ad 100644 --- a/src/api/openapi.rs +++ b/src/api/openapi.rs @@ -12,10 +12,8 @@ pub(super) fn swagger_ui(base_path: &str) -> SwaggerUi { .external_url_unchecked("/api-docs/openapi.json", document(base_path)) .config( SwaggerConfig::new([docs_url]) - .filter(true) - .try_it_out_enabled(true) - .display_request_duration(true) - .persist_authorization(true), + .doc_expansion("none") + .default_models_expand_depth(-1), ) } diff --git a/src/api/websocket.rs b/src/api/websocket.rs index d5f1cba..970a85b 100644 --- a/src/api/websocket.rs +++ b/src/api/websocket.rs @@ -47,7 +47,7 @@ async fn send_ws_bootstrap(state: &AppState, socket: &mut WebSocket) -> Result { if let Ok(text) = serde_json::to_string(&event) { - if socket.send(Message::Text(text)).await.is_err() { break; } + if socket.send(Message::Text(text.into())).await.is_err() { break; } } } Err(tokio::sync::broadcast::error::RecvError::Lagged(skipped)) => { @@ -105,7 +105,7 @@ async fn websocket_loop(state: AppState, mut socket: WebSocket) { continue; } let text = control_plan_ws_message(snapshot.as_ref()).to_string(); - if socket.send(Message::Text(text)).await.is_err() { break; } + if socket.send(Message::Text(text.into())).await.is_err() { break; } last_control_plan_revision = Some(snapshot.revision); } } diff --git a/src/home_assistant.rs b/src/home_assistant.rs index 1dfc9a9..d28d6a1 100644 --- a/src/home_assistant.rs +++ b/src/home_assistant.rs @@ -94,8 +94,8 @@ fn request_client( reqwest::Client::builder() .timeout(Duration::from_secs(10)) .user_agent(concat!("gree-controller/", env!("CARGO_PKG_VERSION"))) - .danger_accept_invalid_certs(true) - .danger_accept_invalid_hostnames(true) + .tls_danger_accept_invalid_certs(true) + .tls_danger_accept_invalid_hostnames(true) .build() .context("cannot build Home Assistant HTTPS client") } diff --git a/src/main.rs b/src/main.rs index 2e458b9..84654ed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -36,6 +36,7 @@ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; #[tokio::main] async fn main() -> Result<()> { + install_rustls_crypto_provider(); let config = Config::load()?; init_tracing(); @@ -191,6 +192,13 @@ async fn main() -> Result<()> { Ok(()) } +fn install_rustls_crypto_provider() { + // reqwest is built with `rustls-no-provider` while tokio-rustls enables only + // `ring`. Install it once at process startup so every rustls consumer uses + // the same provider and rustls never has to guess between ring and AWS-LC. + let _ = tokio_rustls::rustls::crypto::ring::default_provider().install_default(); +} + fn init_tracing() { let filter = tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| "info,tower_http=info".into()); diff --git a/src/protocol/crypto.rs b/src/protocol/crypto.rs index 528ea3e..321f08d 100644 --- a/src/protocol/crypto.rs +++ b/src/protocol/crypto.rs @@ -1,10 +1,10 @@ use aes::{ - cipher::{generic_array::GenericArray, BlockDecrypt, BlockEncrypt, KeyInit}, - Aes128, + cipher::{BlockCipherDecrypt, BlockCipherEncrypt, KeyInit}, + Aes128, Block, }; use aes_gcm::{ - aead::{AeadInPlace, KeyInit as AeadKeyInit}, - Aes128Gcm, Nonce, + aead::{consts::U12, AeadInOut, KeyInit as AeadKeyInit}, + Aes128Gcm, Nonce, Tag, }; use anyhow::{anyhow, bail, Context, Result}; use base64::{ @@ -62,7 +62,8 @@ pub fn encrypt_v1(key: &str, plaintext: &[u8]) -> Result { data.extend_from_slice(plaintext); data.extend(std::iter::repeat(pad as u8).take(pad)); for block in data.chunks_exact_mut(16) { - cipher.encrypt_block(GenericArray::from_mut_slice(block)); + let block: &mut Block = block.try_into().expect("AES block is 16 bytes"); + cipher.encrypt_block(block); } Ok(STANDARD.encode(data)) } @@ -77,7 +78,8 @@ pub fn decrypt_v1(key: &str, ciphertext_b64: &str) -> Result> { bail!("invalid AES-ECB ciphertext length") } for block in data.chunks_exact_mut(16) { - cipher.decrypt_block(GenericArray::from_mut_slice(block)); + let block: &mut Block = block.try_into().expect("AES block is 16 bytes"); + cipher.decrypt_block(block); } let pad = *data.last().ok_or_else(|| anyhow!("empty plaintext"))? as usize; let valid_padding = pad > 0 @@ -106,10 +108,10 @@ pub fn encrypt_v2(key: &str, plaintext: &[u8]) -> Result { let key = normalize_key(key)?; let cipher = ::new_from_slice(&key) .map_err(|_| anyhow!("invalid AES-GCM key"))?; - let nonce = Nonce::from_slice(&GCM_NONCE); + let nonce: Nonce = GCM_NONCE.into(); let mut buffer = plaintext.to_vec(); let tag = cipher - .encrypt_in_place_detached(nonce, GCM_AAD, &mut buffer) + .encrypt_inout_detached(&nonce, GCM_AAD, (&mut buffer[..]).into()) .map_err(|_| anyhow!("AES-GCM encryption failed"))?; Ok(V2Encrypted { ciphertext: STANDARD.encode(buffer), @@ -130,10 +132,13 @@ pub fn decrypt_v2(key: &str, ciphertext_b64: &str, tag_b64: &str) -> Result = GCM_NONCE.into(); + let tag: &Tag = tag_bytes + .as_slice() + .try_into() + .map_err(|_| anyhow!("invalid GCM tag length"))?; cipher - .decrypt_in_place_detached(nonce, GCM_AAD, &mut data, tag) + .decrypt_inout_detached(&nonce, GCM_AAD, (&mut data[..]).into(), tag) .map_err(|_| anyhow!("AES-GCM authentication failed"))?; // A few modules append 0xff filler bytes to decrypted JSON. data.retain(|byte| *byte != 0xff); diff --git a/src/protocol/gree_cloud.rs b/src/protocol/gree_cloud.rs index 364df0a..a34aea8 100644 --- a/src/protocol/gree_cloud.rs +++ b/src/protocol/gree_cloud.rs @@ -1,7 +1,7 @@ use super::crypto::decrypt_v1; use aes::{ - cipher::{generic_array::GenericArray, BlockEncrypt, KeyInit}, - Aes128, + cipher::{BlockCipherEncrypt, KeyInit}, + Aes128, Block, }; use anyhow::{anyhow, bail, Context, Result}; use base64::{engine::general_purpose::STANDARD, Engine as _}; @@ -387,7 +387,8 @@ fn encrypt_cloud_api(plaintext: &[u8]) -> Result { data.extend_from_slice(plaintext); data.extend(std::iter::repeat(pad as u8).take(pad)); for block in data.chunks_exact_mut(16) { - cipher.encrypt_block(GenericArray::from_mut_slice(block)); + let block: &mut Block = block.try_into().expect("AES block is 16 bytes"); + cipher.encrypt_block(block); } Ok(STANDARD.encode(data)) } diff --git a/src/provider.rs b/src/provider.rs index 1c0343d..4752a6b 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -14,7 +14,6 @@ use crate::{ }; use anyhow::{anyhow, bail, Context, Result}; use chrono::{DateTime, Utc}; -use rand::Rng; use serde::Serialize; use serde_json::{json, Value}; use std::{ @@ -1072,8 +1071,7 @@ impl GreeCloudProvider { } else { (encrypt_v1(key, &plaintext)?, None) }; - let cid = rand::thread_rng() - .gen_range(1_000_000_000_u64..=9_999_999_999_u64) + let cid = rand::random_range(1_000_000_000_u64..=9_999_999_999_u64) .to_string(); let request_kind = inner_payload .get("t") @@ -2047,7 +2045,7 @@ pub async fn cloud_reconnect_loop( } } let base = (1_u64 << attempt.min(6)).min(60); - let jitter = rand::thread_rng().gen_range(0..=base.min(10)); + let jitter = rand::random_range(0..=base.min(10)); sleep(Duration::from_secs(base + jitter)).await; } } @@ -2056,6 +2054,11 @@ pub async fn cloud_reconnect_loop( mod tests { use super::*; + fn test_http_client() -> reqwest::Client { + crate::install_rustls_crypto_provider(); + reqwest::Client::new() + } + #[test] fn status_parser_rejects_malformed_column_count() { assert!(properties_from_payload(&json!({"t":"dat","cols":["Pow"],"dat":[]})).is_err()); @@ -2151,7 +2154,7 @@ mod tests { #[tokio::test] async fn mqtt_payload_is_ignored_after_all_cloud_devices_are_removed() { - let provider = GreeCloudProvider::new(reqwest::Client::new()); + let provider = GreeCloudProvider::new(test_http_client()); let result = provider .handle_raw_message("status/stale-parent/device", b"not-json-anymore") .await; @@ -2160,7 +2163,7 @@ mod tests { #[tokio::test] async fn mqtt_payload_for_unknown_parent_still_errors_when_devices_are_registered() { - let provider = GreeCloudProvider::new(reqwest::Client::new()); + let provider = GreeCloudProvider::new(test_http_client()); provider.inner.registered.write().await.insert( "AABBCCDDEEFF".into(), RegisteredDevice { @@ -2190,7 +2193,7 @@ mod tests { None, Arc::new(AtomicBool::new(false)), ); - let providers = ProviderDispatcher::new(local, reqwest::Client::new()); + let providers = ProviderDispatcher::new(local, test_http_client()); let mut device = Device::simulated_default(); device.connection_type = ConnectionType::Local; assert_eq!(providers.provider_name(&device), "local"); @@ -2200,7 +2203,7 @@ mod tests { #[tokio::test] async fn cloud_provider_rejects_local_device_before_network_io() { - let provider = GreeCloudProvider::new(reqwest::Client::new()); + let provider = GreeCloudProvider::new(test_http_client()); let device = Device::simulated_default(); let error = provider.register_device(&device).await.unwrap_err(); assert!(error.to_string().contains("Local device")); @@ -2242,7 +2245,7 @@ mod tests { #[tokio::test] async fn cloud_command_order_matches_reference() { - let provider = GreeCloudProvider::new(reqwest::Client::new()); + let provider = GreeCloudProvider::new(test_http_client()); let mut device = Device::simulated_default(); device.id = "cloud-test".into(); device.connection_type = ConnectionType::GreeCloud;