v0.9.5
This commit is contained in:
Generated
+1
-1
@@ -633,7 +633,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gree-controller"
|
||||
version = "0.9.4"
|
||||
version = "0.9.5"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "gree-controller"
|
||||
version = "0.9.4"
|
||||
version = "0.9.5"
|
||||
edition = "2021"
|
||||
authors = ["GREE Controller contributors"]
|
||||
description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support"
|
||||
|
||||
+40
-35
@@ -1,13 +1,12 @@
|
||||
d67af429e4da9ce08e9d2f2a8472849ffbd70d135b1c5da535a076026794d04c ./.env.example
|
||||
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
|
||||
5330f2eb75251cee43aa853448290bccd0e0d95f89aa1d23bde498eb86e99699 ./build.rs
|
||||
37ba4d5222b221d9a3d560246d968092fa4402288410eaba7e6bab87ebcc5aea ./Cargo.lock
|
||||
a0976abed3b84a5ba0c726410c87d31017d42098fb7e053af986869ea0c9db74 ./Cargo.toml
|
||||
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
||||
a6391cc7fc014d06205c3fac708e0316e7239eaca47e0a2cb05a18275c58f192 ./README.md
|
||||
ec0f495ee6a618bdec10b260ee7838f7a872d8c5b0aa91c546226c1ad818f601 ./build.rs
|
||||
bfa6891d9abc7ac013773e5c7533325981c6887a87af725001a80611bc02e3ea ./data/gree-controller.db
|
||||
e7f085a9b4bd75dd62609e3c9f62bdde532f5cb0675fda2cf5109e57fafef2d2 ./docs/API.md
|
||||
a0893b2a56eb1523f1a72871842e9be2139a5fafba1f51ae942fc407a6e4ca34 ./home-assistant/README.md
|
||||
f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./home-assistant/custom_components/gree_controller/__init__.py
|
||||
d67af429e4da9ce08e9d2f2a8472849ffbd70d135b1c5da535a076026794d04c ./.env
|
||||
d67af429e4da9ce08e9d2f2a8472849ffbd70d135b1c5da535a076026794d04c ./.env.example
|
||||
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
|
||||
ad08bba75bbc38d4c48cecef9ee05a19320d9a6a20b6cc950fdbb8115da573f2 ./gree-controller.zip
|
||||
6910589f27960a28d4de9735884a7e5376e455cd885f19ce2b55947fcd135114 ./home-assistant/custom_components/gree_controller/api.py
|
||||
71c8058f85fd9ce9f063b7a84dcf2956f23cdbbd02bd4bd99d2fbb9d177c72ad ./home-assistant/custom_components/gree_controller/climate.py
|
||||
5e4aef2143e81bedb5a15dd4be5c71b64a3ab448ec6d33a20851edd098e5f529 ./home-assistant/custom_components/gree_controller/config_flow.py
|
||||
@@ -15,6 +14,7 @@ b7f0873109c52be9d7f09bea3dffc416103c50085e1f0680d11661a969479898 ./home-assista
|
||||
ab08fbe40e9bb48ebcbfff98760aaa0c9434b61b705aaaadea0c09c255d99b0e ./home-assistant/custom_components/gree_controller/coordinator.py
|
||||
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./home-assistant/custom_components/gree_controller/entity_map.py
|
||||
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./home-assistant/custom_components/gree_controller/icon.png
|
||||
f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./home-assistant/custom_components/gree_controller/__init__.py
|
||||
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./home-assistant/custom_components/gree_controller/logo.png
|
||||
f30f751b4e561e51a3ff9bf9c8384bc2d160dd157b954dd7061d5844ee410b77 ./home-assistant/custom_components/gree_controller/manifest.json
|
||||
38d659d0273c0d1428679e44574a2666c605d1b3796d323b626baa40560788cf ./home-assistant/custom_components/gree_controller/number.py
|
||||
@@ -24,22 +24,26 @@ cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./home-assista
|
||||
6bddb7b4620021ecd2099a86a77ef5c7f2c2dcd3d07d5db4e7b4c4ce6d3e8c03 ./home-assistant/custom_components/gree_controller/translations/en.json
|
||||
13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./home-assistant/custom_components/gree_controller/translations/pl.json
|
||||
4513070521d3dda0efb0d974a86ba674494cfb2b66fe9e5cac5b1b0430dede97 ./home-assistant/generated/gree_controller_entities.example.json
|
||||
253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md
|
||||
a0893b2a56eb1523f1a72871842e9be2139a5fafba1f51ae942fc407a6e4ca34 ./home-assistant/README.md
|
||||
a3e5842856e956044aefe840eb14fa36f98ae31d5613a7ac9f546df96c6c2366 ./lang/en.json
|
||||
1baff114849223295ecf91251f525ec7e88f8261adcfa0462fa69ec01fe54517 ./lang/pl.json
|
||||
253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md
|
||||
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
||||
d8459024f04ca514bd8e9d6bd3af872fb942fd85a7cdd5583f4a9d28aab6faba ./make_zip.py
|
||||
bb89bac237e750e9b1bf73761d7df97a6b81853091615878c03f13d7b6399aa7 ./scripts/README.md
|
||||
a6391cc7fc014d06205c3fac708e0316e7239eaca47e0a2cb05a18275c58f192 ./README.md
|
||||
5bc736c7bc76ca80aaa406bb171d2aa91baf4c3aa8695dce0e09b888b6ab3146 ./scripts/common.sh
|
||||
6403786610ee6d2f628193c25aee0dd058d62e904aa1a31d5f62fdaae0e94b4f ./scripts/configure-gree-network.sh
|
||||
dbb92ddc27b8724faf709983e4feecd3f188052b2cba39daba96d4bc16914df5 ./scripts/dev.sh
|
||||
a0cc9f6c6fa7322c48b227b1e28521ac3abd3fde91d9931a2607f18d6adcd783 ./scripts/FILE_MANIFEST.sha256
|
||||
14076104c042fba1284ebb07531a6c3ff972df1f9f5b18f70da18ab774efed27 ./scripts/generate_ha_migration.py
|
||||
e4849261fd9ed1f01df96c0637c439c0c4eff8fa317b2918026167bba343af79 ./scripts/install-lxc.sh
|
||||
bb7cd2c5b27c9dceec1d1d2846fbad9600df9c08e0ad07d13fcde97af533091c ./scripts/install.sh
|
||||
e00d211e3885e30d7fed1e43b44e6fdad40a67019060156c0641816a93e3365f ./scripts/network-debug.sh
|
||||
bb89bac237e750e9b1bf73761d7df97a6b81853091615878c03f13d7b6399aa7 ./scripts/README.md
|
||||
01952aa92b217f8eae2493b88870e2dec595100cd15c4d561ff11ae2b936c46f ./scripts/regenerate-sha.sh
|
||||
81345b6a0b51736bdbc98fd23199b62e4c721b4e7437e02dab7ea79b97dff29a ./scripts/service.sh
|
||||
b48fc84d79aab381226363ac8473f981bcba5e4911c4cc0011261182debf4250 ./scripts/smoke.sh
|
||||
b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/update.sh
|
||||
4c8b0d10d83d6130ed6e2703c233ac380b25a6c57fc23a29821f823df90331f9 ./src/api.rs
|
||||
50b653f5ae1c9d24eb2e158fb4af713f5ccabe259c83053fa3cd2a310c7780da ./src/api/assets.rs
|
||||
6c34b1294d76b0eba4c56bfd0bf69bdd502de0e40838104f6ddf2db4e922683d ./src/api/auth.rs
|
||||
08a732a445f44d34c644109762ac389b58c96d0fe47b309ce34f4479d67c3712 ./src/api/automations.rs
|
||||
@@ -52,23 +56,23 @@ a13d4e217fe3ddaa73873ba6e0d1bc93750cf61764d867ff7372274ed21d9599 ./src/api/hist
|
||||
0d7d598f7ed24315ed0547a60a72a06f20ebcf926489e1c454986f42d22cc305 ./src/api/integrations.rs
|
||||
bb2a746ecdcc2da5fe54e18b455c7bd19453486dd5c008e71951a2c81d0e7d64 ./src/api/middleware.rs
|
||||
2b3feefbafc1f813c00dfe20db147aa1f5067ec5b8455f041ac3793802911be3 ./src/api/public_settings.rs
|
||||
4c8b0d10d83d6130ed6e2703c233ac380b25a6c57fc23a29821f823df90331f9 ./src/api.rs
|
||||
8f7f0b8c157e9c97d7dc305b79923646ef47d76497abfcf09e9c67bb12af5dd1 ./src/api/schedules.rs
|
||||
4ffab50d931ca46dc5708914b6b54256d639cc11ad1b4281f649c310db5d41a0 ./src/api/settings.rs
|
||||
74c156717b37e83d329f7c52ac622e02f690621544c4eb07c4502194db55e6e9 ./src/api/system.rs
|
||||
681cccb8d09f4ad9c2e6467a4dbe2f9d991125775a5d2bfc9043daf940fecd29 ./src/api/websocket.rs
|
||||
923e7434e8f5789150eb34ffc4d18d25fa701f4a9040bf856d7926016f1936aa ./src/api/zones.rs
|
||||
2b6eecead75cd4cdb98a9f74dd1c374dbf11ebfa716abbc3476aa12398af9acd ./src/config.rs
|
||||
369455b5ffb125f1a80b767f62fd8c84a953adb69548dbd8adb653a6fbaaa45b ./src/db.rs
|
||||
24580b279cfcd5388ba584eaba2c9bb729b8aae81e77b781c23fb804c5b5fa5d ./src/db/climate.rs
|
||||
3de3fa4262be00029dde2344c4cfa41acd4acc0adec176f344761ff35ea730b6 ./src/db/configuration.rs
|
||||
56b0efe84dbf6bd3ee2397b099220a68966311c187f4d5b53007a1693a5ef327 ./src/db/core_devices.rs
|
||||
d8a2b323e864f2ec38ee15e3023be37a6aa05387f1ddbeedafe1f51556ad8c7d ./src/db/device_history.rs
|
||||
f3bd91d0bdb7699f319b9341d928d3cc3b25f759653fcd2095a5c5f695d08fac ./src/db/events_tokens.rs
|
||||
59912e70b688daf5c4d22679d643ed3b724c262d62466aeaa9ef74db87808178 ./src/db/ha_history.rs
|
||||
369455b5ffb125f1a80b767f62fd8c84a953adb69548dbd8adb653a6fbaaa45b ./src/db.rs
|
||||
7e2fbce70f40aef360534ba38c6700163db77cb7288b3bf58728fce72a126435 ./src/db/schedules_automations.rs
|
||||
35cbb521a8ec456756496b8aee71f9dfebad528a2cf2653ba8b48f6035be0c01 ./src/db/tests.rs
|
||||
a384ea4042d1d11692b5f8693df1f54850dcc4e80726780b44b2b096bf667b78 ./src/db/zone_history.rs
|
||||
952ea5906d39ef917ad71edc345f76b29c07c63079644fd5699b12aa254cb35f ./src/engine.rs
|
||||
384f7027ca48bd4c4048320bc6d4cacd631bee40e8630ea22e0d6e5f22ddc3a6 ./src/engine/automations.rs
|
||||
77931af524e9402fc826050b5fcec422d01b02b625c8ce7f2004f1f6520c9b4d ./src/engine/commands.rs
|
||||
e16c1a65057f6fbf11bb6f27493ed975f5c89309b31dec0fa3248b9237494ed3 ./src/engine/control_plan.rs
|
||||
@@ -78,6 +82,7 @@ d15148382f0c84bdef36750a10b463378e2de6a0fb70eecadeee2b07b8648681 ./src/engine/g
|
||||
4972c199274647bff47122c367e51bae8dab24d7ec4d652288e227a5a64c2310 ./src/engine/local_thermostat.rs
|
||||
ecab67072e756f5a371864282eb470a17de53016593e2e96540674066262c865 ./src/engine/ownership.rs
|
||||
9c37adf514c96840fd6a5c715c579350fa86d6dcc0655a2aa97d1fd7c7e04299 ./src/engine/polling.rs
|
||||
952ea5906d39ef917ad71edc345f76b29c07c63079644fd5699b12aa254cb35f ./src/engine.rs
|
||||
3d48608a065aa52a1fd8b9c59356a74d8216ecee3d47f8ff8ef7d3d47170c617 ./src/engine/runtime.rs
|
||||
ffa72b93502eece187a96adb4ec94aec6048d4a6dc7af66e7c7af0931318787f ./src/engine/schedules.rs
|
||||
7742046c0067c7cd5a74e2b81f8a8bdef9b76fcacf9b4af0b7eede1b050b9036 ./src/engine/targets.rs
|
||||
@@ -88,24 +93,23 @@ ebf8b9ec5c5a84850d8cad4c4faea090e52625b5a0be56625dc84060ecb35186 ./src/engine/z
|
||||
d2c2f3678bd13ec2d92404993173a691803da215dbdb1edafcd96e1963c7004e ./src/engine/zone_control.rs
|
||||
4b271b6fc365b1078c01d6178eb563841b2ecaed5d8639196f58e1312d2236fe ./src/error.rs
|
||||
c6ff66da9ad08506f839ec56a869ead3abc824b5311e0ea9244517d11f7f4207 ./src/home_assistant.rs
|
||||
6f9ef85cd53ba030b477bc3c186f0f7e762674124210eabcb0686f2806eaada1 ./src/influxdb.rs
|
||||
feb50ecd60b9a9fe9de1f7d8e1e26caab5435d59347468f6266a318f431bc3d3 ./src/influxdb/codec.rs
|
||||
553b44ec0321e62480059bc2451fd34ec7aabe9fc87fc717daba0c4b55679d53 ./src/influxdb/query.rs
|
||||
6f9ef85cd53ba030b477bc3c186f0f7e762674124210eabcb0686f2806eaada1 ./src/influxdb.rs
|
||||
5e4d94f8a010df05bae9acab72c518080d2dba94d054df95b87e492305357222 ./src/influxdb/write.rs
|
||||
ef8ad176eb2ee6ceb02bbf3d63b65460013475908fced05388b29727af67ef7e ./src/main.rs
|
||||
e935e1fcf0d379b627df5d5055dbdad3dd55786fde7191376918b05afdde1727 ./src/models.rs
|
||||
fca124ec30b5c9286f0f44cc18e8953bb2809f5009d4d521deaebfdeb00c1bd1 ./src/models/automation.rs
|
||||
da672b06295370a36c69136e15684ab10ccb8fbdc814d76527a05e01213c2d2b ./src/models/control_plan.rs
|
||||
8228b9b6d9e8b1d13de29ce88500beacd88c8877893b7a3e41a4bd1e237ca36c ./src/models/defaults.rs
|
||||
7cdc99a6f0920baf4ac88fbe7e6f1859e8598a00f00b8c3d84f20bc3a4de35f9 ./src/models/device.rs
|
||||
cfbaa853a5185c4be572588577b313a2d618837f7c07a3860d0e8d2cca04ee60 ./src/models/history.rs
|
||||
668c9cf157679f8c9fe72846f743629c79e263b14827110834b4addbdf9d13ec ./src/models/integrations.rs
|
||||
e935e1fcf0d379b627df5d5055dbdad3dd55786fde7191376918b05afdde1727 ./src/models.rs
|
||||
268b4211df93f08423e39374ab9ffe93a7eba647c173168821736af299b36549 ./src/models/runtime.rs
|
||||
e77f8cdcb5fc0e51cdbf2527a69585a2f6f9089e159d1e45ec4a48735ab0e304 ./src/models/temporary_thermostat.rs
|
||||
5b5c80e25ae2aad1b511bd3f0a82b8fbae2440abf8c656ecb90814587d0be137 ./src/models/zone.rs
|
||||
9c735d7c475f21f2f388c21be784376f7184f0bf18af1886544ef51585a3b290 ./src/notifications.rs
|
||||
7fc31fbf8841a073a1544b8c7a6390f1a15b56087486ca0596a8418340fa232a ./src/protocol/crypto.rs
|
||||
f1f765331469f4219a551414833c19b6de413114c22fdd0468e1f417659553c9 ./src/protocol/gree.rs
|
||||
c935e441933ba8709432cc3ac33ed868043a89188d0f48ea6fbfe34b1f8936a3 ./src/protocol/gree/binding.rs
|
||||
563ded1758b135eb523f1fa0b1bf55fe5430ef55935b301fd6d79cbb980e1820 ./src/protocol/gree/commands.rs
|
||||
5d4328199e2285016fd1941e909e5c09f7cdf9fd21ab6538c1bf8bc2f4af3ba3 ./src/protocol/gree/core.rs
|
||||
@@ -113,37 +117,38 @@ c935e441933ba8709432cc3ac33ed868043a89188d0f48ea6fbfe34b1f8936a3 ./src/protocol
|
||||
97284ad37767625cfc2b82a3de5c40f6eecddabe185bd0bcea7cf9b165e017f0 ./src/protocol/gree/merge.rs
|
||||
a96061fbbcadac6c2df2e9708a48dcf819b951eb147f32c7d0d285ac5ae2491b ./src/protocol/gree/network.rs
|
||||
45d0cd0ea40b9255bd811362547f5a667dac6bc7324074726130baf60aa41d2b ./src/protocol/gree/polling.rs
|
||||
f1f765331469f4219a551414833c19b6de413114c22fdd0468e1f417659553c9 ./src/protocol/gree.rs
|
||||
35fc903404045129e3046b7997e941b88f98ceb42485cccc872c2e4aa530c75b ./src/protocol/gree/tests.rs
|
||||
55c2d615e76c9e4b08c4067ea734e81d81915144e637f3b51c19bea4fc879137 ./src/protocol/gree/transport.rs
|
||||
a910bd9432a393740c0f6fab52bfcb551f0ea756718d66d290fd2610767cf07c ./src/protocol/mod.rs
|
||||
830621fa75265da7288b8135704c0ce27e0687f87d55abf3cdbe40a6e2f3d2b1 ./src/queries.rs
|
||||
7fac65a9dcbcecee09816f5447c7792dc94f736b1efb66ac85629db75f6280be ./src/queries/device_history.rs
|
||||
cd5d0befe9f51a7067201a6eaa8d8ed72182d359e42cbdc67c80aa12d722654b ./src/queries/entities.rs
|
||||
2c5fba462b72158b04dbaaa53c8536263f8d72a1338a6c4ff06cb28a36f6ae27 ./src/queries/ha_history.rs
|
||||
2b46a8cdc5efb5f930dd8ff7b9f6c0e720cbca096a51d9ae047711dd280fa3b8 ./src/queries/maintenance.rs
|
||||
830621fa75265da7288b8135704c0ce27e0687f87d55abf3cdbe40a6e2f3d2b1 ./src/queries.rs
|
||||
f688db6f440ee7b0129ccc22838de0ee0e0cf2b6376173b05f853ca2555c2c1e ./src/queries/schema.rs
|
||||
f13f1be3d5789539eba3fc1b59c14835f8c681eca7634e118fa3763a53aeee2b ./src/queries/zone_history.rs
|
||||
6ee23fcaa62231d15006db078d4f763d1b67d2365fcc2d736d8a7da8df5ea382 ./src/state.rs
|
||||
b92a6cb158b494fe145b43c7641e65f6fafff47201d7d76edbec2cfd8b94835c ./systemd/gree-controller.service
|
||||
de66cab9b650cb448814bfeda6d216e168dd3e6f07a1a438e4a9de9acbe6b798 ./web/404.html
|
||||
544a31cb2e5374227026afd6abd0d910381f3fca1638154ebd74e3c3d96a35d1 ./web/404.html
|
||||
e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg
|
||||
44ce3d17b83c1ab505247ba050a923d5ae109a3a06209aa3d362e9d6daf1ecbf ./web/index.html
|
||||
525c7e83930cde6ea9d248220d595f52da4ade6e0f511e8b1075509635f20b32 ./web/index.html
|
||||
fbe1ff0e28708f3b4acdbd361ba28457fe127e6474f4def15125e9d195c929c0 ./web/js/bootstrap.js
|
||||
72fa280996ba331a05bdb29a1f49b4e61bdd8964953c8ce1db952156620f08fe ./web/js/charts.js
|
||||
80bcc8d2214c55c13574e146eb099cb371565e55c7c4b337b71ca57ad29f90d2 ./web/js/core.js
|
||||
83f6a5602da72ed6a307c1b4cc8cd9e4d9a8bf73e58be43af30ba19025a82ea3 ./web/js/dashboard.js
|
||||
40f2363e79e12446ec8750b56c6df063035cd9655ee89e7c536e3b1f6e71746c ./web/js/entities.js
|
||||
9a0e87911f78cd8a969f4c57ce74774f5fa829fdecd79494d9a7f9d5804f9792 ./web/js/events.js
|
||||
cac7615888fd38be3cf714dcf02380c4a41a1802ee1724f91496e7c19cbdffba ./web/js/forms.js
|
||||
dbf36223863ba882c03eccea4516ba8db7acf0c2e72c6c64490cb994f1e20f96 ./web/js/history.js
|
||||
7eaa04992ea828dc89f5eaebf674cbbfd160f53eb8d0d6ef0d4e47bd8c28c435 ./web/js/main.js
|
||||
72f2b4ef1e7de342b1d14a4b2757eb23d5a8acd6e837a0fe9fcc661dc35eeb63 ./web/js/navigation.js
|
||||
9ba3f6fa05b72aa989139b2a909982571b2a02055052e4c40104f1e81a9aa7eb ./web/js/README.md
|
||||
b3d5cb473bf9771de78e14c7de730cb86c73f8cdbb6344da67ba7d6abac879ea ./web/js/bootstrap.js
|
||||
64a43e2142a69ebddf4160c0d0d3b573fa379c650431090fd15c9ba3b62bc4e7 ./web/js/charts.js
|
||||
f3d2a8725f891266c725e3c67557de1f7305db00454ed4147a5c26a32cda31ff ./web/js/core.js
|
||||
9767d5f2bd2844245245c0bd86dddd528975c1d1dd1d05b1449feda7a95214c4 ./web/js/dashboard.js
|
||||
d0233628681160eb0c3d559887e48f0799b6ad0130bc943d0bea3e409ac05bf9 ./web/js/entities.js
|
||||
69a052771dfafbd4b778cbc9d1b7a7695427621ed66047282088a3a07e6e4c2e ./web/js/events.js
|
||||
2fe6c804f86b0613a50a56c54f7a0cbee77273759edf3e6fec36ac77d35edbd7 ./web/js/forms.js
|
||||
be07a341ba4b1f514a5e13553494194b22aa87108cb04de40635a0158921780b ./web/js/history.js
|
||||
9aa199a9ca8d1109cc06d7a7d69f5c5ed45c53f488128ca520258e9c91c31352 ./web/js/main.js
|
||||
e27d5bb4a1579fd5b1d9762a5067b953004ca8ae63506af4e8c2cad754c0c532 ./web/js/navigation.js
|
||||
40446c6bbfa21b645732bb56d7d8a1dd2d7e940b84fc882670d3a3607d127a55 ./web/js/realtime.js
|
||||
45a666dbc1cddcc0ece507130cde7719f6232c710b4288d6a16e1232791f2a3d ./web/js/router.js
|
||||
f9d23d7142ebcd77085ad30b8b5bf927b754b51f10976309d5b0a3f22f3cfafb ./web/js/settings-ui.js
|
||||
a189f4f7cc253087ac271b3c5b7a82751176032fc0f7040f073cdc451d354e06 ./web/js/settings.js
|
||||
fd26156e9f1d6713d3def564ad000553d9a16a24376059701db2ee762c99ee6c ./web/manifest.webmanifest
|
||||
a447e27f1c6f5cd126e4ea08781603afaca0877c495bc38095e192618efbd942 ./web/styles.css
|
||||
bc95830ec8273818ffde0a6b50eb3cc9ecbeee65a7a1d3aeff08cde86d05dc7b ./web/sw.js
|
||||
262208c2487399ebbc94747c4d71267b01b5c4ac5bb20c682fc926840e048828 ./web/js/realtime.js
|
||||
415348a93ac3423c491d5b222035a5ccd073eae9dc82e9c0560829afb6e02767 ./web/js/router.js
|
||||
4a05126dc95c291ede08452b179d77791e270ed0c9ab9806036934ccf7e0f704 ./web/js/settings.js
|
||||
b3e796778d6eee59d663f198115d0c2a45497fdfc23a88ff4b85893ba079d586 ./web/js/settings-ui.js
|
||||
6b653e4fe2d4db4ffae6ff8f39b8ce57a10a990dc0000ee4aae51d949afadd52 ./web/manifest.webmanifest
|
||||
d2e533ca1a445036327095647d15eef89eb810295f4222cf7284ac31ee6b5e10 ./web/styles.css
|
||||
ae1b03f30b494f474a781a5d32072f1e73eba2b7c768109fc1cc8028cb6662a4 ./web/sw.js
|
||||
d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
use serde_json::{json, Value};
|
||||
use std::{env, fs, path::{Path, PathBuf}};
|
||||
use std::{
|
||||
env, fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
fn required_string<'a>(meta: &'a Value, key: &str, file: &str) -> &'a str {
|
||||
meta.get(key)
|
||||
@@ -8,7 +11,6 @@ fn required_string<'a>(meta: &'a Value, key: &str, file: &str) -> &'a str {
|
||||
.unwrap_or_else(|| panic!("{file}: meta.{key} must be a non-empty string"))
|
||||
}
|
||||
|
||||
|
||||
fn fnv1a_update(mut hash: u64, bytes: &[u8]) -> u64 {
|
||||
for byte in bytes {
|
||||
hash ^= u64::from(*byte);
|
||||
@@ -69,14 +71,24 @@ fn main() {
|
||||
let sw_path = web_dir.join("sw.js");
|
||||
let manifest_path = web_dir.join("manifest.webmanifest");
|
||||
let favicon_path = web_dir.join("favicon.svg");
|
||||
for path in [&theme_init_path, &styles_path, &index_path, ¬_found_path, &sw_path, &manifest_path, &favicon_path] {
|
||||
for path in [
|
||||
&theme_init_path,
|
||||
&styles_path,
|
||||
&index_path,
|
||||
¬_found_path,
|
||||
&sw_path,
|
||||
&manifest_path,
|
||||
&favicon_path,
|
||||
] {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
}
|
||||
|
||||
let app_js = bundle_app_js(&web_dir);
|
||||
let app_js_hash = content_hash(app_js.as_bytes());
|
||||
let theme_init_bytes = fs::read(&theme_init_path).unwrap_or_else(|error| panic!("cannot read {}: {error}", theme_init_path.display()));
|
||||
let styles_bytes = fs::read(&styles_path).unwrap_or_else(|error| panic!("cannot read {}: {error}", styles_path.display()));
|
||||
let theme_init_bytes = fs::read(&theme_init_path)
|
||||
.unwrap_or_else(|error| panic!("cannot read {}: {error}", theme_init_path.display()));
|
||||
let styles_bytes = fs::read(&styles_path)
|
||||
.unwrap_or_else(|error| panic!("cannot read {}: {error}", styles_path.display()));
|
||||
let theme_init_hash = content_hash(&theme_init_bytes);
|
||||
let styles_hash = content_hash(&styles_bytes);
|
||||
let app_js_asset_path = format!("/app-{}.js", &app_js_hash[..12]);
|
||||
@@ -84,8 +96,17 @@ fn main() {
|
||||
let styles_asset_path = format!("/styles-{}.css", &styles_hash[..12]);
|
||||
|
||||
let mut build_hash = fnv1a_update(0xcbf29ce484222325u64, app_js.as_bytes());
|
||||
for path in [&theme_init_path, &styles_path, &index_path, ¬_found_path, &sw_path, &manifest_path, &favicon_path] {
|
||||
let bytes = fs::read(path).unwrap_or_else(|error| panic!("cannot read {}: {error}", path.display()));
|
||||
for path in [
|
||||
&theme_init_path,
|
||||
&styles_path,
|
||||
&index_path,
|
||||
¬_found_path,
|
||||
&sw_path,
|
||||
&manifest_path,
|
||||
&favicon_path,
|
||||
] {
|
||||
let bytes = fs::read(path)
|
||||
.unwrap_or_else(|error| panic!("cannot read {}: {error}", path.display()));
|
||||
build_hash = fnv1a_update(build_hash, &bytes);
|
||||
}
|
||||
|
||||
@@ -107,9 +128,18 @@ fn main() {
|
||||
|
||||
for path in files {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
let filename = path.file_name().and_then(|v| v.to_str()).expect("UTF-8 language filename");
|
||||
let stem = path.file_stem().and_then(|v| v.to_str()).expect("UTF-8 language code");
|
||||
if !stem.chars().all(|ch| ch.is_ascii_alphanumeric() || ch == '-' || ch == '_') {
|
||||
let filename = path
|
||||
.file_name()
|
||||
.and_then(|v| v.to_str())
|
||||
.expect("UTF-8 language filename");
|
||||
let stem = path
|
||||
.file_stem()
|
||||
.and_then(|v| v.to_str())
|
||||
.expect("UTF-8 language code");
|
||||
if !stem
|
||||
.chars()
|
||||
.all(|ch| ch.is_ascii_alphanumeric() || ch == '-' || ch == '_')
|
||||
{
|
||||
panic!("{filename}: filename may only contain ASCII letters, digits, '-' and '_'");
|
||||
}
|
||||
|
||||
@@ -118,15 +148,20 @@ fn main() {
|
||||
build_hash = fnv1a_update(build_hash, source.as_bytes());
|
||||
let document: Value = serde_json::from_str(&source)
|
||||
.unwrap_or_else(|error| panic!("{filename}: invalid JSON: {error}"));
|
||||
let root_object = document.as_object().unwrap_or_else(|| panic!("{filename}: language pack root must be an object"));
|
||||
let unexpected: Vec<&str> = root_object.keys()
|
||||
let root_object = document
|
||||
.as_object()
|
||||
.unwrap_or_else(|| panic!("{filename}: language pack root must be an object"));
|
||||
let unexpected: Vec<&str> = root_object
|
||||
.keys()
|
||||
.filter(|key| key.as_str() != "meta" && key.as_str() != "translations")
|
||||
.map(|key| key.as_str())
|
||||
.collect();
|
||||
if !unexpected.is_empty() {
|
||||
panic!("{filename}: unexpected top-level keys {:?}; translation keys must be inside 'translations'", unexpected);
|
||||
}
|
||||
let meta = document.get("meta").unwrap_or_else(|| panic!("{filename}: missing meta object"));
|
||||
let meta = document
|
||||
.get("meta")
|
||||
.unwrap_or_else(|| panic!("{filename}: missing meta object"));
|
||||
let code = required_string(meta, "code", filename);
|
||||
let name = required_string(meta, "name", filename);
|
||||
let native_name = required_string(meta, "native_name", filename);
|
||||
@@ -158,15 +193,31 @@ fn main() {
|
||||
let manifest_json = serde_json::to_string(&json!({
|
||||
"default": "en",
|
||||
"languages": manifest_languages
|
||||
})).expect("serialize language manifest");
|
||||
}))
|
||||
.expect("serialize language manifest");
|
||||
|
||||
let mut generated = String::new();
|
||||
generated.push_str("// @generated by build.rs - do not edit.\n");
|
||||
generated.push_str(&format!("pub const APP_JS_ASSET_PATH: &str = {:?};\n", app_js_asset_path));
|
||||
generated.push_str(&format!("pub const THEME_INIT_ASSET_PATH: &str = {:?};\n", theme_init_asset_path));
|
||||
generated.push_str(&format!("pub const STYLES_CSS_ASSET_PATH: &str = {:?};\n", styles_asset_path));
|
||||
generated.push_str(&format!("pub const ASSET_BUILD_ID: &str = \"{:016x}\";\n", build_hash));
|
||||
generated.push_str(&format!("pub const LANGUAGE_MANIFEST_JSON: &str = {:?};\n", manifest_json));
|
||||
generated.push_str(&format!(
|
||||
"pub const APP_JS_ASSET_PATH: &str = {:?};\n",
|
||||
app_js_asset_path
|
||||
));
|
||||
generated.push_str(&format!(
|
||||
"pub const THEME_INIT_ASSET_PATH: &str = {:?};\n",
|
||||
theme_init_asset_path
|
||||
));
|
||||
generated.push_str(&format!(
|
||||
"pub const STYLES_CSS_ASSET_PATH: &str = {:?};\n",
|
||||
styles_asset_path
|
||||
));
|
||||
generated.push_str(&format!(
|
||||
"pub const ASSET_BUILD_ID: &str = \"{:016x}\";\n",
|
||||
build_hash
|
||||
));
|
||||
generated.push_str(&format!(
|
||||
"pub const LANGUAGE_MANIFEST_JSON: &str = {:?};\n",
|
||||
manifest_json
|
||||
));
|
||||
generated.push_str("pub const LANGUAGE_ASSETS: &[(&str, &str)] = &[\n");
|
||||
for (code, path) in assets {
|
||||
generated.push_str(&format!(
|
||||
|
||||
Symlink
+1
@@ -0,0 +1 @@
|
||||
scripts/regenerate-sha.sh
|
||||
-100
@@ -1,100 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=common.sh
|
||||
source "$SCRIPT_DIR/common.sh"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
MODE="debug"
|
||||
ACTION="run"
|
||||
INSTALL_DEPS=1
|
||||
RESET_DB=0
|
||||
HOST=""
|
||||
PORT=""
|
||||
|
||||
usage() {
|
||||
cat <<'TXT'
|
||||
GREE Controller - development environment
|
||||
|
||||
Usage:
|
||||
./scripts/dev.sh install missing tools, build and run
|
||||
./scripts/dev.sh --release run an optimized build
|
||||
./scripts/dev.sh --check formatting, tests, build and API smoke test
|
||||
./scripts/dev.sh --reset remove the local database before startup
|
||||
./scripts/dev.sh --no-install do not install system packages or Rust
|
||||
./scripts/dev.sh --host 0.0.0.0 --port 8787
|
||||
TXT
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--release) MODE="release"; shift ;;
|
||||
--check) ACTION="check"; shift ;;
|
||||
--reset) RESET_DB=1; shift ;;
|
||||
--no-install) INSTALL_DEPS=0; shift ;;
|
||||
--host) HOST="${2:?missing value for --host}"; shift 2 ;;
|
||||
--port) PORT="${2:?missing value for --port}"; shift 2 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "Unknown argument: $1" >&2; usage; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$INSTALL_DEPS" -eq 1 ]]; then
|
||||
install_build_dependencies
|
||||
ensure_rust
|
||||
else
|
||||
command -v cargo >/dev/null 2>&1 || fail "Cargo is not installed and --no-install was requested."
|
||||
fi
|
||||
|
||||
|
||||
if [[ ! -f .env ]]; then
|
||||
cp .env.example .env
|
||||
say "Created .env from the example configuration"
|
||||
fi
|
||||
mkdir -p data
|
||||
if [[ "$RESET_DB" -eq 1 ]]; then
|
||||
rm -f data/gree-controller.db data/gree-controller.db-shm data/gree-controller.db-wal
|
||||
say "Removed the local database"
|
||||
fi
|
||||
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
source ./.env
|
||||
set +a
|
||||
|
||||
if [[ -n "$HOST" || -n "$PORT" ]]; then
|
||||
current="${GREE_CONTROLLER_BIND:-0.0.0.0:8787}"
|
||||
current_host="${current%:*}"
|
||||
current_port="${current##*:}"
|
||||
export GREE_CONTROLLER_BIND="${HOST:-$current_host}:${PORT:-$current_port}"
|
||||
fi
|
||||
|
||||
if [[ "$ACTION" == "check" ]]; then
|
||||
say "Checking formatting"
|
||||
cargo fmt --all -- --check
|
||||
say "Running Rust tests"
|
||||
cargo test --all-targets
|
||||
say "Building the application"
|
||||
cargo build
|
||||
say "Running HTTP/API smoke test"
|
||||
"$SCRIPT_DIR/smoke.sh"
|
||||
say "All checks passed"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ "$MODE" == "release" ]]; then
|
||||
say "Building release version"
|
||||
cargo build --release
|
||||
BINARY="$PROJECT_ROOT/target/release/gree-controller"
|
||||
else
|
||||
say "Building debug version"
|
||||
cargo build
|
||||
BINARY="$PROJECT_ROOT/target/debug/gree-controller"
|
||||
fi
|
||||
|
||||
bind="${GREE_CONTROLLER_BIND:-0.0.0.0:8787}"
|
||||
display_host="${bind%:*}"
|
||||
[[ "$display_host" == "0.0.0.0" ]] && display_host="127.0.0.1"
|
||||
say "Panel: http://${display_host}:${bind##*:}"
|
||||
say "Stop: Ctrl+C"
|
||||
exec "$BINARY"
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
MANIFEST="FILE_MANIFEST.sha256"
|
||||
TMP="${MANIFEST}.tmp"
|
||||
|
||||
find . -type f \
|
||||
! -path "./${MANIFEST}" \
|
||||
! -path "./${TMP}" \
|
||||
! -path "./.git/*" \
|
||||
! -path "./target/*" \
|
||||
-print0 \
|
||||
| sort -z \
|
||||
| xargs -0 sha256sum > "$TMP"
|
||||
|
||||
mv "$TMP" "$MANIFEST"
|
||||
|
||||
sha256sum -c "$MANIFEST"
|
||||
@@ -1,5 +1,6 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
||||
@@ -10,6 +11,7 @@
|
||||
<script src="__GREE_THEME_INIT_ASSET__"></script>
|
||||
<title>Page not found · GREE Controller</title>
|
||||
</head>
|
||||
|
||||
<body class="error-page">
|
||||
<header class="topbar error-topbar">
|
||||
<div class="brand">
|
||||
@@ -29,4 +31,5 @@
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
+798
-237
File diff suppressed because it is too large
Load Diff
@@ -263,8 +263,6 @@ function renderLanguageOptions() {
|
||||
|
||||
async function loadLanguages() {
|
||||
try {
|
||||
// Language packs must never come from a stale Service Worker/browser cache.
|
||||
// A cache-busting nonce is intentional: translations can change without the JS asset hash changing.
|
||||
const languageNonce = Date.now().toString(36);
|
||||
const languageUrl = path => {
|
||||
const separator = String(path).includes('?') ? '&' : '?';
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ function renderHouseClimate() {
|
||||
const preset = zonePresets.length && zonePresets.every(value => value === zonePresets[0]) ? zonePresets[0] : null;
|
||||
const outdoor = app.outdoorTemperature == null ? tr('common.unavailable') : fmtTemp(app.outdoorTemperature);
|
||||
const powerOn = $('#housePowerOn'), powerOff = $('#housePowerOff');
|
||||
// Global power buttons are bulk thermostat actions, not a persistent master gate.
|
||||
|
||||
if (powerOn) { powerOn.classList.remove('active'); powerOn.removeAttribute('aria-pressed'); }
|
||||
if (powerOff) { powerOff.classList.remove('active'); powerOff.removeAttribute('aria-pressed'); }
|
||||
node.innerHTML = `<div class="house-climate-head"><div><span class="eyebrow">${esc(tr('house.seasonMode'))}</span><h3>${esc(tr('house.smartThermostat'))}</h3><p>${esc(tr('house.setpointStrategy'))}</p></div><div class="outside-pill"><small>${esc(tr('house.outdoor'))}</small><strong>${esc(outdoor)}</strong></div></div>
|
||||
|
||||
+2
-4
@@ -241,8 +241,6 @@ function zoneCard(zone, detailed = true) {
|
||||
const mode = zone.inherit_house_mode ? 'house' : zone.mode;
|
||||
const effectiveMode = zone.effective_mode || (zone.inherit_house_mode ? (app.settings?.house_mode || 'off') : zone.mode) || 'off';
|
||||
const idleWithoutTarget = effectiveMode === 'off' && zone.effective_setpoint == null && zone.manual_setpoint == null && zone.manual_preset == null;
|
||||
// OFF means "no active demand", not "forget the thermostat setting". Keep the last
|
||||
// backend-persisted setpoint visible so Group/Global OFF does not blank the temperature UI.
|
||||
const target = Number(zone.manual_setpoint ?? zone.effective_setpoint ?? zone.setpoint);
|
||||
const displayPreset = idleWithoutTarget ? 'auto' : (zone.manual_preset || zone.active_preset || 'comfort');
|
||||
const globalModeAvailable = ['heat', 'cool'].includes(app.settings?.house_mode);
|
||||
@@ -287,8 +285,8 @@ function zoneCard(zone, detailed = true) {
|
||||
const localRequestedOn = localThermostatPower === true ? true : (localThermostatPower === false ? false : !!device?.power);
|
||||
const localThermostatPowerControl = `<button type="button" class="zone-unit-power-toggle ${localRequestedOn ? 'active' : ''}" title="${esc(tr('zones.unitPowerLocalHint'))}" data-action="zone-device-power" data-id="${esc(zone.id)}" data-value="${localRequestedOn ? 'false' : 'true'}" aria-pressed="${localRequestedOn ? 'true' : 'false'}"${localPowerDisabled}><span aria-hidden="true">⏻</span><b>${esc(tr(localRequestedOn ? 'common.on' : 'common.off'))}</b></button>`;
|
||||
const temporaryThermostatControl = temporarySession
|
||||
? `<button type="button" class="temporary-thermostat-toggle active ${temporaryStatus?.pending ? 'scheduled' : ''}" data-action="zone-open-temporary" data-id="${esc(zone.id)}" title="${esc(temporaryStatus?.detail || tr('zones.temporaryActive'))}"><span aria-hidden="true">⏱</span><b data-temporary-countdown-zone="${esc(zone.id)}">${esc(temporaryStatus?.countdown || '—')}</b></button>`
|
||||
: `<button type="button" class="temporary-thermostat-toggle" data-action="zone-open-temporary" data-id="${esc(zone.id)}" title="${esc(tr('zones.temporaryStartHint'))}"${localPowerDisabled}><span aria-hidden="true">⏱</span><b>${esc(tr('zones.temporaryShort'))}</b></button>`;
|
||||
? `<button type="button" class="temporary-thermostat-toggle active ${temporaryStatus?.pending ? 'scheduled' : ''}" data-action="zone-open-temporary" data-id="${esc(zone.id)}" title="${esc(temporaryStatus?.detail || tr('zones.temporaryActive'))}"><b data-temporary-countdown-zone="${esc(zone.id)}">${esc(temporaryStatus?.countdown || '—')}</b></button>`
|
||||
: `<button type="button" class="temporary-thermostat-toggle" data-action="zone-open-temporary" data-id="${esc(zone.id)}" title="${esc(tr('zones.temporaryStartHint'))}"${localPowerDisabled}><b>${esc(tr('zones.temporaryShort'))}</b></button>`;
|
||||
|
||||
if (detailed) {
|
||||
const groupNames = (app.groups || []).filter(group => (group.zone_ids || []).includes(zone.id)).map(group => group.name);
|
||||
|
||||
@@ -373,8 +373,6 @@ function populateTemporaryThermostat(id) {
|
||||
}
|
||||
}
|
||||
|
||||
// Once ownership has started, the historical start is informational. Editing changes only
|
||||
// target/finish rules; rescheduling requires stopping the session and creating a new one.
|
||||
form.start_kind.disabled = activeSession;
|
||||
form.start_delay_minutes.disabled = activeSession;
|
||||
form.start_at.disabled = activeSession;
|
||||
|
||||
@@ -84,7 +84,6 @@ function applyRouteFromLocation() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep a canonical URL for the application root and legacy /index.html entry point.
|
||||
if (!parts.length || first === 'index.html') updateBrowserUrl(VIEW_ROUTES.dashboard, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1,17 @@
|
||||
{"name":"GREE Controller","short_name":"GREE","start_url":"./dashboard","scope":"./","display":"standalone","background_color":"#151515","theme_color":"#151515","icons":[{"src":"favicon.svg","sizes":"any","type":"image/svg+xml","purpose":"any maskable"}]}
|
||||
{
|
||||
"name": "GREE Controller",
|
||||
"short_name": "GREE",
|
||||
"start_url": "./dashboard",
|
||||
"scope": "./",
|
||||
"display": "standalone",
|
||||
"background_color": "#151515",
|
||||
"theme_color": "#151515",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.svg",
|
||||
"sizes": "any",
|
||||
"type": "image/svg+xml",
|
||||
"purpose": "any maskable"
|
||||
}
|
||||
]
|
||||
}
|
||||
+5625
-952
File diff suppressed because it is too large
Load Diff
@@ -6,8 +6,6 @@ self.addEventListener('install', event => event.waitUntil(caches.open(CACHE).the
|
||||
self.addEventListener('activate', event => event.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(key => key !== CACHE).map(key => caches.delete(key)))).then(() => self.clients.claim())));
|
||||
self.addEventListener('fetch', event => {
|
||||
const url = new URL(event.request.url);
|
||||
// API and language packs stay network-owned. Language JSON is deliberately not
|
||||
// cache-first so a newly deployed translation can never be masked by an old pack.
|
||||
if (event.request.method !== 'GET' || url.pathname.startsWith(path('/api/')) || url.pathname.startsWith(path('/lang/')) || event.request.mode === 'navigate') return;
|
||||
event.respondWith(caches.match(event.request).then(cached => cached || fetch(event.request).then(response => {
|
||||
const copy = response.clone(); caches.open(CACHE).then(cache => cache.put(event.request, copy)); return response;
|
||||
|
||||
Reference in New Issue
Block a user