diff --git a/Cargo.lock b/Cargo.lock index 783b3d7..c704996 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -700,7 +700,7 @@ dependencies = [ [[package]] name = "gree-controller" -version = "0.14.15" +version = "0.14.18" dependencies = [ "aes", "aes-gcm", diff --git a/Cargo.toml b/Cargo.toml index b26767d..2480e37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gree-controller" -version = "0.14.15" +version = "0.14.18" edition = "2021" authors = ["GREE Controller contributors"] description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support" diff --git a/FILE_MANIFEST.sha256 b/FILE_MANIFEST.sha256 index d66e2f2..4081607 100644 --- a/FILE_MANIFEST.sha256 +++ b/FILE_MANIFEST.sha256 @@ -1,14 +1,14 @@ -f809050a6074ba8e98e08c89af1174dffef679114ffae5c2d200150a9588b8d9 ./.env.example +de0793949cf01d27d903653226ecc9b5f72523d8711f20bcab022cf42c4c4ed0 ./.env.example a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore -597f6fb6e6b7306d2b22fa68cf4cc9c438b1d67537db29519a1de57a8775a426 ./Cargo.lock -8839d028f8c3facf329b97d8e2623b6c89b27aa25716ccd4848dff4a5e4041bf ./Cargo.toml +ae81cbdcd9800a5b705f5321034f001571cecc8124671c7ebb77de8ce9d0033e ./Cargo.lock +5190ac715681fbb1aa4b2bcebf1478c58791794507e3f4f70af37fc6bf1b29bc ./Cargo.toml 19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE -699e00f944554597b1684b7892cb43dc96eb3c7b6f04ed8e28fc3a8784765ff2 ./README.md -bdc52c361ff7a2e0fc3e96ab2b1599f4002cc6490064e4064a5688604cde83bc ./SOURCE_MANIFEST.sha256 +414ce67f34d7eccde894167b383a2cf4f18ae9f275e782d61f48569b1297b0a8 ./README.md +a1a12263a9409f687783d79b83e285785cc735ab80288f37b57cf6cccca967d4 ./SOURCE_MANIFEST.sha256 5302570299af2c2650bada12e123f598c5db8009949c75761385f73ed57343c5 ./build.rs -fa74b515483caeea518e392adfe8f235fb3f08131fb2fbd12bebe58c665bd81f ./docs/API.md +a2ce53408ca7ea559da735b1d7d0bb6d3d050eca220a5fcfe43f264b336e583f ./docs/API.md f21d732eb1147f8f3167d2172cdf0b57e61edabdfecbaf97811d46c5bff7e47a ./docs/FLOW.md -809adad678983ed8572dd558768be2f20835ebd92dc527da7207e6b5df096d47 ./docs/openapi.json +9dc6076abac0bd394682206a365a179b64a798104b5f300135de5a74ed6a580c ./docs/openapi.json c65aa543d2e99f8f7d52736307b07ebd182597d80124661d53a16bb23f6f1118 ./ha-addon/.env.example ddec80cf2b5da73fd1bae50e46398033c95aa088afdb7c07d4889b5987a17a3f ./ha-addon/Dockerfile 3702707b5fd4f3a3d5d73e2dc827a6a43c144a22ff94861ab38720207bfcd94b ./ha-addon/README.md @@ -22,7 +22,7 @@ b7f0873109c52be9d7f09bea3dffc416103c50085e1f0680d11661a969479898 ./ha-addon/hom 41a8958a6fe6d10e5679c95ac34832583a2a15ecfd67d09b4e094a83d06f5c47 ./ha-addon/home-assistant/custom_components/gree_controller/coordinator.py 5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./ha-addon/home-assistant/custom_components/gree_controller/entity_map.py c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./ha-addon/home-assistant/custom_components/gree_controller/icon.png -c62ac791ec1abefe26ea97e001a92db2f2905ee603b50aab0e76242b45e863e7 ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json +3af12a645805dd8f70be900d1f962be1dfef1c252ba5d2f72bef89c1e4ed7587 ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json c52a484b671ce738ecc00228a1db19a5d703f69ab27530c2896a5c2ae3b4a96f ./ha-addon/home-assistant/custom_components/gree_controller/number.py 39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./ha-addon/home-assistant/custom_components/gree_controller/select.py cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/home-assistant/custom_components/gree_controller/sensor.py @@ -30,10 +30,10 @@ cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/hom 6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./ha-addon/home-assistant/custom_components/gree_controller/translations/en.json 13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./ha-addon/home-assistant/custom_components/gree_controller/translations/pl.json c5fc5c87273d82d2834a0a5a365c821a416413ed509613441e24e4dc3507c4d2 ./ha-addon/home-assistant/generated/gree_controller_entities.example.json -59f420dcff7b7712ee4fb2afcda8573d2f420b593cc333989b4537179703508c ./ha-addon/repository/gree-controller/CHANGELOG.md +6339b12ea19bcde3628ac34cc7b65fd971e3e44bcaf28c7a144fa8042a25aada ./ha-addon/repository/gree-controller/CHANGELOG.md 1b5599195329cc3e643c23aa1caadcec80f133e8e515eec7d92b9f3cbda5b80b ./ha-addon/repository/gree-controller/DOCS.md c3db302f38d26dc9f8caf37a1a8a07a1334cc07ae301d452f2940a5ec5915719 ./ha-addon/repository/gree-controller/README.md -bc356f1ea4f367084677ae05887a256056d6b403e5a0f0e57c86c11636fb20ea ./ha-addon/repository/gree-controller/config.yaml +a07415454295755b8920fe305deff439e6ebc79f0f4ba184cd3ae91d41c8d420 ./ha-addon/repository/gree-controller/config.yaml 3aae6cdae4c3aaab7786a9575e7093b7e2c5b69288167075f4b7475611691a6b ./ha-addon/repository/gree-controller/topologia-ha-vlan-gree-pl.png 0d0b42a7639b128946eec379175436fa1f150294f39d2dfd169077bfa87fd14d ./ha-addon/repository/gree-controller/topology-ha-vlan-gree-en.png 2272740b185e9520e948f74b8f45cf98b8b5fd28c93bdee760da626f91fe5c2a ./ha-addon/repository/gree-controller/translations/en.yaml @@ -43,8 +43,8 @@ cea12bc74c066a588a5ef0ef7bad9d4906bdbcea99f2d275429b0eefc94b4b5f ./ha-addon/run 081e27b6e43070d44f865335c30a42a5a29668eaa6a5ea5ab6967ac4447b8e06 ./ha-addon/sync-repository.sh f9e31de3d109ead32bf531c074d46a087df398d62488caee0b46b5e0a1c027f7 ./ha_addon.md 253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md -ec091f3cf6745995b1a677df5b064e9ed70e67b61f2c300e146ac8d64d6af570 ./lang/en.json -b14581a982441986df693849feccfcdfe4769b245a2adac0558fc86420d17f82 ./lang/pl.json +9477f8e45e8471867acf9af2b1554c9dc9490808c11507e4ce9cb9101c0ce2df ./lang/en.json +1270413ebdc2ace15ba62f365484207299f2de480bbb87d2b42959dc9ce6fd34 ./lang/pl.json d8459024f04ca514bd8e9d6bd3af872fb942fd85a7cdd5583f4a9d28aab6faba ./make_zip.py b14233a8987e53bbbdd6770386ba10fa166ec25c1e098275c173c544b37846fc ./presets/bedroom_window_night.json 1960841119c0b673fb2f03621b32237552fd828045304cd221401214b997c910 ./presets/device_resilience.json @@ -85,7 +85,7 @@ fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/wind 804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json fd7390d64a2378352c09382accf6efff43903d952d111b22a982f06c5b2a3b4b ./regenerate-sha.sh c64b1c6deeb24f20af662bfce7fa3683703914987241107ce664fa2f6d1a9dcb ./scripts/README.md -8bf77e97e4789242924aa030aa63c63912f5cd7334de0778f2ea9800c6912f8e ./scripts/api_dev_test.py +81f2d3f512f21d167c6d18bd2bda9d9e1557c0b234aa7826148ea557d726ddc2 ./scripts/api_dev_test.py 5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh 6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh 1d6e14e26e49aa9d3527f30a23668bf8d9c48b67e6628ef686c3155c012155de ./scripts/dev.sh @@ -102,7 +102,7 @@ a70ddd9d4c9fca073ff494db73ec13acc7cff1830c9675d0541518d814da3772 ./src/api.rs f6ed359370dacd691344402307843a0ad31bbeb46085f99e81cfa46a618ee87d ./src/api/assets.rs b24092f34a46626d64628b510eba82193f0b203fd097f6a621b91af5d91eb571 ./src/api/auth.rs 9e4fc675306e111ed3db7af9822e2925d88109c31b9e309851665a975c0bd83c ./src/api/automations.rs -1f2e3df47e532c1a222125d3790ec97772cf535af679589fde0ef9217f2db018 ./src/api/configuration.rs +af078ccc0bfcf0c7f2a4a8c1e7ee2f21dc1966ac209d17f17de12bb4d5276244 ./src/api/configuration.rs 19bc141286a336ad67e99079496eb0ae5126f986ab28be62b5f97758e5f6969c ./src/api/debug_tokens.rs 32ade46ec45d6faf7852242b9f5ba1be6eacbacbeb33d2deabfab59bf1610ce0 ./src/api/device_groups.rs fcbb3da0538aab451f71810f829cc248d6bb67e586dc418d71a572980583823d ./src/api/devices.rs @@ -110,7 +110,7 @@ fcbb3da0538aab451f71810f829cc248d6bb67e586dc418d71a572980583823d ./src/api/devi d59b080b392b574ec94276c7b485b455d0d1abacc7de2ef29dcbfcf7d86dbdb0 ./src/api/flows.rs 2cfee7029f065e81628a8942e3dad00a03c3a5cf4f8492d07f12b75d05c07359 ./src/api/gree_cloud.rs b61b0b4f196c5e72e47cf06ca0c14df3cf8eedbdef0242a9d2af33623663489f ./src/api/groups.rs -e41ddb47f46ccad81baab1d25ddba910c087350b4b521844a33eae010cdaaa0b ./src/api/history.rs +92de677265216adb3154f6558684aec44cebff6bf6c57044f37d20f7d5a4a10f ./src/api/history.rs e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs c71540b2b68e805e3a79ac787db9127b87585968a205fc307e93bf68d5b028e0 ./src/api/integrations.rs 7658111f7d125db55a6e23f88157339b110b2cd1ed13ceabd8f860b42dba5101 ./src/api/middleware.rs @@ -200,20 +200,20 @@ f13f1be3d5789539eba3fc1b59c14835f8c681eca7634e118fa3763a53aeee2b ./src/queries/ 7e7037a059b585c5709367b9431a225789e7039796e3ed19fc132776ac234099 ./src/state.rs b92a6cb158b494fe145b43c7641e65f6fafff47201d7d76edbec2cfd8b94835c ./systemd/gree-controller.service 544a31cb2e5374227026afd6abd0d910381f3fca1638154ebd74e3c3d96a35d1 ./web/404.html -4c88441675f8dec968e1a086e0c4514c131a15dce19801ca24c2de0b2e3086f2 ./web/custom-chart.html -f0c3b6ed0cb99a7271dbad6d4003ff98fa1a4314a384e7341441bf988b30c0ba ./web/custom-chart.js +fbd8595c339d245453427c7cb9bca937bd2f60852ba25a15956295abda26878c ./web/custom-chart.html +e13dc8c936b39c9d1f808d6e0e2ed1e9171c4da62ce6ba526220e8aaf478f571 ./web/custom-chart.js e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg -019af8f410a20704e7445d0013fc37728d56b11b2772d679fe12a6c896972d87 ./web/index.html +217a9f99be2356bb15d5fa177bd08c7527eaeff827e572557464dd4e1dfa8fe4 ./web/index.html 9ba3f6fa05b72aa989139b2a909982571b2a02055052e4c40104f1e81a9aa7eb ./web/js/README.md 27eff2821c40395369be15e197fa830535d2327fcb27c93a0e8e65a1c62de3ad ./web/js/bootstrap.js -5970f3d05006ab975c7c88baaed4cc73eb014fc40dbfb3f07a191db3534211ea ./web/js/charts.js -1f1b7d1fdc2755a0888a14a314668a80ed7095763eba9c821e5e0968ec54fd73 ./web/js/core.js -c4ef56259052ec75d362fcffbb42cdd5062485a177108c175d89614527d421e6 ./web/js/dashboard.js -c5476aaa91123bc9d2b0ab1cb2870cba04fd67ae0067f86b3edb415b76cd4864 ./web/js/entities.js -a59fd5b822029d0c1e74ba8078f55f13122347e036a96dec383293ae386f6667 ./web/js/events.js -b08b0fe301642d1daa084b322a02e351d284d2465231505d45079a52ccb4028f ./web/js/flows.js -8e6798405332eec8439c9ea28e967ee2b1d62b57012452c03089aff01dcd6452 ./web/js/forms.js -1868a8afbfc35623b538a1c6cd73246c8cc0aada4881e56941167958c0276b18 ./web/js/history.js +1612896d22fd61747175cd54174a283002ac9911f4164e593c1079f767790cda ./web/js/charts.js +5c46d271550f3db38ecbfc09e3a620f6f0e6a907a3d6d56feae9b08e894df196 ./web/js/core.js +752b3c3b59558b42d867d4a15329238f0213f354b76f7011c10e31b4e6dbb311 ./web/js/dashboard.js +0f975542ae1d9bd7216123dd3718be6e9a25dbe643eb899c67024d293940fae5 ./web/js/entities.js +7c08eb200684e6fff521db589fd4417eea050f4eac02f9a2e6b53d212dd33f75 ./web/js/events.js +473511ca11a0412a794b20430c077843072e9abe0d2510552ac83b226c381453 ./web/js/flows.js +a3d9f77a40a2574a668855125c781c067289944c6f93179ff23e3dae150e7dac ./web/js/forms.js +edde2969c9c1376f4df37224daa291256ebbbe713903d98e26b6aaa6ca467911 ./web/js/history.js 511c4e7cc4c48fbbdab64558a9d1c27e6759c9b6dca255d11f301b9708e955c7 ./web/js/main.js 6bb9386707dcf601111fea15a1a366d8798313b973ca1624878618f4c3095add ./web/js/navigation.js 799613c6d465cb2f92ecb57cb082d0c33729a03d88ab4ca7fa12a3cbd7e38e75 ./web/js/realtime.js @@ -223,6 +223,6 @@ c2710fd9c1f2b31878c1e25ceb02d74ae30456c1bbb400e69fcf7619ecc72bc2 ./web/js/selec 9f50794a92059357301b4c920b066bdb20ce1f64fbccea42effcd196d0a00cc4 ./web/js/settings.js 3815fea7ae1694568c2f249bc8460e0563ced6bde89214f74f21b41fe8cad9a6 ./web/lang-init.js 6b653e4fe2d4db4ffae6ff8f39b8ce57a10a990dc0000ee4aae51d949afadd52 ./web/manifest.webmanifest -e25c0f0419611c47a1870d0f37b5db1fe5632c12eeba0b3556179e13f222e02a ./web/styles.css +0efe0cdff18beff496017a984f6d189ea6463e14b517f2f5c5fc46923579ab15 ./web/styles.css fefdf12cbbb0a5d8a2cb89275cae28455aa42aaf179542305cc8f5e0f4825898 ./web/sw.js d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js diff --git a/README.md b/README.md index a8e7e96..54c299b 100644 --- a/README.md +++ b/README.md @@ -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. -**Version: 0.14.15** +**Version: 0.14.18** -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`. +Version 0.14.18 refactors shared Web UI CSS classes to generic component names. Segmented navigation, configuration forms/sections, chart cards, enable toggles, diagram nodes/ports and Flow block-category styling now use reusable names instead of classes tied to one feature. > [Full API reference](docs/API.md) — authentication, every endpoint, request bodies, response models, WebSocket events and examples. diff --git a/SOURCE_MANIFEST.sha256 b/SOURCE_MANIFEST.sha256 index dad2565..9d6e3fe 100644 --- a/SOURCE_MANIFEST.sha256 +++ b/SOURCE_MANIFEST.sha256 @@ -1,13 +1,13 @@ -f809050a6074ba8e98e08c89af1174dffef679114ffae5c2d200150a9588b8d9 ./.env.example +de0793949cf01d27d903653226ecc9b5f72523d8711f20bcab022cf42c4c4ed0 ./.env.example a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore -597f6fb6e6b7306d2b22fa68cf4cc9c438b1d67537db29519a1de57a8775a426 ./Cargo.lock -8839d028f8c3facf329b97d8e2623b6c89b27aa25716ccd4848dff4a5e4041bf ./Cargo.toml +ae81cbdcd9800a5b705f5321034f001571cecc8124671c7ebb77de8ce9d0033e ./Cargo.lock +5190ac715681fbb1aa4b2bcebf1478c58791794507e3f4f70af37fc6bf1b29bc ./Cargo.toml 19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE -699e00f944554597b1684b7892cb43dc96eb3c7b6f04ed8e28fc3a8784765ff2 ./README.md +414ce67f34d7eccde894167b383a2cf4f18ae9f275e782d61f48569b1297b0a8 ./README.md 5302570299af2c2650bada12e123f598c5db8009949c75761385f73ed57343c5 ./build.rs -fa74b515483caeea518e392adfe8f235fb3f08131fb2fbd12bebe58c665bd81f ./docs/API.md +a2ce53408ca7ea559da735b1d7d0bb6d3d050eca220a5fcfe43f264b336e583f ./docs/API.md f21d732eb1147f8f3167d2172cdf0b57e61edabdfecbaf97811d46c5bff7e47a ./docs/FLOW.md -809adad678983ed8572dd558768be2f20835ebd92dc527da7207e6b5df096d47 ./docs/openapi.json +9dc6076abac0bd394682206a365a179b64a798104b5f300135de5a74ed6a580c ./docs/openapi.json c65aa543d2e99f8f7d52736307b07ebd182597d80124661d53a16bb23f6f1118 ./ha-addon/.env.example ddec80cf2b5da73fd1bae50e46398033c95aa088afdb7c07d4889b5987a17a3f ./ha-addon/Dockerfile 3702707b5fd4f3a3d5d73e2dc827a6a43c144a22ff94861ab38720207bfcd94b ./ha-addon/README.md @@ -21,7 +21,7 @@ b7f0873109c52be9d7f09bea3dffc416103c50085e1f0680d11661a969479898 ./ha-addon/hom 41a8958a6fe6d10e5679c95ac34832583a2a15ecfd67d09b4e094a83d06f5c47 ./ha-addon/home-assistant/custom_components/gree_controller/coordinator.py 5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./ha-addon/home-assistant/custom_components/gree_controller/entity_map.py c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./ha-addon/home-assistant/custom_components/gree_controller/icon.png -c62ac791ec1abefe26ea97e001a92db2f2905ee603b50aab0e76242b45e863e7 ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json +3af12a645805dd8f70be900d1f962be1dfef1c252ba5d2f72bef89c1e4ed7587 ./ha-addon/home-assistant/custom_components/gree_controller/manifest.json c52a484b671ce738ecc00228a1db19a5d703f69ab27530c2896a5c2ae3b4a96f ./ha-addon/home-assistant/custom_components/gree_controller/number.py 39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./ha-addon/home-assistant/custom_components/gree_controller/select.py cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/home-assistant/custom_components/gree_controller/sensor.py @@ -29,10 +29,10 @@ cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./ha-addon/hom 6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./ha-addon/home-assistant/custom_components/gree_controller/translations/en.json 13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./ha-addon/home-assistant/custom_components/gree_controller/translations/pl.json c5fc5c87273d82d2834a0a5a365c821a416413ed509613441e24e4dc3507c4d2 ./ha-addon/home-assistant/generated/gree_controller_entities.example.json -59f420dcff7b7712ee4fb2afcda8573d2f420b593cc333989b4537179703508c ./ha-addon/repository/gree-controller/CHANGELOG.md +6339b12ea19bcde3628ac34cc7b65fd971e3e44bcaf28c7a144fa8042a25aada ./ha-addon/repository/gree-controller/CHANGELOG.md 1b5599195329cc3e643c23aa1caadcec80f133e8e515eec7d92b9f3cbda5b80b ./ha-addon/repository/gree-controller/DOCS.md c3db302f38d26dc9f8caf37a1a8a07a1334cc07ae301d452f2940a5ec5915719 ./ha-addon/repository/gree-controller/README.md -bc356f1ea4f367084677ae05887a256056d6b403e5a0f0e57c86c11636fb20ea ./ha-addon/repository/gree-controller/config.yaml +a07415454295755b8920fe305deff439e6ebc79f0f4ba184cd3ae91d41c8d420 ./ha-addon/repository/gree-controller/config.yaml 3aae6cdae4c3aaab7786a9575e7093b7e2c5b69288167075f4b7475611691a6b ./ha-addon/repository/gree-controller/topologia-ha-vlan-gree-pl.png 0d0b42a7639b128946eec379175436fa1f150294f39d2dfd169077bfa87fd14d ./ha-addon/repository/gree-controller/topology-ha-vlan-gree-en.png 2272740b185e9520e948f74b8f45cf98b8b5fd28c93bdee760da626f91fe5c2a ./ha-addon/repository/gree-controller/translations/en.yaml @@ -42,8 +42,8 @@ cea12bc74c066a588a5ef0ef7bad9d4906bdbcea99f2d275429b0eefc94b4b5f ./ha-addon/run 081e27b6e43070d44f865335c30a42a5a29668eaa6a5ea5ab6967ac4447b8e06 ./ha-addon/sync-repository.sh f9e31de3d109ead32bf531c074d46a087df398d62488caee0b46b5e0a1c027f7 ./ha_addon.md 253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md -ec091f3cf6745995b1a677df5b064e9ed70e67b61f2c300e146ac8d64d6af570 ./lang/en.json -b14581a982441986df693849feccfcdfe4769b245a2adac0558fc86420d17f82 ./lang/pl.json +9477f8e45e8471867acf9af2b1554c9dc9490808c11507e4ce9cb9101c0ce2df ./lang/en.json +1270413ebdc2ace15ba62f365484207299f2de480bbb87d2b42959dc9ce6fd34 ./lang/pl.json d8459024f04ca514bd8e9d6bd3af872fb942fd85a7cdd5583f4a9d28aab6faba ./make_zip.py b14233a8987e53bbbdd6770386ba10fa166ec25c1e098275c173c544b37846fc ./presets/bedroom_window_night.json 1960841119c0b673fb2f03621b32237552fd828045304cd221401214b997c910 ./presets/device_resilience.json @@ -84,7 +84,7 @@ fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/wind 804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json fd7390d64a2378352c09382accf6efff43903d952d111b22a982f06c5b2a3b4b ./regenerate-sha.sh c64b1c6deeb24f20af662bfce7fa3683703914987241107ce664fa2f6d1a9dcb ./scripts/README.md -8bf77e97e4789242924aa030aa63c63912f5cd7334de0778f2ea9800c6912f8e ./scripts/api_dev_test.py +81f2d3f512f21d167c6d18bd2bda9d9e1557c0b234aa7826148ea557d726ddc2 ./scripts/api_dev_test.py 5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh 6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh 1d6e14e26e49aa9d3527f30a23668bf8d9c48b67e6628ef686c3155c012155de ./scripts/dev.sh @@ -101,7 +101,7 @@ a70ddd9d4c9fca073ff494db73ec13acc7cff1830c9675d0541518d814da3772 ./src/api.rs f6ed359370dacd691344402307843a0ad31bbeb46085f99e81cfa46a618ee87d ./src/api/assets.rs b24092f34a46626d64628b510eba82193f0b203fd097f6a621b91af5d91eb571 ./src/api/auth.rs 9e4fc675306e111ed3db7af9822e2925d88109c31b9e309851665a975c0bd83c ./src/api/automations.rs -1f2e3df47e532c1a222125d3790ec97772cf535af679589fde0ef9217f2db018 ./src/api/configuration.rs +af078ccc0bfcf0c7f2a4a8c1e7ee2f21dc1966ac209d17f17de12bb4d5276244 ./src/api/configuration.rs 19bc141286a336ad67e99079496eb0ae5126f986ab28be62b5f97758e5f6969c ./src/api/debug_tokens.rs 32ade46ec45d6faf7852242b9f5ba1be6eacbacbeb33d2deabfab59bf1610ce0 ./src/api/device_groups.rs fcbb3da0538aab451f71810f829cc248d6bb67e586dc418d71a572980583823d ./src/api/devices.rs @@ -109,7 +109,7 @@ fcbb3da0538aab451f71810f829cc248d6bb67e586dc418d71a572980583823d ./src/api/devi d59b080b392b574ec94276c7b485b455d0d1abacc7de2ef29dcbfcf7d86dbdb0 ./src/api/flows.rs 2cfee7029f065e81628a8942e3dad00a03c3a5cf4f8492d07f12b75d05c07359 ./src/api/gree_cloud.rs b61b0b4f196c5e72e47cf06ca0c14df3cf8eedbdef0242a9d2af33623663489f ./src/api/groups.rs -e41ddb47f46ccad81baab1d25ddba910c087350b4b521844a33eae010cdaaa0b ./src/api/history.rs +92de677265216adb3154f6558684aec44cebff6bf6c57044f37d20f7d5a4a10f ./src/api/history.rs e8edfbb725d6de650442444b0a929ad2be0bd2c2d7d227d2b3fdd99d05c94f94 ./src/api/house.rs c71540b2b68e805e3a79ac787db9127b87585968a205fc307e93bf68d5b028e0 ./src/api/integrations.rs 7658111f7d125db55a6e23f88157339b110b2cd1ed13ceabd8f860b42dba5101 ./src/api/middleware.rs @@ -199,20 +199,20 @@ f13f1be3d5789539eba3fc1b59c14835f8c681eca7634e118fa3763a53aeee2b ./src/queries/ 7e7037a059b585c5709367b9431a225789e7039796e3ed19fc132776ac234099 ./src/state.rs b92a6cb158b494fe145b43c7641e65f6fafff47201d7d76edbec2cfd8b94835c ./systemd/gree-controller.service 544a31cb2e5374227026afd6abd0d910381f3fca1638154ebd74e3c3d96a35d1 ./web/404.html -4c88441675f8dec968e1a086e0c4514c131a15dce19801ca24c2de0b2e3086f2 ./web/custom-chart.html -f0c3b6ed0cb99a7271dbad6d4003ff98fa1a4314a384e7341441bf988b30c0ba ./web/custom-chart.js +fbd8595c339d245453427c7cb9bca937bd2f60852ba25a15956295abda26878c ./web/custom-chart.html +e13dc8c936b39c9d1f808d6e0e2ed1e9171c4da62ce6ba526220e8aaf478f571 ./web/custom-chart.js e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg -019af8f410a20704e7445d0013fc37728d56b11b2772d679fe12a6c896972d87 ./web/index.html +217a9f99be2356bb15d5fa177bd08c7527eaeff827e572557464dd4e1dfa8fe4 ./web/index.html 9ba3f6fa05b72aa989139b2a909982571b2a02055052e4c40104f1e81a9aa7eb ./web/js/README.md 27eff2821c40395369be15e197fa830535d2327fcb27c93a0e8e65a1c62de3ad ./web/js/bootstrap.js -5970f3d05006ab975c7c88baaed4cc73eb014fc40dbfb3f07a191db3534211ea ./web/js/charts.js -1f1b7d1fdc2755a0888a14a314668a80ed7095763eba9c821e5e0968ec54fd73 ./web/js/core.js -c4ef56259052ec75d362fcffbb42cdd5062485a177108c175d89614527d421e6 ./web/js/dashboard.js -c5476aaa91123bc9d2b0ab1cb2870cba04fd67ae0067f86b3edb415b76cd4864 ./web/js/entities.js -a59fd5b822029d0c1e74ba8078f55f13122347e036a96dec383293ae386f6667 ./web/js/events.js -b08b0fe301642d1daa084b322a02e351d284d2465231505d45079a52ccb4028f ./web/js/flows.js -8e6798405332eec8439c9ea28e967ee2b1d62b57012452c03089aff01dcd6452 ./web/js/forms.js -1868a8afbfc35623b538a1c6cd73246c8cc0aada4881e56941167958c0276b18 ./web/js/history.js +1612896d22fd61747175cd54174a283002ac9911f4164e593c1079f767790cda ./web/js/charts.js +5c46d271550f3db38ecbfc09e3a620f6f0e6a907a3d6d56feae9b08e894df196 ./web/js/core.js +752b3c3b59558b42d867d4a15329238f0213f354b76f7011c10e31b4e6dbb311 ./web/js/dashboard.js +0f975542ae1d9bd7216123dd3718be6e9a25dbe643eb899c67024d293940fae5 ./web/js/entities.js +7c08eb200684e6fff521db589fd4417eea050f4eac02f9a2e6b53d212dd33f75 ./web/js/events.js +473511ca11a0412a794b20430c077843072e9abe0d2510552ac83b226c381453 ./web/js/flows.js +a3d9f77a40a2574a668855125c781c067289944c6f93179ff23e3dae150e7dac ./web/js/forms.js +edde2969c9c1376f4df37224daa291256ebbbe713903d98e26b6aaa6ca467911 ./web/js/history.js 511c4e7cc4c48fbbdab64558a9d1c27e6759c9b6dca255d11f301b9708e955c7 ./web/js/main.js 6bb9386707dcf601111fea15a1a366d8798313b973ca1624878618f4c3095add ./web/js/navigation.js 799613c6d465cb2f92ecb57cb082d0c33729a03d88ab4ca7fa12a3cbd7e38e75 ./web/js/realtime.js @@ -222,6 +222,6 @@ c2710fd9c1f2b31878c1e25ceb02d74ae30456c1bbb400e69fcf7619ecc72bc2 ./web/js/selec 9f50794a92059357301b4c920b066bdb20ce1f64fbccea42effcd196d0a00cc4 ./web/js/settings.js 3815fea7ae1694568c2f249bc8460e0563ced6bde89214f74f21b41fe8cad9a6 ./web/lang-init.js 6b653e4fe2d4db4ffae6ff8f39b8ce57a10a990dc0000ee4aae51d949afadd52 ./web/manifest.webmanifest -e25c0f0419611c47a1870d0f37b5db1fe5632c12eeba0b3556179e13f222e02a ./web/styles.css +0efe0cdff18beff496017a984f6d189ea6463e14b517f2f5c5fc46923579ab15 ./web/styles.css fefdf12cbbb0a5d8a2cb89275cae28455aa42aaf179542305cc8f5e0f4825898 ./web/sw.js d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js diff --git a/docs/API.md b/docs/API.md index c1a3ea9..9dcc79b 100644 --- a/docs/API.md +++ b/docs/API.md @@ -1,6 +1,6 @@ # GREE Controller API reference -HTTP and WebSocket API for GREE Controller **0.14.15**. +HTTP and WebSocket API for GREE Controller **0.14.18**. [← Main documentation](../README.md) @@ -239,7 +239,7 @@ Response: { "status": "ok", "name": "gree-controller", - "version": "0.14.15", + "version": "0.14.18", "uptime_seconds": 1234, "control_ready": true, "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_revision": 42, "system": { - "version": "0.14.15", + "version": "0.14.18", "uptime_seconds": 1234, "auth_required": false, "control_ready": true, @@ -326,7 +326,7 @@ Returns the initial Web UI snapshot: `POST /api/charts/custom/share` is an administrator endpoint that persists a selected Custom Chart definition and returns a random path such as `/charts/custom/chart_`. Only a hash of the share token is stored. The URL does not contain device names or metric selectors. -`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, and lets the viewer switch the history range. `GET /api/public/charts/custom/:token` returns only the series configured for that share and is intentionally unauthenticated; an optional `hours` query parameter changes only the time range, not the shared series definition. Possession of the unguessable share URL is the authorization for this narrow read-only endpoint. 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://: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`. diff --git a/docs/openapi.json b/docs/openapi.json index 161ba0b..c8373ab 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -2,9 +2,9 @@ "openapi": "3.1.0", "info": { "title": "GREE Controller API", - "version": "0.14.15", + "version": "0.14.18", "summary": "Local HTTP/WebSocket API for GREE HVAC control", - "description": "Self-hosted API used by the GREE Controller Web UI and Home Assistant integration.\n\n### Authentication\nAdministrator endpoints accept `Authorization: Bearer ` or `x-api-token: ` when configured. Restricted Home Assistant control endpoints also accept generated integration tokens.\n\n### Local and GREE Cloud\nDevices use one API model and one command surface. `connection_type=local` is dispatched only to the existing LAN/UDP provider; `connection_type=gree_cloud` is dispatched only to the GREE Cloud provider. No automatic transport fallback is performed.\n\n### GREE Cloud security\nCloud passwords, REST/MQTT tokens, Authorization values and device cipher keys are never returned in normal API responses or Cloud diagnostics. MQTT uses TLS with certificate and hostname validation.\n\n### Energy\nGREE Cloud `ElcAll` and selected Home Assistant cumulative energy sensors are normalized to kWh and converted to consumption deltas before aggregation. Raw cumulative values are retained only as meter samples/baselines.\n\n### 0.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.", + "description": "Self-hosted API used by the GREE Controller Web UI and Home Assistant integration.\n\n### Authentication\nAdministrator endpoints accept `Authorization: Bearer ` or `x-api-token: ` when configured. Restricted Home Assistant control endpoints also accept generated integration tokens.\n\n### Local and GREE Cloud\nDevices use one API model and one command surface. `connection_type=local` is dispatched only to the existing LAN/UDP provider; `connection_type=gree_cloud` is dispatched only to the GREE Cloud provider. No automatic transport fallback is performed.\n\n### GREE Cloud security\nCloud passwords, REST/MQTT tokens, Authorization values and device cipher keys are never returned in normal API responses or Cloud diagnostics. MQTT uses TLS with certificate and hostname validation.\n\n### Energy\nGREE Cloud `ElcAll` and selected Home Assistant cumulative energy sensors are normalized to kWh and converted to consumption deltas before aggregation. Raw cumulative values are retained only as meter samples/baselines.\n\n### 0.14.18\nShared Web UI CSS now uses generic reusable class names for segmented tabs, configuration layouts, chart cards, enable toggles, diagram primitives and Flow block categories; behavior and visual styling are unchanged.\n\n### 0.14.17\nHistory navigation now reuses the same segmented tab component as Flow / Schedules / Automations, with redundant History-specific tab CSS removed.\n\n### 0.14.16\nCustom Charts now expose saved-chart editing in the Web UI, public chart pages can switch history range through an optional hours override, and the standalone chart layout fits the viewport without vertical page scrolling.\n\n### 0.14.15\nHome Assistant add-on Custom Chart links now resolve the primary HA host IPv4 through Supervisor, support an explicit public_chart_base_url override, and enforce the fixed 8787 ingress/application port contract at startup and build time. Standalone bind/port behavior remains configurable.\n\n### 0.14.14\nShared Flow input Home Assistant sources now expose a dedicated entity search box separate from the selected entity_id, making large live entity catalogs easy to filter by name, ID and state.\n\n### 0.14.13\nHome Assistant add-on authentication is now hidden behind an automatic Supervisor status, manual URL/token fallback is unlocked only after a failed HA test, connection tests return a live sample entity reading, and Shared Flow input HA sources include searchable live entity suggestions.\n\n### 0.14.12\nThe Home Assistant add-on now uses the Supervisor Core API proxy and runtime SUPERVISOR_TOKEN automatically; standalone Home Assistant URL/token configuration is unchanged.\n\n### 0.14.11\nWeb UI icons now use a shared inline SVG set instead of font-dependent Unicode glyphs across navigation, dialogs, Flow, charts, controls and event categories for consistent cross-platform rendering.\n\n\n### 0.14.10\nNight mode and Home Assistant / Sensors standalone settings now use the full available page width, matching the other Web UI sections.\n\n### 0.14.9\nPower controls use an embedded SVG icon instead of a font-dependent Unicode glyph. Home Assistant room-sensor stale/error events identify the affected entity and zone, and historical event rows can recover that context from metadata.\n\n### 0.14.8\nRemaining Home Assistant and notification diagnostic errors no longer use device-transport 502 responses. Missing/invalid integration configuration returns 400, configured external dependency failures return 424, and 502 is reserved for Local/LAN GREE device communication.\n\n### 0.14.7\nHome Assistant energy-sensor discovery now returns an empty optional result when HA is not configured, uses 424 for configured external-dependency failures, and custom select popovers use their rendered height when positioning above a field.\n\n\n### 0.14.6\nFixes dynamic custom-select duplication in History → Energy and hides Energy history controls when no energy source is configured.\n\n### 0.14.5\nWeb UI single-choice controls now use one consistent custom dropdown, language packs are loaded on demand, and the dashboard outdoor temperature opens a 24-hour history modal.\n\n### 0.14.4\nHome Assistant connection tests validate only the configured server/API token and require no entity. `outdoor_entity_id` is the global Home Assistant outdoor-temperature sensor; zones can override it with `ha_outdoor_entity_id`. Room-temperature Home Assistant sensors remain configured per zone with `ha_entity_id`. Global/per-zone outdoor sensors are integrated with aliases, metrics/history and Visual Flow entity suggestions.\n\n### 0.14.2\nAdds independent vertical/horizontal swing controls across manual device control, thermostat zones, legacy automations, Visual Flow and Home Assistant zone climates. Swing is treated as an auxiliary one-shot unit setting and does not replace thermostat ownership.\n\n### 0.14.1\nAdds split/multisplit installation groups with shared energy and outdoor-temperature sources, multi-target energy charts with period comparison, cleaner Cloud status/alerts and safe MQTT cleanup after the last Cloud device is removed.\n\n### 0.14.0\nAdds first-class GREE Cloud MQTT status/control, reconnect/resubscribe lifecycle, Cloud diagnostics, per-device capabilities, Cloud/HA energy sources and energy-history aggregation while preserving the LAN transport contract.", "license": { "name": "MIT" } @@ -5697,7 +5697,7 @@ "History" ], "summary": "Read shared Custom Chart data", - "description": "Read-only public data endpoint for exactly one persisted Custom Chart share. Possession of the unguessable share URL is the authorization; arbitrary metric selectors are not accepted.", + "description": "Read-only public data endpoint for exactly one persisted Custom Chart share. Possession of the unguessable share URL is the authorization; the optional hours query changes only the time range and arbitrary metric selectors are not accepted.", "operationId": "publicCustomChart", "security": [], "parameters": [ @@ -5709,6 +5709,17 @@ "type": "string", "pattern": "^chart_" } + }, + { + "name": "hours", + "in": "query", + "required": false, + "description": "Optional history-range override in hours. It changes only the time window; the persisted shared series remain fixed.", + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 87600 + } } ], "responses": { @@ -5819,7 +5830,7 @@ }, "version": { "type": "string", - "example": "0.14.15" + "example": "0.14.18" }, "uptime_seconds": { "type": "integer", diff --git a/ha-addon/home-assistant/custom_components/gree_controller/manifest.json b/ha-addon/home-assistant/custom_components/gree_controller/manifest.json index bdd87d7..d5c3300 100644 --- a/ha-addon/home-assistant/custom_components/gree_controller/manifest.json +++ b/ha-addon/home-assistant/custom_components/gree_controller/manifest.json @@ -1,7 +1,7 @@ { "domain": "gree_controller", "name": "GREE Controller", - "version": "0.14.15", + "version": "0.14.18", "config_flow": true, "integration_type": "hub", "iot_class": "local_polling", diff --git a/ha-addon/repository/gree-controller/CHANGELOG.md b/ha-addon/repository/gree-controller/CHANGELOG.md index 1e5c41a..d8e429a 100644 --- a/ha-addon/repository/gree-controller/CHANGELOG.md +++ b/ha-addon/repository/gree-controller/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## 0.14.18 + +- Renames the shared segmented navigation class from feature-specific `automation-tabs` to generic `segmented-tabs`. +- Generalizes shared configuration layout classes to `config-form`, `form-section`, `form-section-head`, `form-grid`, `sticky-form-actions` and `full-width-form`. +- Generalizes reusable chart, enable-toggle and diagram classes used across History/public charts, Zones/Flow and Simulator/Flow editor. +- Replaces Flow-palette-specific category modifiers with shared `block-category-*` classes also used by the block library. +- Removes all references to the replaced shared class names without changing component behavior or visual styling. + +## 0.14.17 + +- Makes History navigation visually identical to the Flow / Schedules / Automations segmented navigation. +- Reuses the shared `automation-tabs` component for Overview, Zones, GREE devices, Energy, Pings, HA sensors and Custom chart. +- Removes redundant History-only tab CSS, including its separate mobile overrides. + +## 0.14.16 + +- Adds an explicit Saved Charts list to History → Custom Chart with load, edit, update and delete actions. +- Keeps chart name, selected series and range editable when updating an existing saved chart instead of creating duplicates. +- Adds a range selector to standalone public Custom Chart links; the public data endpoint accepts an optional `hours` override while keeping the shared series definition fixed. +- Fits the standalone public chart to the viewport and prevents vertical page scrolling, including compact/mobile layouts. + ## 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. diff --git a/ha-addon/repository/gree-controller/config.yaml b/ha-addon/repository/gree-controller/config.yaml index 5488a00..1d205f3 100644 --- a/ha-addon/repository/gree-controller/config.yaml +++ b/ha-addon/repository/gree-controller/config.yaml @@ -1,5 +1,5 @@ name: "GREE Controller" -version: "0.14.15" +version: "0.14.18" slug: "gree_controller" description: "Local GREE HVAC controller with Web UI and Home Assistant integration" url: "https://git.linuxiarz.pl/gru/gree-controller-ha-addon/" diff --git a/lang/en.json b/lang/en.json index 4f8c26a..bd6ceb2 100644 --- a/lang/en.json +++ b/lang/en.json @@ -422,9 +422,13 @@ "history.copyLink": "Copy link", "history.series": "series", "history.noSavedCharts": "No saved custom charts yet.", + "history.savedCharts": "Saved charts", + "history.editingChart": "Editing chart", + "history.saveChanges": "Save changes", "history.customChart": "Custom climate chart", "history.customChartHint": "Your selected data sources on one timeline.", "history.chartSaved": "Custom chart saved", + "history.chartUpdated": "Custom chart updated", "history.linkCopied": "Chart link copied", "toast.successTitle": "Done", "toast.errorTitle": "Something went wrong", diff --git a/lang/pl.json b/lang/pl.json index 4878cf0..999281c 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -422,9 +422,13 @@ "history.copyLink": "Kopiuj link", "history.series": "serie", "history.noSavedCharts": "Brak zapisanych własnych wykresów.", + "history.savedCharts": "Zapisane wykresy", + "history.editingChart": "Edytujesz wykres", + "history.saveChanges": "Zapisz zmiany", "history.customChart": "Własny wykres klimatu", "history.customChartHint": "Wybrane źródła danych na wspólnej osi czasu.", "history.chartSaved": "Własny wykres zapisany", + "history.chartUpdated": "Własny wykres zaktualizowany", "history.linkCopied": "Link do wykresu skopiowany", "toast.successTitle": "Gotowe", "toast.errorTitle": "Wystąpił błąd", diff --git a/scripts/api_dev_test.py b/scripts/api_dev_test.py index 8d5c9c5..9cfeb1a 100644 --- a/scripts/api_dev_test.py +++ b/scripts/api_dev_test.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Developer smoke/integration tests for GREE Controller API 0.14.15. +"""Developer smoke/integration tests for GREE Controller API 0.14.18. Default mode is read-only and safe to run against a real controller. Use --settings-write to additionally round-trip all split settings resources and @@ -26,7 +26,7 @@ from typing import Any, Callable, Iterable, Optional DEFAULT_BASE_URL = os.environ.get("GREE_API_URL", "http://127.0.0.1:8787") DEFAULT_TOKEN = os.environ.get("GREE_API_TOKEN", "") -DEFAULT_EXPECTED_VERSION = "0.14.15" +DEFAULT_EXPECTED_VERSION = "0.14.18" SETTINGS_PATHS: dict[str, set[str]] = { "/api/settings/application": {"simulator_enabled"}, @@ -593,7 +593,7 @@ def run_suite(args: argparse.Namespace) -> int: print(f"Settings write tests: {'ENABLED' if args.settings_write else 'disabled'}\n") runner.run("public health", lambda: test_health(client, args.expected_version)) - runner.run("OpenAPI 0.14.15 contract", lambda: test_openapi(client, args.expected_version)) + runner.run("OpenAPI 0.14.18 contract", lambda: test_openapi(client, args.expected_version)) runner.run("bootstrap snapshot contract", lambda: test_bootstrap_contract(client)) runner.run("protected API requires auth", lambda: test_protected_auth(client)) @@ -662,7 +662,7 @@ def run_suite(args: argparse.Namespace) -> int: def parse_args(argv: Optional[Iterable[str]] = None) -> argparse.Namespace: parser = argparse.ArgumentParser( - description="Developer smoke/integration tests for GREE Controller API 0.14.15.", + description="Developer smoke/integration tests for GREE Controller API 0.14.18.", formatter_class=argparse.RawDescriptionHelpFormatter, epilog="""Examples: python3 scripts/api_dev_test.py diff --git a/src/api/configuration.rs b/src/api/configuration.rs index dcfde6a..f06cdea 100644 --- a/src/api/configuration.rs +++ b/src/api/configuration.rs @@ -27,7 +27,7 @@ async fn export_configuration( fn validate_configuration_header(export: &ConfigurationExport) -> Result<(), AppError> { if export.format_version != 3 { - return Err(AppError::BadRequest("unsupported configuration export version; version 3 is required by GREE Controller 0.14.15".into())); + return Err(AppError::BadRequest("unsupported configuration export version; version 3 is required by GREE Controller 0.14.18".into())); } if export.settings.control_strategy != "setpoint" { return Err(AppError::BadRequest( diff --git a/src/api/history.rs b/src/api/history.rs index 3aebe1f..1ec2fd7 100644 --- a/src/api/history.rs +++ b/src/api/history.rs @@ -511,6 +511,11 @@ struct PublicCustomChartShare { lang: String, } +#[derive(Debug, Deserialize)] +struct PublicCustomChartQuery { + hours: Option, +} + #[derive(Debug, serde::Serialize)] struct PublicChartPoint { timestamp: chrono::DateTime, @@ -652,6 +657,7 @@ fn zone_reading_points(rows: Vec, field: &str) -> Vec, Path(token): Path, + Query(query): Query, ) -> Result, AppError> { if token.len() < 32 || token.len() > 128 || !token.starts_with("chart_") { return Err(AppError::NotFound("custom chart".into())); @@ -663,7 +669,7 @@ async fn public_custom_chart( let share: PublicCustomChartShare = serde_json::from_value(payload)?; validate_public_chart_spec(&share.series)?; - let hours = share.hours.clamp(1, 24 * 3650); + let hours = query.hours.unwrap_or(share.hours).clamp(1, 24 * 3650); let lang = if share.lang == "pl" { "pl" } else { "en" }; let since = Utc::now() - ChronoDuration::hours(hours); let bucket_seconds = history_bucket_seconds(hours); diff --git a/web/custom-chart.html b/web/custom-chart.html index 9a4b093..401bc87 100644 --- a/web/custom-chart.html +++ b/web/custom-chart.html @@ -12,12 +12,23 @@
-
-
-
+
+
+

Custom chart

Loading…

+
diff --git a/web/custom-chart.js b/web/custom-chart.js index 46c5bf0..6fb6897 100644 --- a/web/custom-chart.js +++ b/web/custom-chart.js @@ -3,6 +3,7 @@ const PUBLIC_CHART_COLORS = ['--accent', '--info', '--warning', '--purple', '--danger', '--teal', '--orange', '--blue']; const $ = selector => document.querySelector(selector); const clamp = (value, min, max) => Math.min(max, Math.max(min, value)); +const PUBLIC_CHART_RANGES = [6, 24, 168, 720, 2160, 8760]; function basePathFromScript() { const src = document.currentScript?.src || ''; @@ -41,7 +42,7 @@ function preciseTime(timestamp, locale) { function prepareCanvas(canvas, height = 520) { const wrap = canvas.parentElement; const width = Math.max(720, Math.floor(wrap?.clientWidth || canvas.getBoundingClientRect().width || 720)); - const actualHeight = Math.max(320, Math.floor(wrap?.clientHeight || height)); + const actualHeight = Math.max(180, Math.floor(wrap?.clientHeight || height)); const dpr = window.devicePixelRatio || 1; canvas.width = Math.floor(width * dpr); canvas.height = Math.floor(actualHeight * dpr); @@ -194,12 +195,64 @@ function drawChart(canvas, payload, locale) { bindTooltip(canvas, series, { pad, width, height, firstTs, lastTs }, locale); } -async function loadPublicChart() { - const token = decodeURIComponent(location.pathname.split('/').filter(Boolean).pop() || ''); +let publicChartPayload = null; +let publicChartLocale = 'en-GB'; +let publicChartResizeFrame = 0; + +function publicChartToken() { + return decodeURIComponent(location.pathname.split('/').filter(Boolean).pop() || ''); +} + +function requestedPublicChartHours() { + const value = Number(new URLSearchParams(location.search).get('hours')); + return Number.isInteger(value) && value >= 1 && value <= 87600 ? value : null; +} + +function setPublicRangeLanguage(lang) { + const pl = lang === 'pl'; + const label = $('#publicChartRangeLabel'); + const select = $('#publicChartHours'); + if (label) label.textContent = pl ? 'Zakres' : 'Range'; + if (!select) return; + const labels = pl + ? ['6 godzin', '24 godziny', '7 dni', '30 dni', '90 dni', '1 rok'] + : ['6 hours', '24 hours', '7 days', '30 days', '90 days', '1 year']; + [...select.options].forEach((option, index) => { if (labels[index]) option.textContent = labels[index]; }); + select.setAttribute('aria-label', pl ? 'Zakres wykresu' : 'Chart range'); +} + +function syncPublicRangeControl(hours) { + const select = $('#publicChartHours'); + if (!select) return; + const value = String(hours); + if (![...select.options].some(option => option.value === value)) { + const option = document.createElement('option'); + option.value = value; + option.textContent = `${value} h`; + select.append(option); + } + select.value = value; +} + +function publicChartApiPath(token, hours) { + const value = Number(hours); + const hasHours = hours !== null && hours !== undefined && Number.isInteger(value) && value >= 1 && value <= 87600; + const query = hasHours ? `?hours=${encodeURIComponent(String(value))}` : ''; + return `/api/public/charts/custom/${encodeURIComponent(token)}${query}`; +} + +function redrawPublicChart() { + if (!publicChartPayload) return; + drawChart($('#publicCustomChart'), publicChartPayload, publicChartLocale); +} + +async function loadPublicChart(hours = requestedPublicChartHours()) { + const token = publicChartToken(); const title = $('#publicChartTitle'); const hint = $('#publicChartHint'); const error = $('#publicChartError'); const canvas = $('#publicCustomChart'); + const range = $('#publicChartHours'); if (!token.startsWith('chart_')) { title.textContent = 'Custom chart'; @@ -210,7 +263,9 @@ async function loadPublicChart() { return; } - const response = await fetch(withBase(`/api/public/charts/custom/${encodeURIComponent(token)}`), { headers: { Accept: 'application/json' }, cache: 'no-store' }); + if (range) range.disabled = true; + error.hidden = true; + const response = await fetch(withBase(publicChartApiPath(token, hours)), { headers: { Accept: 'application/json' }, cache: 'no-store' }); if (!response.ok) { let message = `${response.status}`; try { message = (await response.json()).error || message; } catch (_) { } @@ -223,14 +278,40 @@ async function loadPublicChart() { title.textContent = payload.title || (lang === 'pl' ? 'Wykres niestandardowy' : 'Custom chart'); hint.textContent = payload.hint || ''; canvas.setAttribute('aria-label', title.textContent); + setPublicRangeLanguage(lang); + syncPublicRangeControl(payload.hours); + publicChartPayload = payload; + publicChartLocale = locale; drawChart(canvas, payload, locale); - window.addEventListener('resize', () => drawChart(canvas, payload, locale)); + if (range) range.disabled = false; } +$('#publicChartHours')?.addEventListener('change', async event => { + const hours = Number(event.currentTarget.value); + if (!Number.isInteger(hours) || hours < 1 || hours > 87600) return; + const url = new URL(location.href); + url.searchParams.set('hours', String(hours)); + history.replaceState(null, '', url); + try { + await loadPublicChart(hours); + } catch (error) { + const host = $('#publicChartError'); + host.hidden = false; + host.textContent = `${document.documentElement.lang === 'pl' ? 'Nie udało się wczytać wykresu' : 'Unable to load chart'}: ${error.message}`; + event.currentTarget.disabled = false; + } +}); + +window.addEventListener('resize', () => { + cancelAnimationFrame(publicChartResizeFrame); + publicChartResizeFrame = requestAnimationFrame(redrawPublicChart); +}); + loadPublicChart().catch(error => { const host = $('#publicChartError'); host.hidden = false; host.textContent = `Unable to load chart: ${error.message}`; $('#publicChartHint').textContent = ''; + $('#publicChartHours').disabled = false; drawEmpty($('#publicCustomChart'), host.textContent); }); diff --git a/web/index.html b/web/index.html index ee10c5a..47b300e 100644 --- a/web/index.html +++ b/web/index.html @@ -189,7 +189,7 @@ data-i18n="flow.import">Import Flow
-
-