v0.3.8
This commit is contained in:
@@ -1,3 +1,22 @@
|
|||||||
|
# Build report — v0.3.8
|
||||||
|
|
||||||
|
## Fix in this release
|
||||||
|
|
||||||
|
- Fixed multi-NIC LXC failures where `getifaddrs()` returned `EAFNOSUPPORT` (`os error 97`).
|
||||||
|
- The systemd sandbox now allows `AF_NETLINK`, which Linux `getifaddrs()` uses to enumerate interface addresses.
|
||||||
|
- Existing hardening remains enabled (`NoNewPrivileges`, `ProtectSystem`, restricted address families).
|
||||||
|
- With `GREE_CONTROLLER_GREE_INTERFACE=eth1`, GREE UDP sockets can now resolve and bind the IPv4 address assigned to `eth1`.
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
|
||||||
|
- systemd unit includes `AF_NETLINK`.
|
||||||
|
- shell scripts pass `bash -n`.
|
||||||
|
- JSON language files parse successfully.
|
||||||
|
- all SQL remains centralized in `src/queries.rs`.
|
||||||
|
- Rust compilation is not available in the packaging environment; `scripts/update.sh` runs Cargo tests/build on the target LXC before installation.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# GREE Controller v0.3.6 - build and validation report
|
# GREE Controller v0.3.6 - build and validation report
|
||||||
|
|
||||||
## Scope
|
## Scope
|
||||||
@@ -43,3 +62,10 @@ journalctl -u gree-controller -f
|
|||||||
```
|
```
|
||||||
|
|
||||||
Expected request logs should show a concrete local address such as `10.87.65.27:<port>` rather than `0.0.0.0:<port>`.
|
Expected request logs should show a concrete local address such as `10.87.65.27:<port>` rather than `0.0.0.0:<port>`.
|
||||||
|
|
||||||
|
## v0.3.8 legacy V1 bind compatibility
|
||||||
|
|
||||||
|
- Canonicalize the on-wire GREE device identifier to lowercase hexadecimal for `tcid` and inner `mac` fields.
|
||||||
|
- This specifically targets legacy V1 modules such as the `502cc6...` family which can answer discovery yet silently ignore bind packets when the identifier casing differs from the value returned by discovery.
|
||||||
|
- Database IDs, friendly names and stored MAC display values are unchanged.
|
||||||
|
- Existing V2/GCM crypto and the `eth1`/AF_NETLINK networking fixes are unchanged.
|
||||||
|
|||||||
Generated
+1
-1
@@ -633,7 +633,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gree-controller"
|
name = "gree-controller"
|
||||||
version = "0.3.6"
|
version = "0.3.8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"aes-gcm",
|
"aes-gcm",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "gree-controller"
|
name = "gree-controller"
|
||||||
version = "0.3.6"
|
version = "0.3.8"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["GREE Controller contributors"]
|
authors = ["GREE Controller contributors"]
|
||||||
description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support"
|
description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support"
|
||||||
|
|||||||
+15
-7
@@ -1,24 +1,31 @@
|
|||||||
6b10bf7903a32a6cdd902d990911105589690deafe7da12e5b3b9c994c1fd4f6 ./.env.example
|
6b10bf7903a32a6cdd902d990911105589690deafe7da12e5b3b9c994c1fd4f6 ./.env.example
|
||||||
2fe1cf4e544fead5ae58436145a5b45e7a5a105143dfd815d28e307c94d5d19b ./.gitignore
|
2fe1cf4e544fead5ae58436145a5b45e7a5a105143dfd815d28e307c94d5d19b ./.gitignore
|
||||||
d75023129d63417a5af399567944d99a65c4570e1cef671ba2f68fdd734fd8d1 ./BUILD_REPORT.md
|
1e1867ebd5cd1633d511a4a65853da9a2ef1c018dc4e66d823e20ae032e0d1a7 ./BUILD_REPORT.md
|
||||||
baad3cddff5a160ac1e5f5200838c83bd1edc2a3d4dec09b95b8858a1a4bfeb7 ./Cargo.toml
|
6b2eacdaf0a8f285fd832b39617e849e992fd3f6ab094f13da9c453c0c99b79d ./Cargo.toml
|
||||||
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
||||||
349344b41f5bb6680079c5ed95f6294c9c9df6a73bdbda452d351033abf4768a ./README.md
|
3c552aab65ddba02d79835f2cec13c9cde5328774503c53e8461fa54bce9cc41 ./README.md
|
||||||
a4fa9bfee9735ed8ed95ea31456e0cce503d82502ae3f550108ffca51b0f0c3d ./build.rs
|
a4fa9bfee9735ed8ed95ea31456e0cce503d82502ae3f550108ffca51b0f0c3d ./build.rs
|
||||||
37453ecce2c7290ecae5ada4249cfd36bc70fb50c479aa680b74e4f1bc707251 ./docs/API.md
|
37453ecce2c7290ecae5ada4249cfd36bc70fb50c479aa680b74e4f1bc707251 ./docs/API.md
|
||||||
234dd200e380a13ecd3e61b4ea455f6f08d64ce89382077dee80684acadb9703 ./docs/HOME_ASSISTANT_MIGRATION.md
|
234dd200e380a13ecd3e61b4ea455f6f08d64ce89382077dee80684acadb9703 ./docs/HOME_ASSISTANT_MIGRATION.md
|
||||||
7a88d6e76fda21e5d34ab351e26bc10dc1f8f7b3055505aefad1df7c56d65ae4 ./docs/LOCALIZATION.md
|
7a88d6e76fda21e5d34ab351e26bc10dc1f8f7b3055505aefad1df7c56d65ae4 ./docs/LOCALIZATION.md
|
||||||
456b65737d3b4579e40edba2655c0cb1a63620d8a7bfa0f8844acf81b21fc374 ./docs/LXC.md
|
3d754c7120a086654f2666cac510b10a76529aa849c012a85427b0472a3ac261 ./docs/LXC.md
|
||||||
a728ddc324613671932bd83522155b09c7503d4fbcd0d04d8e217676ea9e10e4 ./docs/PROJECT_SPEC.md
|
a728ddc324613671932bd83522155b09c7503d4fbcd0d04d8e217676ea9e10e4 ./docs/PROJECT_SPEC.md
|
||||||
33214270b96ac4c64e3db41c11e54158792b4a87ee5668c651bad571766b591a ./home-assistant/README.md
|
33214270b96ac4c64e3db41c11e54158792b4a87ee5668c651bad571766b591a ./home-assistant/README.md
|
||||||
f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./home-assistant/custom_components/gree_controller/__init__.py
|
f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./home-assistant/custom_components/gree_controller/__init__.py
|
||||||
|
9151cd32bfcea786eb8a9af9ca11af775abdc6bf23b55d6a291b76433473eb2a ./home-assistant/custom_components/gree_controller/__pycache__/__init__.cpython-313.pyc
|
||||||
|
8c3753163d45895da5856525fe3e988a38c73bce4457b1358200453cc9a9ac2c ./home-assistant/custom_components/gree_controller/__pycache__/api.cpython-313.pyc
|
||||||
|
e0d8043f39885375cfecf8e82153a257f2166e5319e975dbbb648482ec77474e ./home-assistant/custom_components/gree_controller/__pycache__/climate.cpython-313.pyc
|
||||||
|
32097fe487c1c5fb428230d35a39f62c2bc17285036604315ec80545e8c185a5 ./home-assistant/custom_components/gree_controller/__pycache__/config_flow.cpython-313.pyc
|
||||||
|
05791fb1cb4345726506a20ef5b36d355e8235b8ccd46a81a2b8ce5b42e4c3f7 ./home-assistant/custom_components/gree_controller/__pycache__/const.cpython-313.pyc
|
||||||
|
bf1a90d03325dd37a86a05b586faf387bfd5a02732fd2c0e4d998369a13ba70f ./home-assistant/custom_components/gree_controller/__pycache__/coordinator.cpython-313.pyc
|
||||||
|
cc4f2ab07b1a641bdc36f3738280fa643baac617d753863c288e5788b1c3d455 ./home-assistant/custom_components/gree_controller/__pycache__/entity_map.cpython-313.pyc
|
||||||
e0cf725c9f84be51cdbd83a5ab12b2b8288f90b36623cb4671cefcbf04378504 ./home-assistant/custom_components/gree_controller/api.py
|
e0cf725c9f84be51cdbd83a5ab12b2b8288f90b36623cb4671cefcbf04378504 ./home-assistant/custom_components/gree_controller/api.py
|
||||||
fde31b8e020fd36be2d9d9b1e554254f5da8a1cc593240ebb8d78820154dd790 ./home-assistant/custom_components/gree_controller/climate.py
|
fde31b8e020fd36be2d9d9b1e554254f5da8a1cc593240ebb8d78820154dd790 ./home-assistant/custom_components/gree_controller/climate.py
|
||||||
5e4aef2143e81bedb5a15dd4be5c71b64a3ab448ec6d33a20851edd098e5f529 ./home-assistant/custom_components/gree_controller/config_flow.py
|
5e4aef2143e81bedb5a15dd4be5c71b64a3ab448ec6d33a20851edd098e5f529 ./home-assistant/custom_components/gree_controller/config_flow.py
|
||||||
e1821b74859bc40773a6ee39e6ccc9650980b62af50d6426b46cdb3e3a90d200 ./home-assistant/custom_components/gree_controller/const.py
|
e1821b74859bc40773a6ee39e6ccc9650980b62af50d6426b46cdb3e3a90d200 ./home-assistant/custom_components/gree_controller/const.py
|
||||||
2d27d7cb67c53e819b99a0302cd0bd339c27e3e2dfc85e07d30c31f505f740b5 ./home-assistant/custom_components/gree_controller/coordinator.py
|
2d27d7cb67c53e819b99a0302cd0bd339c27e3e2dfc85e07d30c31f505f740b5 ./home-assistant/custom_components/gree_controller/coordinator.py
|
||||||
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./home-assistant/custom_components/gree_controller/entity_map.py
|
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./home-assistant/custom_components/gree_controller/entity_map.py
|
||||||
23fc6d9d7136492db8dc046e3f54c65070e5f65e1c6303ecab1bac5ef686661d ./home-assistant/custom_components/gree_controller/manifest.json
|
4e0f31984b94f3da7fd98e3804b591bbe1c79d2c05b04b7c4fb484a4caec587e ./home-assistant/custom_components/gree_controller/manifest.json
|
||||||
6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./home-assistant/custom_components/gree_controller/translations/en.json
|
6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./home-assistant/custom_components/gree_controller/translations/en.json
|
||||||
13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./home-assistant/custom_components/gree_controller/translations/pl.json
|
13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./home-assistant/custom_components/gree_controller/translations/pl.json
|
||||||
4513070521d3dda0efb0d974a86ba674494cfb2b66fe9e5cac5b1b0430dede97 ./home-assistant/generated/gree_controller_entities.example.json
|
4513070521d3dda0efb0d974a86ba674494cfb2b66fe9e5cac5b1b0430dede97 ./home-assistant/generated/gree_controller_entities.example.json
|
||||||
@@ -26,6 +33,7 @@ e1821b74859bc40773a6ee39e6ccc9650980b62af50d6426b46cdb3e3a90d200 ./home-assista
|
|||||||
c604815c850574c573315306f368a8379ab87f5e2a99aca32be3131b05070afa ./lang/en.json
|
c604815c850574c573315306f368a8379ab87f5e2a99aca32be3131b05070afa ./lang/en.json
|
||||||
0b2d174258610440d5d4c2d6c5bec5ecc2528f41946bf7d59cc2206aab50ce58 ./lang/pl.json
|
0b2d174258610440d5d4c2d6c5bec5ecc2528f41946bf7d59cc2206aab50ce58 ./lang/pl.json
|
||||||
09caaa48f9979f209b96e6d0feebbecda053b997c470a5d80abb80b7fb06a484 ./scripts/README.md
|
09caaa48f9979f209b96e6d0feebbecda053b997c470a5d80abb80b7fb06a484 ./scripts/README.md
|
||||||
|
896caae04468f743d85d011638a0683253d8271c0db8365aea9bcdc646795cf1 ./scripts/__pycache__/generate_ha_migration.cpython-313.pyc
|
||||||
be8c4bf17723d5e2e23e774a679ca75b02ab49825a93201237bf58cdd4974136 ./scripts/common.sh
|
be8c4bf17723d5e2e23e774a679ca75b02ab49825a93201237bf58cdd4974136 ./scripts/common.sh
|
||||||
6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh
|
6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh
|
||||||
054e6862857fd1d02dabedd977d4175c2011f451aba51b5d4fc3a3363e66e80f ./scripts/dev.sh
|
054e6862857fd1d02dabedd977d4175c2011f451aba51b5d4fc3a3363e66e80f ./scripts/dev.sh
|
||||||
@@ -45,11 +53,11 @@ f85cb4ba6435843431d93779aa0653fd24ec8987e06ef36efde096cbea321d7a ./src/home_ass
|
|||||||
27eca87a9078aad7a7a4ef1fc39ce7ddaffcf05466acb995d571e0a35dfe898c ./src/main.rs
|
27eca87a9078aad7a7a4ef1fc39ce7ddaffcf05466acb995d571e0a35dfe898c ./src/main.rs
|
||||||
a5923f8fb72ebac68c13e4767dd35012041e2783167969521e757bf502fafabd ./src/models.rs
|
a5923f8fb72ebac68c13e4767dd35012041e2783167969521e757bf502fafabd ./src/models.rs
|
||||||
7fc31fbf8841a073a1544b8c7a6390f1a15b56087486ca0596a8418340fa232a ./src/protocol/crypto.rs
|
7fc31fbf8841a073a1544b8c7a6390f1a15b56087486ca0596a8418340fa232a ./src/protocol/crypto.rs
|
||||||
53e6fdb575da4790cdf88013073b973461fb9ace362fbe51dda95c0eaadf2365 ./src/protocol/gree.rs
|
b66ae7c0186b6cc3939d922b0a83f763fd670662c170c97cebca8235d99f663c ./src/protocol/gree.rs
|
||||||
a910bd9432a393740c0f6fab52bfcb551f0ea756718d66d290fd2610767cf07c ./src/protocol/mod.rs
|
a910bd9432a393740c0f6fab52bfcb551f0ea756718d66d290fd2610767cf07c ./src/protocol/mod.rs
|
||||||
c80164631bba476db29469fa43b28d73f68412c06bafabe2143ab8d4cd330a52 ./src/queries.rs
|
c80164631bba476db29469fa43b28d73f68412c06bafabe2143ab8d4cd330a52 ./src/queries.rs
|
||||||
521070a4c63bec73372cf4873f20c5fad23c37db4df7199bcc5bf6f6e566b3f6 ./src/state.rs
|
521070a4c63bec73372cf4873f20c5fad23c37db4df7199bcc5bf6f6e566b3f6 ./src/state.rs
|
||||||
52aea29e17e7ce45ea10f7783be7278ecefe976141c5823360f10f0ea2bbcf33 ./systemd/gree-controller.service
|
b92a6cb158b494fe145b43c7641e65f6fafff47201d7d76edbec2cfd8b94835c ./systemd/gree-controller.service
|
||||||
9d05fe7219a4e9806239792169417d577c56a38bea4561e4064ae4cf41418257 ./web/app.js
|
9d05fe7219a4e9806239792169417d577c56a38bea4561e4064ae4cf41418257 ./web/app.js
|
||||||
b6bba1e1e7127d06c885a9f8fffbf0becde339e0f2464da8b4725f11ddabe433 ./web/favicon.svg
|
b6bba1e1e7127d06c885a9f8fffbf0becde339e0f2464da8b4725f11ddabe433 ./web/favicon.svg
|
||||||
45f0ddc583cf0ee3197dda5c72209f80389291e33c72a29e7555ebaa329819de ./web/index.html
|
45f0ddc583cf0ee3197dda5c72209f80389291e33c72a29e7555ebaa329819de ./web/index.html
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
Standalone local GREE air-conditioner controller written in Rust. It runs on a regular Linux host or an LXC container and provides a mobile-first web interface without depending on the vendor cloud.
|
Standalone local GREE air-conditioner controller written in Rust. It runs on a regular Linux host or an LXC container and provides a mobile-first web interface without depending on the vendor cloud.
|
||||||
|
|
||||||
Current version: **0.3.6**.
|
Current version: **0.3.8**.
|
||||||
|
|
||||||
## Highlights
|
## Highlights
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ See [`BUILD_REPORT.md`](BUILD_REPORT.md) for package validation details and [`do
|
|||||||
On Debian, Ubuntu or an LXC container:
|
On Debian, Ubuntu or an LXC container:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
unzip gree-controller-v0.3.6.zip
|
unzip gree-controller-v0.3.8.zip
|
||||||
cd gree-controller
|
cd gree-controller
|
||||||
chmod +x scripts/*.sh
|
chmod +x scripts/*.sh
|
||||||
./scripts/dev.sh
|
./scripts/dev.sh
|
||||||
@@ -92,7 +92,7 @@ The selected appearance is stored in the `gree_controller_theme` cookie. The int
|
|||||||
5. New devices immediately open a naming step so you can enter room-friendly names such as **Salon** or **Sypialnia**. They can also be renamed later from **Devices -> Rename**. Re-discovery preserves your custom name.
|
5. New devices immediately open a naming step so you can enter room-friendly names such as **Salon** or **Sypialnia**. They can also be renamed later from **Devices -> Rename**. Re-discovery preserves your custom name.
|
||||||
6. If LXC/VLAN broadcast does not pass, add the unit manually with IP and MAC/CID.
|
6. If LXC/VLAN broadcast does not pass, add the unit manually with IP and MAC/CID.
|
||||||
|
|
||||||
Version 0.3.6 additionally uses forgiving GREE Base64 decoding for non-canonical GCM tags seen on real Wi-Fi modules, automatically selects the directly connected local IPv4 interface for unicast GREE traffic, and refreshes the short bind window with a subnet broadcast immediately before bind. A single lost UDP response no longer marks a device offline; three consecutive communication failures are required.
|
Version 0.3.7 additionally uses forgiving GREE Base64 decoding for non-canonical GCM tags seen on real Wi-Fi modules, automatically selects the directly connected local IPv4 interface for unicast GREE traffic, and refreshes the short bind window with a subnet broadcast immediately before bind. A single lost UDP response no longer marks a device offline; three consecutive communication failures are required.
|
||||||
|
|
||||||
## LXC/systemd installation and updates
|
## LXC/systemd installation and updates
|
||||||
|
|
||||||
@@ -318,3 +318,11 @@ GREE_CONTROLLER_AUTO_SEED=false
|
|||||||
`GREE_CONTROLLER_GREE_INTERFACE` is resolved to the interface current IPv4 address whenever a UDP socket is created, so DHCP address changes do not require hard-coding the source IP. `GREE_CONTROLLER_DISCOVERY_BROADCAST=auto` derives the subnet broadcast from the selected interface and overrides an older runtime value stored in SQLite.
|
`GREE_CONTROLLER_GREE_INTERFACE` is resolved to the interface current IPv4 address whenever a UDP socket is created, so DHCP address changes do not require hard-coding the source IP. `GREE_CONTROLLER_DISCOVERY_BROADCAST=auto` derives the subnet broadcast from the selected interface and overrides an older runtime value stored in SQLite.
|
||||||
|
|
||||||
Run `sudo ./scripts/network-debug.sh eth1 10.87.65.127` to verify addressing and routing.
|
Run `sudo ./scripts/network-debug.sh eth1 10.87.65.127` to verify addressing and routing.
|
||||||
|
|
||||||
|
### v0.3.7 LXC networking fix
|
||||||
|
|
||||||
|
The systemd service explicitly allows `AF_NETLINK`. This is required by Linux `getifaddrs()` when resolving `GREE_CONTROLLER_GREE_INTERFACE` on multi-NIC LXC installations. Without it, older releases could fail with `Address family not supported by protocol (os error 97)` even though the configured interface was correct.
|
||||||
|
|
||||||
|
### v0.3.8 legacy V1 device compatibility
|
||||||
|
|
||||||
|
GREE protocol identifiers are now emitted as canonical lowercase hexadecimal in `tcid` and `pack.mac`. This improves compatibility with older V1 Wi-Fi modules (including devices in the `502cc6...` family) that can answer discovery but silently ignore bind/status packets when MAC casing differs from their discovery identity. Stored device IDs and friendly names are not changed.
|
||||||
|
|||||||
+26
-2
@@ -118,7 +118,7 @@ When the LXC has a management interface and a dedicated GREE network, configure
|
|||||||
GREE_CONTROLLER_GREE_INTERFACE=eth1
|
GREE_CONTROLLER_GREE_INTERFACE=eth1
|
||||||
GREE_CONTROLLER_DISCOVERY_BROADCAST=auto
|
GREE_CONTROLLER_DISCOVERY_BROADCAST=auto
|
||||||
|
|
||||||
This explicit interface configuration is recommended for predictable LXC deployments. Version 0.3.6 also automatically selects the directly connected local IPv4 address for a GREE device when the interface variable is omitted; for example, a target in `10.87.65.0/25` selects the local address on that subnet.
|
This explicit interface configuration is recommended for predictable LXC deployments. Version 0.3.7 also automatically selects the directly connected local IPv4 address for a GREE device when the interface variable is omitted; for example, a target in `10.87.65.0/25` selects the local address on that subnet.
|
||||||
GREE_CONTROLLER_SIMULATE=false
|
GREE_CONTROLLER_SIMULATE=false
|
||||||
GREE_CONTROLLER_AUTO_SEED=false
|
GREE_CONTROLLER_AUTO_SEED=false
|
||||||
```
|
```
|
||||||
@@ -141,6 +141,30 @@ Use `scripts/network-debug.sh` for routing diagnostics.
|
|||||||
|
|
||||||
## Mixed GREE model generations
|
## Mixed GREE model generations
|
||||||
|
|
||||||
Version 0.3.6 can discover both AES-ECB and AES-GCM modules. In the Web UI choose **Discover -> Auto (V1 + V2)** and use 3-5 scan passes. If a family is still missing, repeat with V1-only and V2-only to see which protocol its Wi-Fi module answers with.
|
Version 0.3.7 can discover both AES-ECB and AES-GCM modules. In the Web UI choose **Discover -> Auto (V1 + V2)** and use 3-5 scan passes. If a family is still missing, repeat with V1-only and V2-only to see which protocol its Wi-Fi module answers with.
|
||||||
|
|
||||||
A single command/status timeout no longer immediately flips a device offline; offline requires three consecutive communication failures.
|
A single command/status timeout no longer immediately flips a device offline; offline requires three consecutive communication failures.
|
||||||
|
|
||||||
|
## Multi-NIC LXC and AF_NETLINK
|
||||||
|
|
||||||
|
When `GREE_CONTROLLER_GREE_INTERFACE` is set, the controller enumerates IPv4 addresses with Linux `getifaddrs()`. On Linux this requires a Netlink socket. The systemd sandbox therefore allows `AF_NETLINK` in addition to `AF_UNIX`, `AF_INET`, and `AF_INET6`.
|
||||||
|
|
||||||
|
If an older unit reports:
|
||||||
|
|
||||||
|
```text
|
||||||
|
getifaddrs failed
|
||||||
|
Address family not supported by protocol (os error 97)
|
||||||
|
```
|
||||||
|
|
||||||
|
update the systemd unit or add `AF_NETLINK` to `RestrictAddressFamilies`, then run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl restart gree-controller
|
||||||
|
```
|
||||||
|
|
||||||
|
For a dedicated GREE NIC such as `eth1`, the expected startup/bind log should identify the IPv4 address of that interface instead of `0.0.0.0`.
|
||||||
|
|
||||||
|
### Legacy V1 devices discovered but not binding
|
||||||
|
|
||||||
|
Version 0.3.8 sends the GREE protocol `tcid` and inner `mac` identifiers in canonical lowercase hexadecimal. If an older `502cc6...` device is discovered on UDP/7000 but stays offline after bind timeouts, update to v0.3.8 before changing routing or firewall settings. With debug logging, `Sending GREE request` should show `wire_mac=502cc6...` in lowercase.
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"domain": "gree_controller",
|
"domain": "gree_controller",
|
||||||
"name": "GREE Controller",
|
"name": "GREE Controller",
|
||||||
"version": "0.3.6",
|
"version": "0.3.8",
|
||||||
"config_flow": true,
|
"config_flow": true,
|
||||||
"integration_type": "hub",
|
"integration_type": "hub",
|
||||||
"iot_class": "local_polling",
|
"iot_class": "local_polling",
|
||||||
|
|||||||
Binary file not shown.
+15
-4
@@ -244,6 +244,15 @@ impl GreeClient {
|
|||||||
bail!("unable to bind device ({})", errors.join("; "))
|
bail!("unable to bind device ({})", errors.join("; "))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// GREE Wi-Fi modules use the 12-hex device id as a protocol identifier.
|
||||||
|
/// Older V1 modules (notably 502cc6...) can silently ignore bind/status
|
||||||
|
/// packets when tcid/mac casing differs from the lowercase value returned
|
||||||
|
/// by discovery. Keep the database/display representation independent from
|
||||||
|
/// the on-wire representation and always send canonical lowercase hex.
|
||||||
|
fn wire_mac(device: &Device) -> String {
|
||||||
|
device.mac.replace([':', '-'], "").to_ascii_lowercase()
|
||||||
|
}
|
||||||
|
|
||||||
async fn bind_attempt(&self, device: &Device, version: u8) -> Result<String> {
|
async fn bind_attempt(&self, device: &Device, version: u8) -> Result<String> {
|
||||||
let target = self.device_target(device)?;
|
let target = self.device_target(device)?;
|
||||||
let target_hint = match target { SocketAddr::V4(addr) => Some(*addr.ip()), SocketAddr::V6(_) => None };
|
let target_hint = match target { SocketAddr::V4(addr) => Some(*addr.ip()), SocketAddr::V6(_) => None };
|
||||||
@@ -271,7 +280,8 @@ impl GreeClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let inner = json!({"mac": device.mac, "t": "bind", "uid": 0});
|
let wire_mac = Self::wire_mac(device);
|
||||||
|
let inner = json!({"mac": wire_mac, "t": "bind", "uid": 0});
|
||||||
let generic_key = if version == 2 { GENERIC_GREE_V2_KEY } else { GENERIC_GREE_V1_KEY };
|
let generic_key = if version == 2 { GENERIC_GREE_V2_KEY } else { GENERIC_GREE_V1_KEY };
|
||||||
let response = self.request_on_socket(device, &inner, generic_key, true, version, &socket).await?;
|
let response = self.request_on_socket(device, &inner, generic_key, true, version, &socket).await?;
|
||||||
let kind = response.get("t").and_then(Value::as_str).unwrap_or_default();
|
let kind = response.get("t").and_then(Value::as_str).unwrap_or_default();
|
||||||
@@ -309,7 +319,7 @@ impl GreeClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn status_request(&self, device: &Device, key: &str, cols: &[&str]) -> Result<Value> {
|
async fn status_request(&self, device: &Device, key: &str, cols: &[&str]) -> Result<Value> {
|
||||||
let inner = json!({"cols": cols, "mac": device.mac, "t": "status"});
|
let inner = json!({"cols": cols, "mac": Self::wire_mac(device), "t": "status"});
|
||||||
self.request(device, &inner, key, false, device.protocol_version).await
|
self.request(device, &inner, key, false, device.protocol_version).await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -382,11 +392,12 @@ impl GreeClient {
|
|||||||
let target = self.device_target(device)?;
|
let target = self.device_target(device)?;
|
||||||
let version = if protocol_version == 2 { 2 } else { 1 };
|
let version = if protocol_version == 2 { 2 } else { 1 };
|
||||||
let inner_bytes = serde_json::to_vec(inner)?;
|
let inner_bytes = serde_json::to_vec(inner)?;
|
||||||
|
let wire_mac = Self::wire_mac(device);
|
||||||
let mut outer = json!({
|
let mut outer = json!({
|
||||||
"cid": "app",
|
"cid": "app",
|
||||||
"i": if binding { 1 } else { 0 },
|
"i": if binding { 1 } else { 0 },
|
||||||
"t": "pack",
|
"t": "pack",
|
||||||
"tcid": device.mac,
|
"tcid": wire_mac,
|
||||||
"uid": 0
|
"uid": 0
|
||||||
});
|
});
|
||||||
if version == 2 {
|
if version == 2 {
|
||||||
@@ -397,7 +408,7 @@ impl GreeClient {
|
|||||||
outer["pack"] = json!(encrypt_v1(key, &inner_bytes)?);
|
outer["pack"] = json!(encrypt_v1(key, &inner_bytes)?);
|
||||||
}
|
}
|
||||||
let payload = serde_json::to_vec(&outer)?;
|
let payload = serde_json::to_vec(&outer)?;
|
||||||
tracing::debug!(target=%target, local=%socket.local_addr()?, protocol=version, interface=%self.interface.as_deref().unwrap_or("auto"), binding, "Sending GREE request");
|
tracing::debug!(target=%target, local=%socket.local_addr()?, protocol=version, wire_mac=%wire_mac, interface=%self.interface.as_deref().unwrap_or("auto"), binding, "Sending GREE request");
|
||||||
socket.send_to(&payload, target).await?;
|
socket.send_to(&payload, target).await?;
|
||||||
|
|
||||||
let deadline = Instant::now() + Duration::from_secs(4);
|
let deadline = Instant::now() + Duration::from_secs(4);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ PrivateTmp=true
|
|||||||
ProtectSystem=strict
|
ProtectSystem=strict
|
||||||
ProtectHome=true
|
ProtectHome=true
|
||||||
ReadWritePaths=/var/lib/gree-controller
|
ReadWritePaths=/var/lib/gree-controller
|
||||||
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
|
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
|
||||||
LockPersonality=true
|
LockPersonality=true
|
||||||
MemoryDenyWriteExecute=true
|
MemoryDenyWriteExecute=true
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user