v0.14.15-fix

This commit is contained in:
Mateusz Gruszczyński
2026-09-16 17:07:17 +02:00
parent 1862fed87f
commit c7d47db64e
26 changed files with 324 additions and 377 deletions
-2
View File
@@ -1,5 +1,3 @@
# GREE Controller 0.14.15 - standalone environment example
# HTTP / WebSocket # HTTP / WebSocket
GREE_CONTROLLER_BIND=0.0.0.0:8787 GREE_CONTROLLER_BIND=0.0.0.0:8787
GREE_CONTROLLER_DATABASE=./data/gree-controller.db GREE_CONTROLLER_DATABASE=./data/gree-controller.db
Generated
+1 -1
View File
@@ -700,7 +700,7 @@ dependencies = [
[[package]] [[package]]
name = "gree-controller" name = "gree-controller"
version = "0.14.14" version = "0.14.15"
dependencies = [ dependencies = [
"aes", "aes",
"aes-gcm", "aes-gcm",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "gree-controller" name = "gree-controller"
version = "0.14.14" version = "0.14.15"
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"
+43 -47
View File
@@ -1,18 +1,20 @@
5302570299af2c2650bada12e123f598c5db8009949c75761385f73ed57343c5 ./build.rs
6c60703633b9d6a696c22beca15e2bbc0c90424a1b98a5dd53cdc0d670dffffd ./Cargo.lock
b19e576628872d7344786c71a65de6b30f67f384b9306930b1aaa6018bf2caaa ./Cargo.toml
91e37862ce8780696128bc84ad941b27f13f2badde5748d8ba73328a8f2201af ./data/gree-controller.db
c4a46a314f328075d95ca9bf6e88f24dbc243223412c33468de0901c6d19423c ./docs/API.md
f21d732eb1147f8f3167d2172cdf0b57e61edabdfecbaf97811d46c5bff7e47a ./docs/FLOW.md
f42e2dd9d0ad82958fd554bc8a7faf08a1bbd502f897a93cb32cc86089bda2b2 ./docs/openapi.json
d67af429e4da9ce08e9d2f2a8472849ffbd70d135b1c5da535a076026794d04c ./.env
f809050a6074ba8e98e08c89af1174dffef679114ffae5c2d200150a9588b8d9 ./.env.example f809050a6074ba8e98e08c89af1174dffef679114ffae5c2d200150a9588b8d9 ./.env.example
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
14f342bc7d1762a04df5875d32a621f06b35b06dc86ea50f1fc554f8d7b3f94d ./gree-controller.zip 597f6fb6e6b7306d2b22fa68cf4cc9c438b1d67537db29519a1de57a8775a426 ./Cargo.lock
cd7fd4b937a1d6138699f7effd184e3c077912b881e9c73c37b90bbafba68477 ./ha-addon/build.sh 8839d028f8c3facf329b97d8e2623b6c89b27aa25716ccd4848dff4a5e4041bf ./Cargo.toml
a18d2460340264d34c267fa704ee51a42e59bcc1783ee4c0dbb2a8ef42fa0f16 ./ha-addon/Dockerfile 19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
fef9a676b9ce82d0539d44e456237a814169a17a158557d7b803a455985bc020 ./ha-addon/.env 699e00f944554597b1684b7892cb43dc96eb3c7b6f04ed8e28fc3a8784765ff2 ./README.md
bdc52c361ff7a2e0fc3e96ab2b1599f4002cc6490064e4064a5688604cde83bc ./SOURCE_MANIFEST.sha256
5302570299af2c2650bada12e123f598c5db8009949c75761385f73ed57343c5 ./build.rs
fa74b515483caeea518e392adfe8f235fb3f08131fb2fbd12bebe58c665bd81f ./docs/API.md
f21d732eb1147f8f3167d2172cdf0b57e61edabdfecbaf97811d46c5bff7e47a ./docs/FLOW.md
809adad678983ed8572dd558768be2f20835ebd92dc527da7207e6b5df096d47 ./docs/openapi.json
c65aa543d2e99f8f7d52736307b07ebd182597d80124661d53a16bb23f6f1118 ./ha-addon/.env.example c65aa543d2e99f8f7d52736307b07ebd182597d80124661d53a16bb23f6f1118 ./ha-addon/.env.example
ddec80cf2b5da73fd1bae50e46398033c95aa088afdb7c07d4889b5987a17a3f ./ha-addon/Dockerfile
3702707b5fd4f3a3d5d73e2dc827a6a43c144a22ff94861ab38720207bfcd94b ./ha-addon/README.md
dd9291b12afade6fc20d66e80a5513251270e18e4c265260b2bbbe393a5a94c4 ./ha-addon/build.sh
082dfeb6326f3e1b9841ccf7f2954117ecdf0aa1a90b0aef1e6a1960dacdecbf ./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 3f6ef15ef58456376ac53fde7cace1ef359d6a6f7a64c5b575ad77ea6e55ccc4 ./ha-addon/home-assistant/custom_components/gree_controller/api.py
0c008329aad15f5af6328380c1afe1f49db186b37b3d1cafec4b6f4088386e8e ./ha-addon/home-assistant/custom_components/gree_controller/climate.py 0c008329aad15f5af6328380c1afe1f49db186b37b3d1cafec4b6f4088386e8e ./ha-addon/home-assistant/custom_components/gree_controller/climate.py
5e4aef2143e81bedb5a15dd4be5c71b64a3ab448ec6d33a20851edd098e5f529 ./ha-addon/home-assistant/custom_components/gree_controller/config_flow.py 5e4aef2143e81bedb5a15dd4be5c71b64a3ab448ec6d33a20851edd098e5f529 ./ha-addon/home-assistant/custom_components/gree_controller/config_flow.py
@@ -20,8 +22,7 @@ b7f0873109c52be9d7f09bea3dffc416103c50085e1f0680d11661a969479898 ./ha-addon/hom
41a8958a6fe6d10e5679c95ac34832583a2a15ecfd67d09b4e094a83d06f5c47 ./ha-addon/home-assistant/custom_components/gree_controller/coordinator.py 41a8958a6fe6d10e5679c95ac34832583a2a15ecfd67d09b4e094a83d06f5c47 ./ha-addon/home-assistant/custom_components/gree_controller/coordinator.py
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./ha-addon/home-assistant/custom_components/gree_controller/entity_map.py 5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./ha-addon/home-assistant/custom_components/gree_controller/entity_map.py
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./ha-addon/home-assistant/custom_components/gree_controller/icon.png c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./ha-addon/home-assistant/custom_components/gree_controller/icon.png
f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./ha-addon/home-assistant/custom_components/gree_controller/__init__.py c62ac791ec1abefe26ea97e001a92db2f2905ee603b50aab0e76242b45e863e7 ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json
2348f11fcbadc83258cdd63ec81a946a38163a7729dbcf531d93cbdd51faea9d ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json
c52a484b671ce738ecc00228a1db19a5d703f69ab27530c2896a5c2ae3b4a96f ./ha-addon/home-assistant/custom_components/gree_controller/number.py c52a484b671ce738ecc00228a1db19a5d703f69ab27530c2896a5c2ae3b4a96f ./ha-addon/home-assistant/custom_components/gree_controller/number.py
39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./ha-addon/home-assistant/custom_components/gree_controller/select.py 39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./ha-addon/home-assistant/custom_components/gree_controller/select.py
cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/home-assistant/custom_components/gree_controller/sensor.py cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/home-assistant/custom_components/gree_controller/sensor.py
@@ -29,24 +30,21 @@ cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/hom
6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./ha-addon/home-assistant/custom_components/gree_controller/translations/en.json 6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./ha-addon/home-assistant/custom_components/gree_controller/translations/en.json
13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./ha-addon/home-assistant/custom_components/gree_controller/translations/pl.json 13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./ha-addon/home-assistant/custom_components/gree_controller/translations/pl.json
c5fc5c87273d82d2834a0a5a365c821a416413ed509613441e24e4dc3507c4d2 ./ha-addon/home-assistant/generated/gree_controller_entities.example.json c5fc5c87273d82d2834a0a5a365c821a416413ed509613441e24e4dc3507c4d2 ./ha-addon/home-assistant/generated/gree_controller_entities.example.json
082dfeb6326f3e1b9841ccf7f2954117ecdf0aa1a90b0aef1e6a1960dacdecbf ./ha-addon/home-assistant/README.md 59f420dcff7b7712ee4fb2afcda8573d2f420b593cc333989b4537179703508c ./ha-addon/repository/gree-controller/CHANGELOG.md
f9e31de3d109ead32bf531c074d46a087df398d62488caee0b46b5e0a1c027f7 ./ha_addon.md 1b5599195329cc3e643c23aa1caadcec80f133e8e515eec7d92b9f3cbda5b80b ./ha-addon/repository/gree-controller/DOCS.md
0417c88a990c72aecf071fba64d5d9da65dcda4d396cd7565477f7a4532c8c5e ./ha-addon/README.md
f3e47cf1a186608f0b70d54be54ccbd1e120c968e773f31fc85ec52a03392e61 ./ha-addon/repository/gree-controller/CHANGELOG.md
40f4f7156a882ef390011915fe38ee8299633e8b51ab554cd67a7b1e4c99f4ea ./ha-addon/repository/gree-controller/config.yaml
28936708e6cfcc7eafd0d587f6d6cb50f926f70959bdfc7e07849c81d251c71a ./ha-addon/repository/gree-controller/DOCS.md
c3db302f38d26dc9f8caf37a1a8a07a1334cc07ae301d452f2940a5ec5915719 ./ha-addon/repository/gree-controller/README.md c3db302f38d26dc9f8caf37a1a8a07a1334cc07ae301d452f2940a5ec5915719 ./ha-addon/repository/gree-controller/README.md
bc356f1ea4f367084677ae05887a256056d6b403e5a0f0e57c86c11636fb20ea ./ha-addon/repository/gree-controller/config.yaml
3aae6cdae4c3aaab7786a9575e7093b7e2c5b69288167075f4b7475611691a6b ./ha-addon/repository/gree-controller/topologia-ha-vlan-gree-pl.png 3aae6cdae4c3aaab7786a9575e7093b7e2c5b69288167075f4b7475611691a6b ./ha-addon/repository/gree-controller/topologia-ha-vlan-gree-pl.png
0d0b42a7639b128946eec379175436fa1f150294f39d2dfd169077bfa87fd14d ./ha-addon/repository/gree-controller/topology-ha-vlan-gree-en.png 0d0b42a7639b128946eec379175436fa1f150294f39d2dfd169077bfa87fd14d ./ha-addon/repository/gree-controller/topology-ha-vlan-gree-en.png
ad3715c719f53dca932a208cfacbe9c65834d9552e41bfef8172bef5ce76be35 ./ha-addon/repository/gree-controller/translations/en.yaml 2272740b185e9520e948f74b8f45cf98b8b5fd28c93bdee760da626f91fe5c2a ./ha-addon/repository/gree-controller/translations/en.yaml
5564559ed847e42375ceec55e5e9f37c6c69f91b501a2d5c4e8c6656938a766d ./ha-addon/repository/gree-controller/translations/pl.yaml e6b93d3701d83a31506617a0e6f44ff32d8c24a52be038c8540c862b13546b50 ./ha-addon/repository/gree-controller/translations/pl.yaml
2153b230357aab4766398577e23a7a9ff83bb135ddc86d1b3f2cbfc852efe0a1 ./ha-addon/repository/repository.yaml 2153b230357aab4766398577e23a7a9ff83bb135ddc86d1b3f2cbfc852efe0a1 ./ha-addon/repository/repository.yaml
e8a77dbdb98c6ebcfbe6a08b0b5546178d965f25496c19f7aebaff287630838e ./ha-addon/run.sh cea12bc74c066a588a5ef0ef7bad9d4906bdbcea99f2d275429b0eefc94b4b5f ./ha-addon/run.sh
081e27b6e43070d44f865335c30a42a5a29668eaa6a5ea5ab6967ac4447b8e06 ./ha-addon/sync-repository.sh 081e27b6e43070d44f865335c30a42a5a29668eaa6a5ea5ab6967ac4447b8e06 ./ha-addon/sync-repository.sh
f9e31de3d109ead32bf531c074d46a087df398d62488caee0b46b5e0a1c027f7 ./ha_addon.md
253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md
ec091f3cf6745995b1a677df5b064e9ed70e67b61f2c300e146ac8d64d6af570 ./lang/en.json ec091f3cf6745995b1a677df5b064e9ed70e67b61f2c300e146ac8d64d6af570 ./lang/en.json
b14581a982441986df693849feccfcdfe4769b245a2adac0558fc86420d17f82 ./lang/pl.json b14581a982441986df693849feccfcdfe4769b245a2adac0558fc86420d17f82 ./lang/pl.json
253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
d8459024f04ca514bd8e9d6bd3af872fb942fd85a7cdd5583f4a9d28aab6faba ./make_zip.py d8459024f04ca514bd8e9d6bd3af872fb942fd85a7cdd5583f4a9d28aab6faba ./make_zip.py
b14233a8987e53bbbdd6770386ba10fa166ec25c1e098275c173c544b37846fc ./presets/bedroom_window_night.json b14233a8987e53bbbdd6770386ba10fa166ec25c1e098275c173c544b37846fc ./presets/bedroom_window_night.json
1960841119c0b673fb2f03621b32237552fd828045304cd221401214b997c910 ./presets/device_resilience.json 1960841119c0b673fb2f03621b32237552fd828045304cd221401214b997c910 ./presets/device_resilience.json
@@ -85,9 +83,9 @@ fffa18bd989a0dcc1c5458975522517d40af4af40cc1ca30640e79d3db711053 ./presets/unoc
ae21459a261712bcb8d57594528b1648432e8d03a8a38502234829c0dbfef774 ./presets/weekend_comfort.json ae21459a261712bcb8d57594528b1648432e8d03a8a38502234829c0dbfef774 ./presets/weekend_comfort.json
fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/window_available_guard.json fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/window_available_guard.json
804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json 804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json
2b0c8072501b7c63cefb16a92694132d311c0fde79bc43a5f7681d630e035b75 ./README.md fd7390d64a2378352c09382accf6efff43903d952d111b22a982f06c5b2a3b4b ./regenerate-sha.sh
01952aa92b217f8eae2493b88870e2dec595100cd15c4d561ff11ae2b936c46f ./regenerate-sha.sh c64b1c6deeb24f20af662bfce7fa3683703914987241107ce664fa2f6d1a9dcb ./scripts/README.md
0d2fd90f690d00a1f21aa4e3810a3dce976b55583df752c1cb7a90bc3742e7d3 ./scripts/api_dev_test.py 8bf77e97e4789242924aa030aa63c63912f5cd7334de0778f2ea9800c6912f8e ./scripts/api_dev_test.py
5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh 5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh
6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh 6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh
1d6e14e26e49aa9d3527f30a23668bf8d9c48b67e6628ef686c3155c012155de ./scripts/dev.sh 1d6e14e26e49aa9d3527f30a23668bf8d9c48b67e6628ef686c3155c012155de ./scripts/dev.sh
@@ -96,16 +94,15 @@ e4849261fd9ed1f01df96c0637c439c0c4eff8fa317b2918026167bba343af79 ./scripts/inst
bb7cd2c5b27c9dceec1d1d2846fbad9600df9c08e0ad07d13fcde97af533091c ./scripts/install.sh bb7cd2c5b27c9dceec1d1d2846fbad9600df9c08e0ad07d13fcde97af533091c ./scripts/install.sh
1a84c91a89bf7f60aa4816a7650640f315efadf39bf7b54dc20f1259b2e2d5ce ./scripts/live_realtime_test.js 1a84c91a89bf7f60aa4816a7650640f315efadf39bf7b54dc20f1259b2e2d5ce ./scripts/live_realtime_test.js
e00d211e3885e30d7fed1e43b44e6fdad40a67019060156c0641816a93e3365f ./scripts/network-debug.sh e00d211e3885e30d7fed1e43b44e6fdad40a67019060156c0641816a93e3365f ./scripts/network-debug.sh
c64b1c6deeb24f20af662bfce7fa3683703914987241107ce664fa2f6d1a9dcb ./scripts/README.md
01952aa92b217f8eae2493b88870e2dec595100cd15c4d561ff11ae2b936c46f ./scripts/regenerate-sha.sh 01952aa92b217f8eae2493b88870e2dec595100cd15c4d561ff11ae2b936c46f ./scripts/regenerate-sha.sh
81345b6a0b51736bdbc98fd23199b62e4c721b4e7437e02dab7ea79b97dff29a ./scripts/service.sh 81345b6a0b51736bdbc98fd23199b62e4c721b4e7437e02dab7ea79b97dff29a ./scripts/service.sh
bd703ef841f9763f13367aaa5764381b9c59ee87210e806c24617f3cc0739a9b ./scripts/smoke.sh bd703ef841f9763f13367aaa5764381b9c59ee87210e806c24617f3cc0739a9b ./scripts/smoke.sh
b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/update.sh b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/update.sh
28dde10947ac7a9c4b0301b67286cd01653d4d372989c1c948ec5dc39ae5dec9 ./SOURCE_MANIFEST.sha256 a70ddd9d4c9fca073ff494db73ec13acc7cff1830c9675d0541518d814da3772 ./src/api.rs
f6ed359370dacd691344402307843a0ad31bbeb46085f99e81cfa46a618ee87d ./src/api/assets.rs f6ed359370dacd691344402307843a0ad31bbeb46085f99e81cfa46a618ee87d ./src/api/assets.rs
b24092f34a46626d64628b510eba82193f0b203fd097f6a621b91af5d91eb571 ./src/api/auth.rs b24092f34a46626d64628b510eba82193f0b203fd097f6a621b91af5d91eb571 ./src/api/auth.rs
9e4fc675306e111ed3db7af9822e2925d88109c31b9e309851665a975c0bd83c ./src/api/automations.rs 9e4fc675306e111ed3db7af9822e2925d88109c31b9e309851665a975c0bd83c ./src/api/automations.rs
5d1cbc16bcdf0e048c9ec554bfb3a8c26068f3a99fc947ae195221015b90834c ./src/api/configuration.rs 1f2e3df47e532c1a222125d3790ec97772cf535af679589fde0ef9217f2db018 ./src/api/configuration.rs
19bc141286a336ad67e99079496eb0ae5126f986ab28be62b5f97758e5f6969c ./src/api/debug_tokens.rs 19bc141286a336ad67e99079496eb0ae5126f986ab28be62b5f97758e5f6969c ./src/api/debug_tokens.rs
32ade46ec45d6faf7852242b9f5ba1be6eacbacbeb33d2deabfab59bf1610ce0 ./src/api/device_groups.rs 32ade46ec45d6faf7852242b9f5ba1be6eacbacbeb33d2deabfab59bf1610ce0 ./src/api/device_groups.rs
fcbb3da0538aab451f71810f829cc248d6bb67e586dc418d71a572980583823d ./src/api/devices.rs fcbb3da0538aab451f71810f829cc248d6bb67e586dc418d71a572980583823d ./src/api/devices.rs
@@ -116,16 +113,16 @@ b61b0b4f196c5e72e47cf06ca0c14df3cf8eedbdef0242a9d2af33623663489f ./src/api/grou
e41ddb47f46ccad81baab1d25ddba910c087350b4b521844a33eae010cdaaa0b ./src/api/history.rs e41ddb47f46ccad81baab1d25ddba910c087350b4b521844a33eae010cdaaa0b ./src/api/history.rs
e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs
c71540b2b68e805e3a79ac787db9127b87585968a205fc307e93bf68d5b028e0 ./src/api/integrations.rs c71540b2b68e805e3a79ac787db9127b87585968a205fc307e93bf68d5b028e0 ./src/api/integrations.rs
cafff8c070b146619a541f7b03502e85594c2d9a442ab23610b076e6bd251abe ./src/api/middleware.rs 7658111f7d125db55a6e23f88157339b110b2cd1ed13ceabd8f860b42dba5101 ./src/api/middleware.rs
45e34a447ff384d99a3c42c489ca9fa75849c74d4d246caa91c63d927de17396 ./src/api/openapi.rs 45e34a447ff384d99a3c42c489ca9fa75849c74d4d246caa91c63d927de17396 ./src/api/openapi.rs
b777e7fbeccef699e11ffd16bb18633843c99afecacce2221280e54b09f6d2da ./src/api/public_settings.rs b777e7fbeccef699e11ffd16bb18633843c99afecacce2221280e54b09f6d2da ./src/api/public_settings.rs
a70ddd9d4c9fca073ff494db73ec13acc7cff1830c9675d0541518d814da3772 ./src/api.rs
5b29f2e5aa2c422c5829ef89c7b59cf753883aa7f60661c95ab0f95cf676fa3f ./src/api/schedules.rs 5b29f2e5aa2c422c5829ef89c7b59cf753883aa7f60661c95ab0f95cf676fa3f ./src/api/schedules.rs
6acf6417b077a0204a815e255c667928476014ce5f94c1559c9d4268c00342d5 ./src/api/settings.rs 6acf6417b077a0204a815e255c667928476014ce5f94c1559c9d4268c00342d5 ./src/api/settings.rs
dfa04f2acc0bcbfca826c4196ab960b38d6bb4193312477ca1167b190aef4b13 ./src/api/system.rs 0de92f241b5da2b7f13aaf9c24ef76eba8d26f8e27d87c9312bd644ab13d31bd ./src/api/system.rs
94d3845def693aafe15fa6e8b390881c46c3c236b62f247ddfdc055d9226ed22 ./src/api/websocket.rs 94d3845def693aafe15fa6e8b390881c46c3c236b62f247ddfdc055d9226ed22 ./src/api/websocket.rs
ddd1bfc8625b66f6e5f3d24b3122ac86c25f89b0af527e3dfce9102551a8f142 ./src/api/zones.rs ddd1bfc8625b66f6e5f3d24b3122ac86c25f89b0af527e3dfce9102551a8f142 ./src/api/zones.rs
e495bbb37e81b539bfacfce065fe791f630ccd524e2a33b9dcfd8fe6856941cf ./src/config.rs 7b15febe046c79917a22664f50d9063fd6d0968521544ef31b854424f73b4408 ./src/config.rs
f8394e0daca284070ac9ae0844d6b04fed7c30386f2d1ec409ecf07880bb0e6a ./src/db.rs
fdc9d019097becc5c36a0560caa1619aa35d802c0d208902b3bfecbe1643e3e8 ./src/db/climate.rs fdc9d019097becc5c36a0560caa1619aa35d802c0d208902b3bfecbe1643e3e8 ./src/db/climate.rs
e5d2027d40a99e61c2c572499af617a92de9e554f8916f3ea6f6731d1d6b09b4 ./src/db/configuration.rs e5d2027d40a99e61c2c572499af617a92de9e554f8916f3ea6f6731d1d6b09b4 ./src/db/configuration.rs
46213497ae26b2f799364a2e64e41df26c93a39eb4e7167b59c1e42b525f61f7 ./src/db/core_devices.rs 46213497ae26b2f799364a2e64e41df26c93a39eb4e7167b59c1e42b525f61f7 ./src/db/core_devices.rs
@@ -135,10 +132,10 @@ f99de2230082f17eafaf03f5361bb67419205a23d64f22480c996f9c32c55ac5 ./src/db/energ
bb5048ee60053f39ce3c1203dc1f24c7047310538d2357f105a052c016d21ec4 ./src/db/flows.rs bb5048ee60053f39ce3c1203dc1f24c7047310538d2357f105a052c016d21ec4 ./src/db/flows.rs
5f4b567c6bc866d0674b3b0c66f4aeccf561774623f575b872ff25bf015b91c2 ./src/db/ha_history.rs 5f4b567c6bc866d0674b3b0c66f4aeccf561774623f575b872ff25bf015b91c2 ./src/db/ha_history.rs
7840c89515d08a23050e2634dd91bcdbf7aecc0a8a80bf5002f3eb660ca46f20 ./src/db/network_history.rs 7840c89515d08a23050e2634dd91bcdbf7aecc0a8a80bf5002f3eb660ca46f20 ./src/db/network_history.rs
f8394e0daca284070ac9ae0844d6b04fed7c30386f2d1ec409ecf07880bb0e6a ./src/db.rs
d6b9b70a04c774173c97f7426487d5e2932d7713e12ae3fb7f64cf2b4e0b3c10 ./src/db/schedules_automations.rs d6b9b70a04c774173c97f7426487d5e2932d7713e12ae3fb7f64cf2b4e0b3c10 ./src/db/schedules_automations.rs
8b312e258f079d844466ad516134cdd065a017be78be41214b4239fc0f9e5b36 ./src/db/tests.rs 8b312e258f079d844466ad516134cdd065a017be78be41214b4239fc0f9e5b36 ./src/db/tests.rs
f90fbb14f29a20b799b3856bdaa22812a9f0d9dfa46693f1341c160dccda8a97 ./src/db/zone_history.rs f90fbb14f29a20b799b3856bdaa22812a9f0d9dfa46693f1341c160dccda8a97 ./src/db/zone_history.rs
4ed54df6321496a6afabf9443beb9fa8d3434c510aa01dade318bbaa44f0f0ac ./src/engine.rs
ed5c9a0c61c6e597acb33f58593ebe02b562ddc68fa61271e1c1cd436c1003d3 ./src/engine/automations.rs ed5c9a0c61c6e597acb33f58593ebe02b562ddc68fa61271e1c1cd436c1003d3 ./src/engine/automations.rs
0bf7fe7d28b4749e53ec25d71effbb78bc8f70c716714f838a4a2d8f20627d63 ./src/engine/commands.rs 0bf7fe7d28b4749e53ec25d71effbb78bc8f70c716714f838a4a2d8f20627d63 ./src/engine/commands.rs
f7de7b9b756bef9d6cffbc6ffdb7504b3121476f188e6ff5c8077d5fc54be811 ./src/engine/connectivity.rs f7de7b9b756bef9d6cffbc6ffdb7504b3121476f188e6ff5c8077d5fc54be811 ./src/engine/connectivity.rs
@@ -150,7 +147,6 @@ e350aa63f3bb14ca887eaaa7555edbeae00fb584cbcaf552cc972f0c8918f5d8 ./src/engine/g
41b7045877771b7c352328998cb45ce2433e7f9631fad3eb1a882ab4897dc31f ./src/engine/local_thermostat.rs 41b7045877771b7c352328998cb45ce2433e7f9631fad3eb1a882ab4897dc31f ./src/engine/local_thermostat.rs
99527adab9fea1caede9ebb24faa6a63d5cef4810c64c06306b571cf5cbbb0da ./src/engine/ownership.rs 99527adab9fea1caede9ebb24faa6a63d5cef4810c64c06306b571cf5cbbb0da ./src/engine/ownership.rs
1a29b7fd8de77f0a5e5964ca05e41cc5ea78855c1ab961750d40461faec305e5 ./src/engine/polling.rs 1a29b7fd8de77f0a5e5964ca05e41cc5ea78855c1ab961750d40461faec305e5 ./src/engine/polling.rs
4ed54df6321496a6afabf9443beb9fa8d3434c510aa01dade318bbaa44f0f0ac ./src/engine.rs
d48ae1799e045fb212e73e630a5d26ed3c5e3359a3dac3ebd5638532efdd4285 ./src/engine/runtime.rs d48ae1799e045fb212e73e630a5d26ed3c5e3359a3dac3ebd5638532efdd4285 ./src/engine/runtime.rs
c1e8de5392681ba1255e3e2d871a6ee860fb8ca987a0a8f973d9ded3977a68fb ./src/engine/schedules.rs c1e8de5392681ba1255e3e2d871a6ee860fb8ca987a0a8f973d9ded3977a68fb ./src/engine/schedules.rs
b0189f28d0f337dfd3ce0934da7a565e4a5535afc1c242214c26ed584b3b7840 ./src/engine/targets.rs b0189f28d0f337dfd3ce0934da7a565e4a5535afc1c242214c26ed584b3b7840 ./src/engine/targets.rs
@@ -161,11 +157,12 @@ c89ff36c6a67bf4fbf68c43e18aa0a556de2dc69263fd79db376363afc741a4f ./src/engine/z
3a7fada1f6dd9ebab4026b353f41b21d8ca19342b02538c711dbb2dfb599cbe7 ./src/engine/zone_control.rs 3a7fada1f6dd9ebab4026b353f41b21d8ca19342b02538c711dbb2dfb599cbe7 ./src/engine/zone_control.rs
bfac95cec87f0df6ce562153cd3cfe6731359d703e6c592d2c2f7ba01ea62d99 ./src/error.rs bfac95cec87f0df6ce562153cd3cfe6731359d703e6c592d2c2f7ba01ea62d99 ./src/error.rs
a1bd54026f9c7e9f84da1a730136db81095e8ba1ceeb2596fc01479def76df83 ./src/home_assistant.rs a1bd54026f9c7e9f84da1a730136db81095e8ba1ceeb2596fc01479def76df83 ./src/home_assistant.rs
e78ca9aff23362971eb6450534ea21bdc15150456c378ef9b226cb93a8dbc612 ./src/influxdb.rs
da4068295f37c23222bb13bebac022d88ba7729604a49ad25438c55e45458a49 ./src/influxdb/codec.rs da4068295f37c23222bb13bebac022d88ba7729604a49ad25438c55e45458a49 ./src/influxdb/codec.rs
b96624fa34b218a6d5f028ba09579633f6f8a04c109f0e94801e8d89ceeeb4b5 ./src/influxdb/query.rs b96624fa34b218a6d5f028ba09579633f6f8a04c109f0e94801e8d89ceeeb4b5 ./src/influxdb/query.rs
e78ca9aff23362971eb6450534ea21bdc15150456c378ef9b226cb93a8dbc612 ./src/influxdb.rs
8089b8eca47419bb6b3ee02560e5cc39c00479164bc76d11992679b2cef3258e ./src/influxdb/write.rs 8089b8eca47419bb6b3ee02560e5cc39c00479164bc76d11992679b2cef3258e ./src/influxdb/write.rs
6479dd1e5d7f8eb2ffb945ca958124107c5585c0abdfb34555367db0c21145da ./src/main.rs 6479dd1e5d7f8eb2ffb945ca958124107c5585c0abdfb34555367db0c21145da ./src/main.rs
23688a5cb68efded89471ce959328d27adff370d451bd9f378a283ab51437e76 ./src/models.rs
920e028d96a14cca9f74a964bb296e68a109cfead314d3164c180201e606d151 ./src/models/automation.rs 920e028d96a14cca9f74a964bb296e68a109cfead314d3164c180201e606d151 ./src/models/automation.rs
fc5f2802a073a175a8985e56bcb87eb1ff481226d5b4eeabad73dbba1839fc45 ./src/models/control_plan.rs fc5f2802a073a175a8985e56bcb87eb1ff481226d5b4eeabad73dbba1839fc45 ./src/models/control_plan.rs
06357b352ff6494d83e72796b869573a8b8f36b835985a5900ac571c922b8da9 ./src/models/defaults.rs 06357b352ff6494d83e72796b869573a8b8f36b835985a5900ac571c922b8da9 ./src/models/defaults.rs
@@ -173,32 +170,31 @@ fc5f2802a073a175a8985e56bcb87eb1ff481226d5b4eeabad73dbba1839fc45 ./src/models/c
aeab5b5acf35d38a54fd1d82e964fe56635ade69c0149ad423df317095d01555 ./src/models/flow.rs aeab5b5acf35d38a54fd1d82e964fe56635ade69c0149ad423df317095d01555 ./src/models/flow.rs
ba5d359e4d6c12d9f62c1b28bdfb40d312737930df5421814f5310f7183e96c1 ./src/models/history.rs ba5d359e4d6c12d9f62c1b28bdfb40d312737930df5421814f5310f7183e96c1 ./src/models/history.rs
1fee89f939018bf1f3686c15f25434f01ab96b3239164108db7f348a1f1f8d82 ./src/models/integrations.rs 1fee89f939018bf1f3686c15f25434f01ab96b3239164108db7f348a1f1f8d82 ./src/models/integrations.rs
23688a5cb68efded89471ce959328d27adff370d451bd9f378a283ab51437e76 ./src/models.rs
f1359b68f1d041cd441f80429e77893eeb6f6194613b58fd3e7a212fb511db3e ./src/models/runtime.rs f1359b68f1d041cd441f80429e77893eeb6f6194613b58fd3e7a212fb511db3e ./src/models/runtime.rs
e3dfdd6dba63f6febd0b64da413b2fe7ca258a54abc2fdd6f2982c27425abfd6 ./src/models/settings_api.rs e3dfdd6dba63f6febd0b64da413b2fe7ca258a54abc2fdd6f2982c27425abfd6 ./src/models/settings_api.rs
c4de6101de85d9d7e6814b2504b87d9216561e3d9e274054f081f505fb152140 ./src/models/temporary_thermostat.rs c4de6101de85d9d7e6814b2504b87d9216561e3d9e274054f081f505fb152140 ./src/models/temporary_thermostat.rs
bc2818ce8d0dae1edfb1b98e5d1c00b193f03eeaa28e343d3532f6023288738c ./src/models/zone.rs bc2818ce8d0dae1edfb1b98e5d1c00b193f03eeaa28e343d3532f6023288738c ./src/models/zone.rs
62e696df8b86835df7ad127f03c257a78580769dc82bc66daa5041f71e8440a5 ./src/notifications.rs 62e696df8b86835df7ad127f03c257a78580769dc82bc66daa5041f71e8440a5 ./src/notifications.rs
cca742bb2b500eb9269f69385fcf88053cd08aabf6a98b7669b8a7a2fd67df13 ./src/protocol/crypto.rs cca742bb2b500eb9269f69385fcf88053cd08aabf6a98b7669b8a7a2fd67df13 ./src/protocol/crypto.rs
cd0612021f8ed6c9e0823d63883c0790db09aa485583f3f3fc9f2579f2c28ea3 ./src/protocol/gree.rs
7907c33e6396c7e0d61705b735b21c84d6ed784012fb61022b872c6745540f1d ./src/protocol/gree/binding.rs 7907c33e6396c7e0d61705b735b21c84d6ed784012fb61022b872c6745540f1d ./src/protocol/gree/binding.rs
d406a2c5a49fe059f3f3a00ea534a32f9bdd972c09cc051cbfc4317f7c91b38c ./src/protocol/gree_cloud_mqtt.rs
49dcca1e4a4ad858b312386e3b729f36da691916d8fe62ad682ddb86d40695b7 ./src/protocol/gree_cloud.rs
d71771855d5ac90fae4994debf53ed09472b216c17bb2155d80aa2de13c57e18 ./src/protocol/gree/commands.rs d71771855d5ac90fae4994debf53ed09472b216c17bb2155d80aa2de13c57e18 ./src/protocol/gree/commands.rs
4e419ba3b86ca9d154e8c04445cf005965175c54041093b2daad3666d4d852bd ./src/protocol/gree/core.rs 4e419ba3b86ca9d154e8c04445cf005965175c54041093b2daad3666d4d852bd ./src/protocol/gree/core.rs
05fa2e4ec133a61c23a3f4ab2ce792bbfab93feaea9f0ce0d4ccc67fc479833d ./src/protocol/gree/discovery.rs 05fa2e4ec133a61c23a3f4ab2ce792bbfab93feaea9f0ce0d4ccc67fc479833d ./src/protocol/gree/discovery.rs
0ab094f609edb99715402d8eeaa7e38cbfd2d271036aec787dcbb3be3e005720 ./src/protocol/gree/merge.rs 0ab094f609edb99715402d8eeaa7e38cbfd2d271036aec787dcbb3be3e005720 ./src/protocol/gree/merge.rs
c09c931fa8d512a8883fb14f3142be694af3c51290e023d25c7c972e156e4bd2 ./src/protocol/gree/network.rs c09c931fa8d512a8883fb14f3142be694af3c51290e023d25c7c972e156e4bd2 ./src/protocol/gree/network.rs
0a901ff258a74072af3812c5417196da1a9b8daa8a2eff30c96d038558601739 ./src/protocol/gree/polling.rs 0a901ff258a74072af3812c5417196da1a9b8daa8a2eff30c96d038558601739 ./src/protocol/gree/polling.rs
cd0612021f8ed6c9e0823d63883c0790db09aa485583f3f3fc9f2579f2c28ea3 ./src/protocol/gree.rs
50152bcad4a843ae04000b991a2365abb302fc1583ea69f09320e25740f3c38c ./src/protocol/gree/tests.rs 50152bcad4a843ae04000b991a2365abb302fc1583ea69f09320e25740f3c38c ./src/protocol/gree/tests.rs
3c93e5b254a2a40a07854532cb5fc07e493ad65d9ba2cf28093cff4a4a4e451c ./src/protocol/gree/transport.rs 3c93e5b254a2a40a07854532cb5fc07e493ad65d9ba2cf28093cff4a4a4e451c ./src/protocol/gree/transport.rs
49dcca1e4a4ad858b312386e3b729f36da691916d8fe62ad682ddb86d40695b7 ./src/protocol/gree_cloud.rs
d406a2c5a49fe059f3f3a00ea534a32f9bdd972c09cc051cbfc4317f7c91b38c ./src/protocol/gree_cloud_mqtt.rs
6258ee3888a5f9a4f8bb6cfbbac97f2621de07f9da6bcb2fa596d452f47f2e49 ./src/protocol/mod.rs 6258ee3888a5f9a4f8bb6cfbbac97f2621de07f9da6bcb2fa596d452f47f2e49 ./src/protocol/mod.rs
823da603035619894d8a0252c6a9782c44fdf8d539f09a0a0c120dc8e4b8e4f2 ./src/provider.rs 823da603035619894d8a0252c6a9782c44fdf8d539f09a0a0c120dc8e4b8e4f2 ./src/provider.rs
830621fa75265da7288b8135704c0ce27e0687f87d55abf3cdbe40a6e2f3d2b1 ./src/queries.rs
7fac65a9dcbcecee09816f5447c7792dc94f736b1efb66ac85629db75f6280be ./src/queries/device_history.rs 7fac65a9dcbcecee09816f5447c7792dc94f736b1efb66ac85629db75f6280be ./src/queries/device_history.rs
580917b91441fe9b3276cf0cfc31536ba7954b6a86f4080347b93f9367a5b1ac ./src/queries/entities.rs 580917b91441fe9b3276cf0cfc31536ba7954b6a86f4080347b93f9367a5b1ac ./src/queries/entities.rs
2c5fba462b72158b04dbaaa53c8536263f8d72a1338a6c4ff06cb28a36f6ae27 ./src/queries/ha_history.rs 2c5fba462b72158b04dbaaa53c8536263f8d72a1338a6c4ff06cb28a36f6ae27 ./src/queries/ha_history.rs
7e12e8704faa7ac15a312bcc1d714ee1c6f27c1dce0972d4ccd6e5a40c69c884 ./src/queries/maintenance.rs 7e12e8704faa7ac15a312bcc1d714ee1c6f27c1dce0972d4ccd6e5a40c69c884 ./src/queries/maintenance.rs
830621fa75265da7288b8135704c0ce27e0687f87d55abf3cdbe40a6e2f3d2b1 ./src/queries.rs
7da8b73a1c8c30e2a12071062d36f5393938fde0b5ffebbe4af1891da40f3233 ./src/queries/schema.rs 7da8b73a1c8c30e2a12071062d36f5393938fde0b5ffebbe4af1891da40f3233 ./src/queries/schema.rs
f13f1be3d5789539eba3fc1b59c14835f8c681eca7634e118fa3763a53aeee2b ./src/queries/zone_history.rs f13f1be3d5789539eba3fc1b59c14835f8c681eca7634e118fa3763a53aeee2b ./src/queries/zone_history.rs
7e7037a059b585c5709367b9431a225789e7039796e3ed19fc132776ac234099 ./src/state.rs 7e7037a059b585c5709367b9431a225789e7039796e3ed19fc132776ac234099 ./src/state.rs
@@ -208,6 +204,7 @@ b92a6cb158b494fe145b43c7641e65f6fafff47201d7d76edbec2cfd8b94835c ./systemd/gree
f0c3b6ed0cb99a7271dbad6d4003ff98fa1a4314a384e7341441bf988b30c0ba ./web/custom-chart.js f0c3b6ed0cb99a7271dbad6d4003ff98fa1a4314a384e7341441bf988b30c0ba ./web/custom-chart.js
e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg
019af8f410a20704e7445d0013fc37728d56b11b2772d679fe12a6c896972d87 ./web/index.html 019af8f410a20704e7445d0013fc37728d56b11b2772d679fe12a6c896972d87 ./web/index.html
9ba3f6fa05b72aa989139b2a909982571b2a02055052e4c40104f1e81a9aa7eb ./web/js/README.md
27eff2821c40395369be15e197fa830535d2327fcb27c93a0e8e65a1c62de3ad ./web/js/bootstrap.js 27eff2821c40395369be15e197fa830535d2327fcb27c93a0e8e65a1c62de3ad ./web/js/bootstrap.js
5970f3d05006ab975c7c88baaed4cc73eb014fc40dbfb3f07a191db3534211ea ./web/js/charts.js 5970f3d05006ab975c7c88baaed4cc73eb014fc40dbfb3f07a191db3534211ea ./web/js/charts.js
1f1b7d1fdc2755a0888a14a314668a80ed7095763eba9c821e5e0968ec54fd73 ./web/js/core.js 1f1b7d1fdc2755a0888a14a314668a80ed7095763eba9c821e5e0968ec54fd73 ./web/js/core.js
@@ -216,17 +213,16 @@ c5476aaa91123bc9d2b0ab1cb2870cba04fd67ae0067f86b3edb415b76cd4864 ./web/js/entit
a59fd5b822029d0c1e74ba8078f55f13122347e036a96dec383293ae386f6667 ./web/js/events.js a59fd5b822029d0c1e74ba8078f55f13122347e036a96dec383293ae386f6667 ./web/js/events.js
b08b0fe301642d1daa084b322a02e351d284d2465231505d45079a52ccb4028f ./web/js/flows.js b08b0fe301642d1daa084b322a02e351d284d2465231505d45079a52ccb4028f ./web/js/flows.js
8e6798405332eec8439c9ea28e967ee2b1d62b57012452c03089aff01dcd6452 ./web/js/forms.js 8e6798405332eec8439c9ea28e967ee2b1d62b57012452c03089aff01dcd6452 ./web/js/forms.js
c48f1947ade3ac461a8633b56bacd8be229639c53f2057f841d6ec8fc8f4e971 ./web/js/history.js 1868a8afbfc35623b538a1c6cd73246c8cc0aada4881e56941167958c0276b18 ./web/js/history.js
511c4e7cc4c48fbbdab64558a9d1c27e6759c9b6dca255d11f301b9708e955c7 ./web/js/main.js 511c4e7cc4c48fbbdab64558a9d1c27e6759c9b6dca255d11f301b9708e955c7 ./web/js/main.js
6bb9386707dcf601111fea15a1a366d8798313b973ca1624878618f4c3095add ./web/js/navigation.js 6bb9386707dcf601111fea15a1a366d8798313b973ca1624878618f4c3095add ./web/js/navigation.js
9ba3f6fa05b72aa989139b2a909982571b2a02055052e4c40104f1e81a9aa7eb ./web/js/README.md
799613c6d465cb2f92ecb57cb082d0c33729a03d88ab4ca7fa12a3cbd7e38e75 ./web/js/realtime.js 799613c6d465cb2f92ecb57cb082d0c33729a03d88ab4ca7fa12a3cbd7e38e75 ./web/js/realtime.js
9546ca5c5566994aff3c33d92295be46b65d51d874681764abe77470dc9c9c73 ./web/js/router.js 9546ca5c5566994aff3c33d92295be46b65d51d874681764abe77470dc9c9c73 ./web/js/router.js
c2710fd9c1f2b31878c1e25ceb02d74ae30456c1bbb400e69fcf7619ecc72bc2 ./web/js/select-ui.js c2710fd9c1f2b31878c1e25ceb02d74ae30456c1bbb400e69fcf7619ecc72bc2 ./web/js/select-ui.js
9f50794a92059357301b4c920b066bdb20ce1f64fbccea42effcd196d0a00cc4 ./web/js/settings.js
420cc44008d739ece4031093db772cc2bd6cdc0573b971b04ccce2aedb5762dd ./web/js/settings-ui.js 420cc44008d739ece4031093db772cc2bd6cdc0573b971b04ccce2aedb5762dd ./web/js/settings-ui.js
9f50794a92059357301b4c920b066bdb20ce1f64fbccea42effcd196d0a00cc4 ./web/js/settings.js
3815fea7ae1694568c2f249bc8460e0563ced6bde89214f74f21b41fe8cad9a6 ./web/lang-init.js 3815fea7ae1694568c2f249bc8460e0563ced6bde89214f74f21b41fe8cad9a6 ./web/lang-init.js
6b653e4fe2d4db4ffae6ff8f39b8ce57a10a990dc0000ee4aae51d949afadd52 ./web/manifest.webmanifest 6b653e4fe2d4db4ffae6ff8f39b8ce57a10a990dc0000ee4aae51d949afadd52 ./web/manifest.webmanifest
8f2631e2c681940773667672b1cd0e467c82c5f93a0749300ff6852bbaf669f4 ./web/styles.css e25c0f0419611c47a1870d0f37b5db1fe5632c12eeba0b3556179e13f222e02a ./web/styles.css
fefdf12cbbb0a5d8a2cb89275cae28455aa42aaf179542305cc8f5e0f4825898 ./web/sw.js fefdf12cbbb0a5d8a2cb89275cae28455aa42aaf179542305cc8f5e0f4825898 ./web/sw.js
d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js
+4 -3
View File
@@ -2,9 +2,9 @@
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. 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.14.14** **Version: 0.14.15**
Version 0.14.14 makes Home Assistant entity selection in Reusable data -> Shared Flow input explicit: a separate search field filters the live HA entity catalog by name, entity_id and current state, while the selected entity_id remains a separate editable value. It keeps the automatic Supervisor authentication and manual fallback behavior introduced in 0.14.13. Standalone Home Assistant configuration remains unchanged. Version 0.14.15 hardens Home Assistant add-on publishing and direct-access behavior. The add-on keeps a fixed internal HTTP/ingress port (`8787`), validates that contract at startup/build time, resolves the primary Home Assistant host IPv4 through the Supervisor API for chart-only share links, and supports an explicit `public_chart_base_url` override for reverse proxies or unusual network layouts. Standalone port handling remains dynamic through `GREE_CONTROLLER_BIND`.
> [Full API reference](docs/API.md) — authentication, every endpoint, request bodies, response models, WebSocket events and examples. > [Full API reference](docs/API.md) — authentication, every endpoint, request bodies, response models, WebSocket events and examples.
@@ -126,6 +126,7 @@ Environment values explicitly supplied for supported runtime overrides win over
| `GREE_CONTROLLER_DATABASE` | `./data/gree-controller.db` | SQLite database path. | | `GREE_CONTROLLER_DATABASE` | `./data/gree-controller.db` | SQLite database path. |
| `GREE_CONTROLLER_APP_TOKEN` | empty | Administrator API/Web UI token. Empty means trusted-LAN mode in standalone installs; with HA Supervisor auth active, empty disables direct dashboard/API access on the exposed port. | | `GREE_CONTROLLER_APP_TOKEN` | empty | Administrator API/Web UI token. Empty means trusted-LAN mode in standalone installs; with HA Supervisor auth active, empty disables direct dashboard/API access on the exposed port. |
| `GREE_CONTROLLER_BASE_PATH` | empty | Optional reverse-proxy prefix such as `/gree`. | | `GREE_CONTROLLER_BASE_PATH` | empty | Optional reverse-proxy prefix such as `/gree`. |
| `GREE_CONTROLLER_PUBLIC_CHART_BASE_URL` | empty | Optional absolute HTTP(S) base URL used only when generating public Custom Chart links; useful behind a reverse proxy or alternate external port. |
| `GREE_CONTROLLER_ID` | `gree-controller` | GREE client/controller identifier. | | `GREE_CONTROLLER_ID` | `gree-controller` | GREE client/controller identifier. |
| `GREE_CONTROLLER_SIMULATE` | `false` | Initial Simulation mode. | | `GREE_CONTROLLER_SIMULATE` | `false` | Initial Simulation mode. |
| `GREE_CONTROLLER_AUTO_SEED` | `false` | Seed simulated sample data when applicable. | | `GREE_CONTROLLER_AUTO_SEED` | `false` | Seed simulated sample data when applicable. |
@@ -283,7 +284,7 @@ There are two independent Home Assistant directions.
In the Home Assistant add-on, the connection to Home Assistant Core is automatic through the Supervisor API proxy; no Home Assistant URL or Long-Lived Access Token is required. In the Home Assistant add-on, the connection to Home Assistant Core is automatic through the Supervisor API proxy; no Home Assistant URL or Long-Lived Access Token is required.
When the add-on detects `SUPERVISOR_TOKEN`, Home Assistant ingress remains trusted, but direct Web UI/API access on TCP `8787` requires `app_token`. If `app_token` is empty, direct dashboard/API access is disabled. History → Custom Charts → Copy link creates a random persisted share token and returns a chart-only URL. In the add-on it bypasses HA ingress and targets the same HA host/IP on the direct HTTP port (normally `8787`); in standalone mode it uses the current controller origin/base path. Only the generated chart view/data endpoint is public to the network. When the add-on detects `SUPERVISOR_TOKEN`, Home Assistant ingress remains trusted, but direct Web UI/API access on TCP `8787` requires `app_token`. If `app_token` is empty, direct dashboard/API access is disabled. The Home Assistant add-on intentionally uses `8787` as a fixed internal ingress/application port; it is not a user-configurable Network option. The startup script verifies the Supervisor-reported `ingress_port` and refuses to start on a mismatched manually modified package. History → Custom Charts → Copy link creates a random persisted share token and returns a chart-only URL. The add-on resolves the primary HA host IPv4 through the Supervisor API and uses `http://<HA-IP>:8787` by default; `public_chart_base_url` can override that address for a reverse proxy or non-standard routing. Standalone mode uses the current controller origin/base path and follows `GREE_CONTROLLER_BIND`. Only the generated chart view/data endpoint is public to the network.
For standalone installations, configure **Home Assistant / Sensors** in the Web UI or use: For standalone installations, configure **Home Assistant / Sensors** in the Web UI or use:
+23 -23
View File
@@ -1,17 +1,17 @@
d67af429e4da9ce08e9d2f2a8472849ffbd70d135b1c5da535a076026794d04c ./.env.example f809050a6074ba8e98e08c89af1174dffef679114ffae5c2d200150a9588b8d9 ./.env.example
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
6c60703633b9d6a696c22beca15e2bbc0c90424a1b98a5dd53cdc0d670dffffd ./Cargo.lock 597f6fb6e6b7306d2b22fa68cf4cc9c438b1d67537db29519a1de57a8775a426 ./Cargo.lock
b19e576628872d7344786c71a65de6b30f67f384b9306930b1aaa6018bf2caaa ./Cargo.toml 8839d028f8c3facf329b97d8e2623b6c89b27aa25716ccd4848dff4a5e4041bf ./Cargo.toml
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE 19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
2b0c8072501b7c63cefb16a92694132d311c0fde79bc43a5f7681d630e035b75 ./README.md 699e00f944554597b1684b7892cb43dc96eb3c7b6f04ed8e28fc3a8784765ff2 ./README.md
5302570299af2c2650bada12e123f598c5db8009949c75761385f73ed57343c5 ./build.rs 5302570299af2c2650bada12e123f598c5db8009949c75761385f73ed57343c5 ./build.rs
c4a46a314f328075d95ca9bf6e88f24dbc243223412c33468de0901c6d19423c ./docs/API.md fa74b515483caeea518e392adfe8f235fb3f08131fb2fbd12bebe58c665bd81f ./docs/API.md
f21d732eb1147f8f3167d2172cdf0b57e61edabdfecbaf97811d46c5bff7e47a ./docs/FLOW.md f21d732eb1147f8f3167d2172cdf0b57e61edabdfecbaf97811d46c5bff7e47a ./docs/FLOW.md
f42e2dd9d0ad82958fd554bc8a7faf08a1bbd502f897a93cb32cc86089bda2b2 ./docs/openapi.json 809adad678983ed8572dd558768be2f20835ebd92dc527da7207e6b5df096d47 ./docs/openapi.json
c65aa543d2e99f8f7d52736307b07ebd182597d80124661d53a16bb23f6f1118 ./ha-addon/.env.example c65aa543d2e99f8f7d52736307b07ebd182597d80124661d53a16bb23f6f1118 ./ha-addon/.env.example
a18d2460340264d34c267fa704ee51a42e59bcc1783ee4c0dbb2a8ef42fa0f16 ./ha-addon/Dockerfile ddec80cf2b5da73fd1bae50e46398033c95aa088afdb7c07d4889b5987a17a3f ./ha-addon/Dockerfile
0417c88a990c72aecf071fba64d5d9da65dcda4d396cd7565477f7a4532c8c5e ./ha-addon/README.md 3702707b5fd4f3a3d5d73e2dc827a6a43c144a22ff94861ab38720207bfcd94b ./ha-addon/README.md
cd7fd4b937a1d6138699f7effd184e3c077912b881e9c73c37b90bbafba68477 ./ha-addon/build.sh dd9291b12afade6fc20d66e80a5513251270e18e4c265260b2bbbe393a5a94c4 ./ha-addon/build.sh
082dfeb6326f3e1b9841ccf7f2954117ecdf0aa1a90b0aef1e6a1960dacdecbf ./ha-addon/home-assistant/README.md 082dfeb6326f3e1b9841ccf7f2954117ecdf0aa1a90b0aef1e6a1960dacdecbf ./ha-addon/home-assistant/README.md
f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./ha-addon/home-assistant/custom_components/gree_controller/__init__.py f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./ha-addon/home-assistant/custom_components/gree_controller/__init__.py
3f6ef15ef58456376ac53fde7cace1ef359d6a6f7a64c5b575ad77ea6e55ccc4 ./ha-addon/home-assistant/custom_components/gree_controller/api.py 3f6ef15ef58456376ac53fde7cace1ef359d6a6f7a64c5b575ad77ea6e55ccc4 ./ha-addon/home-assistant/custom_components/gree_controller/api.py
@@ -21,7 +21,7 @@ b7f0873109c52be9d7f09bea3dffc416103c50085e1f0680d11661a969479898 ./ha-addon/hom
41a8958a6fe6d10e5679c95ac34832583a2a15ecfd67d09b4e094a83d06f5c47 ./ha-addon/home-assistant/custom_components/gree_controller/coordinator.py 41a8958a6fe6d10e5679c95ac34832583a2a15ecfd67d09b4e094a83d06f5c47 ./ha-addon/home-assistant/custom_components/gree_controller/coordinator.py
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./ha-addon/home-assistant/custom_components/gree_controller/entity_map.py 5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./ha-addon/home-assistant/custom_components/gree_controller/entity_map.py
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./ha-addon/home-assistant/custom_components/gree_controller/icon.png c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./ha-addon/home-assistant/custom_components/gree_controller/icon.png
2348f11fcbadc83258cdd63ec81a946a38163a7729dbcf531d93cbdd51faea9d ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json c62ac791ec1abefe26ea97e001a92db2f2905ee603b50aab0e76242b45e863e7 ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json
c52a484b671ce738ecc00228a1db19a5d703f69ab27530c2896a5c2ae3b4a96f ./ha-addon/home-assistant/custom_components/gree_controller/number.py c52a484b671ce738ecc00228a1db19a5d703f69ab27530c2896a5c2ae3b4a96f ./ha-addon/home-assistant/custom_components/gree_controller/number.py
39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./ha-addon/home-assistant/custom_components/gree_controller/select.py 39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./ha-addon/home-assistant/custom_components/gree_controller/select.py
cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/home-assistant/custom_components/gree_controller/sensor.py cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/home-assistant/custom_components/gree_controller/sensor.py
@@ -29,16 +29,16 @@ cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/hom
6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./ha-addon/home-assistant/custom_components/gree_controller/translations/en.json 6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./ha-addon/home-assistant/custom_components/gree_controller/translations/en.json
13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./ha-addon/home-assistant/custom_components/gree_controller/translations/pl.json 13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./ha-addon/home-assistant/custom_components/gree_controller/translations/pl.json
c5fc5c87273d82d2834a0a5a365c821a416413ed509613441e24e4dc3507c4d2 ./ha-addon/home-assistant/generated/gree_controller_entities.example.json c5fc5c87273d82d2834a0a5a365c821a416413ed509613441e24e4dc3507c4d2 ./ha-addon/home-assistant/generated/gree_controller_entities.example.json
f3e47cf1a186608f0b70d54be54ccbd1e120c968e773f31fc85ec52a03392e61 ./ha-addon/repository/gree-controller/CHANGELOG.md 59f420dcff7b7712ee4fb2afcda8573d2f420b593cc333989b4537179703508c ./ha-addon/repository/gree-controller/CHANGELOG.md
28936708e6cfcc7eafd0d587f6d6cb50f926f70959bdfc7e07849c81d251c71a ./ha-addon/repository/gree-controller/DOCS.md 1b5599195329cc3e643c23aa1caadcec80f133e8e515eec7d92b9f3cbda5b80b ./ha-addon/repository/gree-controller/DOCS.md
c3db302f38d26dc9f8caf37a1a8a07a1334cc07ae301d452f2940a5ec5915719 ./ha-addon/repository/gree-controller/README.md c3db302f38d26dc9f8caf37a1a8a07a1334cc07ae301d452f2940a5ec5915719 ./ha-addon/repository/gree-controller/README.md
40f4f7156a882ef390011915fe38ee8299633e8b51ab554cd67a7b1e4c99f4ea ./ha-addon/repository/gree-controller/config.yaml bc356f1ea4f367084677ae05887a256056d6b403e5a0f0e57c86c11636fb20ea ./ha-addon/repository/gree-controller/config.yaml
3aae6cdae4c3aaab7786a9575e7093b7e2c5b69288167075f4b7475611691a6b ./ha-addon/repository/gree-controller/topologia-ha-vlan-gree-pl.png 3aae6cdae4c3aaab7786a9575e7093b7e2c5b69288167075f4b7475611691a6b ./ha-addon/repository/gree-controller/topologia-ha-vlan-gree-pl.png
0d0b42a7639b128946eec379175436fa1f150294f39d2dfd169077bfa87fd14d ./ha-addon/repository/gree-controller/topology-ha-vlan-gree-en.png 0d0b42a7639b128946eec379175436fa1f150294f39d2dfd169077bfa87fd14d ./ha-addon/repository/gree-controller/topology-ha-vlan-gree-en.png
ad3715c719f53dca932a208cfacbe9c65834d9552e41bfef8172bef5ce76be35 ./ha-addon/repository/gree-controller/translations/en.yaml 2272740b185e9520e948f74b8f45cf98b8b5fd28c93bdee760da626f91fe5c2a ./ha-addon/repository/gree-controller/translations/en.yaml
5564559ed847e42375ceec55e5e9f37c6c69f91b501a2d5c4e8c6656938a766d ./ha-addon/repository/gree-controller/translations/pl.yaml e6b93d3701d83a31506617a0e6f44ff32d8c24a52be038c8540c862b13546b50 ./ha-addon/repository/gree-controller/translations/pl.yaml
2153b230357aab4766398577e23a7a9ff83bb135ddc86d1b3f2cbfc852efe0a1 ./ha-addon/repository/repository.yaml 2153b230357aab4766398577e23a7a9ff83bb135ddc86d1b3f2cbfc852efe0a1 ./ha-addon/repository/repository.yaml
e8a77dbdb98c6ebcfbe6a08b0b5546178d965f25496c19f7aebaff287630838e ./ha-addon/run.sh cea12bc74c066a588a5ef0ef7bad9d4906bdbcea99f2d275429b0eefc94b4b5f ./ha-addon/run.sh
081e27b6e43070d44f865335c30a42a5a29668eaa6a5ea5ab6967ac4447b8e06 ./ha-addon/sync-repository.sh 081e27b6e43070d44f865335c30a42a5a29668eaa6a5ea5ab6967ac4447b8e06 ./ha-addon/sync-repository.sh
f9e31de3d109ead32bf531c074d46a087df398d62488caee0b46b5e0a1c027f7 ./ha_addon.md f9e31de3d109ead32bf531c074d46a087df398d62488caee0b46b5e0a1c027f7 ./ha_addon.md
253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md 253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md
@@ -82,9 +82,9 @@ fffa18bd989a0dcc1c5458975522517d40af4af40cc1ca30640e79d3db711053 ./presets/unoc
ae21459a261712bcb8d57594528b1648432e8d03a8a38502234829c0dbfef774 ./presets/weekend_comfort.json ae21459a261712bcb8d57594528b1648432e8d03a8a38502234829c0dbfef774 ./presets/weekend_comfort.json
fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/window_available_guard.json fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/window_available_guard.json
804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json 804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json
01952aa92b217f8eae2493b88870e2dec595100cd15c4d561ff11ae2b936c46f ./regenerate-sha.sh fd7390d64a2378352c09382accf6efff43903d952d111b22a982f06c5b2a3b4b ./regenerate-sha.sh
c64b1c6deeb24f20af662bfce7fa3683703914987241107ce664fa2f6d1a9dcb ./scripts/README.md c64b1c6deeb24f20af662bfce7fa3683703914987241107ce664fa2f6d1a9dcb ./scripts/README.md
0d2fd90f690d00a1f21aa4e3810a3dce976b55583df752c1cb7a90bc3742e7d3 ./scripts/api_dev_test.py 8bf77e97e4789242924aa030aa63c63912f5cd7334de0778f2ea9800c6912f8e ./scripts/api_dev_test.py
5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh 5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh
6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh 6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh
1d6e14e26e49aa9d3527f30a23668bf8d9c48b67e6628ef686c3155c012155de ./scripts/dev.sh 1d6e14e26e49aa9d3527f30a23668bf8d9c48b67e6628ef686c3155c012155de ./scripts/dev.sh
@@ -101,7 +101,7 @@ a70ddd9d4c9fca073ff494db73ec13acc7cff1830c9675d0541518d814da3772 ./src/api.rs
f6ed359370dacd691344402307843a0ad31bbeb46085f99e81cfa46a618ee87d ./src/api/assets.rs f6ed359370dacd691344402307843a0ad31bbeb46085f99e81cfa46a618ee87d ./src/api/assets.rs
b24092f34a46626d64628b510eba82193f0b203fd097f6a621b91af5d91eb571 ./src/api/auth.rs b24092f34a46626d64628b510eba82193f0b203fd097f6a621b91af5d91eb571 ./src/api/auth.rs
9e4fc675306e111ed3db7af9822e2925d88109c31b9e309851665a975c0bd83c ./src/api/automations.rs 9e4fc675306e111ed3db7af9822e2925d88109c31b9e309851665a975c0bd83c ./src/api/automations.rs
5d1cbc16bcdf0e048c9ec554bfb3a8c26068f3a99fc947ae195221015b90834c ./src/api/configuration.rs 1f2e3df47e532c1a222125d3790ec97772cf535af679589fde0ef9217f2db018 ./src/api/configuration.rs
19bc141286a336ad67e99079496eb0ae5126f986ab28be62b5f97758e5f6969c ./src/api/debug_tokens.rs 19bc141286a336ad67e99079496eb0ae5126f986ab28be62b5f97758e5f6969c ./src/api/debug_tokens.rs
32ade46ec45d6faf7852242b9f5ba1be6eacbacbeb33d2deabfab59bf1610ce0 ./src/api/device_groups.rs 32ade46ec45d6faf7852242b9f5ba1be6eacbacbeb33d2deabfab59bf1610ce0 ./src/api/device_groups.rs
fcbb3da0538aab451f71810f829cc248d6bb67e586dc418d71a572980583823d ./src/api/devices.rs fcbb3da0538aab451f71810f829cc248d6bb67e586dc418d71a572980583823d ./src/api/devices.rs
@@ -112,15 +112,15 @@ b61b0b4f196c5e72e47cf06ca0c14df3cf8eedbdef0242a9d2af33623663489f ./src/api/grou
e41ddb47f46ccad81baab1d25ddba910c087350b4b521844a33eae010cdaaa0b ./src/api/history.rs e41ddb47f46ccad81baab1d25ddba910c087350b4b521844a33eae010cdaaa0b ./src/api/history.rs
e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs
c71540b2b68e805e3a79ac787db9127b87585968a205fc307e93bf68d5b028e0 ./src/api/integrations.rs c71540b2b68e805e3a79ac787db9127b87585968a205fc307e93bf68d5b028e0 ./src/api/integrations.rs
cafff8c070b146619a541f7b03502e85594c2d9a442ab23610b076e6bd251abe ./src/api/middleware.rs 7658111f7d125db55a6e23f88157339b110b2cd1ed13ceabd8f860b42dba5101 ./src/api/middleware.rs
45e34a447ff384d99a3c42c489ca9fa75849c74d4d246caa91c63d927de17396 ./src/api/openapi.rs 45e34a447ff384d99a3c42c489ca9fa75849c74d4d246caa91c63d927de17396 ./src/api/openapi.rs
b777e7fbeccef699e11ffd16bb18633843c99afecacce2221280e54b09f6d2da ./src/api/public_settings.rs b777e7fbeccef699e11ffd16bb18633843c99afecacce2221280e54b09f6d2da ./src/api/public_settings.rs
5b29f2e5aa2c422c5829ef89c7b59cf753883aa7f60661c95ab0f95cf676fa3f ./src/api/schedules.rs 5b29f2e5aa2c422c5829ef89c7b59cf753883aa7f60661c95ab0f95cf676fa3f ./src/api/schedules.rs
6acf6417b077a0204a815e255c667928476014ce5f94c1559c9d4268c00342d5 ./src/api/settings.rs 6acf6417b077a0204a815e255c667928476014ce5f94c1559c9d4268c00342d5 ./src/api/settings.rs
dfa04f2acc0bcbfca826c4196ab960b38d6bb4193312477ca1167b190aef4b13 ./src/api/system.rs 0de92f241b5da2b7f13aaf9c24ef76eba8d26f8e27d87c9312bd644ab13d31bd ./src/api/system.rs
94d3845def693aafe15fa6e8b390881c46c3c236b62f247ddfdc055d9226ed22 ./src/api/websocket.rs 94d3845def693aafe15fa6e8b390881c46c3c236b62f247ddfdc055d9226ed22 ./src/api/websocket.rs
ddd1bfc8625b66f6e5f3d24b3122ac86c25f89b0af527e3dfce9102551a8f142 ./src/api/zones.rs ddd1bfc8625b66f6e5f3d24b3122ac86c25f89b0af527e3dfce9102551a8f142 ./src/api/zones.rs
e495bbb37e81b539bfacfce065fe791f630ccd524e2a33b9dcfd8fe6856941cf ./src/config.rs 7b15febe046c79917a22664f50d9063fd6d0968521544ef31b854424f73b4408 ./src/config.rs
f8394e0daca284070ac9ae0844d6b04fed7c30386f2d1ec409ecf07880bb0e6a ./src/db.rs f8394e0daca284070ac9ae0844d6b04fed7c30386f2d1ec409ecf07880bb0e6a ./src/db.rs
fdc9d019097becc5c36a0560caa1619aa35d802c0d208902b3bfecbe1643e3e8 ./src/db/climate.rs fdc9d019097becc5c36a0560caa1619aa35d802c0d208902b3bfecbe1643e3e8 ./src/db/climate.rs
e5d2027d40a99e61c2c572499af617a92de9e554f8916f3ea6f6731d1d6b09b4 ./src/db/configuration.rs e5d2027d40a99e61c2c572499af617a92de9e554f8916f3ea6f6731d1d6b09b4 ./src/db/configuration.rs
@@ -212,7 +212,7 @@ c5476aaa91123bc9d2b0ab1cb2870cba04fd67ae0067f86b3edb415b76cd4864 ./web/js/entit
a59fd5b822029d0c1e74ba8078f55f13122347e036a96dec383293ae386f6667 ./web/js/events.js a59fd5b822029d0c1e74ba8078f55f13122347e036a96dec383293ae386f6667 ./web/js/events.js
b08b0fe301642d1daa084b322a02e351d284d2465231505d45079a52ccb4028f ./web/js/flows.js b08b0fe301642d1daa084b322a02e351d284d2465231505d45079a52ccb4028f ./web/js/flows.js
8e6798405332eec8439c9ea28e967ee2b1d62b57012452c03089aff01dcd6452 ./web/js/forms.js 8e6798405332eec8439c9ea28e967ee2b1d62b57012452c03089aff01dcd6452 ./web/js/forms.js
c48f1947ade3ac461a8633b56bacd8be229639c53f2057f841d6ec8fc8f4e971 ./web/js/history.js 1868a8afbfc35623b538a1c6cd73246c8cc0aada4881e56941167958c0276b18 ./web/js/history.js
511c4e7cc4c48fbbdab64558a9d1c27e6759c9b6dca255d11f301b9708e955c7 ./web/js/main.js 511c4e7cc4c48fbbdab64558a9d1c27e6759c9b6dca255d11f301b9708e955c7 ./web/js/main.js
6bb9386707dcf601111fea15a1a366d8798313b973ca1624878618f4c3095add ./web/js/navigation.js 6bb9386707dcf601111fea15a1a366d8798313b973ca1624878618f4c3095add ./web/js/navigation.js
799613c6d465cb2f92ecb57cb082d0c33729a03d88ab4ca7fa12a3cbd7e38e75 ./web/js/realtime.js 799613c6d465cb2f92ecb57cb082d0c33729a03d88ab4ca7fa12a3cbd7e38e75 ./web/js/realtime.js
+5 -4
View File
@@ -1,6 +1,6 @@
# GREE Controller API reference # GREE Controller API reference
HTTP and WebSocket API for GREE Controller **0.14.14**. HTTP and WebSocket API for GREE Controller **0.14.15**.
[← Main documentation](../README.md) [← Main documentation](../README.md)
@@ -239,7 +239,7 @@ Response:
{ {
"status": "ok", "status": "ok",
"name": "gree-controller", "name": "gree-controller",
"version": "0.14.14", "version": "0.14.15",
"uptime_seconds": 1234, "uptime_seconds": 1234,
"control_ready": true, "control_ready": true,
"time": "2026-08-30T06:54:00Z" "time": "2026-08-30T06:54:00Z"
@@ -302,7 +302,7 @@ Returns the initial Web UI snapshot:
"control_plan": {"generated_at": "2026-09-04T08:00:00Z", "zones": [], "rules": []}, "control_plan": {"generated_at": "2026-09-04T08:00:00Z", "zones": [], "rules": []},
"control_plan_revision": 42, "control_plan_revision": 42,
"system": { "system": {
"version": "0.14.14", "version": "0.14.15",
"uptime_seconds": 1234, "uptime_seconds": 1234,
"auth_required": false, "auth_required": false,
"control_ready": true, "control_ready": true,
@@ -312,6 +312,7 @@ Returns the initial Web UI snapshot:
"simulator_count": 0, "simulator_count": 0,
"bind": "0.0.0.0:8787", "bind": "0.0.0.0:8787",
"base_path": "/", "base_path": "/",
"public_chart_base_url": "http://192.168.1.20:8787",
"gree_interface": "auto", "gree_interface": "auto",
"gree_received_frames": 809, "gree_received_frames": 809,
"gree_received_frames_by_device": {} "gree_received_frames_by_device": {}
@@ -327,7 +328,7 @@ Returns the initial Web UI snapshot:
`GET /charts/custom/:token` renders only the shared chart, without the dashboard. `GET /api/public/charts/custom/:token` returns only the series configured for that share and is intentionally unauthenticated. Possession of the unguessable share URL is the authorization for this narrow read-only endpoint. `GET /charts/custom/:token` renders only the shared chart, without the dashboard. `GET /api/public/charts/custom/:token` returns only the series configured for that share and is intentionally unauthenticated. Possession of the unguessable share URL is the authorization for this narrow read-only endpoint.
In Home Assistant add-on ingress, the Web UI builds the copied URL against the direct add-on host and bound HTTP port (normally `8787`) instead of the `/api/hassio_ingress/...` prefix. Standalone installations use their current origin and configured base path. In the Home Assistant add-on, TCP `8787` is the fixed internal application/ingress port. The startup script validates that Supervisor reports the same `ingress_port`; a manually modified mismatched package fails fast instead of starting partially. For generated links, the add-on discovers the primary Home Assistant host IPv4 through the Supervisor API and publishes `http://<HA-IP>:8787/charts/custom/...` by default. The optional `public_chart_base_url` add-on setting overrides that base for reverse proxies or unusual routing. Standalone installations use their current origin/configured base path and therefore follow any port configured in `GREE_CONTROLLER_BIND`.
### `GET /api/system/info` ### `GET /api/system/info`
+3 -3
View File
@@ -2,9 +2,9 @@
"openapi": "3.1.0", "openapi": "3.1.0",
"info": { "info": {
"title": "GREE Controller API", "title": "GREE Controller API",
"version": "0.14.14", "version": "0.14.15",
"summary": "Local HTTP/WebSocket API for GREE HVAC control", "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 <APP_TOKEN>` or `x-api-token: <APP_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.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.", "description": "Self-hosted API used by the GREE Controller Web UI and Home Assistant integration.\n\n### Authentication\nAdministrator endpoints accept `Authorization: Bearer <APP_TOKEN>` or `x-api-token: <APP_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.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.",
"license": { "license": {
"name": "MIT" "name": "MIT"
} }
@@ -5819,7 +5819,7 @@
}, },
"version": { "version": {
"type": "string", "type": "string",
"example": "0.14.14" "example": "0.14.15"
}, },
"uptime_seconds": { "uptime_seconds": {
"type": "integer", "type": "integer",
+2 -2
View File
@@ -37,7 +37,7 @@ LABEL io.hass.version="${BUILD_VERSION}" \
org.opencontainers.image.version="${BUILD_VERSION}" \ org.opencontainers.image.version="${BUILD_VERSION}" \
org.opencontainers.image.architecture="${TARGETARCH}" org.opencontainers.image.architecture="${TARGETARCH}"
RUN apt-get update \ RUN apt-get update \
&& apt-get install -y --no-install-recommends ca-certificates tzdata jq iproute2 \ && apt-get install -y --no-install-recommends ca-certificates tzdata jq iproute2 curl \
&& rm -rf /var/lib/apt/lists/* && rm -rf /var/lib/apt/lists/*
COPY --from=builder-trixie /src/target/release/gree-controller /usr/local/bin/gree-controller COPY --from=builder-trixie /src/target/release/gree-controller /usr/local/bin/gree-controller
COPY ha-addon/run.sh /usr/local/bin/run.sh COPY ha-addon/run.sh /usr/local/bin/run.sh
@@ -56,7 +56,7 @@ LABEL io.hass.version="${BUILD_VERSION}" \
org.opencontainers.image.title="GREE Controller" \ org.opencontainers.image.title="GREE Controller" \
org.opencontainers.image.version="${BUILD_VERSION}" \ org.opencontainers.image.version="${BUILD_VERSION}" \
org.opencontainers.image.architecture="${TARGETARCH}" org.opencontainers.image.architecture="${TARGETARCH}"
RUN apk add --no-cache ca-certificates tzdata jq iproute2 RUN apk add --no-cache ca-certificates tzdata jq iproute2 curl
COPY --from=builder-alpine /src/target/release/gree-controller /usr/local/bin/gree-controller COPY --from=builder-alpine /src/target/release/gree-controller /usr/local/bin/gree-controller
COPY ha-addon/run.sh /usr/local/bin/run.sh COPY ha-addon/run.sh /usr/local/bin/run.sh
RUN chmod 0755 /usr/local/bin/run.sh /usr/local/bin/gree-controller RUN chmod 0755 /usr/local/bin/run.sh /usr/local/bin/gree-controller
+2
View File
@@ -42,6 +42,8 @@ INTEGRATION_DOMAIN=gree_controller
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 `Cargo.lock`, add-on `config.yaml` and the custom integration `manifest.json`, and sets the OCI image from `.env`.
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.
## Home Assistant repository ## Home Assistant repository
```bash ```bash
+27
View File
@@ -35,6 +35,8 @@ CONFIG="$SCRIPT_DIR/repository/$ADDON_DIR/config.yaml"
LOCKFILE="$PROJECT_ROOT/Cargo.lock" LOCKFILE="$PROJECT_ROOT/Cargo.lock"
INTEGRATION_MANIFEST="$SCRIPT_DIR/home-assistant/custom_components/$INTEGRATION_DOMAIN/manifest.json" INTEGRATION_MANIFEST="$SCRIPT_DIR/home-assistant/custom_components/$INTEGRATION_DOMAIN/manifest.json"
REPOSITORY_CONFIG="$SCRIPT_DIR/repository/repository.yaml" REPOSITORY_CONFIG="$SCRIPT_DIR/repository/repository.yaml"
RUN_SCRIPT="$SCRIPT_DIR/run.sh"
DOCKERFILE="$SCRIPT_DIR/Dockerfile"
[[ -f "$CONFIG" ]] || { echo "Missing add-on config: $CONFIG" >&2; exit 1; } [[ -f "$CONFIG" ]] || { echo "Missing add-on config: $CONFIG" >&2; exit 1; }
[[ -f "$INTEGRATION_MANIFEST" ]] || { echo "Missing integration manifest: $INTEGRATION_MANIFEST" >&2; exit 1; } [[ -f "$INTEGRATION_MANIFEST" ]] || { echo "Missing integration manifest: $INTEGRATION_MANIFEST" >&2; exit 1; }
@@ -87,6 +89,30 @@ PY
printf 'Synced version %s; image %s\n' "$VERSION" "$IMAGE_REPO" printf 'Synced version %s; image %s\n' "$VERSION" "$IMAGE_REPO"
} }
validate_addon_port_contract() {
local ingress_port
ingress_port="$(awk '/^ingress_port:/ {print $2; exit}' "$CONFIG")"
[[ "$ingress_port" =~ ^[0-9]+$ ]] || { echo "Invalid ingress_port in $CONFIG" >&2; exit 1; }
grep -Fqx "readonly HA_HTTP_PORT=${ingress_port}" "$RUN_SCRIPT" || {
echo "HA port contract mismatch: ingress_port=${ingress_port}, run.sh differs" >&2
exit 1
}
grep -Fq "watchdog: \"http://[HOST]:[PORT:${ingress_port}]/api/health\"" "$CONFIG" || {
echo "HA port contract mismatch: watchdog must use [PORT:${ingress_port}]" >&2
exit 1
}
grep -Fqx "hassio_api: true" "$CONFIG" || {
echo "HA add-on contract mismatch: hassio_api must be enabled for Supervisor runtime discovery" >&2
exit 1
}
local expose_count
expose_count="$(grep -Ec "^EXPOSE ${ingress_port}/tcp$" "$DOCKERFILE" || true)"
(( expose_count >= 1 )) || {
echo "HA port contract mismatch: Dockerfile must expose ${ingress_port}/tcp" >&2
exit 1
}
}
ensure_builder() { ensure_builder() {
command -v docker >/dev/null 2>&1 || { echo "docker is required" >&2; exit 1; } command -v docker >/dev/null 2>&1 || { echo "docker is required" >&2; exit 1; }
docker buildx version >/dev/null 2>&1 || { echo "docker buildx is required" >&2; exit 1; } docker buildx version >/dev/null 2>&1 || { echo "docker buildx is required" >&2; exit 1; }
@@ -136,6 +162,7 @@ build_load() {
} }
render_metadata render_metadata
validate_addon_port_contract
case "$ACTION" in case "$ACTION" in
render) ;; render) ;;
@@ -1,7 +1,7 @@
{ {
"domain": "gree_controller", "domain": "gree_controller",
"name": "GREE Controller", "name": "GREE Controller",
"version": "0.14.14", "version": "0.14.15",
"config_flow": true, "config_flow": true,
"integration_type": "hub", "integration_type": "hub",
"iot_class": "local_polling", "iot_class": "local_polling",
@@ -1,5 +1,14 @@
# Changelog # Changelog
## 0.14.15
- Treats TCP `8787` as the fixed internal Home Assistant add-on application/ingress port and validates the Supervisor-reported ingress port at startup.
- Makes the add-on build fail when `run.sh`, `ingress_port` and watchdog port metadata diverge.
- Uses the Home Assistant Supervisor network API to resolve the primary host IPv4 for generated chart-only share links instead of depending on the browser/ingress hostname.
- Adds optional `public_chart_base_url` for reverse proxies, alternate hostnames or non-standard external routing while keeping the public surface limited to generated Custom Chart shares.
- Uses Home Assistant's `[PORT:8787]` watchdog placeholder so Supervisor resolves the effective watchdog port from the add-on port contract.
- Keeps standalone installations fully port-configurable through `GREE_CONTROLLER_BIND`.
## 0.14.14 ## 0.14.14
- Changes History → Custom Charts links to open a standalone chart-only page instead of the full dashboard. - Changes History → Custom Charts links to open a standalone chart-only page instead of the full dashboard.
+4 -2
View File
@@ -56,6 +56,7 @@ Broadcast zwykle nie przechodzi przez router. Sterowanie unicast może działać
| `zone_interval_seconds` | interwał sterowania strefami/termostatem | | `zone_interval_seconds` | interwał sterowania strefami/termostatem |
| `discovery_timeout_ms` | timeout discovery UDP | | `discovery_timeout_ms` | timeout discovery UDP |
| `app_token` | token bezpośredniego Web UI/API; w trybie Supervisor pusty = direct access zablokowany | | `app_token` | token bezpośredniego Web UI/API; w trybie Supervisor pusty = direct access zablokowany |
| `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` | | `log_level` | `error`, `warn`, `info`, `debug`, `trace` |
### Home Assistant API ### Home Assistant API
@@ -64,7 +65,7 @@ Dodatek korzysta automatycznie z wewnętrznego proxy Home Assistant Core (`http:
### Dostęp, dane i bezpieczeństwo ### Dostęp, dane i bezpieczeństwo
Usługa słucha na TCP `8787`; ingress Home Assistant przekazuje Web UI na ten port. Gdy wykryty jest `SUPERVISOR_TOKEN`, bezpośredni dashboard/API na `:8787` wymaga `app_token`; przy pustym `app_token` bezpośredni dashboard jest zablokowany. Z sieci bez poświadczeń dostępny jest tylko publiczny widok i endpoint danych pojedynczego Custom Chart (`/charts/custom/<share-token>`, `/api/public/charts/custom/<share-token>`). Token udostępnienia jest losowy, jego skrót jest zapisywany w SQLite, a sam URL nie zawiera nazw urządzeń ani listy metryk. Link kopiowany z History → Custom chart omija HA ingress i wskazuje bezpośrednio host/IP dodatku na jego porcie HTTP (domyślnie `8787`). `/api/health` bez tokenu jest akceptowane tylko od peera Supervisora na potrzeby watchdoga; bezpośrednie żądanie sieciowe wymaga `app_token`. Baza jest zapisywana w `/data/gree-controller.db`; konfiguracja używa `backup: cold`, więc dane są objęte backupem dodatku. Usługa używa stałego wewnętrznego portu TCP `8787`; ingress Home Assistant przekazuje Web UI na ten port. Port nie jest opcją użytkownika w zakładce Network. Przy starcie add-on porównuje port raportowany przez Supervisor z kontraktem `8787` i odmawia startu, jeśli ręcznie zmodyfikowana paczka jest niespójna. Gdy wykryty jest `SUPERVISOR_TOKEN`, bezpośredni dashboard/API na `:8787` wymaga `app_token`; przy pustym `app_token` bezpośredni dashboard jest zablokowany. Z sieci bez poświadczeń dostępny jest tylko publiczny widok i endpoint danych pojedynczego Custom Chart (`/charts/custom/<share-token>`, `/api/public/charts/custom/<share-token>`). Token udostępnienia jest losowy, jego skrót jest zapisywany w SQLite, a sam URL nie zawiera nazw urządzeń ani listy metryk. Link kopiowany z History → Custom chart omija HA ingress; domyślnie add-on pobiera główne IPv4 hosta z Supervisor API i tworzy `http://<IP-HA>:8787/charts/custom/...`. `public_chart_base_url` pozwala jawnie wskazać reverse proxy, inną nazwę hosta lub alternatywną trasę. `/api/health` bez tokenu jest akceptowane tylko od peera Supervisora na potrzeby watchdoga; bezpośrednie żądanie sieciowe wymaga `app_token`. Baza jest zapisywana w `/data/gree-controller.db`; konfiguracja używa `backup: cold`, więc dane są objęte backupem dodatku.
Watchdog sprawdza `/api/health`. Do diagnostyki sieci najpierw sprawdź `ha network info`, poprawność `gree_interface`, broadcast konkretnej podsieci i reguły UDP/firewalla. Watchdog sprawdza `/api/health`. Do diagnostyki sieci najpierw sprawdź `ha network info`, poprawność `gree_interface`, broadcast konkretnej podsieci i reguły UDP/firewalla.
@@ -121,6 +122,7 @@ Broadcast normally does not cross routers. Unicast control may work through rout
| `zone_interval_seconds` | thermostat/zone control interval | | `zone_interval_seconds` | thermostat/zone control interval |
| `discovery_timeout_ms` | UDP discovery timeout | | `discovery_timeout_ms` | UDP discovery timeout |
| `app_token` | token for direct Web UI/API access; in Supervisor mode empty = direct access disabled | | `app_token` | token for direct Web UI/API access; in Supervisor mode empty = direct access disabled |
| `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` | | `log_level` | `error`, `warn`, `info`, `debug`, `trace` |
### Home Assistant API ### Home Assistant API
@@ -129,6 +131,6 @@ The add-on automatically uses the internal Home Assistant Core proxy (`http://su
### Access, data and security ### Access, data and security
The service listens on TCP `8787`; Home Assistant ingress proxies the Web UI to that port. When `SUPERVISOR_TOKEN` is detected, direct dashboard/API access on `:8787` requires `app_token`; with an empty `app_token`, direct dashboard access is disabled. From the network, the only unauthenticated application data is the single public Custom Chart view/data endpoint (`/charts/custom/<share-token>`, `/api/public/charts/custom/<share-token>`). The share token is random, only its hash is stored in SQLite, and the URL does not expose device names or metric selectors. Links copied from History → Custom chart bypass HA ingress and point directly to the add-on host/IP on its HTTP port (default `8787`). `/api/health` is accepted without a token only from the Supervisor peer for the add-on watchdog; direct network requests require `app_token`. The database is stored in `/data/gree-controller.db`; `backup: cold` keeps it in the add-on backup. The service uses fixed internal TCP port `8787`; Home Assistant ingress proxies the Web UI to that port. The port is not a user-facing Network option. On startup the add-on compares the Supervisor-reported ingress port with the `8787` contract and refuses to start if a manually modified package is inconsistent. When `SUPERVISOR_TOKEN` is detected, direct dashboard/API access on `:8787` requires `app_token`; with an empty `app_token`, direct dashboard access is disabled. From the network, the only unauthenticated application data is the single public Custom Chart view/data endpoint (`/charts/custom/<share-token>`, `/api/public/charts/custom/<share-token>`). The share token is random, only its hash is stored in SQLite, and the URL does not expose device names or metric selectors. Links copied from History → Custom chart bypass HA ingress; by default the add-on obtains the primary host IPv4 from the Supervisor API and builds `http://<HA-IP>:8787/charts/custom/...`. `public_chart_base_url` can explicitly select a reverse proxy, alternate hostname or routing path. `/api/health` is accepted without a token only from the Supervisor peer for the add-on watchdog; direct network requests require `app_token`. The database is stored in `/data/gree-controller.db`; `backup: cold` keeps it in the add-on backup.
The watchdog checks `/api/health`. For network troubleshooting, verify `ha network info`, `gree_interface`, the selected subnet broadcast, and UDP/firewall rules first. The watchdog checks `/api/health`. For network troubleshooting, verify `ha network info`, `gree_interface`, the selected subnet broadcast, and UDP/firewall rules first.
@@ -1,5 +1,5 @@
name: "GREE Controller" name: "GREE Controller"
version: "0.14.14" version: "0.14.15"
slug: "gree_controller" slug: "gree_controller"
description: "Local GREE HVAC controller with Web UI and Home Assistant integration" description: "Local GREE HVAC controller with Web UI and Home Assistant integration"
url: "https://git.linuxiarz.pl/gru/gree-controller-ha-addon/" url: "https://git.linuxiarz.pl/gru/gree-controller-ha-addon/"
@@ -12,13 +12,14 @@ boot: auto
init: false init: false
host_network: true host_network: true
homeassistant_api: true homeassistant_api: true
hassio_api: true
ingress: true ingress: true
ingress_port: 8787 ingress_port: 8787
ingress_stream: true ingress_stream: true
panel_icon: mdi:air-conditioner panel_icon: mdi:air-conditioner
panel_title: GREE Controller panel_title: GREE Controller
panel_admin: true panel_admin: true
watchdog: "http://[HOST]:8787/api/health" watchdog: "http://[HOST]:[PORT:8787]/api/health"
backup: cold backup: cold
options: options:
gree_interface: "" gree_interface: ""
@@ -29,6 +30,7 @@ options:
zone_interval_seconds: 5 zone_interval_seconds: 5
discovery_timeout_ms: 3000 discovery_timeout_ms: 3000
app_token: "" app_token: ""
public_chart_base_url: ""
log_level: info log_level: info
schema: schema:
gree_interface: str gree_interface: str
@@ -39,4 +41,5 @@ schema:
zone_interval_seconds: "int(2,3600)" zone_interval_seconds: "int(2,3600)"
discovery_timeout_ms: "int(500,30000)" discovery_timeout_ms: "int(500,30000)"
app_token: password app_token: password
public_chart_base_url: str
log_level: "list(error|warn|info|debug|trace)" log_level: "list(error|warn|info|debug|trace)"
@@ -23,6 +23,9 @@ configuration:
app_token: app_token:
name: Application token name: Application token
description: Token required for direct dashboard/API access on port 8787. With SUPERVISOR_TOKEN active, an empty token disables direct access; only generated Custom Chart share links remain public. description: Token required for direct dashboard/API access on port 8787. With SUPERVISOR_TOKEN active, an empty token disables direct access; only generated Custom Chart share links remain public.
public_chart_base_url:
name: Public chart base URL
description: Optional override for generated Custom Chart links, for example http://192.168.1.20:8787 or a reverse-proxy URL. Leave empty to use the primary Home Assistant host IPv4 and the fixed add-on port 8787 automatically.
log_level: log_level:
name: Log level name: Log level
description: Controller log verbosity. description: Controller log verbosity.
@@ -23,6 +23,9 @@ configuration:
app_token: app_token:
name: Token aplikacji name: Token aplikacji
description: Token wymagany do bezpośredniego dostępu do dashboardu/API na porcie 8787. Przy aktywnym SUPERVISOR_TOKEN pusty token blokuje direct access; publiczne pozostają wyłącznie wygenerowane linki Custom Chart. description: Token wymagany do bezpośredniego dostępu do dashboardu/API na porcie 8787. Przy aktywnym SUPERVISOR_TOKEN pusty token blokuje direct access; publiczne pozostają wyłącznie wygenerowane linki Custom Chart.
public_chart_base_url:
name: Bazowy URL publicznych wykresów
description: Opcjonalne nadpisanie adresu generowanych linków Custom Chart, np. http://192.168.1.20:8787 albo adres reverse proxy. Pozostaw puste, aby automatycznie użyć głównego IPv4 hosta Home Assistant i stałego portu add-onu 8787.
log_level: log_level:
name: Poziom logowania name: Poziom logowania
description: Szczegółowość logów kontrolera. description: Szczegółowość logów kontrolera.
+56 -3
View File
@@ -2,6 +2,8 @@
set -Eeuo pipefail set -Eeuo pipefail
CONFIG=/data/options.json CONFIG=/data/options.json
readonly HA_HTTP_PORT=8787
SUPERVISOR_API="${SUPERVISOR:-http://supervisor}"
read_option() { read_option() {
local key="$1" default_value="${2-}" local key="$1" default_value="${2-}"
@@ -13,6 +15,44 @@ read_option() {
fi fi
} }
supervisor_get() {
local path="$1"
[[ -n "${SUPERVISOR_TOKEN:-}" ]] || return 1
curl --fail --silent --show-error --max-time 5 \
-H "Authorization: Bearer ${SUPERVISOR_TOKEN}" \
"${SUPERVISOR_API%/}${path}"
}
validate_ingress_port_contract() {
local payload ingress_port
payload="$(supervisor_get /addons/self/info 2>/dev/null || true)"
[[ -n "$payload" ]] || return 0
ingress_port="$(jq -r '.data.ingress_port // empty' <<<"$payload" 2>/dev/null || true)"
if [[ "$ingress_port" =~ ^[0-9]+$ ]] && (( ingress_port != HA_HTTP_PORT )); then
printf 'GREE Controller: refusing to start: HA ingress_port=%s but the add-on HTTP port contract is %s. Reinstall/update the official add-on package instead of changing ingress_port manually.\n' \
"$ingress_port" "$HA_HTTP_PORT" >&2
exit 78
fi
}
detect_primary_host_ipv4() {
local payload address
payload="$(supervisor_get /network/info 2>/dev/null || true)"
[[ -n "$payload" ]] || return 1
address="$(jq -r '
(.data.interfaces // [])
| (if type == "object" then [to_entries[] | (.value + {interface: (.value.interface // .key)})] else . end)
| map(select((.enabled // true) == true and (.connected // true) == true))
| map(. + {candidate_ipv4: (.ipv4.ip_address // .ip_address // (try .ipv4.address[0] catch empty) // empty)})
| map(select(.candidate_ipv4 != ""))
| ((map(select((.primary // false) == true)) | .[0]) // .[0] // {})
| (.candidate_ipv4 // empty)
' <<<"$payload" 2>/dev/null || true)"
address="${address%%/*}"
[[ "$address" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]] || return 1
printf '%s\n' "$address"
}
GREE_INTERFACE="$(read_option gree_interface '')" GREE_INTERFACE="$(read_option gree_interface '')"
DISCOVERY_BROADCAST="$(read_option discovery_broadcast '255.255.255.255:7000')" DISCOVERY_BROADCAST="$(read_option discovery_broadcast '255.255.255.255:7000')"
SIMULATE="$(read_option simulate 'false')" SIMULATE="$(read_option simulate 'false')"
@@ -21,9 +61,20 @@ POLL_INTERVAL="$(read_option poll_interval_seconds '15')"
ZONE_INTERVAL="$(read_option zone_interval_seconds '5')" ZONE_INTERVAL="$(read_option zone_interval_seconds '5')"
DISCOVERY_TIMEOUT="$(read_option discovery_timeout_ms '3000')" DISCOVERY_TIMEOUT="$(read_option discovery_timeout_ms '3000')"
APP_TOKEN="$(read_option app_token '')" APP_TOKEN="$(read_option app_token '')"
PUBLIC_CHART_BASE_URL="$(read_option public_chart_base_url '')"
LOG_LEVEL="$(read_option log_level 'info')" LOG_LEVEL="$(read_option log_level 'info')"
export GREE_CONTROLLER_BIND="0.0.0.0:8787" validate_ingress_port_contract
PUBLIC_CHART_BASE_SOURCE="configured"
if [[ -z "$PUBLIC_CHART_BASE_URL" ]]; then
PUBLIC_CHART_BASE_SOURCE="browser-fallback"
if PRIMARY_HOST_IPV4="$(detect_primary_host_ipv4)"; then
PUBLIC_CHART_BASE_URL="http://${PRIMARY_HOST_IPV4}:${HA_HTTP_PORT}"
PUBLIC_CHART_BASE_SOURCE="supervisor-primary-ipv4"
fi
fi
export GREE_CONTROLLER_BIND="0.0.0.0:${HA_HTTP_PORT}"
export GREE_CONTROLLER_DATABASE="/data/gree-controller.db" export GREE_CONTROLLER_DATABASE="/data/gree-controller.db"
export GREE_CONTROLLER_GREE_INTERFACE="$GREE_INTERFACE" export GREE_CONTROLLER_GREE_INTERFACE="$GREE_INTERFACE"
export GREE_CONTROLLER_DISCOVERY_BROADCAST="$DISCOVERY_BROADCAST" export GREE_CONTROLLER_DISCOVERY_BROADCAST="$DISCOVERY_BROADCAST"
@@ -33,9 +84,11 @@ export GREE_CONTROLLER_POLL_INTERVAL_SECONDS="$POLL_INTERVAL"
export GREE_CONTROLLER_ZONE_INTERVAL_SECONDS="$ZONE_INTERVAL" export GREE_CONTROLLER_ZONE_INTERVAL_SECONDS="$ZONE_INTERVAL"
export GREE_CONTROLLER_DISCOVERY_TIMEOUT_MS="$DISCOVERY_TIMEOUT" export GREE_CONTROLLER_DISCOVERY_TIMEOUT_MS="$DISCOVERY_TIMEOUT"
export GREE_CONTROLLER_APP_TOKEN="$APP_TOKEN" export GREE_CONTROLLER_APP_TOKEN="$APP_TOKEN"
export GREE_CONTROLLER_PUBLIC_CHART_BASE_URL="$PUBLIC_CHART_BASE_URL"
export GREE_CONTROLLER_HA_AUTH="supervisor" export GREE_CONTROLLER_HA_AUTH="supervisor"
export RUST_LOG="gree_controller=${LOG_LEVEL},tower_http=${LOG_LEVEL}" export RUST_LOG="gree_controller=${LOG_LEVEL},tower_http=${LOG_LEVEL}"
printf 'GREE Controller: interface=%s discovery=%s database=%s\n' \ printf 'GREE Controller: interface=%s discovery=%s database=%s http_port=%s public_chart_base_source=%s\n' \
"${GREE_INTERFACE:-auto}" "$DISCOVERY_BROADCAST" "$GREE_CONTROLLER_DATABASE" "${GREE_INTERFACE:-auto}" "$DISCOVERY_BROADCAST" "$GREE_CONTROLLER_DATABASE" "$HA_HTTP_PORT" \
"$PUBLIC_CHART_BASE_SOURCE"
exec /usr/local/bin/gree-controller exec /usr/local/bin/gree-controller
+26 -7
View File
@@ -3,18 +3,37 @@ set -euo pipefail
cd "$(dirname "$0")" cd "$(dirname "$0")"
MANIFEST="FILE_MANIFEST.sha256" SOURCE_MANIFEST="SOURCE_MANIFEST.sha256"
TMP="${MANIFEST}.tmp" FILE_MANIFEST="FILE_MANIFEST.sha256"
SOURCE_TMP="${SOURCE_MANIFEST}.tmp"
FILE_TMP="${FILE_MANIFEST}.tmp"
find . -type f \ find . -type f \
! -path "./${MANIFEST}" \ ! -path "./${SOURCE_MANIFEST}" \
! -path "./${TMP}" \ ! -path "./${SOURCE_TMP}" \
! -path "./${FILE_MANIFEST}" \
! -path "./${FILE_TMP}" \
! -path "./.git/*" \ ! -path "./.git/*" \
! -path "./target/*" \ ! -path "./target/*" \
! -name '*.pyc' \
! -path '*/__pycache__/*' \
-print0 \ -print0 \
| sort -z \ | sort -z \
| xargs -0 sha256sum > "$TMP" | xargs -0 sha256sum > "$SOURCE_TMP"
mv "$TMP" "$MANIFEST" mv "$SOURCE_TMP" "$SOURCE_MANIFEST"
sha256sum -c "$SOURCE_MANIFEST"
sha256sum -c "$MANIFEST" find . -type f \
! -path "./${FILE_MANIFEST}" \
! -path "./${FILE_TMP}" \
! -path "./.git/*" \
! -path "./target/*" \
! -name '*.pyc' \
! -path '*/__pycache__/*' \
-print0 \
| sort -z \
| xargs -0 sha256sum > "$FILE_TMP"
mv "$FILE_TMP" "$FILE_MANIFEST"
sha256sum -c "$FILE_MANIFEST"
+4 -4
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Developer smoke/integration tests for GREE Controller API 0.14.14. """Developer smoke/integration tests for GREE Controller API 0.14.15.
Default mode is read-only and safe to run against a real controller. 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 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_BASE_URL = os.environ.get("GREE_API_URL", "http://127.0.0.1:8787")
DEFAULT_TOKEN = os.environ.get("GREE_API_TOKEN", "") DEFAULT_TOKEN = os.environ.get("GREE_API_TOKEN", "")
DEFAULT_EXPECTED_VERSION = "0.14.14" DEFAULT_EXPECTED_VERSION = "0.14.15"
SETTINGS_PATHS: dict[str, set[str]] = { SETTINGS_PATHS: dict[str, set[str]] = {
"/api/settings/application": {"simulator_enabled"}, "/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") 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("public health", lambda: test_health(client, args.expected_version))
runner.run("OpenAPI 0.14.14 contract", lambda: test_openapi(client, args.expected_version)) runner.run("OpenAPI 0.14.15 contract", lambda: test_openapi(client, args.expected_version))
runner.run("bootstrap snapshot contract", lambda: test_bootstrap_contract(client)) runner.run("bootstrap snapshot contract", lambda: test_bootstrap_contract(client))
runner.run("protected API requires auth", lambda: test_protected_auth(client)) runner.run("protected API requires auth", lambda: test_protected_auth(client))
@@ -662,7 +662,7 @@ def run_suite(args: argparse.Namespace) -> int:
def parse_args(argv: Optional[Iterable[str]] = None) -> argparse.Namespace: def parse_args(argv: Optional[Iterable[str]] = None) -> argparse.Namespace:
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
description="Developer smoke/integration tests for GREE Controller API 0.14.14.", description="Developer smoke/integration tests for GREE Controller API 0.14.15.",
formatter_class=argparse.RawDescriptionHelpFormatter, formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""Examples: epilog="""Examples:
python3 scripts/api_dev_test.py python3 scripts/api_dev_test.py
+1 -1
View File
@@ -27,7 +27,7 @@ async fn export_configuration(
fn validate_configuration_header(export: &ConfigurationExport) -> Result<(), AppError> { fn validate_configuration_header(export: &ConfigurationExport) -> Result<(), AppError> {
if export.format_version != 3 { if export.format_version != 3 {
return Err(AppError::BadRequest("unsupported configuration export version; version 3 is required by GREE Controller 0.14.14".into())); return Err(AppError::BadRequest("unsupported configuration export version; version 3 is required by GREE Controller 0.14.15".into()));
} }
if export.settings.control_strategy != "setpoint" { if export.settings.control_strategy != "setpoint" {
return Err(AppError::BadRequest( return Err(AppError::BadRequest(
+2 -1
View File
@@ -2,6 +2,7 @@ async fn security_headers(request: Request, next: Next) -> Response {
let path = request.uri().path(); let path = request.uri().path();
let is_api = path == "/api" || path.starts_with("/api/"); let is_api = path == "/api" || path.starts_with("/api/");
let is_api_docs = path == "/api-docs" || path.starts_with("/api-docs/"); let is_api_docs = path == "/api-docs" || path.starts_with("/api-docs/");
let is_custom_chart = path.starts_with("/charts/custom/");
let mut response = next.run(request).await; let mut response = next.run(request).await;
@@ -24,7 +25,7 @@ async fn security_headers(request: Request, next: Next) -> Response {
); );
headers.insert( headers.insert(
header::HeaderName::from_static("referrer-policy"), header::HeaderName::from_static("referrer-policy"),
HeaderValue::from_static(if path.starts_with("/charts/custom/") { HeaderValue::from_static(if is_custom_chart {
"no-referrer" "no-referrer"
} else { } else {
"same-origin" "same-origin"
+2
View File
@@ -15,6 +15,7 @@ struct SystemInfoResponse {
simulator_count: usize, simulator_count: usize,
bind: String, bind: String,
base_path: String, base_path: String,
public_chart_base_url: String,
gree_interface: String, gree_interface: String,
gree_received_frames: u64, gree_received_frames: u64,
gree_received_frames_by_device: std::collections::HashMap<String, u64>, gree_received_frames_by_device: std::collections::HashMap<String, u64>,
@@ -191,6 +192,7 @@ fn build_system_info(state: &AppState, devices: &[Device]) -> SystemInfoResponse
} else { } else {
state.config.base_path.clone() state.config.base_path.clone()
}, },
public_chart_base_url: state.config.public_chart_base_url.clone(),
gree_interface: if state.config.gree_interface.trim().is_empty() { gree_interface: if state.config.gree_interface.trim().is_empty() {
"auto".to_string() "auto".to_string()
} else { } else {
+24
View File
@@ -21,6 +21,8 @@ pub struct Config {
pub app_token: String, pub app_token: String,
#[arg(long, env = "GREE_CONTROLLER_BASE_PATH", default_value = "")] #[arg(long, env = "GREE_CONTROLLER_BASE_PATH", default_value = "")]
pub base_path: String, pub base_path: String,
#[arg(long, env = "GREE_CONTROLLER_PUBLIC_CHART_BASE_URL", default_value = "")]
pub public_chart_base_url: String,
#[arg(long, env = "GREE_CONTROLLER_SIMULATE", default_value_t = false)] #[arg(long, env = "GREE_CONTROLLER_SIMULATE", default_value_t = false)]
pub simulate: bool, pub simulate: bool,
#[arg(long, env = "GREE_CONTROLLER_AUTO_SEED", default_value_t = false)] #[arg(long, env = "GREE_CONTROLLER_AUTO_SEED", default_value_t = false)]
@@ -60,6 +62,7 @@ impl Config {
dotenvy::dotenv().ok(); dotenvy::dotenv().ok();
let mut config = Self::parse(); let mut config = Self::parse();
config.base_path = normalize_base_path(&config.base_path)?; config.base_path = normalize_base_path(&config.base_path)?;
config.public_chart_base_url = normalize_public_chart_base_url(&config.public_chart_base_url)?;
if let Some(parent) = config.database.parent() { if let Some(parent) = config.database.parent() {
std::fs::create_dir_all(parent).with_context(|| { std::fs::create_dir_all(parent).with_context(|| {
format!("cannot create database directory {}", parent.display()) format!("cannot create database directory {}", parent.display())
@@ -282,6 +285,27 @@ fn normalize_base_path(value: &str) -> Result<String> {
Ok(format!("/{}", value.trim_matches('/'))) Ok(format!("/{}", value.trim_matches('/')))
} }
fn normalize_public_chart_base_url(value: &str) -> Result<String> {
let value = value.trim();
if value.is_empty() {
return Ok(String::new());
}
let parsed = url::Url::parse(value)
.with_context(|| "GREE_CONTROLLER_PUBLIC_CHART_BASE_URL must be an absolute HTTP(S) URL")?;
if !matches!(parsed.scheme(), "http" | "https")
|| parsed.host_str().is_none()
|| !parsed.username().is_empty()
|| parsed.password().is_some()
|| parsed.query().is_some()
|| parsed.fragment().is_some()
{
anyhow::bail!("GREE_CONTROLLER_PUBLIC_CHART_BASE_URL must be an absolute HTTP(S) URL without credentials, query or fragment");
}
Ok(value.trim_end_matches('/').to_string())
}
fn env_bool(name: &str) -> Option<bool> { fn env_bool(name: &str) -> Option<bool> {
env::var(name) env::var(name)
.ok() .ok()
+2
View File
@@ -312,6 +312,8 @@ function drawCurrentChartIfVisible() {
} }
function publicCustomChartUrl(path) { function publicCustomChartUrl(path) {
const configuredPublicBase = String(app.system?.public_chart_base_url || '').trim().replace(/\/+$/, '');
if (configuredPublicBase) return `${configuredPublicBase}${path}`;
if (!APP_BASE.startsWith('/api/hassio_ingress/')) return `${location.origin}${APP_BASE}${path}`; if (!APP_BASE.startsWith('/api/hassio_ingress/')) return `${location.origin}${APP_BASE}${path}`;
const bind = String(app.system?.bind || ''); const bind = String(app.system?.bind || '');
const port = bind.match(/:(\d+)$/)?.[1] || '8787'; const port = bind.match(/:(\d+)$/)?.[1] || '8787';
+62 -261
View File
@@ -2937,9 +2937,7 @@ button.outside-pill:focus-visible {
align-items: end; align-items: end;
} }
.history-network-controls label { .history-network-controls label { min-width: 0; }
min-width: 0;
}
.history-jitter-toggle { .history-jitter-toggle {
min-height: 45px; min-height: 45px;
@@ -9040,25 +9038,13 @@ body.flow-editor-open {
} }
@keyframes cloud-command-pulse { @keyframes cloud-command-pulse {
from { from { opacity: .72; }
opacity: .72; to { opacity: 1; }
}
to {
opacity: 1;
}
} }
@keyframes cloud-command-dot { @keyframes cloud-command-dot {
from { from { transform: scale(.65); opacity: .45; }
transform: scale(.65); to { transform: scale(1); opacity: 1; }
opacity: .45;
}
to {
transform: scale(1);
opacity: 1;
}
} }
@@ -9390,7 +9376,7 @@ body.flow-editor-open {
content: none; content: none;
} }
} }
/* Notification delivery audit in Events. */
.log-row .kind .log-notification-badge { .log-row .kind .log-notification-badge {
margin-left: .45rem; margin-left: .45rem;
padding: 3px 7px; padding: 3px 7px;
@@ -9403,6 +9389,7 @@ body.flow-editor-open {
vertical-align: middle; vertical-align: middle;
} }
/* Keep the Flow footer compact before the full mobile layout kicks in. */
@media (min-width:761px) and (max-width:1200px) { @media (min-width:761px) and (max-width:1200px) {
.flow-natural-preview { .flow-natural-preview {
display: block; display: block;
@@ -9472,6 +9459,7 @@ body.flow-editor-open {
} }
} }
/* GREE Cloud runtime summary */
.cloud-runtime-summary { .cloud-runtime-summary {
display: grid; display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-columns: repeat(3, minmax(0, 1fr));
@@ -9540,6 +9528,7 @@ body.flow-editor-open {
} }
} }
/* Shared alerts and split/multisplit installation configuration */
.inline-alert { .inline-alert {
display: grid; display: grid;
gap: 4px; gap: 4px;
@@ -9570,30 +9559,18 @@ body.flow-editor-open {
color: var(--danger); color: var(--danger);
} }
.inline-alert.error strong { .inline-alert.error strong { color: var(--danger); }
color: var(--danger);
}
.inline-alert.success { .inline-alert.success {
border-color: color-mix(in srgb, var(--accent) 42%, var(--line)); border-color: color-mix(in srgb, var(--accent) 42%, var(--line));
background: color-mix(in srgb, var(--accent) 10%, var(--surface)); background: color-mix(in srgb, var(--accent) 10%, var(--surface));
} }
.inline-alert.info { .inline-alert.info {
border-color: color-mix(in srgb, var(--info) 38%, var(--line)); border-color: color-mix(in srgb, var(--info) 38%, var(--line));
background: color-mix(in srgb, var(--info) 9%, var(--surface)); background: color-mix(in srgb, var(--info) 9%, var(--surface));
} }
.inline-alert.wide { grid-column: 1 / -1; }
.inline-alert.wide { .device-installation-summary { display: grid; gap: 8px; margin-bottom: 12px; }
grid-column: 1 / -1;
}
.device-installation-summary {
display: grid;
gap: 8px;
margin-bottom: 12px;
}
.installation-summary-card, .installation-summary-card,
.installation-list-row { .installation-list-row {
display: grid; display: grid;
@@ -9605,105 +9582,35 @@ body.flow-editor-open {
border-radius: 12px; border-radius: 12px;
background: var(--surface-muted); background: var(--surface-muted);
} }
.installation-summary-card > div, .installation-summary-card > div,
.installation-list-row>button:first-child { .installation-list-row > button:first-child { display: grid; gap: 3px; }
display: grid;
gap: 3px;
}
.installation-summary-card strong, .installation-summary-card strong,
.installation-list-row strong { .installation-list-row strong { color: var(--text); }
color: var(--text);
}
.installation-summary-card small, .installation-summary-card small,
.installation-list-row small { .installation-list-row small { color: var(--muted); }
color: var(--muted); .installation-list { display: grid; gap: 8px; }
} .installation-list-row > button:first-child { border: 0; background: transparent; padding: 0; text-align: left; }
.installation-list-row > div { display: flex; align-items: center; justify-content: flex-end; gap: 8px; flex-wrap: wrap; }
.installation-list { .installation-form { border-top: 1px solid var(--line); padding-top: 14px; margin-top: 14px; }
display: grid; .installation-device-choices { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; margin-top: 6px; }
gap: 8px; .installation-device-choices .check { margin: 0; padding: 8px 9px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface); }
} .installation-device-choices .check.disabled { opacity: .55; }
.installation-list-row>button:first-child {
border: 0;
background: transparent;
padding: 0;
text-align: left;
}
.installation-list-row>div {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 8px;
flex-wrap: wrap;
}
.installation-form {
border-top: 1px solid var(--line);
padding-top: 14px;
margin-top: 14px;
}
.installation-device-choices {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 6px;
margin-top: 6px;
}
.installation-device-choices .check {
margin: 0;
padding: 8px 9px;
border: 1px solid var(--line);
border-radius: 9px;
background: var(--surface);
}
.installation-device-choices .check.disabled {
opacity: .55;
}
.installation-energy-metric b { .installation-energy-metric b {
color: var(--text); color: var(--text);
font-size: 18px; font-size: 18px;
font-variant-numeric: tabular-nums; font-variant-numeric: tabular-nums;
letter-spacing: -.01em; letter-spacing: -.01em;
} }
.history-context-controls.energy-context-controls { .history-context-controls.energy-context-controls {
display: grid; display: grid;
grid-template-columns: minmax(240px, 1.5fr) repeat(3, minmax(132px, .8fr)); grid-template-columns: minmax(240px, 1.5fr) repeat(3, minmax(132px, .8fr));
gap: 10px; gap: 10px;
align-items: start; align-items: start;
} }
.history-energy-targets { display: grid; gap: 7px; min-width: 0; color: var(--muted); font-size: 12px; font-weight: 650; }
.history-energy-targets {
display: grid;
gap: 7px;
min-width: 0;
color: var(--muted);
font-size: 12px;
font-weight: 650;
}
.history-energy-targets small, .history-energy-targets small,
.history-range-control small { .history-range-control small { display: block; color: var(--muted); font-size: 10px; font-weight: 550; line-height: 1.35; }
display: block; .history-energy-picker { position: relative; min-width: 0; }
color: var(--muted);
font-size: 10px;
font-weight: 550;
line-height: 1.35;
}
.history-energy-picker {
position: relative;
min-width: 0;
}
.history-energy-picker > summary { .history-energy-picker > summary {
display: grid; display: grid;
grid-template-columns: minmax(0, 1fr) auto; grid-template-columns: minmax(0, 1fr) auto;
@@ -9718,17 +9625,8 @@ body.flow-editor-open {
cursor: pointer; cursor: pointer;
list-style: none; list-style: none;
} }
.history-energy-picker > summary::-webkit-details-marker { display: none; }
.history-energy-picker>summary::-webkit-details-marker { .history-energy-picker > summary span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
display: none;
}
.history-energy-picker>summary span {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.history-energy-picker > summary b { .history-energy-picker > summary b {
min-width: 34px; min-width: 34px;
padding: 3px 6px; padding: 3px 6px;
@@ -9738,13 +9636,7 @@ body.flow-editor-open {
font-size: 10px; font-size: 10px;
text-align: center; text-align: center;
} }
.history-energy-picker[open] > summary { border-color: var(--accent); outline: 2px solid color-mix(in srgb, var(--accent) 18%, transparent); outline-offset: 1px; }
.history-energy-picker[open]>summary {
border-color: var(--accent);
outline: 2px solid color-mix(in srgb, var(--accent) 18%, transparent);
outline-offset: 1px;
}
.history-energy-options { .history-energy-options {
position: absolute; position: absolute;
z-index: 20; z-index: 20;
@@ -9759,7 +9651,6 @@ body.flow-editor-open {
background: var(--surface); background: var(--surface);
box-shadow: 0 14px 34px rgba(0, 0, 0, .22); box-shadow: 0 14px 34px rgba(0, 0, 0, .22);
} }
.history-energy-option { .history-energy-option {
display: grid; display: grid;
grid-template-columns: 20px minmax(0, 1fr); grid-template-columns: 20px minmax(0, 1fr);
@@ -9773,67 +9664,28 @@ body.flow-editor-open {
font-size: 11px; font-size: 11px;
font-weight: 600; font-weight: 600;
} }
.history-energy-option:hover { background: var(--surface-muted); }
.history-energy-option:hover { .history-energy-option input { width: 17px; min-height: 17px; margin: 0; padding: 0; accent-color: var(--accent); }
background: var(--surface-muted); .history-energy-option span { overflow-wrap: anywhere; }
} .history-range-control.energy-period-control { min-width: 0; }
.history-energy-option input {
width: 17px;
min-height: 17px;
margin: 0;
padding: 0;
accent-color: var(--accent);
}
.history-energy-option span {
overflow-wrap: anywhere;
}
.history-range-control.energy-period-control {
min-width: 0;
}
@media (max-width: 760px) { @media (max-width: 760px) {
.installation-summary-card, .installation-summary-card,
.installation-list-row { .installation-list-row { grid-template-columns: 1fr; }
grid-template-columns: 1fr; .installation-list-row > div { justify-content: flex-start; }
} .installation-device-choices { grid-template-columns: 1fr; }
.history-context-controls.energy-context-controls { grid-template-columns: 1fr; }
.installation-list-row>div { .history-toolbar-panel .chart-toolbar.energy-toolbar .history-refresh-button { margin-top: 0; }
justify-content: flex-start; .history-energy-options { width: min(420px, calc(100vw - 40px)); max-height: 46vh; }
}
.installation-device-choices {
grid-template-columns: 1fr;
}
.history-context-controls.energy-context-controls {
grid-template-columns: 1fr;
}
.history-toolbar-panel .chart-toolbar.energy-toolbar .history-refresh-button {
margin-top: 0;
}
.history-energy-options {
width: min(420px, calc(100vw - 40px));
max-height: 46vh;
}
} }
@media (max-width: 640px) { @media (max-width: 640px) {
.history-network-controls { .history-network-controls { grid-template-columns: 1fr; }
grid-template-columns: 1fr; .history-jitter-toggle { width: 100%; }
}
.history-jitter-toggle {
width: 100%;
}
} }
/* Unified custom selects -------------------------------------------------- */
.select-native-proxy { .select-native-proxy {
position: absolute !important; position: absolute !important;
width: 1px !important; width: 1px !important;
@@ -10034,26 +9886,13 @@ select.select-native-proxy[aria-invalid="true"]+.custom-select .custom-select-tr
} }
} }
@media (max-width: 900px), @media (max-width: 900px), (orientation: landscape) and (max-height: 700px) {
(orientation: landscape) and (max-height: 700px) { .flow-fit-button-icon { display: inline-grid; place-items: center; }
.flow-fit-button-icon { .flow-fit-button-label { display: none; }
display: inline-grid;
place-items: center;
} }
.flow-fit-button-label {
display: none;
}
}
@media (orientation: landscape) and (max-height: 700px) and (min-width: 500px) { @media (orientation: landscape) and (max-height: 700px) and (min-width: 500px) {
.flow-fit-button-icon { .flow-fit-button-icon { display: none; }
display: none; .flow-fit-button-label { display: inline; }
}
.flow-fit-button-label {
display: inline;
}
} }
.ha-supervisor-status { .ha-supervisor-status {
@@ -10066,27 +9905,11 @@ select.select-native-proxy[aria-invalid="true"]+.custom-select .custom-select-tr
background: var(--surface-2); background: var(--surface-2);
} }
.ha-supervisor-status strong { .ha-supervisor-status strong { font-size: .92rem; }
font-size: .92rem; .ha-supervisor-status span { color: var(--muted); font-size: .82rem; line-height: 1.45; }
} .ha-supervisor-status.success { border-left-color: var(--teal); }
.ha-supervisor-status.warning { border-left-color: var(--accent); }
.ha-supervisor-status span { .ha-supervisor-status.error { border-left-color: var(--danger); }
color: var(--muted);
font-size: .82rem;
line-height: 1.45;
}
.ha-supervisor-status.success {
border-left-color: var(--teal);
}
.ha-supervisor-status.warning {
border-left-color: var(--accent);
}
.ha-supervisor-status.error {
border-left-color: var(--danger);
}
.ha-entity-picker { .ha-entity-picker {
display: grid; display: grid;
@@ -10094,13 +9917,8 @@ select.select-native-proxy[aria-invalid="true"]+.custom-select .custom-select-tr
min-width: 0; min-width: 0;
} }
.ha-entity-picker>label { .ha-entity-picker > label { margin: 0; }
margin: 0; .ha-entity-picker > .field-note { margin: 0; }
}
.ha-entity-picker>.field-note {
margin: 0;
}
.ha-entity-results { .ha-entity-results {
display: grid; display: grid;
@@ -10153,26 +9971,15 @@ select.select-native-proxy[aria-invalid="true"]+.custom-select .custom-select-tr
font-size: .76rem; font-size: .76rem;
} }
.ha-entity-option small { .ha-entity-option small { flex: 0 0 auto; }
flex: 0 0 auto; .ha-entity-empty { padding: 9px 10px; }
}
.ha-entity-empty { /* Shared Flow HA entity picker: keep search and selected entity visually distinct. */
padding: 9px 10px; .ha-entity-search-field input[type="search"] { width: 100%; }
} .ha-entity-selected-field { margin-top: 2px; }
.ha-entity-selected-field input { font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace); }
.ha-entity-search-field input[type="search"] {
width: 100%;
}
.ha-entity-selected-field {
margin-top: 2px;
}
.ha-entity-selected-field input {
font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
}
/* Standalone public custom chart */
.public-custom-chart-page { .public-custom-chart-page {
min-height: 100vh; min-height: 100vh;
overflow: hidden; overflow: hidden;
@@ -10220,12 +10027,6 @@ select.select-native-proxy[aria-invalid="true"]+.custom-select .custom-select-tr
} }
@media (max-width: 700px) { @media (max-width: 700px) {
.public-custom-chart-shell { .public-custom-chart-shell { padding: 8px; }
padding: 8px; .public-custom-chart-card { min-height: calc(100vh - 16px); padding: 14px; }
}
.public-custom-chart-card {
min-height: calc(100vh - 16px);
padding: 14px;
}
} }