v0.9.9
This commit is contained in:
Generated
+1
-1
@@ -633,7 +633,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gree-controller"
|
||||
version = "0.9.7"
|
||||
version = "0.9.9"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"aes-gcm",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "gree-controller"
|
||||
version = "0.9.7"
|
||||
version = "0.9.9"
|
||||
edition = "2021"
|
||||
authors = ["GREE Controller contributors"]
|
||||
description = "Standalone local GREE HVAC controller with Web UI, SQLite and Home Assistant sensor support"
|
||||
|
||||
+51
-14
@@ -1,12 +1,12 @@
|
||||
d67af429e4da9ce08e9d2f2a8472849ffbd70d135b1c5da535a076026794d04c ./.env.example
|
||||
a4ec3874a2e3ab1bad28fb40bb620f7b01f64d01ad9b699306bf70ada31227db ./.gitignore
|
||||
53a52a76fbcec088d3aded0f4e6c9a80f3dbce7c17a682e424fb06ba335fbb38 ./Cargo.lock
|
||||
dbeeca58fcd5786b2dfb005f1d13262e22dd4e75d6ee0ad94231132eddc145f0 ./Cargo.toml
|
||||
b0a17a6d6445239d1e307f5e685a6b87dbf7e700a6a362f9a57e713de204a802 ./Cargo.lock
|
||||
3ec8130c8c6266652fae17f214c2e57c8faf161709c2cba4d9c7da95db281031 ./Cargo.toml
|
||||
19b2943504acb8f8de280f873a8dbec4bb6ebbe3870b158f5655d4fb8c298f5f ./LICENSE
|
||||
ffab397a9ddbde4c9956aa1eeec6fe00ead649da2d8516fd0afb6ad5d3a976c2 ./README.md
|
||||
07acba9eab602e8d5b7387b16476308799ad629565fe501b18f3c1ea024a3ccf ./build.rs
|
||||
1b83a141db1d69c100f74517b2ee122d51c960fa958fe76741600d42a22d96aa ./docs/API.md
|
||||
9712c0ed25f278d442c8a09cd6477ed39e801aa6c18904572f588f5faf76f4e9 ./docs/FLOW.md
|
||||
081853b6c3874cda25374f86ba30f1a3796aeefc498bfb486f752f2741e59fc0 ./README.md
|
||||
41dfdc6d099b54f87d4dd51f696122b3c88d3bf3ddf420bea8f4bc621ba920b0 ./build.rs
|
||||
6275b530ace5c60b43036665feb5e5fd29f5bda784ec48f56d3f9969caeb70d1 ./docs/API.md
|
||||
e0642446a28e7241d5e418896850b0ecd61d272c2df74fd0bf3cd3d9addde17a ./docs/FLOW.md
|
||||
a0893b2a56eb1523f1a72871842e9be2139a5fafba1f51ae942fc407a6e4ca34 ./home-assistant/README.md
|
||||
f8e8559fe10fe523ac5bc9aac25c6e26e862f679d502e8f3c39f38a0a8e40911 ./home-assistant/custom_components/gree_controller/__init__.py
|
||||
6910589f27960a28d4de9735884a7e5376e455cd885f19ce2b55947fcd135114 ./home-assistant/custom_components/gree_controller/api.py
|
||||
@@ -17,7 +17,7 @@ ab08fbe40e9bb48ebcbfff98760aaa0c9434b61b705aaaadea0c09c255d99b0e ./home-assista
|
||||
5a96fe8f5c035c34f1339370270cd078056202d09e236dec75735be11de92a7d ./home-assistant/custom_components/gree_controller/entity_map.py
|
||||
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./home-assistant/custom_components/gree_controller/icon.png
|
||||
c4fb75c246db651087900ebfc2291ff41ac87652cd6194fc0b776b0005c1cbcf ./home-assistant/custom_components/gree_controller/logo.png
|
||||
6392b1b9178cfb1394d20575adc5219476e2fa3ee65a588e0de41effe316672b ./home-assistant/custom_components/gree_controller/manifest.json
|
||||
2302987becea57c561706fdd3f4571db4632225e11e8281b146a1fd59a3478a7 ./home-assistant/custom_components/gree_controller/manifest.json
|
||||
38d659d0273c0d1428679e44574a2666c605d1b3796d323b626baa40560788cf ./home-assistant/custom_components/gree_controller/number.py
|
||||
39c4309001b75abb56234f05662bc06e077054986876f1927937edbce528ec95 ./home-assistant/custom_components/gree_controller/select.py
|
||||
cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./home-assistant/custom_components/gree_controller/sensor.py
|
||||
@@ -26,9 +26,46 @@ cca65482e36d48035aca178121a378fe7d578d600acff267ae81a6399c0da653 ./home-assista
|
||||
13f30e2dcdcedbd1b6c3f99c2335e0487108fd72c8e86922368b84f2fa2038ae ./home-assistant/custom_components/gree_controller/translations/pl.json
|
||||
4513070521d3dda0efb0d974a86ba674494cfb2b66fe9e5cac5b1b0430dede97 ./home-assistant/generated/gree_controller_entities.example.json
|
||||
253a0bc912786e67ea7fc92a64e4a510ad973bec343a88ccfb1f28fca3e8cf01 ./lang/README.md
|
||||
a26d514b839deff2e49c352e4056a561c4af9e48626b008e0ad524cdf086fa8f ./lang/en.json
|
||||
e1a2ca5aa42158267bdf4fcbee4992eccc611e6ec3ecc5093a3567e166275fbc ./lang/pl.json
|
||||
c9f0244b7b908d57fa4b9cf32fc1a999527fcfbb469e302fd62b75743f887753 ./lang/en.json
|
||||
b7bcd0bfc806c4bf488ca9771635066ccea8503c9a41ab00e97fe07ee6aaf4e9 ./lang/pl.json
|
||||
d8459024f04ca514bd8e9d6bd3af872fb942fd85a7cdd5583f4a9d28aab6faba ./make_zip.py
|
||||
b14233a8987e53bbbdd6770386ba10fa166ec25c1e098275c173c544b37846fc ./presets/bedroom_window_night.json
|
||||
1960841119c0b673fb2f03621b32237552fd828045304cd221401214b997c910 ./presets/device_resilience.json
|
||||
c5276fecc6a33c5de912e5a73b0a829d4e18c18d57b9c0ee49179ef96f133fc7 ./presets/dual_threshold_control.json
|
||||
aa190f51cb20bd0f3749c080e39b4182d8d843db51d9bf7c2315528f67b45a7e ./presets/energy_price_eco.json
|
||||
19d001dc0703dccf9c9ba3c78d866afafae94591ddb6d0d9e2d8c7703eabeea2 ./presets/frost_guard.json
|
||||
a86718e22f79769b40b363f32ec669bf77974e6a6ade081ed4b90792d5803ef7 ./presets/ha_attribute_mode_guard.json
|
||||
cc0d35fb5ad4bd52f1a8a122745bbda19922119cec48338f391f8c0619dab896 ./presets/ha_boiler_supply_boost.json
|
||||
515b2580221fb38975c7f1ac46f267af7d8ac418efd52d30b40d5ce3e4fae1d2 ./presets/ha_external_heat_source_assist.json
|
||||
07907f47c6c5c8dbd142b161135eae123889fb8845cd846fa7d1b05eda7b0740 ./presets/ha_external_heat_source_off.json
|
||||
349df3ee451da70958529bf6c8e8c09e717a26f69fb56e9d6b73831087055966 ./presets/ha_gas_backup_heat.json
|
||||
6fddede93fcb97913139791e6a75fb62322f425c59365b48bd8bb32a48c4ddee ./presets/ha_gas_heating_boost.json
|
||||
40e6bb0a22e29cc9e32844b90eafffb753df4c368ab55b5112c5bf25593491da ./presets/ha_gas_heating_off.json
|
||||
b6dce178fb517509f31e3ce58f6fa512d038ffcea98fae10dd41844b1d954144 ./presets/ha_gas_heating_reduce.json
|
||||
eb95423754fc798b0b5db01757f0fbe97f07bae9f16a95f5ca51ce379809ab7a ./presets/ha_heating_demand_follow.json
|
||||
0e34f595cebea8662646293b75e7422ac2b01c92fe75f152d71b13f6c8fb53d1 ./presets/ha_thermostat_idle_fallback.json
|
||||
e8946176bf86975c04ef40e82565d7f7a4c171bcf8b245c001121ed8aae938c9 ./presets/ha_window_guard.json
|
||||
a87a919d73003f774becc2d48aab646c21af43e50ceb54577cd37f26606a1674 ./presets/humidity_guard.json
|
||||
e78a5a9c02bc47fa6530aad3803581b10b3a0676705cb41f9d003b4da455aa14 ./presets/mild_weather_eco.json
|
||||
c3c10990e992948c2792bb71fa6606e616abb2a5455e1f11d9209c2f05132b86 ./presets/morning_boost.json
|
||||
664afa80d27130799899e54f5a2152a27955e6e2d8c035c2a594c8da6bd902a9 ./presets/multi_room_group_guard.json
|
||||
7518e0c694208c6ff69209edf8eec605fcf9e9abe8130d092c8c89524d7a24b3 ./presets/nested_guard.json
|
||||
863e557fe9c798a5aaa175f29d71752e148bb8d49910485d738bba00671d1198 ./presets/night_group.json
|
||||
c675cf84430f3c2d058c69dbfea1b5c6fcd82e927d53a301b3e517409a324f9a ./presets/night_quiet.json
|
||||
3b87def6c5fdd7f50cd9e6003bd8e0628b1365e1de8bbc414d5a65d1d7d76298 ./presets/occupancy_weather_matrix.json
|
||||
2360e1939cb46352042bd914a1a125fc98252ea80b68c89cc6ce3f5f197cc464 ./presets/offline_safe_off.json
|
||||
0f00f10c2d11984827738cd2910aa24910acbc8f36e754627a76fd5a0aeef7eb ./presets/overheat_guard.json
|
||||
f118ab957389bc4a47fe8c36b2911fb717a23970ec97d14c37a65f65eb479fc5 ./presets/peak_power_guard.json
|
||||
dfb2f5f382a7f83b7a6fe475a26bae73a4510a46e1e7949a99ac752e39f58b4b ./presets/presence_eco.json
|
||||
8e40d01a07911455c3c6607ba3435488fd6e520bebfc84cbf5eaad481883a4ed ./presets/sensor_availability_guard.json
|
||||
45183d75ce254315cd4032acd42fbb0d505df0e7ab1fefecad931a74db2f43c4 ./presets/sleep_temperature_guard.json
|
||||
7e819f2976ff48d89ccb636d08439d6e9736e7e95837c150dca157fb5bc78cb1 ./presets/smart_demand.json
|
||||
6d16f0a35b023afccd0f2011056ed8b15b5e5d2a3be6a52d122733aac862e85d ./presets/thermostat_enabled_guard.json
|
||||
fffa18bd989a0dcc1c5458975522517d40af4af40cc1ca30640e79d3db711053 ./presets/unoccupied_shutdown.json
|
||||
993b8e8151647cbda6e62312266d37d89178b3a4bb13f7df0950840e1ce647a8 ./presets/weather_comfort.json
|
||||
ae21459a261712bcb8d57594528b1648432e8d03a8a38502234829c0dbfef774 ./presets/weekend_comfort.json
|
||||
fdcd9a5055d08037278b842e7ab69265345c5811f0a06867136c511d140bb191 ./presets/window_available_guard.json
|
||||
804f22123cd3e8db0fac791826c8dd9f758fb866c8e3b5655fb6d25d259dccf1 ./presets/workday_comfort.json
|
||||
01952aa92b217f8eae2493b88870e2dec595100cd15c4d561ff11ae2b936c46f ./regenerate-sha.sh
|
||||
6408d99fbb6154afa65a9bda016dab9c9236e57cf4ae4ccb89943c1a4c5a5a56 ./scripts/FILE_MANIFEST.sha256
|
||||
bb89bac237e750e9b1bf73761d7df97a6b81853091615878c03f13d7b6399aa7 ./scripts/README.md
|
||||
@@ -43,8 +80,8 @@ e00d211e3885e30d7fed1e43b44e6fdad40a67019060156c0641816a93e3365f ./scripts/netw
|
||||
81345b6a0b51736bdbc98fd23199b62e4c721b4e7437e02dab7ea79b97dff29a ./scripts/service.sh
|
||||
8ccca8ed49576cf0b8e3453436ac3ff9c2a222cd41b27db98ceb62bd5f87aeef ./scripts/smoke.sh
|
||||
b50782b3742dfbf8a319c60571c968e93fdf8547db747c759edcffae68cb98bf ./scripts/update.sh
|
||||
037cc98e65772dade518aea33e13270c9c91afd639126a8a95be97495aecc447 ./src/api.rs
|
||||
50b653f5ae1c9d24eb2e158fb4af713f5ccabe259c83053fa3cd2a310c7780da ./src/api/assets.rs
|
||||
51b26ee9a02278f086f69d2ca5874feabcc90ebeb32149d1fa4b9f4fd55d91c2 ./src/api.rs
|
||||
825370f409124a719043200742c01c3441bc65f483108106140d13fe7bbcba91 ./src/api/assets.rs
|
||||
6c34b1294d76b0eba4c56bfd0bf69bdd502de0e40838104f6ddf2db4e922683d ./src/api/auth.rs
|
||||
5643425214a0ad228d6229398b715d9a6823c8c5823cdb4fbf73912d9b1eb74b ./src/api/automations.rs
|
||||
2317b7cd0c2437c128ac4982d64412c8184ecb5e774825761d61aab6e45fae4a ./src/api/debug_tokens.rs
|
||||
@@ -134,7 +171,7 @@ f13f1be3d5789539eba3fc1b59c14835f8c681eca7634e118fa3763a53aeee2b ./src/queries/
|
||||
b92a6cb158b494fe145b43c7641e65f6fafff47201d7d76edbec2cfd8b94835c ./systemd/gree-controller.service
|
||||
544a31cb2e5374227026afd6abd0d910381f3fca1638154ebd74e3c3d96a35d1 ./web/404.html
|
||||
e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.svg
|
||||
64dad888573f60e94175c93171eb3f0352c8b480958b7ac2b5e50caffd8ee801 ./web/index.html
|
||||
142c46fa8e1b9b726c2c05f50b0b0d19ab5667683f63d8d50fde922771dce6af ./web/index.html
|
||||
9ba3f6fa05b72aa989139b2a909982571b2a02055052e4c40104f1e81a9aa7eb ./web/js/README.md
|
||||
21b662914590e720dafefe4dc3dccc91dbeb963cce9ae91f007c835d2d0c1fe5 ./web/js/bootstrap.js
|
||||
72fa280996ba331a05bdb29a1f49b4e61bdd8964953c8ce1db952156620f08fe ./web/js/charts.js
|
||||
@@ -142,7 +179,7 @@ e98bdd7204349cce1ec6f57283509697af0bbc72280622a6c3efa6fed242db4f ./web/favicon.
|
||||
d34953aec21ade81ca9770c9c99873b0b2a4862a1bf671a6e13b507a5dd5b7ed ./web/js/dashboard.js
|
||||
2887856e35e086bb575e9fc0d8b0ed1160b6912297a2957535d5416bda68b4b7 ./web/js/entities.js
|
||||
9a0e87911f78cd8a969f4c57ce74774f5fa829fdecd79494d9a7f9d5804f9792 ./web/js/events.js
|
||||
40a5f342ed1447b09ed9fcbf65ee2c1035128fc608b4b743d259d51cc6741680 ./web/js/flows.js
|
||||
b7d4d428f0f40ce84d358fa90086c3161d9cac604281211ea46a11f6406fbbf6 ./web/js/flows.js
|
||||
f06557c6d338259059b990f8f79c91d68ac8ec1f245c302468f08929b5506901 ./web/js/forms.js
|
||||
dbf36223863ba882c03eccea4516ba8db7acf0c2e72c6c64490cb994f1e20f96 ./web/js/history.js
|
||||
7eaa04992ea828dc89f5eaebf674cbbfd160f53eb8d0d6ef0d4e47bd8c28c435 ./web/js/main.js
|
||||
@@ -152,6 +189,6 @@ c8c82e88c3715b1bfabf155e36266a4c94f5e2fc03eb39dcdd9d08a1985a997c ./web/js/route
|
||||
566702c0dafd304581c0438597578bccce1cf21c428171a36415728eb4867d04 ./web/js/settings-ui.js
|
||||
d299216bb707f494be77e0d46f87b203cf1a2c020e0036af86d8f5818ba03c88 ./web/js/settings.js
|
||||
6b653e4fe2d4db4ffae6ff8f39b8ce57a10a990dc0000ee4aae51d949afadd52 ./web/manifest.webmanifest
|
||||
f1f028e197f6caef639ef0ddb20950d00bd821f94e0e4a0ef2ad8bab1bb1fd24 ./web/styles.css
|
||||
a1590b58b6a0e3fc632489de55a41261787f1340f7d9bf778a44d6f8ab1a19d6 ./web/styles.css
|
||||
ae1b03f30b494f474a781a5d32072f1e73eba2b7c768109fc1cc8028cb6662a4 ./web/sw.js
|
||||
d505d793ce7cc9485b45b78bba1c0d51887adc7451ab59a42702946e5b991382 ./web/theme-init.js
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
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.
|
||||
|
||||
**Current release: 0.9.7**
|
||||
**Current release: 0.9.9**
|
||||
|
||||
> [Full API reference](docs/API.md) — authentication, every endpoint, request bodies, response models, WebSocket events and examples.
|
||||
|
||||
@@ -207,6 +207,8 @@ Schedules select profiles or a custom target for selected ISO weekdays (`1=Monda
|
||||
|
||||
**Flow** is the authoring layer for combined schedules and automations. The full-screen editor stores a block graph as the source of truth and compiles it automatically: a pure weekday + time-range + thermostat path becomes a native schedule, while richer logic becomes a generated automation. Generated schedule/automation rows carry their Flow provenance and are read-only in the legacy editors.
|
||||
|
||||
The reusable Flow preset library is stored as standalone JSON files in `presets/`. Each file contains its name, description and complete Flow graph, while the UI loads the embedded preset catalog dynamically instead of hard-coding graphs in JavaScript.
|
||||
|
||||
Available blocks include weekday/time/date ranges, the application Night mode, outdoor/device/zone temperature, house/device/zone/group state, arbitrary Home Assistant state/numeric/attribute/availability checks, a constant diagnostic source, AND/OR/NOT, thermostat actions, direct GREE actions and group actions. The GREE action uses the existing `DeviceCommand` fields (power, mode, target, fan, swing, quiet, turbo, light, air, xfan, health and sleep). Multiple branches can feed an action; the compiled runtime preserves the graph logic.
|
||||
|
||||
Quick preset/setpoint overrides normally hand control back at the next schedule boundary. Temporary Quick Thermostat adds explicit start/finish rules such as duration, exact time, temperature reached/stable or next schedule boundary.
|
||||
|
||||
@@ -11,6 +11,16 @@ 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 has_text(value: Option<&Value>) -> bool {
|
||||
match value {
|
||||
Some(Value::String(text)) => !text.trim().is_empty(),
|
||||
Some(Value::Object(items)) => items
|
||||
.values()
|
||||
.any(|item| item.as_str().is_some_and(|text| !text.trim().is_empty())),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
fn fnv1a_update(mut hash: u64, bytes: &[u8]) -> u64 {
|
||||
for byte in bytes {
|
||||
hash ^= u64::from(*byte);
|
||||
@@ -62,8 +72,10 @@ fn bundle_app_js(web_dir: &Path) -> String {
|
||||
fn main() {
|
||||
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR"));
|
||||
let lang_dir = manifest_dir.join("lang");
|
||||
let preset_dir = manifest_dir.join("presets");
|
||||
let web_dir = manifest_dir.join("web");
|
||||
println!("cargo:rerun-if-changed={}", lang_dir.display());
|
||||
println!("cargo:rerun-if-changed={}", preset_dir.display());
|
||||
|
||||
let theme_init_path = web_dir.join("theme-init.js");
|
||||
let styles_path = web_dir.join("styles.css");
|
||||
@@ -191,12 +203,86 @@ fn main() {
|
||||
panic!("lang/en.json is required as the default fallback language");
|
||||
}
|
||||
|
||||
let mut preset_files: Vec<PathBuf> = fs::read_dir(&preset_dir)
|
||||
.unwrap_or_else(|error| panic!("cannot read {}: {error}", preset_dir.display()))
|
||||
.filter_map(Result::ok)
|
||||
.map(|entry| entry.path())
|
||||
.filter(|path| path.extension().and_then(|ext| ext.to_str()) == Some("json"))
|
||||
.collect();
|
||||
preset_files.sort();
|
||||
if preset_files.is_empty() {
|
||||
panic!("no flow preset files found in {}", preset_dir.display());
|
||||
}
|
||||
|
||||
let mut preset_assets = Vec::new();
|
||||
let mut preset_manifest = Vec::new();
|
||||
for path in preset_files {
|
||||
println!("cargo:rerun-if-changed={}", path.display());
|
||||
let filename = path
|
||||
.file_name()
|
||||
.and_then(|value| value.to_str())
|
||||
.expect("UTF-8 preset filename");
|
||||
let stem = path
|
||||
.file_stem()
|
||||
.and_then(|value| value.to_str())
|
||||
.expect("UTF-8 preset id");
|
||||
if !stem.chars().all(|ch| ch.is_ascii_alphanumeric() || ch == '-' || ch == '_') {
|
||||
panic!("{filename}: filename may only contain ASCII letters, digits, '-' and '_'");
|
||||
}
|
||||
let source = fs::read_to_string(&path)
|
||||
.unwrap_or_else(|error| panic!("cannot read {}: {error}", path.display()));
|
||||
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 object = document
|
||||
.as_object()
|
||||
.unwrap_or_else(|| panic!("{filename}: preset root must be an object"));
|
||||
let id = object
|
||||
.get("id")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
.unwrap_or_else(|| panic!("{filename}: id must be a non-empty string"));
|
||||
if id != stem {
|
||||
panic!("{filename}: id '{id}' must match filename '{stem}.json'");
|
||||
}
|
||||
let category = object
|
||||
.get("category")
|
||||
.and_then(Value::as_str)
|
||||
.filter(|value| !value.trim().is_empty())
|
||||
.unwrap_or_else(|| panic!("{filename}: category must be a non-empty string"));
|
||||
if !has_text(object.get("name")) {
|
||||
panic!("{filename}: name must be a string or localized object with text");
|
||||
}
|
||||
if !has_text(object.get("description")) {
|
||||
panic!("{filename}: description must be a string or localized object with text");
|
||||
}
|
||||
let flow = object
|
||||
.get("flow")
|
||||
.and_then(Value::as_object)
|
||||
.unwrap_or_else(|| panic!("{filename}: flow must be an object"));
|
||||
if !flow.get("nodes").is_some_and(Value::is_array) || !flow.get("edges").is_some_and(Value::is_array) {
|
||||
panic!("{filename}: flow.nodes and flow.edges must be arrays");
|
||||
}
|
||||
preset_manifest.push(json!({
|
||||
"id": id,
|
||||
"category": category,
|
||||
"file": filename,
|
||||
}));
|
||||
preset_assets.push((filename.to_owned(), path));
|
||||
}
|
||||
|
||||
let manifest_json = serde_json::to_string(&json!({
|
||||
"default": "en",
|
||||
"languages": manifest_languages
|
||||
}))
|
||||
.expect("serialize language manifest");
|
||||
|
||||
let preset_manifest_json = serde_json::to_string(&json!({
|
||||
"version": 1,
|
||||
"presets": preset_manifest,
|
||||
}))
|
||||
.expect("serialize preset manifest");
|
||||
|
||||
let mut generated = String::new();
|
||||
generated.push_str("// @generated by build.rs - do not edit.\n");
|
||||
generated.push_str(&format!(
|
||||
@@ -228,6 +314,19 @@ fn main() {
|
||||
));
|
||||
}
|
||||
generated.push_str("];\n");
|
||||
generated.push_str(&format!(
|
||||
"pub const PRESET_MANIFEST_JSON: &str = {:?};\n",
|
||||
preset_manifest_json
|
||||
));
|
||||
generated.push_str("pub const PRESET_ASSETS: &[(&str, &str)] = &[\n");
|
||||
for (filename, path) in preset_assets {
|
||||
generated.push_str(&format!(
|
||||
" ({:?}, include_str!({:?})),\n",
|
||||
filename,
|
||||
path.to_string_lossy()
|
||||
));
|
||||
}
|
||||
generated.push_str("];\n");
|
||||
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").expect("OUT_DIR"));
|
||||
fs::write(out_dir.join("app.bundle.js"), app_js).expect("write generated app.bundle.js");
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
# GREE Controller API reference
|
||||
|
||||
HTTP and WebSocket API for GREE Controller **0.9.7**.
|
||||
HTTP and WebSocket API for GREE Controller **0.9.9**.
|
||||
|
||||
[← Main documentation](../README.md)
|
||||
|
||||
@@ -212,7 +212,7 @@ Response:
|
||||
{
|
||||
"status": "ok",
|
||||
"name": "gree-controller",
|
||||
"version": "0.9.7",
|
||||
"version": "0.9.9",
|
||||
"uptime_seconds": 1234,
|
||||
"control_ready": true,
|
||||
"time": "2026-08-30T06:54:00Z"
|
||||
@@ -236,7 +236,7 @@ Returns the initial Web UI snapshot:
|
||||
"settings": {},
|
||||
"outdoor_temperature": null,
|
||||
"system": {
|
||||
"version": "0.9.7",
|
||||
"version": "0.9.9",
|
||||
"uptime_seconds": 1234,
|
||||
"auth_required": false,
|
||||
"control_ready": true,
|
||||
|
||||
+4
-2
@@ -61,9 +61,11 @@ Condition/source blocks currently include weekday, time range, date range, appli
|
||||
|
||||
Actions include thermostat zone, GREE device and climate group. Direct GREE actions expose power, HVAC mode, target temperature, fan speed, vertical/horizontal swing, quiet, turbo, light, air, xfan, health and sleep.
|
||||
|
||||
## Built-in templates
|
||||
## Built-in presets
|
||||
|
||||
The editor ships 37 editable templates grouped into seven categories: Comfort, Energy & cost, Protection & safety, Night, Reliability, Home Assistant / heat sources and Advanced. The library includes workday/weekend comfort, weather-aware demand, morning boost, presence and energy-price eco modes, peak-power limiting, open-window/humidity/overheat/frost guards, night profiles, sensor/device resilience, dual heating/cooling thresholds, multi-room group control, nested AND/OR/NOT Home Assistant scenarios, and gas-boiler/external-heat-source coordination including off, reduced-target, boost and fallback heating patterns.
|
||||
The editor ships 37 editable presets grouped into seven categories: Comfort, Energy & cost, Protection & safety, Night, Reliability, Home Assistant / heat sources and Advanced. The library includes workday/weekend comfort, weather-aware demand, morning boost, presence and energy-price eco modes, peak-power limiting, open-window/humidity/overheat/frost guards, night profiles, sensor/device resilience, dual heating/cooling thresholds, multi-room group control, nested AND/OR/NOT Home Assistant scenarios, and gas-boiler/external-heat-source coordination including off, reduced-target, boost and fallback heating patterns.
|
||||
|
||||
Presets are data files, not JavaScript definitions. Every preset lives in `presets/<id>.json` and contains `id`, `category`, localized `name`, localized `description`, and the complete `flow` graph (`nodes` + `edges`). `build.rs` validates and embeds the directory, exposes `/presets/index.json` plus `/presets/<file>.json`, and the Flow editor loads that library dynamically. Device/zone/group placeholders such as `$zone1`, `$zone2`, `$device1` and `$group1` are resolved when a preset is applied. Adding a preset therefore does not require adding graph-building code to `web/js/flows.js`.
|
||||
|
||||
The canvas supports multi-selection (Shift/Ctrl/Cmd), `Ctrl/Cmd+A`, Select all / Clear selection toolbar actions, and dragging the whole selected group while preserving relative positions.
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"domain": "gree_controller",
|
||||
"name": "GREE Controller",
|
||||
"version": "0.9.7",
|
||||
"version": "0.9.9",
|
||||
"config_flow": true,
|
||||
"integration_type": "hub",
|
||||
"iot_class": "local_polling",
|
||||
|
||||
+8
-79
@@ -882,10 +882,10 @@
|
||||
"flow.exported": "Flow exported.",
|
||||
"flow.imported": "Flow imported and compiled.",
|
||||
"flow.importFailed": "Flow import failed",
|
||||
"flow.templates": "Templates",
|
||||
"flow.templateLibrary": "Flow library",
|
||||
"flow.templatesHint": "Ready-made layouts create an editable graph using existing zones, devices and groups.",
|
||||
"flow.templateReplaceConfirm": "Replace the current blocks with this template?",
|
||||
"flow.templates": "Presets",
|
||||
"flow.templateLibrary": "Flow preset library",
|
||||
"flow.templatesHint": "Ready-made presets create an editable graph using existing zones, devices and groups.",
|
||||
"flow.templateReplaceConfirm": "Replace the current blocks with this preset?",
|
||||
"flow.dryRun": "Dry-run",
|
||||
"flow.logs": "Logs",
|
||||
"flow.testMode": "Flow diagnostics",
|
||||
@@ -914,30 +914,10 @@
|
||||
"flow.node.deviceState": "Device state",
|
||||
"flow.node.zoneState": "Thermostat state",
|
||||
"flow.node.constant": "Test constant",
|
||||
"flow.template.workday_comfort.title": "Workday comfort",
|
||||
"flow.template.workday_comfort.description": "Weekday morning comfort preset for the selected thermostat zone.",
|
||||
"flow.template.weather_comfort.title": "Weather-aware comfort",
|
||||
"flow.template.weather_comfort.description": "Combines weekday, time and outdoor temperature with AND before thermostat control.",
|
||||
"flow.template.smart_demand.title": "Smart demand",
|
||||
"flow.template.smart_demand.description": "Complex time, house-mode and outdoor-or-room temperature logic.",
|
||||
"flow.template.device_resilience.title": "Only when device is healthy",
|
||||
"flow.template.device_resilience.description": "Runs the thermostat only when the device is enabled, online and house mode allows operation.",
|
||||
"flow.template.night_group.title": "Night group",
|
||||
"flow.template.night_group.description": "Night time + house mode applies sleep preset to a group or zone.",
|
||||
"flow.template.ha_window_guard.title": "Open window — stop HVAC",
|
||||
"flow.template.ha_window_guard.description": "Home Assistant binary_sensor example: an open window turns the thermostat off. Set the correct entity_id.",
|
||||
"flow.node.groupState": "Group state",
|
||||
"flow.node.nightMode": "Night mode",
|
||||
"flow.nightModeActive": "active according to app settings",
|
||||
"flow.nightModeHint": "This condition is true while the Night mode configured in the app is currently active. Use NOT to match time outside Night mode.",
|
||||
"flow.template.presence_eco.title": "Presence: comfort / eco",
|
||||
"flow.template.presence_eco.description": "Two explicit Home Assistant branches: home enables comfort while not_home selects the away preset. Set the correct person or presence entity_id.",
|
||||
"flow.template.frost_guard.title": "Frost protection",
|
||||
"flow.template.frost_guard.description": "In heating mode, low outdoor and room temperatures select a safe low thermostat target.",
|
||||
"flow.template.nested_guard.title": "Nested OR and NOT guard",
|
||||
"flow.template.nested_guard.description": "Weekdays and time + outdoor OR room temperature + NOT open window. An example of a multi-level graph.",
|
||||
"flow.template.night_quiet.title": "Night group profile",
|
||||
"flow.template.night_quiet.description": "Uses the app Night mode and group state directly to apply the sleep preset.",
|
||||
"flow.node.haAvailable": "HA: availability",
|
||||
"flow.available": "available",
|
||||
"flow.haAvailableHint": "This condition is true only when the Home Assistant entity returns a state other than unknown/unavailable. Connection errors fail closed as false. Useful as a guard before NOT and safety logic.",
|
||||
@@ -983,61 +963,10 @@
|
||||
"flow.templateCategory.reliability.hint": "Flows resilient to unavailable sensors, offline devices and disabled thermostats.",
|
||||
"flow.templateCategory.advanced": "Advanced",
|
||||
"flow.templateCategory.advanced.hint": "Nested AND/OR/NOT logic, multiple rooms and Home Assistant states.",
|
||||
"flow.template.morning_boost.title": "Cold-weather morning boost",
|
||||
"flow.template.morning_boost.description": "On workday mornings, only in heating mode and during cold weather, raises the target to 22.5°C.",
|
||||
"flow.template.weekend_comfort.title": "Weekend comfort",
|
||||
"flow.template.weekend_comfort.description": "Keeps daytime comfort on Saturday and Sunday while the house climate mode is not off.",
|
||||
"flow.template.energy_price_eco.title": "Expensive energy + nobody home",
|
||||
"flow.template.energy_price_eco.description": "When energy is expensive and nobody is home, switches the selected zone to an economical away profile.",
|
||||
"flow.template.peak_power_guard.title": "Peak power guard",
|
||||
"flow.template.peak_power_guard.description": "Turns HVAC off when household power draw exceeds the configured threshold while climate control is active.",
|
||||
"flow.template.mild_weather_eco.title": "Mild weather — HVAC off",
|
||||
"flow.template.mild_weather_eco.description": "When outdoor temperature is within a comfortable band and the window is closed, turns HVAC off.",
|
||||
"flow.template.unoccupied_shutdown.title": "Shut down while away",
|
||||
"flow.template.unoccupied_shutdown.description": "During daytime hours, turns off a group or zone when the selected person is away.",
|
||||
"flow.template.humidity_guard.title": "High humidity cooling",
|
||||
"flow.template.humidity_guard.description": "With high humidity, occupancy and cooling house mode, applies moderate cooling.",
|
||||
"flow.template.overheat_guard.title": "Overheat guard",
|
||||
"flow.template.overheat_guard.description": "If a zone is very warm, house mode is cooling and the window is closed, starts protective cooling.",
|
||||
"flow.template.window_available_guard.title": "Window availability + open state",
|
||||
"flow.template.window_available_guard.description": "Turns HVAC off only when the window sensor is available and reports open, avoiding false reactions to unavailable.",
|
||||
"flow.template.sleep_temperature_guard.title": "Night cooling only when needed",
|
||||
"flow.template.sleep_temperature_guard.description": "In night mode, cools only when room temperature is above the threshold and the house is in cooling mode.",
|
||||
"flow.template.bedroom_window_night.title": "Bedroom: night + closed window",
|
||||
"flow.template.bedroom_window_night.description": "Combines night mode with NOT open-window logic so the sleep profile runs only with a closed window.",
|
||||
"flow.template.sensor_availability_guard.title": "Cooling with sensor validation",
|
||||
"flow.template.sensor_availability_guard.description": "Checks HA sensor availability first, then temperature and house mode before starting cooling.",
|
||||
"flow.template.offline_safe_off.title": "Offline device safe-off",
|
||||
"flow.template.offline_safe_off.description": "When a device is offline while its thermostat remains active, issues a conservative off command with a long cooldown.",
|
||||
"flow.template.thermostat_enabled_guard.title": "Control only an active thermostat",
|
||||
"flow.template.thermostat_enabled_guard.description": "Requires an enabled zone, active demand and a non-off house mode before the action executes.",
|
||||
"flow.template.occupancy_weather_matrix.title": "Occupancy + weather + window",
|
||||
"flow.template.occupancy_weather_matrix.description": "Comfort runs only when someone is home, outdoor or room demand exists, and the window is not open.",
|
||||
"flow.template.dual_threshold_control.title": "Dual threshold heating/cooling",
|
||||
"flow.template.dual_threshold_control.description": "Two independent branches heat below the lower threshold and cool above the upper threshold.",
|
||||
"flow.template.multi_room_group_guard.title": "Multiple rooms → one group",
|
||||
"flow.template.multi_room_group_guard.description": "If either of two zones is too warm and house mode is cooling, starts a shared group or zone.",
|
||||
"flow.template.ha_attribute_mode_guard.title": "HA attribute + window + availability",
|
||||
"flow.template.ha_attribute_mode_guard.description": "Reads hvac_action, entity availability and window state to stop HVAC only when the data is trustworthy.",
|
||||
"flow.templateCategory.home_assistant": "Home Assistant / heat sources",
|
||||
"flow.templateCategory.home_assistant.hint": "Coordinate GREE with a gas boiler, external heat source, heating demand and temperatures read from Home Assistant.",
|
||||
"flow.template.ha_gas_heating_off.title": "Gas boiler heating → turn GREE off",
|
||||
"flow.template.ha_gas_heating_off.description": "Reads hvac_action from climate.gas_boiler. When HA reports heating and the entity is available, the selected GREE zone is turned off.",
|
||||
"flow.template.ha_gas_heating_boost.title": "Gas boiler heating → GREE heat boost",
|
||||
"flow.template.ha_gas_heating_boost.description": "When the gas boiler is actively heating, the room is below 20°C and house mode is heat, GREE assists with a 23.5°C target.",
|
||||
"flow.template.ha_gas_heating_reduce.title": "Boiler heating + room warm → reduce GREE",
|
||||
"flow.template.ha_gas_heating_reduce.description": "When gas heat is already active and the zone reaches at least 21°C, lowers the GREE target to 18°C so the heat sources do not fight each other.",
|
||||
"flow.template.ha_gas_backup_heat.title": "Gas not heating + room cold → GREE backup",
|
||||
"flow.template.ha_gas_backup_heat.description": "When the boiler entity is available but does not report heating and the room drops below 19°C, GREE provides backup heat to 22°C.",
|
||||
"flow.template.ha_external_heat_source_off.title": "Other heat source ON → turn GREE off",
|
||||
"flow.template.ha_external_heat_source_off.description": "Generic fireplace, furnace or other source preset. binary_sensor.external_heat_source = on turns the GREE group or zone off.",
|
||||
"flow.template.ha_external_heat_source_assist.title": "Other heat source ON → assist with GREE",
|
||||
"flow.template.ha_external_heat_source_assist.description": "When an external heat source is running but the room is still below 20°C, GREE assists in heat mode with a 23°C target.",
|
||||
"flow.template.ha_heating_demand_follow.title": "Follow Home Assistant heating demand",
|
||||
"flow.template.ha_heating_demand_follow.description": "binary_sensor.heating_demand = on starts GREE heating to 22.5°C while the house is in heat mode.",
|
||||
"flow.template.ha_boiler_supply_boost.title": "Hot boiler supply + cold room → boost",
|
||||
"flow.template.ha_boiler_supply_boost.description": "Reads sensor.boiler_supply_temperature. Above 45°C with a cold room, GREE is set to 23.5°C.",
|
||||
"flow.template.ha_thermostat_idle_fallback.title": "Gas thermostat idle → GREE fallback heat",
|
||||
"flow.template.ha_thermostat_idle_fallback.description": "If climate.gas_boiler is available, reports hvac_action=idle and the room falls below 19°C, GREE heats to 21.5°C."
|
||||
}
|
||||
"flow.templatesLoadFailed": "Unable to load preset library."
|
||||
},
|
||||
"flow.sharedInputsSettingsLink": "Shared Flow inputs in Home Assistant →",
|
||||
"flow.templateCategories": "Preset categories"
|
||||
}
|
||||
|
||||
+6
-77
@@ -883,8 +883,8 @@
|
||||
"flow.imported": "Flow zaimportowany i skompilowany.",
|
||||
"flow.importFailed": "Nie udało się zaimportować Flow",
|
||||
"flow.templates": "Presety",
|
||||
"flow.templateLibrary": "Biblioteka Flow",
|
||||
"flow.templatesHint": "Gotowe układy tworzą edytowalny graf z użyciem istniejących stref, urządzeń i grup.",
|
||||
"flow.templateLibrary": "Biblioteka presetów Flow",
|
||||
"flow.templatesHint": "Gotowe presety tworzą edytowalny graf z użyciem istniejących stref, urządzeń i grup.",
|
||||
"flow.templateReplaceConfirm": "Zastąpić obecne bloki wybranym presetem?",
|
||||
"flow.dryRun": "Dry-run",
|
||||
"flow.logs": "Logi",
|
||||
@@ -914,30 +914,10 @@
|
||||
"flow.node.deviceState": "Stan urządzenia",
|
||||
"flow.node.zoneState": "Stan termostatu",
|
||||
"flow.node.constant": "Stała testowa",
|
||||
"flow.template.workday_comfort.title": "Komfort w dni robocze",
|
||||
"flow.template.workday_comfort.description": "Pon.–pt. rano uruchamia preset komfortu w wybranej strefie.",
|
||||
"flow.template.weather_comfort.title": "Komfort zależny od pogody",
|
||||
"flow.template.weather_comfort.description": "Łączy dzień, godzinę i temperaturę zewnętrzną przez AND przed sterowaniem termostatem.",
|
||||
"flow.template.smart_demand.title": "Inteligentne zapotrzebowanie",
|
||||
"flow.template.smart_demand.description": "Złożona logika czasu, trybu domu i alternatywy temperatury zewnętrznej lub pokojowej.",
|
||||
"flow.template.device_resilience.title": "Sterowanie tylko przy sprawnym urządzeniu",
|
||||
"flow.template.device_resilience.description": "Uruchamia termostat tylko gdy urządzenie jest włączone, online i tryb domu pozwala na pracę.",
|
||||
"flow.template.night_group.title": "Noc dla grupy",
|
||||
"flow.template.night_group.description": "Nocny przedział czasu + tryb domu sterują presetem sleep dla grupy lub strefy.",
|
||||
"flow.template.ha_window_guard.title": "Otwarte okno — wyłącz HVAC",
|
||||
"flow.template.ha_window_guard.description": "Przykład integracji z binary_sensor Home Assistant: otwarte okno wyłącza termostat. Ustaw właściwy entity_id.",
|
||||
"flow.node.groupState": "Stan grupy",
|
||||
"flow.node.nightMode": "Tryb nocny",
|
||||
"flow.nightModeActive": "aktywny zgodnie z ustawieniami aplikacji",
|
||||
"flow.nightModeHint": "Warunek jest prawdziwy, gdy skonfigurowany w aplikacji Tryb nocny jest aktualnie aktywny. Użyj NOT, aby sprawdzić czas poza trybem nocnym.",
|
||||
"flow.template.presence_eco.title": "Obecność: komfort / eco",
|
||||
"flow.template.presence_eco.description": "Dwie jawne gałęzie Home Assistant: stan home włącza komfort, a not_home ustawia preset away. Ustaw właściwy entity_id osoby lub czujnika obecności.",
|
||||
"flow.template.frost_guard.title": "Ochrona przeciwzamrożeniowa",
|
||||
"flow.template.frost_guard.description": "W trybie grzania, przy niskiej temperaturze zewnętrznej i pokojowej, ustawia bezpieczny niski cel termostatu.",
|
||||
"flow.template.nested_guard.title": "Złożony warunek z OR i NOT",
|
||||
"flow.template.nested_guard.description": "Dni i godziny + temperatura zewnętrzna LUB pokojowa + NOT dla otwartego okna. Przykład wielopoziomowego grafu.",
|
||||
"flow.template.night_quiet.title": "Nocny profil grupy",
|
||||
"flow.template.night_quiet.description": "Korzysta bezpośrednio z istniejącego Trybu nocnego aplikacji i stanu grupy, aby zastosować preset sleep.",
|
||||
"flow.node.haAvailable": "HA: dostępność",
|
||||
"flow.available": "dostępna",
|
||||
"flow.haAvailableHint": "Warunek jest prawdziwy tylko wtedy, gdy encja Home Assistant odpowiada stanem innym niż unknown/unavailable. Błąd połączenia jest traktowany bezpiecznie jako false. Przydatne jako bramka przed NOT i logiką bezpieczeństwa.",
|
||||
@@ -983,61 +963,10 @@
|
||||
"flow.templateCategory.reliability.hint": "Automatyzacje odporne na niedostępne sensory, urządzenia offline i wyłączone termostaty.",
|
||||
"flow.templateCategory.advanced": "Zaawansowane",
|
||||
"flow.templateCategory.advanced.hint": "Wielopoziomowe AND/OR/NOT, wiele pomieszczeń i stany Home Assistant.",
|
||||
"flow.template.morning_boost.title": "Poranne dogrzanie przy mrozie",
|
||||
"flow.template.morning_boost.description": "W dni robocze rano, tylko w trybie grzania i przy mrozie na zewnątrz, podnosi cel do 22,5°C.",
|
||||
"flow.template.weekend_comfort.title": "Weekendowy komfort",
|
||||
"flow.template.weekend_comfort.description": "W sobotę i niedzielę utrzymuje komfort w ciągu dnia, jeśli tryb domu nie jest wyłączony.",
|
||||
"flow.template.energy_price_eco.title": "Droga energia + brak domowników",
|
||||
"flow.template.energy_price_eco.description": "Przy wysokiej cenie energii i nieobecności przełącza wybraną strefę w oszczędny profil away.",
|
||||
"flow.template.peak_power_guard.title": "Ochrona przed szczytem mocy",
|
||||
"flow.template.peak_power_guard.description": "Wyłącza HVAC, gdy pobór mocy domu przekroczy ustawiony próg i system klimatu jest aktywny.",
|
||||
"flow.template.mild_weather_eco.title": "Łagodna pogoda — HVAC off",
|
||||
"flow.template.mild_weather_eco.description": "Gdy temperatura zewnętrzna mieści się w komfortowym zakresie i okno jest zamknięte, wyłącza HVAC.",
|
||||
"flow.template.unoccupied_shutdown.title": "Wyłącz podczas nieobecności",
|
||||
"flow.template.unoccupied_shutdown.description": "W godzinach dziennych wyłącza grupę lub strefę, gdy wskazana osoba jest poza domem.",
|
||||
"flow.template.humidity_guard.title": "Wysoka wilgotność — chłodzenie",
|
||||
"flow.template.humidity_guard.description": "Przy wysokiej wilgotności, obecności domowników i trybie chłodzenia wymusza umiarkowane chłodzenie.",
|
||||
"flow.template.overheat_guard.title": "Ochrona przed przegrzaniem",
|
||||
"flow.template.overheat_guard.description": "Jeśli strefa jest bardzo ciepła, tryb domu to chłodzenie i okno jest zamknięte, uruchamia chłodzenie ochronne.",
|
||||
"flow.template.window_available_guard.title": "Okno: dostępność + otwarcie",
|
||||
"flow.template.window_available_guard.description": "Wyłącza HVAC dopiero gdy czujnik okna jest dostępny i zgłasza otwarcie — bez fałszywej reakcji na unavailable.",
|
||||
"flow.template.sleep_temperature_guard.title": "Nocne chłodzenie tylko gdy trzeba",
|
||||
"flow.template.sleep_temperature_guard.description": "W trybie nocnym chłodzi tylko wtedy, gdy temperatura pokoju przekracza próg i dom jest w trybie cool.",
|
||||
"flow.template.bedroom_window_night.title": "Sypialnia: noc + zamknięte okno",
|
||||
"flow.template.bedroom_window_night.description": "Łączy tryb nocny z NOT otwartego okna, aby profil sleep działał tylko przy zamkniętym oknie.",
|
||||
"flow.template.sensor_availability_guard.title": "Chłodzenie z kontrolą sensora",
|
||||
"flow.template.sensor_availability_guard.description": "Najpierw sprawdza dostępność sensora HA, potem temperaturę i tryb domu; dopiero wtedy uruchamia chłodzenie.",
|
||||
"flow.template.offline_safe_off.title": "Urządzenie offline — bezpieczne wyłączenie",
|
||||
"flow.template.offline_safe_off.description": "Gdy urządzenie jest offline, a termostat nadal aktywny, wydaje bezpieczne polecenie wyłączenia z długim cooldownem.",
|
||||
"flow.template.thermostat_enabled_guard.title": "Steruj tylko aktywnym termostatem",
|
||||
"flow.template.thermostat_enabled_guard.description": "Wymaga włączonej strefy, aktywnego zapotrzebowania i niezerowego trybu domu przed akcją.",
|
||||
"flow.template.occupancy_weather_matrix.title": "Obecność + pogoda + okno",
|
||||
"flow.template.occupancy_weather_matrix.description": "Komfort działa tylko gdy ktoś jest w domu, występuje zapotrzebowanie pogodowe lub pokojowe i okno nie jest otwarte.",
|
||||
"flow.template.dual_threshold_control.title": "Dwa progi: grzanie i chłodzenie",
|
||||
"flow.template.dual_threshold_control.description": "Dwie niezależne gałęzie sterują grzaniem poniżej dolnego progu i chłodzeniem powyżej górnego.",
|
||||
"flow.template.multi_room_group_guard.title": "Wiele pokoi → jedna grupa",
|
||||
"flow.template.multi_room_group_guard.description": "Jeśli dowolna z dwóch stref jest za ciepła i dom jest w trybie cool, uruchamia wspólną grupę lub strefę.",
|
||||
"flow.template.ha_attribute_mode_guard.title": "Atrybut HA + okno + dostępność",
|
||||
"flow.template.ha_attribute_mode_guard.description": "Czyta atrybut hvac_action, dostępność encji i stan okna, aby zatrzymać HVAC tylko przy wiarygodnych danych.",
|
||||
"flow.templateCategory.home_assistant": "Home Assistant / źródła ciepła",
|
||||
"flow.templateCategory.home_assistant.hint": "Koordynacja GREE z kotłem gazowym, zewnętrznym ogrzewaniem, zapotrzebowaniem i temperaturami pobieranymi z Home Assistant.",
|
||||
"flow.template.ha_gas_heating_off.title": "Kocioł gazowy grzeje → wyłącz GREE",
|
||||
"flow.template.ha_gas_heating_off.description": "Czyta hvac_action z climate.gas_boiler. Gdy HA zgłasza heating i encja jest dostępna, wyłącza wybraną strefę GREE.",
|
||||
"flow.template.ha_gas_heating_boost.title": "Kocioł gazowy grzeje → dogrzewanie GREE",
|
||||
"flow.template.ha_gas_heating_boost.description": "Gdy kocioł gazowy aktywnie grzeje, pokój ma mniej niż 20°C i dom jest w trybie heat, GREE wspomaga ogrzewanie celem 23,5°C.",
|
||||
"flow.template.ha_gas_heating_reduce.title": "Kocioł grzeje + pokój ciepły → obniż GREE",
|
||||
"flow.template.ha_gas_heating_reduce.description": "Jeśli gaz już grzeje, a strefa osiągnęła co najmniej 21°C, obniża cel GREE do 18°C, aby źródła ciepła nie walczyły ze sobą.",
|
||||
"flow.template.ha_gas_backup_heat.title": "Gaz nie grzeje + zimno → GREE jako backup",
|
||||
"flow.template.ha_gas_backup_heat.description": "Gdy encja kotła jest dostępna, ale nie zgłasza heating, a w pokoju jest poniżej 19°C, GREE przejmuje awaryjne grzanie do 22°C.",
|
||||
"flow.template.ha_external_heat_source_off.title": "Inne źródło ciepła ON → wyłącz GREE",
|
||||
"flow.template.ha_external_heat_source_off.description": "Ogólny preset dla kominka, pieca lub innego źródła. Stan binary_sensor.external_heat_source = on wyłącza grupę albo strefę GREE.",
|
||||
"flow.template.ha_external_heat_source_assist.title": "Inne źródło ciepła ON → wspomagaj GREE",
|
||||
"flow.template.ha_external_heat_source_assist.description": "Gdy zewnętrzne źródło działa, ale pokój nadal ma mniej niż 20°C, GREE wspomaga je w trybie heat z celem 23°C.",
|
||||
"flow.template.ha_heating_demand_follow.title": "Podążaj za żądaniem grzania z HA",
|
||||
"flow.template.ha_heating_demand_follow.description": "Stan binary_sensor.heating_demand = on uruchamia ogrzewanie GREE do 22,5°C, jeśli dom jest w trybie heat.",
|
||||
"flow.template.ha_boiler_supply_boost.title": "Gorące zasilanie kotła + zimny pokój → boost",
|
||||
"flow.template.ha_boiler_supply_boost.description": "Czyta sensor.boiler_supply_temperature. Przy temperaturze zasilania powyżej 45°C i zimnym pokoju ustawia GREE na 23,5°C.",
|
||||
"flow.template.ha_thermostat_idle_fallback.title": "Termostat gazowy idle → awaryjne grzanie GREE",
|
||||
"flow.template.ha_thermostat_idle_fallback.description": "Jeśli climate.gas_boiler jest dostępny, ma hvac_action=idle i pokój spadnie poniżej 19°C, GREE uruchamia grzanie do 21,5°C."
|
||||
}
|
||||
"flow.templatesLoadFailed": "Nie udało się wczytać biblioteki presetów."
|
||||
},
|
||||
"flow.sharedInputsSettingsLink": "Wspólne wejścia Flow w Home Assistant →",
|
||||
"flow.templateCategories": "Kategorie presetów"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"id": "bedroom_window_night",
|
||||
"category": "night",
|
||||
"name": {
|
||||
"pl": "Sypialnia: noc + zamknięte okno",
|
||||
"en": "Bedroom: night + closed window"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Łączy tryb nocny z NOT otwartego okna, aby profil sleep działał tylko przy zamkniętym oknie.",
|
||||
"en": "Combines night mode with NOT open-window logic so the sleep profile runs only with a closed window."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000148",
|
||||
"kind": "night_mode",
|
||||
"x": 35,
|
||||
"y": 65,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000149",
|
||||
"kind": "ha_state",
|
||||
"x": 35,
|
||||
"y": 185,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.bedroom_window",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000150",
|
||||
"kind": "logic_not",
|
||||
"x": 275,
|
||||
"y": 185,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000151",
|
||||
"kind": "logic_and",
|
||||
"x": 500,
|
||||
"y": 125,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000152",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 745,
|
||||
"y": 125,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "sleep",
|
||||
"setpoint": 20,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 180
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000153",
|
||||
"from": "node-00000000-0000-4000-8000-000000000149",
|
||||
"to": "node-00000000-0000-4000-8000-000000000150"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000154",
|
||||
"from": "node-00000000-0000-4000-8000-000000000148",
|
||||
"to": "node-00000000-0000-4000-8000-000000000151"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000155",
|
||||
"from": "node-00000000-0000-4000-8000-000000000150",
|
||||
"to": "node-00000000-0000-4000-8000-000000000151"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000156",
|
||||
"from": "node-00000000-0000-4000-8000-000000000151",
|
||||
"to": "node-00000000-0000-4000-8000-000000000152"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"id": "device_resilience",
|
||||
"category": "reliability",
|
||||
"name": {
|
||||
"pl": "Sterowanie tylko przy sprawnym urządzeniu",
|
||||
"en": "Only when device is healthy"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Uruchamia termostat tylko gdy urządzenie jest włączone, online i tryb domu pozwala na pracę.",
|
||||
"en": "Runs the thermostat only when the device is enabled, online and house mode allows operation."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000157",
|
||||
"kind": "device_state",
|
||||
"x": 40,
|
||||
"y": 55,
|
||||
"config": {
|
||||
"device_id": "$device1",
|
||||
"field": "online",
|
||||
"operator": "eq",
|
||||
"value": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000158",
|
||||
"kind": "device_state",
|
||||
"x": 40,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"device_id": "$device1",
|
||||
"field": "enabled",
|
||||
"operator": "eq",
|
||||
"value": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000159",
|
||||
"kind": "house_mode",
|
||||
"x": 40,
|
||||
"y": 295,
|
||||
"config": {
|
||||
"operator": "neq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000160",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 175,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000161",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 570,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000162",
|
||||
"from": "node-00000000-0000-4000-8000-000000000157",
|
||||
"to": "node-00000000-0000-4000-8000-000000000160"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000163",
|
||||
"from": "node-00000000-0000-4000-8000-000000000158",
|
||||
"to": "node-00000000-0000-4000-8000-000000000160"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000164",
|
||||
"from": "node-00000000-0000-4000-8000-000000000159",
|
||||
"to": "node-00000000-0000-4000-8000-000000000160"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000165",
|
||||
"from": "node-00000000-0000-4000-8000-000000000160",
|
||||
"to": "node-00000000-0000-4000-8000-000000000161"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"id": "dual_threshold_control",
|
||||
"category": "advanced",
|
||||
"name": {
|
||||
"pl": "Dwa progi: grzanie i chłodzenie",
|
||||
"en": "Dual threshold heating/cooling"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Dwie niezależne gałęzie sterują grzaniem poniżej dolnego progu i chłodzeniem powyżej górnego.",
|
||||
"en": "Two independent branches heat below the lower threshold and cool above the upper threshold."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000312",
|
||||
"kind": "zone_temperature",
|
||||
"x": 35,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000313",
|
||||
"kind": "zone_temperature",
|
||||
"x": 35,
|
||||
"y": 245,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "gt",
|
||||
"value": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000314",
|
||||
"kind": "house_mode",
|
||||
"x": 250,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000315",
|
||||
"kind": "house_mode",
|
||||
"x": 250,
|
||||
"y": 245,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "cool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000316",
|
||||
"kind": "logic_and",
|
||||
"x": 470,
|
||||
"y": 70,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000317",
|
||||
"kind": "logic_and",
|
||||
"x": 470,
|
||||
"y": 245,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000318",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 715,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000319",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 715,
|
||||
"y": 245,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "cool",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000320",
|
||||
"from": "node-00000000-0000-4000-8000-000000000312",
|
||||
"to": "node-00000000-0000-4000-8000-000000000316"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000321",
|
||||
"from": "node-00000000-0000-4000-8000-000000000314",
|
||||
"to": "node-00000000-0000-4000-8000-000000000316"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000322",
|
||||
"from": "node-00000000-0000-4000-8000-000000000313",
|
||||
"to": "node-00000000-0000-4000-8000-000000000317"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000323",
|
||||
"from": "node-00000000-0000-4000-8000-000000000315",
|
||||
"to": "node-00000000-0000-4000-8000-000000000317"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000324",
|
||||
"from": "node-00000000-0000-4000-8000-000000000316",
|
||||
"to": "node-00000000-0000-4000-8000-000000000318"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000325",
|
||||
"from": "node-00000000-0000-4000-8000-000000000317",
|
||||
"to": "node-00000000-0000-4000-8000-000000000319"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"id": "energy_price_eco",
|
||||
"category": "energy",
|
||||
"name": {
|
||||
"pl": "Droga energia + brak domowników",
|
||||
"en": "Expensive energy + nobody home"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Przy wysokiej cenie energii i nieobecności przełącza wybraną strefę w oszczędny profil away.",
|
||||
"en": "When energy is expensive and nobody is home, switches the selected zone to an economical away profile."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000054",
|
||||
"kind": "ha_numeric",
|
||||
"x": 40,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"entity_id": "sensor.energy_price",
|
||||
"operator": "gt",
|
||||
"value": 0.8
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000055",
|
||||
"kind": "ha_state",
|
||||
"x": 40,
|
||||
"y": 190,
|
||||
"config": {
|
||||
"entity_id": "person.someone",
|
||||
"operator": "neq",
|
||||
"value": "home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000056",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 130,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000057",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 570,
|
||||
"y": 130,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "away",
|
||||
"setpoint": 18,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 300
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000058",
|
||||
"from": "node-00000000-0000-4000-8000-000000000054",
|
||||
"to": "node-00000000-0000-4000-8000-000000000056"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000059",
|
||||
"from": "node-00000000-0000-4000-8000-000000000055",
|
||||
"to": "node-00000000-0000-4000-8000-000000000056"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000060",
|
||||
"from": "node-00000000-0000-4000-8000-000000000056",
|
||||
"to": "node-00000000-0000-4000-8000-000000000057"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"id": "frost_guard",
|
||||
"category": "safety",
|
||||
"name": {
|
||||
"pl": "Ochrona przeciwzamrożeniowa",
|
||||
"en": "Frost protection"
|
||||
},
|
||||
"description": {
|
||||
"pl": "W trybie grzania, przy niskiej temperaturze zewnętrznej i pokojowej, ustawia bezpieczny niski cel termostatu.",
|
||||
"en": "In heating mode, low outdoor and room temperatures select a safe low thermostat target."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000084",
|
||||
"kind": "house_mode",
|
||||
"x": 35,
|
||||
"y": 50,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000085",
|
||||
"kind": "outdoor_temperature",
|
||||
"x": 35,
|
||||
"y": 170,
|
||||
"config": {
|
||||
"operator": "lt",
|
||||
"value": 3
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000086",
|
||||
"kind": "zone_temperature",
|
||||
"x": 35,
|
||||
"y": 290,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 9
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000087",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 170,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000088",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 575,
|
||||
"y": 170,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 12,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 300
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000089",
|
||||
"from": "node-00000000-0000-4000-8000-000000000084",
|
||||
"to": "node-00000000-0000-4000-8000-000000000087"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000090",
|
||||
"from": "node-00000000-0000-4000-8000-000000000085",
|
||||
"to": "node-00000000-0000-4000-8000-000000000087"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000091",
|
||||
"from": "node-00000000-0000-4000-8000-000000000086",
|
||||
"to": "node-00000000-0000-4000-8000-000000000087"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000092",
|
||||
"from": "node-00000000-0000-4000-8000-000000000087",
|
||||
"to": "node-00000000-0000-4000-8000-000000000088"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"id": "ha_attribute_mode_guard",
|
||||
"category": "advanced",
|
||||
"name": {
|
||||
"pl": "Atrybut HA + okno + dostępność",
|
||||
"en": "HA attribute + window + availability"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Czyta atrybut hvac_action, dostępność encji i stan okna, aby zatrzymać HVAC tylko przy wiarygodnych danych.",
|
||||
"en": "Reads hvac_action, entity availability and window state to stop HVAC only when the data is trustworthy."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000337",
|
||||
"kind": "ha_attribute",
|
||||
"x": 35,
|
||||
"y": 60,
|
||||
"config": {
|
||||
"entity_id": "climate.living_room",
|
||||
"attribute": "hvac_action",
|
||||
"operator": "neq",
|
||||
"value": "idle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000338",
|
||||
"kind": "ha_state",
|
||||
"x": 35,
|
||||
"y": 180,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000339",
|
||||
"kind": "ha_available",
|
||||
"x": 35,
|
||||
"y": 300,
|
||||
"config": {
|
||||
"entity_id": "climate.living_room"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000340",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 180,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000341",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 575,
|
||||
"y": 180,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 60,
|
||||
"power": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000342",
|
||||
"from": "node-00000000-0000-4000-8000-000000000337",
|
||||
"to": "node-00000000-0000-4000-8000-000000000340"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000343",
|
||||
"from": "node-00000000-0000-4000-8000-000000000338",
|
||||
"to": "node-00000000-0000-4000-8000-000000000340"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000344",
|
||||
"from": "node-00000000-0000-4000-8000-000000000339",
|
||||
"to": "node-00000000-0000-4000-8000-000000000340"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000345",
|
||||
"from": "node-00000000-0000-4000-8000-000000000340",
|
||||
"to": "node-00000000-0000-4000-8000-000000000341"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"id": "ha_boiler_supply_boost",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Gorące zasilanie kotła + zimny pokój → boost",
|
||||
"en": "Hot boiler supply + cold room → boost"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Czyta sensor.boiler_supply_temperature. Przy temperaturze zasilania powyżej 45°C i zimnym pokoju ustawia GREE na 23,5°C.",
|
||||
"en": "Reads sensor.boiler_supply_temperature. Above 45°C with a cold room, GREE is set to 23.5°C."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000256",
|
||||
"kind": "ha_available",
|
||||
"x": 25,
|
||||
"y": 45,
|
||||
"config": {
|
||||
"entity_id": "sensor.boiler_supply_temperature"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000257",
|
||||
"kind": "ha_numeric",
|
||||
"x": 25,
|
||||
"y": 160,
|
||||
"config": {
|
||||
"entity_id": "sensor.boiler_supply_temperature",
|
||||
"operator": "gt",
|
||||
"value": 45
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000258",
|
||||
"kind": "zone_temperature",
|
||||
"x": 25,
|
||||
"y": 275,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000259",
|
||||
"kind": "house_mode",
|
||||
"x": 25,
|
||||
"y": 390,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000260",
|
||||
"kind": "logic_and",
|
||||
"x": 320,
|
||||
"y": 215,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000261",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 590,
|
||||
"y": 215,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 23.5,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 180,
|
||||
"power": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000262",
|
||||
"from": "node-00000000-0000-4000-8000-000000000256",
|
||||
"to": "node-00000000-0000-4000-8000-000000000260"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000263",
|
||||
"from": "node-00000000-0000-4000-8000-000000000257",
|
||||
"to": "node-00000000-0000-4000-8000-000000000260"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000264",
|
||||
"from": "node-00000000-0000-4000-8000-000000000258",
|
||||
"to": "node-00000000-0000-4000-8000-000000000260"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000265",
|
||||
"from": "node-00000000-0000-4000-8000-000000000259",
|
||||
"to": "node-00000000-0000-4000-8000-000000000260"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000266",
|
||||
"from": "node-00000000-0000-4000-8000-000000000260",
|
||||
"to": "node-00000000-0000-4000-8000-000000000261"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
{
|
||||
"id": "ha_external_heat_source_assist",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Inne źródło ciepła ON → wspomagaj GREE",
|
||||
"en": "Other heat source ON → assist with GREE"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Gdy zewnętrzne źródło działa, ale pokój nadal ma mniej niż 20°C, GREE wspomaga je w trybie heat z celem 23°C.",
|
||||
"en": "When an external heat source is running but the room is still below 20°C, GREE assists in heat mode with a 23°C target."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000236",
|
||||
"kind": "ha_available",
|
||||
"x": 25,
|
||||
"y": 40,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.external_heat_source"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000237",
|
||||
"kind": "ha_state",
|
||||
"x": 25,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.external_heat_source",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000238",
|
||||
"kind": "zone_temperature",
|
||||
"x": 25,
|
||||
"y": 270,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000239",
|
||||
"kind": "house_mode",
|
||||
"x": 25,
|
||||
"y": 385,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000240",
|
||||
"kind": "logic_and",
|
||||
"x": 320,
|
||||
"y": 210,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000241",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 590,
|
||||
"y": 210,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 23,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 180,
|
||||
"power": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000242",
|
||||
"from": "node-00000000-0000-4000-8000-000000000236",
|
||||
"to": "node-00000000-0000-4000-8000-000000000240"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000243",
|
||||
"from": "node-00000000-0000-4000-8000-000000000237",
|
||||
"to": "node-00000000-0000-4000-8000-000000000240"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000244",
|
||||
"from": "node-00000000-0000-4000-8000-000000000238",
|
||||
"to": "node-00000000-0000-4000-8000-000000000240"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000245",
|
||||
"from": "node-00000000-0000-4000-8000-000000000239",
|
||||
"to": "node-00000000-0000-4000-8000-000000000240"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000246",
|
||||
"from": "node-00000000-0000-4000-8000-000000000240",
|
||||
"to": "node-00000000-0000-4000-8000-000000000241"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"id": "ha_external_heat_source_off",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Inne źródło ciepła ON → wyłącz GREE",
|
||||
"en": "Other heat source ON → turn GREE off"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Ogólny preset dla kominka, pieca lub innego źródła. Stan binary_sensor.external_heat_source = on wyłącza grupę albo strefę GREE.",
|
||||
"en": "Generic fireplace, furnace or other source preset. binary_sensor.external_heat_source = on turns the GREE group or zone off."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000229",
|
||||
"kind": "ha_available",
|
||||
"x": 35,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.external_heat_source"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000230",
|
||||
"kind": "ha_state",
|
||||
"x": 35,
|
||||
"y": 200,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.external_heat_source",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000231",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 135,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000232",
|
||||
"kind": "group_action",
|
||||
"x": 575,
|
||||
"y": 135,
|
||||
"config": {
|
||||
"group_id": "$group1",
|
||||
"power": false,
|
||||
"mode": "auto",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"cooldown_seconds": 120
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000233",
|
||||
"from": "node-00000000-0000-4000-8000-000000000229",
|
||||
"to": "node-00000000-0000-4000-8000-000000000231"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000234",
|
||||
"from": "node-00000000-0000-4000-8000-000000000230",
|
||||
"to": "node-00000000-0000-4000-8000-000000000231"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000235",
|
||||
"from": "node-00000000-0000-4000-8000-000000000231",
|
||||
"to": "node-00000000-0000-4000-8000-000000000232"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"id": "ha_gas_backup_heat",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Gaz nie grzeje + zimno → GREE jako backup",
|
||||
"en": "Gas not heating + room cold → GREE backup"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Gdy encja kotła jest dostępna, ale nie zgłasza heating, a w pokoju jest poniżej 19°C, GREE przejmuje awaryjne grzanie do 22°C.",
|
||||
"en": "When the boiler entity is available but does not report heating and the room drops below 19°C, GREE provides backup heat to 22°C."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000218",
|
||||
"kind": "ha_available",
|
||||
"x": 25,
|
||||
"y": 40,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000219",
|
||||
"kind": "ha_attribute",
|
||||
"x": 25,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler",
|
||||
"attribute": "hvac_action",
|
||||
"operator": "neq",
|
||||
"value": "heating"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000220",
|
||||
"kind": "zone_temperature",
|
||||
"x": 25,
|
||||
"y": 270,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000221",
|
||||
"kind": "house_mode",
|
||||
"x": 25,
|
||||
"y": 385,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000222",
|
||||
"kind": "logic_and",
|
||||
"x": 320,
|
||||
"y": 210,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000223",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 590,
|
||||
"y": 210,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 22,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 180,
|
||||
"power": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000224",
|
||||
"from": "node-00000000-0000-4000-8000-000000000218",
|
||||
"to": "node-00000000-0000-4000-8000-000000000222"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000225",
|
||||
"from": "node-00000000-0000-4000-8000-000000000219",
|
||||
"to": "node-00000000-0000-4000-8000-000000000222"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000226",
|
||||
"from": "node-00000000-0000-4000-8000-000000000220",
|
||||
"to": "node-00000000-0000-4000-8000-000000000222"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000227",
|
||||
"from": "node-00000000-0000-4000-8000-000000000221",
|
||||
"to": "node-00000000-0000-4000-8000-000000000222"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000228",
|
||||
"from": "node-00000000-0000-4000-8000-000000000222",
|
||||
"to": "node-00000000-0000-4000-8000-000000000223"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"id": "ha_gas_heating_boost",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Kocioł gazowy grzeje → dogrzewanie GREE",
|
||||
"en": "Gas boiler heating → GREE heat boost"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Gdy kocioł gazowy aktywnie grzeje, pokój ma mniej niż 20°C i dom jest w trybie heat, GREE wspomaga ogrzewanie celem 23,5°C.",
|
||||
"en": "When the gas boiler is actively heating, the room is below 20°C and house mode is heat, GREE assists with a 23.5°C target."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000198",
|
||||
"kind": "ha_available",
|
||||
"x": 25,
|
||||
"y": 35,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000199",
|
||||
"kind": "ha_attribute",
|
||||
"x": 25,
|
||||
"y": 145,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler",
|
||||
"attribute": "hvac_action",
|
||||
"operator": "eq",
|
||||
"value": "heating"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000200",
|
||||
"kind": "zone_temperature",
|
||||
"x": 25,
|
||||
"y": 255,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000201",
|
||||
"kind": "house_mode",
|
||||
"x": 25,
|
||||
"y": 365,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000202",
|
||||
"kind": "logic_and",
|
||||
"x": 320,
|
||||
"y": 200,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000203",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 590,
|
||||
"y": 200,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 23.5,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 180,
|
||||
"power": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000204",
|
||||
"from": "node-00000000-0000-4000-8000-000000000198",
|
||||
"to": "node-00000000-0000-4000-8000-000000000202"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000205",
|
||||
"from": "node-00000000-0000-4000-8000-000000000199",
|
||||
"to": "node-00000000-0000-4000-8000-000000000202"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000206",
|
||||
"from": "node-00000000-0000-4000-8000-000000000200",
|
||||
"to": "node-00000000-0000-4000-8000-000000000202"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000207",
|
||||
"from": "node-00000000-0000-4000-8000-000000000201",
|
||||
"to": "node-00000000-0000-4000-8000-000000000202"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000208",
|
||||
"from": "node-00000000-0000-4000-8000-000000000202",
|
||||
"to": "node-00000000-0000-4000-8000-000000000203"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"id": "ha_gas_heating_off",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Kocioł gazowy grzeje → wyłącz GREE",
|
||||
"en": "Gas boiler heating → turn GREE off"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Czyta hvac_action z climate.gas_boiler. Gdy HA zgłasza heating i encja jest dostępna, wyłącza wybraną strefę GREE.",
|
||||
"en": "Reads hvac_action from climate.gas_boiler. When HA reports heating and the entity is available, the selected GREE zone is turned off."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000191",
|
||||
"kind": "ha_available",
|
||||
"x": 35,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000192",
|
||||
"kind": "ha_attribute",
|
||||
"x": 35,
|
||||
"y": 200,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler",
|
||||
"attribute": "hvac_action",
|
||||
"operator": "eq",
|
||||
"value": "heating"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000193",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 135,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000194",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 575,
|
||||
"y": 135,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 120,
|
||||
"power": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000195",
|
||||
"from": "node-00000000-0000-4000-8000-000000000191",
|
||||
"to": "node-00000000-0000-4000-8000-000000000193"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000196",
|
||||
"from": "node-00000000-0000-4000-8000-000000000192",
|
||||
"to": "node-00000000-0000-4000-8000-000000000193"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000197",
|
||||
"from": "node-00000000-0000-4000-8000-000000000193",
|
||||
"to": "node-00000000-0000-4000-8000-000000000194"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"id": "ha_gas_heating_reduce",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Kocioł grzeje + pokój ciepły → obniż GREE",
|
||||
"en": "Boiler heating + room warm → reduce GREE"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Jeśli gaz już grzeje, a strefa osiągnęła co najmniej 21°C, obniża cel GREE do 18°C, aby źródła ciepła nie walczyły ze sobą.",
|
||||
"en": "When gas heat is already active and the zone reaches at least 21°C, lowers the GREE target to 18°C so the heat sources do not fight each other."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000209",
|
||||
"kind": "ha_available",
|
||||
"x": 35,
|
||||
"y": 50,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000210",
|
||||
"kind": "ha_attribute",
|
||||
"x": 35,
|
||||
"y": 165,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler",
|
||||
"attribute": "hvac_action",
|
||||
"operator": "eq",
|
||||
"value": "heating"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000211",
|
||||
"kind": "zone_temperature",
|
||||
"x": 35,
|
||||
"y": 280,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "gte",
|
||||
"value": 21
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000212",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 165,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000213",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 575,
|
||||
"y": 165,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 18,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 180,
|
||||
"power": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000214",
|
||||
"from": "node-00000000-0000-4000-8000-000000000209",
|
||||
"to": "node-00000000-0000-4000-8000-000000000212"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000215",
|
||||
"from": "node-00000000-0000-4000-8000-000000000210",
|
||||
"to": "node-00000000-0000-4000-8000-000000000212"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000216",
|
||||
"from": "node-00000000-0000-4000-8000-000000000211",
|
||||
"to": "node-00000000-0000-4000-8000-000000000212"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000217",
|
||||
"from": "node-00000000-0000-4000-8000-000000000212",
|
||||
"to": "node-00000000-0000-4000-8000-000000000213"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
{
|
||||
"id": "ha_heating_demand_follow",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Podążaj za żądaniem grzania z HA",
|
||||
"en": "Follow Home Assistant heating demand"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Stan binary_sensor.heating_demand = on uruchamia ogrzewanie GREE do 22,5°C, jeśli dom jest w trybie heat.",
|
||||
"en": "binary_sensor.heating_demand = on starts GREE heating to 22.5°C while the house is in heat mode."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000247",
|
||||
"kind": "ha_available",
|
||||
"x": 35,
|
||||
"y": 60,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.heating_demand"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000248",
|
||||
"kind": "ha_state",
|
||||
"x": 35,
|
||||
"y": 180,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.heating_demand",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000249",
|
||||
"kind": "house_mode",
|
||||
"x": 35,
|
||||
"y": 300,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000250",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 180,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000251",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 575,
|
||||
"y": 180,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 22.5,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 120,
|
||||
"power": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000252",
|
||||
"from": "node-00000000-0000-4000-8000-000000000247",
|
||||
"to": "node-00000000-0000-4000-8000-000000000250"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000253",
|
||||
"from": "node-00000000-0000-4000-8000-000000000248",
|
||||
"to": "node-00000000-0000-4000-8000-000000000250"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000254",
|
||||
"from": "node-00000000-0000-4000-8000-000000000249",
|
||||
"to": "node-00000000-0000-4000-8000-000000000250"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000255",
|
||||
"from": "node-00000000-0000-4000-8000-000000000250",
|
||||
"to": "node-00000000-0000-4000-8000-000000000251"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
{
|
||||
"id": "ha_thermostat_idle_fallback",
|
||||
"category": "home_assistant",
|
||||
"name": {
|
||||
"pl": "Termostat gazowy idle → awaryjne grzanie GREE",
|
||||
"en": "Gas thermostat idle → GREE fallback heat"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Jeśli climate.gas_boiler jest dostępny, ma hvac_action=idle i pokój spadnie poniżej 19°C, GREE uruchamia grzanie do 21,5°C.",
|
||||
"en": "If climate.gas_boiler is available, reports hvac_action=idle and the room falls below 19°C, GREE heats to 21.5°C."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000267",
|
||||
"kind": "ha_available",
|
||||
"x": 25,
|
||||
"y": 40,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000268",
|
||||
"kind": "ha_attribute",
|
||||
"x": 25,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"entity_id": "climate.gas_boiler",
|
||||
"attribute": "hvac_action",
|
||||
"operator": "eq",
|
||||
"value": "idle"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000269",
|
||||
"kind": "zone_temperature",
|
||||
"x": 25,
|
||||
"y": 270,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000270",
|
||||
"kind": "house_mode",
|
||||
"x": 25,
|
||||
"y": 385,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000271",
|
||||
"kind": "logic_and",
|
||||
"x": 320,
|
||||
"y": 210,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000272",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 590,
|
||||
"y": 210,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 21.5,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 240,
|
||||
"power": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000273",
|
||||
"from": "node-00000000-0000-4000-8000-000000000267",
|
||||
"to": "node-00000000-0000-4000-8000-000000000271"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000274",
|
||||
"from": "node-00000000-0000-4000-8000-000000000268",
|
||||
"to": "node-00000000-0000-4000-8000-000000000271"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000275",
|
||||
"from": "node-00000000-0000-4000-8000-000000000269",
|
||||
"to": "node-00000000-0000-4000-8000-000000000271"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000276",
|
||||
"from": "node-00000000-0000-4000-8000-000000000270",
|
||||
"to": "node-00000000-0000-4000-8000-000000000271"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000277",
|
||||
"from": "node-00000000-0000-4000-8000-000000000271",
|
||||
"to": "node-00000000-0000-4000-8000-000000000272"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"id": "ha_window_guard",
|
||||
"category": "safety",
|
||||
"name": {
|
||||
"pl": "Otwarte okno — wyłącz HVAC",
|
||||
"en": "Open window — stop HVAC"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Przykład integracji z binary_sensor Home Assistant: otwarte okno wyłącza termostat. Ustaw właściwy entity_id.",
|
||||
"en": "Home Assistant binary_sensor example: an open window turns the thermostat off. Set the correct entity_id."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000093",
|
||||
"kind": "ha_state",
|
||||
"x": 45,
|
||||
"y": 90,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000094",
|
||||
"kind": "house_mode",
|
||||
"x": 45,
|
||||
"y": 220,
|
||||
"config": {
|
||||
"operator": "neq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000095",
|
||||
"kind": "logic_and",
|
||||
"x": 305,
|
||||
"y": 155,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000096",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 560,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 60,
|
||||
"power": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000097",
|
||||
"from": "node-00000000-0000-4000-8000-000000000093",
|
||||
"to": "node-00000000-0000-4000-8000-000000000095"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000098",
|
||||
"from": "node-00000000-0000-4000-8000-000000000094",
|
||||
"to": "node-00000000-0000-4000-8000-000000000095"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000099",
|
||||
"from": "node-00000000-0000-4000-8000-000000000095",
|
||||
"to": "node-00000000-0000-4000-8000-000000000096"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"id": "humidity_guard",
|
||||
"category": "safety",
|
||||
"name": {
|
||||
"pl": "Wysoka wilgotność — chłodzenie",
|
||||
"en": "High humidity cooling"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Przy wysokiej wilgotności, obecności domowników i trybie chłodzenia wymusza umiarkowane chłodzenie.",
|
||||
"en": "With high humidity, occupancy and cooling house mode, applies moderate cooling."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000100",
|
||||
"kind": "ha_numeric",
|
||||
"x": 40,
|
||||
"y": 60,
|
||||
"config": {
|
||||
"entity_id": "sensor.living_room_humidity",
|
||||
"operator": "gt",
|
||||
"value": 70
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000101",
|
||||
"kind": "house_mode",
|
||||
"x": 40,
|
||||
"y": 180,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "cool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000102",
|
||||
"kind": "ha_state",
|
||||
"x": 40,
|
||||
"y": 300,
|
||||
"config": {
|
||||
"entity_id": "person.someone",
|
||||
"operator": "eq",
|
||||
"value": "home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000103",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 180,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000104",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 575,
|
||||
"y": 180,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 22,
|
||||
"mode": "cool",
|
||||
"cooldown_seconds": 180
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000105",
|
||||
"from": "node-00000000-0000-4000-8000-000000000100",
|
||||
"to": "node-00000000-0000-4000-8000-000000000103"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000106",
|
||||
"from": "node-00000000-0000-4000-8000-000000000101",
|
||||
"to": "node-00000000-0000-4000-8000-000000000103"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000107",
|
||||
"from": "node-00000000-0000-4000-8000-000000000102",
|
||||
"to": "node-00000000-0000-4000-8000-000000000103"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000108",
|
||||
"from": "node-00000000-0000-4000-8000-000000000103",
|
||||
"to": "node-00000000-0000-4000-8000-000000000104"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"id": "mild_weather_eco",
|
||||
"category": "energy",
|
||||
"name": {
|
||||
"pl": "Łagodna pogoda — HVAC off",
|
||||
"en": "Mild weather — HVAC off"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Gdy temperatura zewnętrzna mieści się w komfortowym zakresie i okno jest zamknięte, wyłącza HVAC.",
|
||||
"en": "When outdoor temperature is within a comfortable band and the window is closed, turns HVAC off."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000068",
|
||||
"kind": "outdoor_temperature",
|
||||
"x": 35,
|
||||
"y": 55,
|
||||
"config": {
|
||||
"operator": "gte",
|
||||
"value": 17
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000069",
|
||||
"kind": "outdoor_temperature",
|
||||
"x": 35,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"operator": "lte",
|
||||
"value": 24
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000070",
|
||||
"kind": "ha_state",
|
||||
"x": 35,
|
||||
"y": 295,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window",
|
||||
"operator": "eq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000071",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 175,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000072",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 565,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 300,
|
||||
"power": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000073",
|
||||
"from": "node-00000000-0000-4000-8000-000000000068",
|
||||
"to": "node-00000000-0000-4000-8000-000000000071"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000074",
|
||||
"from": "node-00000000-0000-4000-8000-000000000069",
|
||||
"to": "node-00000000-0000-4000-8000-000000000071"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000075",
|
||||
"from": "node-00000000-0000-4000-8000-000000000070",
|
||||
"to": "node-00000000-0000-4000-8000-000000000071"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000076",
|
||||
"from": "node-00000000-0000-4000-8000-000000000071",
|
||||
"to": "node-00000000-0000-4000-8000-000000000072"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
{
|
||||
"id": "morning_boost",
|
||||
"category": "comfort",
|
||||
"name": {
|
||||
"pl": "Poranne dogrzanie przy mrozie",
|
||||
"en": "Cold-weather morning boost"
|
||||
},
|
||||
"description": {
|
||||
"pl": "W dni robocze rano, tylko w trybie grzania i przy mrozie na zewnątrz, podnosi cel do 22,5°C.",
|
||||
"en": "On workday mornings, only in heating mode and during cold weather, raises the target to 22.5°C."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000028",
|
||||
"kind": "weekday",
|
||||
"x": 35,
|
||||
"y": 50,
|
||||
"config": {
|
||||
"days": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000029",
|
||||
"kind": "time_range",
|
||||
"x": 35,
|
||||
"y": 170,
|
||||
"config": {
|
||||
"start": "05:30",
|
||||
"end": "07:30"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000030",
|
||||
"kind": "outdoor_temperature",
|
||||
"x": 35,
|
||||
"y": 290,
|
||||
"config": {
|
||||
"operator": "lt",
|
||||
"value": 5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000031",
|
||||
"kind": "house_mode",
|
||||
"x": 35,
|
||||
"y": 410,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "heat"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000032",
|
||||
"kind": "logic_and",
|
||||
"x": 320,
|
||||
"y": 220,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000033",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 585,
|
||||
"y": 220,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 22.5,
|
||||
"mode": "heat",
|
||||
"cooldown_seconds": 180
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000034",
|
||||
"from": "node-00000000-0000-4000-8000-000000000028",
|
||||
"to": "node-00000000-0000-4000-8000-000000000032"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000035",
|
||||
"from": "node-00000000-0000-4000-8000-000000000029",
|
||||
"to": "node-00000000-0000-4000-8000-000000000032"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000036",
|
||||
"from": "node-00000000-0000-4000-8000-000000000030",
|
||||
"to": "node-00000000-0000-4000-8000-000000000032"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000037",
|
||||
"from": "node-00000000-0000-4000-8000-000000000031",
|
||||
"to": "node-00000000-0000-4000-8000-000000000032"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000038",
|
||||
"from": "node-00000000-0000-4000-8000-000000000032",
|
||||
"to": "node-00000000-0000-4000-8000-000000000033"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
{
|
||||
"id": "multi_room_group_guard",
|
||||
"category": "advanced",
|
||||
"name": {
|
||||
"pl": "Wiele pokoi → jedna grupa",
|
||||
"en": "Multiple rooms → one group"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Jeśli dowolna z dwóch stref jest za ciepła i dom jest w trybie cool, uruchamia wspólną grupę lub strefę.",
|
||||
"en": "If either of two zones is too warm and house mode is cooling, starts a shared group or zone."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000326",
|
||||
"kind": "zone_temperature",
|
||||
"x": 30,
|
||||
"y": 55,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "gt",
|
||||
"value": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000327",
|
||||
"kind": "zone_temperature",
|
||||
"x": 30,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"zone_id": "$zone2",
|
||||
"operator": "gt",
|
||||
"value": 25
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000328",
|
||||
"kind": "logic_or",
|
||||
"x": 280,
|
||||
"y": 115,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000329",
|
||||
"kind": "house_mode",
|
||||
"x": 280,
|
||||
"y": 245,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "cool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000330",
|
||||
"kind": "logic_and",
|
||||
"x": 505,
|
||||
"y": 175,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000331",
|
||||
"kind": "group_action",
|
||||
"x": 760,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"group_id": "$group1",
|
||||
"power": true,
|
||||
"mode": "auto",
|
||||
"preset": "comfort",
|
||||
"setpoint": 22,
|
||||
"cooldown_seconds": 120
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000332",
|
||||
"from": "node-00000000-0000-4000-8000-000000000326",
|
||||
"to": "node-00000000-0000-4000-8000-000000000328"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000333",
|
||||
"from": "node-00000000-0000-4000-8000-000000000327",
|
||||
"to": "node-00000000-0000-4000-8000-000000000328"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000334",
|
||||
"from": "node-00000000-0000-4000-8000-000000000328",
|
||||
"to": "node-00000000-0000-4000-8000-000000000330"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000335",
|
||||
"from": "node-00000000-0000-4000-8000-000000000329",
|
||||
"to": "node-00000000-0000-4000-8000-000000000330"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000336",
|
||||
"from": "node-00000000-0000-4000-8000-000000000330",
|
||||
"to": "node-00000000-0000-4000-8000-000000000331"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
{
|
||||
"id": "nested_guard",
|
||||
"category": "advanced",
|
||||
"name": {
|
||||
"pl": "Złożony warunek z OR i NOT",
|
||||
"en": "Nested OR and NOT guard"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Dni i godziny + temperatura zewnętrzna LUB pokojowa + NOT dla otwartego okna. Przykład wielopoziomowego grafu.",
|
||||
"en": "Weekdays and time + outdoor OR room temperature + NOT open window. An example of a multi-level graph."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000278",
|
||||
"kind": "weekday",
|
||||
"x": 25,
|
||||
"y": 35,
|
||||
"config": {
|
||||
"days": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000279",
|
||||
"kind": "time_range",
|
||||
"x": 25,
|
||||
"y": 145,
|
||||
"config": {
|
||||
"start": "06:00",
|
||||
"end": "22:30"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000280",
|
||||
"kind": "outdoor_temperature",
|
||||
"x": 25,
|
||||
"y": 255,
|
||||
"config": {
|
||||
"operator": "lt",
|
||||
"value": 8
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000281",
|
||||
"kind": "zone_temperature",
|
||||
"x": 25,
|
||||
"y": 365,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000282",
|
||||
"kind": "logic_or",
|
||||
"x": 275,
|
||||
"y": 310,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000283",
|
||||
"kind": "ha_available",
|
||||
"x": 275,
|
||||
"y": 430,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000284",
|
||||
"kind": "ha_state",
|
||||
"x": 275,
|
||||
"y": 540,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000285",
|
||||
"kind": "logic_not",
|
||||
"x": 495,
|
||||
"y": 540,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000286",
|
||||
"kind": "logic_and",
|
||||
"x": 510,
|
||||
"y": 235,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000287",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 770,
|
||||
"y": 235,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000288",
|
||||
"from": "node-00000000-0000-4000-8000-000000000280",
|
||||
"to": "node-00000000-0000-4000-8000-000000000282"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000289",
|
||||
"from": "node-00000000-0000-4000-8000-000000000281",
|
||||
"to": "node-00000000-0000-4000-8000-000000000282"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000290",
|
||||
"from": "node-00000000-0000-4000-8000-000000000284",
|
||||
"to": "node-00000000-0000-4000-8000-000000000285"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000291",
|
||||
"from": "node-00000000-0000-4000-8000-000000000278",
|
||||
"to": "node-00000000-0000-4000-8000-000000000286"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000292",
|
||||
"from": "node-00000000-0000-4000-8000-000000000279",
|
||||
"to": "node-00000000-0000-4000-8000-000000000286"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000293",
|
||||
"from": "node-00000000-0000-4000-8000-000000000282",
|
||||
"to": "node-00000000-0000-4000-8000-000000000286"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000294",
|
||||
"from": "node-00000000-0000-4000-8000-000000000283",
|
||||
"to": "node-00000000-0000-4000-8000-000000000286"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000295",
|
||||
"from": "node-00000000-0000-4000-8000-000000000285",
|
||||
"to": "node-00000000-0000-4000-8000-000000000286"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000296",
|
||||
"from": "node-00000000-0000-4000-8000-000000000286",
|
||||
"to": "node-00000000-0000-4000-8000-000000000287"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"id": "night_group",
|
||||
"category": "night",
|
||||
"name": {
|
||||
"pl": "Noc dla grupy",
|
||||
"en": "Night group"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Nocny przedział czasu + tryb domu sterują presetem sleep dla grupy lub strefy.",
|
||||
"en": "Night time + house mode applies sleep preset to a group or zone."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000125",
|
||||
"kind": "time_range",
|
||||
"x": 50,
|
||||
"y": 100,
|
||||
"config": {
|
||||
"start": "22:30",
|
||||
"end": "06:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000126",
|
||||
"kind": "house_mode",
|
||||
"x": 50,
|
||||
"y": 230,
|
||||
"config": {
|
||||
"operator": "neq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000127",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 165,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000128",
|
||||
"kind": "group_action",
|
||||
"x": 570,
|
||||
"y": 165,
|
||||
"config": {
|
||||
"group_id": "$group1",
|
||||
"power": true,
|
||||
"mode": "auto",
|
||||
"preset": "sleep",
|
||||
"setpoint": 20,
|
||||
"cooldown_seconds": 120
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000129",
|
||||
"from": "node-00000000-0000-4000-8000-000000000125",
|
||||
"to": "node-00000000-0000-4000-8000-000000000127"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000130",
|
||||
"from": "node-00000000-0000-4000-8000-000000000126",
|
||||
"to": "node-00000000-0000-4000-8000-000000000127"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000131",
|
||||
"from": "node-00000000-0000-4000-8000-000000000127",
|
||||
"to": "node-00000000-0000-4000-8000-000000000128"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"id": "night_quiet",
|
||||
"category": "night",
|
||||
"name": {
|
||||
"pl": "Nocny profil grupy",
|
||||
"en": "Night group profile"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Korzysta bezpośrednio z istniejącego Trybu nocnego aplikacji i stanu grupy, aby zastosować preset sleep.",
|
||||
"en": "Uses the app Night mode and group state directly to apply the sleep preset."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000132",
|
||||
"kind": "night_mode",
|
||||
"x": 45,
|
||||
"y": 90,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000133",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 155,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000134",
|
||||
"kind": "group_action",
|
||||
"x": 565,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"group_id": "$group1",
|
||||
"power": null,
|
||||
"mode": "auto",
|
||||
"preset": "sleep",
|
||||
"setpoint": 20,
|
||||
"cooldown_seconds": 180
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000136",
|
||||
"kind": "group_state",
|
||||
"x": 45,
|
||||
"y": 225,
|
||||
"config": {
|
||||
"group_id": "$group1",
|
||||
"field": "power_enabled",
|
||||
"operator": "eq",
|
||||
"value": "true"
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000135",
|
||||
"from": "node-00000000-0000-4000-8000-000000000132",
|
||||
"to": "node-00000000-0000-4000-8000-000000000133"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000137",
|
||||
"from": "node-00000000-0000-4000-8000-000000000136",
|
||||
"to": "node-00000000-0000-4000-8000-000000000133"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000138",
|
||||
"from": "node-00000000-0000-4000-8000-000000000133",
|
||||
"to": "node-00000000-0000-4000-8000-000000000134"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
{
|
||||
"id": "occupancy_weather_matrix",
|
||||
"category": "advanced",
|
||||
"name": {
|
||||
"pl": "Obecność + pogoda + okno",
|
||||
"en": "Occupancy + weather + window"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Komfort działa tylko gdy ktoś jest w domu, występuje zapotrzebowanie pogodowe lub pokojowe i okno nie jest otwarte.",
|
||||
"en": "Comfort runs only when someone is home, outdoor or room demand exists, and the window is not open."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000297",
|
||||
"kind": "ha_state",
|
||||
"x": 25,
|
||||
"y": 40,
|
||||
"config": {
|
||||
"entity_id": "person.someone",
|
||||
"operator": "eq",
|
||||
"value": "home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000298",
|
||||
"kind": "outdoor_temperature",
|
||||
"x": 25,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"operator": "lt",
|
||||
"value": 9
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000299",
|
||||
"kind": "zone_temperature",
|
||||
"x": 25,
|
||||
"y": 270,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000300",
|
||||
"kind": "logic_or",
|
||||
"x": 275,
|
||||
"y": 215,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000301",
|
||||
"kind": "ha_state",
|
||||
"x": 275,
|
||||
"y": 345,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000302",
|
||||
"kind": "logic_not",
|
||||
"x": 495,
|
||||
"y": 345,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000303",
|
||||
"kind": "logic_and",
|
||||
"x": 505,
|
||||
"y": 150,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000304",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 765,
|
||||
"y": 150,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000305",
|
||||
"from": "node-00000000-0000-4000-8000-000000000298",
|
||||
"to": "node-00000000-0000-4000-8000-000000000300"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000306",
|
||||
"from": "node-00000000-0000-4000-8000-000000000299",
|
||||
"to": "node-00000000-0000-4000-8000-000000000300"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000307",
|
||||
"from": "node-00000000-0000-4000-8000-000000000301",
|
||||
"to": "node-00000000-0000-4000-8000-000000000302"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000308",
|
||||
"from": "node-00000000-0000-4000-8000-000000000297",
|
||||
"to": "node-00000000-0000-4000-8000-000000000303"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000309",
|
||||
"from": "node-00000000-0000-4000-8000-000000000300",
|
||||
"to": "node-00000000-0000-4000-8000-000000000303"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000310",
|
||||
"from": "node-00000000-0000-4000-8000-000000000302",
|
||||
"to": "node-00000000-0000-4000-8000-000000000303"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000311",
|
||||
"from": "node-00000000-0000-4000-8000-000000000303",
|
||||
"to": "node-00000000-0000-4000-8000-000000000304"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
{
|
||||
"id": "offline_safe_off",
|
||||
"category": "reliability",
|
||||
"name": {
|
||||
"pl": "Urządzenie offline — bezpieczne wyłączenie",
|
||||
"en": "Offline device safe-off"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Gdy urządzenie jest offline, a termostat nadal aktywny, wydaje bezpieczne polecenie wyłączenia z długim cooldownem.",
|
||||
"en": "When a device is offline while its thermostat remains active, issues a conservative off command with a long cooldown."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000175",
|
||||
"kind": "device_state",
|
||||
"x": 35,
|
||||
"y": 85,
|
||||
"config": {
|
||||
"device_id": "$device1",
|
||||
"field": "online",
|
||||
"operator": "eq",
|
||||
"value": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000176",
|
||||
"kind": "zone_state",
|
||||
"x": 35,
|
||||
"y": 215,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"field": "enabled",
|
||||
"operator": "eq",
|
||||
"value": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000177",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 150,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000178",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 565,
|
||||
"y": 150,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 300,
|
||||
"power": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000179",
|
||||
"from": "node-00000000-0000-4000-8000-000000000175",
|
||||
"to": "node-00000000-0000-4000-8000-000000000177"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000180",
|
||||
"from": "node-00000000-0000-4000-8000-000000000176",
|
||||
"to": "node-00000000-0000-4000-8000-000000000177"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000181",
|
||||
"from": "node-00000000-0000-4000-8000-000000000177",
|
||||
"to": "node-00000000-0000-4000-8000-000000000178"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"id": "overheat_guard",
|
||||
"category": "safety",
|
||||
"name": {
|
||||
"pl": "Ochrona przed przegrzaniem",
|
||||
"en": "Overheat guard"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Jeśli strefa jest bardzo ciepła, tryb domu to chłodzenie i okno jest zamknięte, uruchamia chłodzenie ochronne.",
|
||||
"en": "If a zone is very warm, house mode is cooling and the window is closed, starts protective cooling."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000109",
|
||||
"kind": "zone_temperature",
|
||||
"x": 35,
|
||||
"y": 65,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "gt",
|
||||
"value": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000110",
|
||||
"kind": "house_mode",
|
||||
"x": 35,
|
||||
"y": 185,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "cool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000111",
|
||||
"kind": "ha_state",
|
||||
"x": 35,
|
||||
"y": 305,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window",
|
||||
"operator": "eq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000112",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 185,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000113",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 570,
|
||||
"y": 185,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "custom",
|
||||
"setpoint": 22,
|
||||
"mode": "cool",
|
||||
"cooldown_seconds": 120
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000114",
|
||||
"from": "node-00000000-0000-4000-8000-000000000109",
|
||||
"to": "node-00000000-0000-4000-8000-000000000112"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000115",
|
||||
"from": "node-00000000-0000-4000-8000-000000000110",
|
||||
"to": "node-00000000-0000-4000-8000-000000000112"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000116",
|
||||
"from": "node-00000000-0000-4000-8000-000000000111",
|
||||
"to": "node-00000000-0000-4000-8000-000000000112"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000117",
|
||||
"from": "node-00000000-0000-4000-8000-000000000112",
|
||||
"to": "node-00000000-0000-4000-8000-000000000113"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"id": "peak_power_guard",
|
||||
"category": "energy",
|
||||
"name": {
|
||||
"pl": "Ochrona przed szczytem mocy",
|
||||
"en": "Peak power guard"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Wyłącza HVAC, gdy pobór mocy domu przekroczy ustawiony próg i system klimatu jest aktywny.",
|
||||
"en": "Turns HVAC off when household power draw exceeds the configured threshold while climate control is active."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000061",
|
||||
"kind": "ha_numeric",
|
||||
"x": 40,
|
||||
"y": 75,
|
||||
"config": {
|
||||
"entity_id": "sensor.house_power",
|
||||
"operator": "gt",
|
||||
"value": 5000
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000062",
|
||||
"kind": "house_mode",
|
||||
"x": 40,
|
||||
"y": 200,
|
||||
"config": {
|
||||
"operator": "neq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000063",
|
||||
"kind": "logic_and",
|
||||
"x": 315,
|
||||
"y": 140,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000064",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 570,
|
||||
"y": 140,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 180,
|
||||
"power": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000065",
|
||||
"from": "node-00000000-0000-4000-8000-000000000061",
|
||||
"to": "node-00000000-0000-4000-8000-000000000063"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000066",
|
||||
"from": "node-00000000-0000-4000-8000-000000000062",
|
||||
"to": "node-00000000-0000-4000-8000-000000000063"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000067",
|
||||
"from": "node-00000000-0000-4000-8000-000000000063",
|
||||
"to": "node-00000000-0000-4000-8000-000000000064"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"id": "presence_eco",
|
||||
"category": "energy",
|
||||
"name": {
|
||||
"pl": "Obecność: komfort / eco",
|
||||
"en": "Presence: comfort / eco"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Dwie jawne gałęzie Home Assistant: stan home włącza komfort, a not_home ustawia preset away. Ustaw właściwy entity_id osoby lub czujnika obecności.",
|
||||
"en": "Two explicit Home Assistant branches: home enables comfort while not_home selects the away preset. Set the correct person or presence entity_id."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000048",
|
||||
"kind": "ha_state",
|
||||
"x": 45,
|
||||
"y": 75,
|
||||
"config": {
|
||||
"entity_id": "person.someone",
|
||||
"operator": "eq",
|
||||
"value": "home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000049",
|
||||
"kind": "ha_state",
|
||||
"x": 45,
|
||||
"y": 245,
|
||||
"config": {
|
||||
"entity_id": "person.someone",
|
||||
"operator": "eq",
|
||||
"value": "not_home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000050",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 360,
|
||||
"y": 65,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000051",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 360,
|
||||
"y": 245,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "away",
|
||||
"setpoint": 18,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 180
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000052",
|
||||
"from": "node-00000000-0000-4000-8000-000000000048",
|
||||
"to": "node-00000000-0000-4000-8000-000000000050"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000053",
|
||||
"from": "node-00000000-0000-4000-8000-000000000049",
|
||||
"to": "node-00000000-0000-4000-8000-000000000051"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"id": "sensor_availability_guard",
|
||||
"category": "reliability",
|
||||
"name": {
|
||||
"pl": "Chłodzenie z kontrolą sensora",
|
||||
"en": "Cooling with sensor validation"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Najpierw sprawdza dostępność sensora HA, potem temperaturę i tryb domu; dopiero wtedy uruchamia chłodzenie.",
|
||||
"en": "Checks HA sensor availability first, then temperature and house mode before starting cooling."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000166",
|
||||
"kind": "ha_available",
|
||||
"x": 35,
|
||||
"y": 55,
|
||||
"config": {
|
||||
"entity_id": "sensor.room_temperature"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000167",
|
||||
"kind": "ha_numeric",
|
||||
"x": 35,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"entity_id": "sensor.room_temperature",
|
||||
"operator": "gt",
|
||||
"value": 26
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000168",
|
||||
"kind": "house_mode",
|
||||
"x": 35,
|
||||
"y": 295,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "cool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000169",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 175,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000170",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 570,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "cool",
|
||||
"cooldown_seconds": 120
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000171",
|
||||
"from": "node-00000000-0000-4000-8000-000000000166",
|
||||
"to": "node-00000000-0000-4000-8000-000000000169"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000172",
|
||||
"from": "node-00000000-0000-4000-8000-000000000167",
|
||||
"to": "node-00000000-0000-4000-8000-000000000169"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000173",
|
||||
"from": "node-00000000-0000-4000-8000-000000000168",
|
||||
"to": "node-00000000-0000-4000-8000-000000000169"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000174",
|
||||
"from": "node-00000000-0000-4000-8000-000000000169",
|
||||
"to": "node-00000000-0000-4000-8000-000000000170"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"id": "sleep_temperature_guard",
|
||||
"category": "night",
|
||||
"name": {
|
||||
"pl": "Nocne chłodzenie tylko gdy trzeba",
|
||||
"en": "Night cooling only when needed"
|
||||
},
|
||||
"description": {
|
||||
"pl": "W trybie nocnym chłodzi tylko wtedy, gdy temperatura pokoju przekracza próg i dom jest w trybie cool.",
|
||||
"en": "In night mode, cools only when room temperature is above the threshold and the house is in cooling mode."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000139",
|
||||
"kind": "night_mode",
|
||||
"x": 35,
|
||||
"y": 55,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000140",
|
||||
"kind": "zone_temperature",
|
||||
"x": 35,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "gt",
|
||||
"value": 23.5
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000141",
|
||||
"kind": "house_mode",
|
||||
"x": 35,
|
||||
"y": 295,
|
||||
"config": {
|
||||
"operator": "eq",
|
||||
"value": "cool"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000142",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 175,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000143",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 570,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "sleep",
|
||||
"setpoint": 20,
|
||||
"mode": "cool",
|
||||
"cooldown_seconds": 180
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000144",
|
||||
"from": "node-00000000-0000-4000-8000-000000000139",
|
||||
"to": "node-00000000-0000-4000-8000-000000000142"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000145",
|
||||
"from": "node-00000000-0000-4000-8000-000000000140",
|
||||
"to": "node-00000000-0000-4000-8000-000000000142"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000146",
|
||||
"from": "node-00000000-0000-4000-8000-000000000141",
|
||||
"to": "node-00000000-0000-4000-8000-000000000142"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000147",
|
||||
"from": "node-00000000-0000-4000-8000-000000000142",
|
||||
"to": "node-00000000-0000-4000-8000-000000000143"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
{
|
||||
"id": "smart_demand",
|
||||
"category": "comfort",
|
||||
"name": {
|
||||
"pl": "Inteligentne zapotrzebowanie",
|
||||
"en": "Smart demand"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Złożona logika czasu, trybu domu i alternatywy temperatury zewnętrznej lub pokojowej.",
|
||||
"en": "Complex time, house-mode and outdoor-or-room temperature logic."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000015",
|
||||
"kind": "time_range",
|
||||
"x": 30,
|
||||
"y": 40,
|
||||
"config": {
|
||||
"start": "05:30",
|
||||
"end": "23:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000016",
|
||||
"kind": "outdoor_temperature",
|
||||
"x": 30,
|
||||
"y": 160,
|
||||
"config": {
|
||||
"operator": "lt",
|
||||
"value": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000017",
|
||||
"kind": "zone_temperature",
|
||||
"x": 30,
|
||||
"y": 280,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"operator": "lt",
|
||||
"value": 20
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000018",
|
||||
"kind": "logic_or",
|
||||
"x": 280,
|
||||
"y": 220,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000019",
|
||||
"kind": "house_mode",
|
||||
"x": 280,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"operator": "neq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000020",
|
||||
"kind": "logic_and",
|
||||
"x": 510,
|
||||
"y": 155,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000021",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 760,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000022",
|
||||
"from": "node-00000000-0000-4000-8000-000000000016",
|
||||
"to": "node-00000000-0000-4000-8000-000000000018"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000023",
|
||||
"from": "node-00000000-0000-4000-8000-000000000017",
|
||||
"to": "node-00000000-0000-4000-8000-000000000018"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000024",
|
||||
"from": "node-00000000-0000-4000-8000-000000000015",
|
||||
"to": "node-00000000-0000-4000-8000-000000000020"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000025",
|
||||
"from": "node-00000000-0000-4000-8000-000000000019",
|
||||
"to": "node-00000000-0000-4000-8000-000000000020"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000026",
|
||||
"from": "node-00000000-0000-4000-8000-000000000018",
|
||||
"to": "node-00000000-0000-4000-8000-000000000020"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000027",
|
||||
"from": "node-00000000-0000-4000-8000-000000000020",
|
||||
"to": "node-00000000-0000-4000-8000-000000000021"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"id": "thermostat_enabled_guard",
|
||||
"category": "reliability",
|
||||
"name": {
|
||||
"pl": "Steruj tylko aktywnym termostatem",
|
||||
"en": "Control only an active thermostat"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Wymaga włączonej strefy, aktywnego zapotrzebowania i niezerowego trybu domu przed akcją.",
|
||||
"en": "Requires an enabled zone, active demand and a non-off house mode before the action executes."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000182",
|
||||
"kind": "zone_state",
|
||||
"x": 35,
|
||||
"y": 55,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"field": "enabled",
|
||||
"operator": "eq",
|
||||
"value": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000183",
|
||||
"kind": "zone_state",
|
||||
"x": 35,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"field": "demand",
|
||||
"operator": "eq",
|
||||
"value": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000184",
|
||||
"kind": "house_mode",
|
||||
"x": 35,
|
||||
"y": 295,
|
||||
"config": {
|
||||
"operator": "neq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000185",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 175,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000186",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 570,
|
||||
"y": 175,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 120
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000187",
|
||||
"from": "node-00000000-0000-4000-8000-000000000182",
|
||||
"to": "node-00000000-0000-4000-8000-000000000185"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000188",
|
||||
"from": "node-00000000-0000-4000-8000-000000000183",
|
||||
"to": "node-00000000-0000-4000-8000-000000000185"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000189",
|
||||
"from": "node-00000000-0000-4000-8000-000000000184",
|
||||
"to": "node-00000000-0000-4000-8000-000000000185"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000190",
|
||||
"from": "node-00000000-0000-4000-8000-000000000185",
|
||||
"to": "node-00000000-0000-4000-8000-000000000186"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"id": "unoccupied_shutdown",
|
||||
"category": "energy",
|
||||
"name": {
|
||||
"pl": "Wyłącz podczas nieobecności",
|
||||
"en": "Shut down while away"
|
||||
},
|
||||
"description": {
|
||||
"pl": "W godzinach dziennych wyłącza grupę lub strefę, gdy wskazana osoba jest poza domem.",
|
||||
"en": "During daytime hours, turns off a group or zone when the selected person is away."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000077",
|
||||
"kind": "ha_state",
|
||||
"x": 35,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"entity_id": "person.someone",
|
||||
"operator": "eq",
|
||||
"value": "not_home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000078",
|
||||
"kind": "time_range",
|
||||
"x": 35,
|
||||
"y": 190,
|
||||
"config": {
|
||||
"start": "09:00",
|
||||
"end": "16:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000079",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 130,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000080",
|
||||
"kind": "group_action",
|
||||
"x": 565,
|
||||
"y": 130,
|
||||
"config": {
|
||||
"group_id": "$group1",
|
||||
"power": false,
|
||||
"mode": "",
|
||||
"preset": "",
|
||||
"setpoint": 21,
|
||||
"cooldown_seconds": 300
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000081",
|
||||
"from": "node-00000000-0000-4000-8000-000000000077",
|
||||
"to": "node-00000000-0000-4000-8000-000000000079"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000082",
|
||||
"from": "node-00000000-0000-4000-8000-000000000078",
|
||||
"to": "node-00000000-0000-4000-8000-000000000079"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000083",
|
||||
"from": "node-00000000-0000-4000-8000-000000000079",
|
||||
"to": "node-00000000-0000-4000-8000-000000000080"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"id": "weather_comfort",
|
||||
"category": "comfort",
|
||||
"name": {
|
||||
"pl": "Komfort zależny od pogody",
|
||||
"en": "Weather-aware comfort"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Łączy dzień, godzinę i temperaturę zewnętrzną przez AND przed sterowaniem termostatem.",
|
||||
"en": "Combines weekday, time and outdoor temperature with AND before thermostat control."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000006",
|
||||
"kind": "weekday",
|
||||
"x": 35,
|
||||
"y": 40,
|
||||
"config": {
|
||||
"days": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000007",
|
||||
"kind": "time_range",
|
||||
"x": 35,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"start": "06:00",
|
||||
"end": "22:30"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000008",
|
||||
"kind": "outdoor_temperature",
|
||||
"x": 35,
|
||||
"y": 270,
|
||||
"config": {
|
||||
"operator": "lt",
|
||||
"value": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000009",
|
||||
"kind": "logic_and",
|
||||
"x": 300,
|
||||
"y": 155,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000010",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 555,
|
||||
"y": 155,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000011",
|
||||
"from": "node-00000000-0000-4000-8000-000000000006",
|
||||
"to": "node-00000000-0000-4000-8000-000000000009"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000012",
|
||||
"from": "node-00000000-0000-4000-8000-000000000007",
|
||||
"to": "node-00000000-0000-4000-8000-000000000009"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000013",
|
||||
"from": "node-00000000-0000-4000-8000-000000000008",
|
||||
"to": "node-00000000-0000-4000-8000-000000000009"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000014",
|
||||
"from": "node-00000000-0000-4000-8000-000000000009",
|
||||
"to": "node-00000000-0000-4000-8000-000000000010"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"id": "weekend_comfort",
|
||||
"category": "comfort",
|
||||
"name": {
|
||||
"pl": "Weekendowy komfort",
|
||||
"en": "Weekend comfort"
|
||||
},
|
||||
"description": {
|
||||
"pl": "W sobotę i niedzielę utrzymuje komfort w ciągu dnia, jeśli tryb domu nie jest wyłączony.",
|
||||
"en": "Keeps daytime comfort on Saturday and Sunday while the house climate mode is not off."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000039",
|
||||
"kind": "weekday",
|
||||
"x": 40,
|
||||
"y": 90,
|
||||
"config": {
|
||||
"days": [
|
||||
6,
|
||||
7
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000040",
|
||||
"kind": "time_range",
|
||||
"x": 250,
|
||||
"y": 90,
|
||||
"config": {
|
||||
"start": "08:00",
|
||||
"end": "23:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000041",
|
||||
"kind": "house_mode",
|
||||
"x": 40,
|
||||
"y": 220,
|
||||
"config": {
|
||||
"operator": "neq",
|
||||
"value": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000042",
|
||||
"kind": "logic_and",
|
||||
"x": 465,
|
||||
"y": 145,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000043",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 710,
|
||||
"y": 145,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000044",
|
||||
"from": "node-00000000-0000-4000-8000-000000000039",
|
||||
"to": "node-00000000-0000-4000-8000-000000000042"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000045",
|
||||
"from": "node-00000000-0000-4000-8000-000000000040",
|
||||
"to": "node-00000000-0000-4000-8000-000000000042"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000046",
|
||||
"from": "node-00000000-0000-4000-8000-000000000041",
|
||||
"to": "node-00000000-0000-4000-8000-000000000042"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000047",
|
||||
"from": "node-00000000-0000-4000-8000-000000000042",
|
||||
"to": "node-00000000-0000-4000-8000-000000000043"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"id": "window_available_guard",
|
||||
"category": "safety",
|
||||
"name": {
|
||||
"pl": "Okno: dostępność + otwarcie",
|
||||
"en": "Window availability + open state"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Wyłącza HVAC dopiero gdy czujnik okna jest dostępny i zgłasza otwarcie — bez fałszywej reakcji na unavailable.",
|
||||
"en": "Turns HVAC off only when the window sensor is available and reports open, avoiding false reactions to unavailable."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000118",
|
||||
"kind": "ha_available",
|
||||
"x": 35,
|
||||
"y": 80,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000119",
|
||||
"kind": "ha_state",
|
||||
"x": 35,
|
||||
"y": 210,
|
||||
"config": {
|
||||
"entity_id": "binary_sensor.window",
|
||||
"operator": "eq",
|
||||
"value": "on"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000120",
|
||||
"kind": "logic_and",
|
||||
"x": 310,
|
||||
"y": 145,
|
||||
"config": {}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000121",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 565,
|
||||
"y": 145,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "auto",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 60,
|
||||
"power": false
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000122",
|
||||
"from": "node-00000000-0000-4000-8000-000000000118",
|
||||
"to": "node-00000000-0000-4000-8000-000000000120"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000123",
|
||||
"from": "node-00000000-0000-4000-8000-000000000119",
|
||||
"to": "node-00000000-0000-4000-8000-000000000120"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000124",
|
||||
"from": "node-00000000-0000-4000-8000-000000000120",
|
||||
"to": "node-00000000-0000-4000-8000-000000000121"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"id": "workday_comfort",
|
||||
"category": "comfort",
|
||||
"name": {
|
||||
"pl": "Komfort w dni robocze",
|
||||
"en": "Workday comfort"
|
||||
},
|
||||
"description": {
|
||||
"pl": "Pon.–pt. rano uruchamia preset komfortu w wybranej strefie.",
|
||||
"en": "Weekday morning comfort preset for the selected thermostat zone."
|
||||
},
|
||||
"flow": {
|
||||
"nodes": [
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000001",
|
||||
"kind": "weekday",
|
||||
"x": 40,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"days": [
|
||||
1,
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
5
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000002",
|
||||
"kind": "time_range",
|
||||
"x": 250,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"start": "06:00",
|
||||
"end": "08:30"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "node-00000000-0000-4000-8000-000000000003",
|
||||
"kind": "zone_thermostat",
|
||||
"x": 500,
|
||||
"y": 70,
|
||||
"config": {
|
||||
"zone_id": "$zone1",
|
||||
"preset": "comfort",
|
||||
"setpoint": 21,
|
||||
"mode": "auto",
|
||||
"cooldown_seconds": 90
|
||||
}
|
||||
}
|
||||
],
|
||||
"edges": [
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000004",
|
||||
"from": "node-00000000-0000-4000-8000-000000000001",
|
||||
"to": "node-00000000-0000-4000-8000-000000000002"
|
||||
},
|
||||
{
|
||||
"id": "edge-00000000-0000-4000-8000-000000000005",
|
||||
"from": "node-00000000-0000-4000-8000-000000000002",
|
||||
"to": "node-00000000-0000-4000-8000-000000000003"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -135,6 +135,8 @@ pub fn router(state: AppState) -> Router {
|
||||
.route("/flows/:id", get(index))
|
||||
.route("/lang/index.json", get(language_index))
|
||||
.route("/lang/:file", get(language_file))
|
||||
.route("/presets/index.json", get(preset_index))
|
||||
.route("/presets/:file", get(preset_file))
|
||||
.merge(protected)
|
||||
.merge(home_assistant_api);
|
||||
|
||||
|
||||
@@ -69,6 +69,18 @@ async fn language_file(Path(file): Path<String>) -> Response {
|
||||
response.headers_mut().insert(header::CONTENT_TYPE, HeaderValue::from_static("text/plain; charset=utf-8"));
|
||||
response
|
||||
}
|
||||
async fn preset_index() -> Response {
|
||||
static_response(PRESET_MANIFEST_JSON, "application/json; charset=utf-8", "no-cache")
|
||||
}
|
||||
async fn preset_file(Path(file): Path<String>) -> Response {
|
||||
if let Some((_, body)) = PRESET_ASSETS.iter().find(|(filename, _)| *filename == file) {
|
||||
return static_response(*body, "application/json; charset=utf-8", "no-cache");
|
||||
}
|
||||
let mut response = Response::new(Body::from("Preset not found"));
|
||||
*response.status_mut() = StatusCode::NOT_FOUND;
|
||||
response.headers_mut().insert(header::CONTENT_TYPE, HeaderValue::from_static("text/plain; charset=utf-8"));
|
||||
response
|
||||
}
|
||||
fn static_response(body: &'static str, content_type: &'static str, cache: &'static str) -> Response {
|
||||
let mut response = Response::new(Body::from(body));
|
||||
response.headers_mut().insert(header::CONTENT_TYPE, HeaderValue::from_static(content_type));
|
||||
|
||||
+6
-4
@@ -184,7 +184,8 @@
|
||||
</div>
|
||||
<div class="panel flow-info-panel">
|
||||
<div><strong data-i18n="flow.infoTitle">One place for schedules and automations</strong>
|
||||
<p data-i18n="flow.infoText">Build the logic from blocks. GREE Controller translates Flow into generated schedules and automations. Generated entries are read-only outside this editor.</p></div>
|
||||
<p data-i18n="flow.infoText">Build the logic from blocks. GREE Controller translates Flow into generated schedules and automations. Generated entries are read-only outside this editor.</p>
|
||||
<button type="button" class="secondary flow-shared-settings-link" data-action="flow-shared-input-settings" data-i18n="flow.sharedInputsSettingsLink">Wspólne wejścia Flow w Home Assistant →</button></div>
|
||||
<span class="badge" data-i18n="flow.sourceOfTruth">Flow = source of truth</span>
|
||||
</div>
|
||||
<section class="flow-list-section">
|
||||
@@ -394,8 +395,8 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel settings-block flow-shared-settings">
|
||||
<div class="settings-block-head"><div><h3 data-i18n="flow.sharedInputsTitle">Wspólne wejścia Flow</h3><p data-i18n="flow.sharedInputsHint">Zdefiniuj stałe i warunki czujników raz, a potem używaj ich w wielu Flow.</p></div><button type="button" class="primary" id="addFlowSharedInput" data-i18n="flow.sharedInputAdd">Dodaj wejście</button></div>
|
||||
<section class="panel settings-block flow-shared-settings" id="flowSharedInputsSettings">
|
||||
<div class="settings-block-head flow-shared-settings-head"><div><h3 data-i18n="flow.sharedInputsTitle">Wspólne wejścia Flow</h3><p data-i18n="flow.sharedInputsHint">Zdefiniuj stałe i warunki czujników raz, a potem używaj ich w wielu Flow.</p></div><button type="button" class="primary flow-shared-add-button" id="addFlowSharedInput" data-i18n="flow.sharedInputAdd">Dodaj wejście</button></div>
|
||||
<input type="hidden" id="flowSharedInputsRevision" name="flow_inputs_revision" value="[]"><div id="flowSharedInputList" class="flow-shared-input-list"></div>
|
||||
</section>
|
||||
|
||||
@@ -727,13 +728,14 @@
|
||||
<label><span data-i18n="common.name">Nazwa</span><input name="name" maxlength="100" required placeholder="Okno w salonie zamknięte"></label>
|
||||
<label><span data-i18n="flow.sharedInputType">Typ źródła</span><select name="kind" id="flowSharedInputKind"></select></label>
|
||||
<div id="flowSharedInputFields" class="flow-shared-input-fields"></div>
|
||||
<div class="dialog-actions"><button type="button" class="secondary" data-close data-i18n="actions.cancel">Anuluj</button><button type="submit" class="primary" data-i18n="actions.save">Zapisz</button></div>
|
||||
<div class="dialog-actions flow-shared-dialog-actions"><button type="button" class="secondary" data-close data-i18n="actions.cancel">Anuluj</button><button type="submit" class="primary" data-i18n="actions.save">Zapisz</button></div>
|
||||
</form>
|
||||
</dialog>
|
||||
|
||||
<dialog id="flowTemplateDialog" class="flow-tool-dialog">
|
||||
<div class="dialog-head"><div><span class="eyebrow" data-i18n="flow.templateLibrary">Flow library</span><h2 data-i18n="flow.templates">Templates</h2></div><button type="button" data-close>×</button></div>
|
||||
<p class="field-note" data-i18n="flow.templatesHint">Ready-made layouts create an editable graph using existing zones, devices and groups.</p>
|
||||
<div id="flowTemplateTabs" class="flow-template-tabs" role="tablist" data-i18n-aria="flow.templateCategories" aria-label="Preset categories"></div>
|
||||
<div id="flowTemplateList" class="flow-template-list"></div>
|
||||
</dialog>
|
||||
|
||||
|
||||
+125
-103
@@ -302,117 +302,128 @@ async function importFlowFile(file) {
|
||||
finally { const input = $('#flowImportFile'); if (input) input.value = ''; }
|
||||
}
|
||||
|
||||
function flowTemplateGraph(key) {
|
||||
const zone = app.zones[0]?.id || '', zone2 = app.zones[1]?.id || zone, device = app.devices[0]?.id || '', group = app.groups[0]?.id || '';
|
||||
const nodes = [], edges = [];
|
||||
const add = (kind, x, y, config = flowDefaultConfig(kind)) => { const node = { id:newFlowId('node'), kind, x, y, config:{ ...config } }; nodes.push(node); return node; };
|
||||
const link = (a, b) => edges.push({ id:newFlowId('edge'), from:a.id, to:b.id });
|
||||
const links = (items, target) => items.forEach(item => link(item, target));
|
||||
const thermostat = (x, y, config = {}) => add('zone_thermostat', x, y, { zone_id:zone, preset:'comfort', setpoint:21, mode:'auto', cooldown_seconds:90, ...config });
|
||||
const groupOrZone = (x, y, config = {}) => group
|
||||
? add('group_action', x, y, { group_id:group, power:null, mode:'auto', preset:'comfort', setpoint:21, cooldown_seconds:120, ...config })
|
||||
: thermostat(x, y, config);
|
||||
const titleKey = `flow.template.${key}.title`, descriptionKey = `flow.template.${key}.description`;
|
||||
const FLOW_PRESET_CATEGORY_ORDER = ['comfort','energy','safety','night','reliability','home_assistant','advanced'];
|
||||
let flowPresetLoadPromise = null;
|
||||
let flowPresetActiveCategory = '';
|
||||
|
||||
if (key === 'workday_comfort') {
|
||||
const days=add('weekday',40,70), time=add('time_range',250,70,{start:'06:00',end:'08:30'}), action=thermostat(500,70); link(days,time); link(time,action);
|
||||
} else if (key === 'weather_comfort') {
|
||||
const days=add('weekday',35,40), time=add('time_range',35,155,{start:'06:00',end:'22:30'}), outside=add('outdoor_temperature',35,270,{operator:'lt',value:12}), and=add('logic_and',300,155), action=thermostat(555,155); links([days,time,outside],and); link(and,action);
|
||||
} else if (key === 'smart_demand') {
|
||||
const time=add('time_range',30,40,{start:'05:30',end:'23:00'}), outside=add('outdoor_temperature',30,160,{operator:'lt',value:10}), room=add('zone_temperature',30,280,{zone_id:zone,operator:'lt',value:20}), or=add('logic_or',280,220), mode=add('house_mode',280,70,{operator:'neq',value:'off'}), and=add('logic_and',510,155), action=thermostat(760,155); links([outside,room],or); links([time,mode,or],and); link(and,action);
|
||||
} else if (key === 'morning_boost') {
|
||||
const days=add('weekday',35,50), time=add('time_range',35,170,{start:'05:30',end:'07:30'}), cold=add('outdoor_temperature',35,290,{operator:'lt',value:5}), heat=add('house_mode',35,410,{operator:'eq',value:'heat'}), and=add('logic_and',320,220), action=thermostat(585,220,{preset:'custom',setpoint:22.5,mode:'heat',cooldown_seconds:180}); links([days,time,cold,heat],and); link(and,action);
|
||||
} else if (key === 'weekend_comfort') {
|
||||
const days=add('weekday',40,90,{days:[6,7]}), time=add('time_range',250,90,{start:'08:00',end:'23:00'}), mode=add('house_mode',40,220,{operator:'neq',value:'off'}), and=add('logic_and',465,145), action=thermostat(710,145); links([days,time,mode],and); link(and,action);
|
||||
} else if (key === 'presence_eco') {
|
||||
const home=add('ha_state',45,75,{entity_id:'person.someone',operator:'eq',value:'home'}), away=add('ha_state',45,245,{entity_id:'person.someone',operator:'eq',value:'not_home'}), comfort=thermostat(360,65), eco=thermostat(360,245,{preset:'away',setpoint:18,cooldown_seconds:180}); link(home,comfort); link(away,eco);
|
||||
} else if (key === 'energy_price_eco') {
|
||||
const price=add('ha_numeric',40,70,{entity_id:'sensor.energy_price',operator:'gt',value:0.8}), occupied=add('ha_state',40,190,{entity_id:'person.someone',operator:'neq',value:'home'}), and=add('logic_and',315,130), action=thermostat(570,130,{preset:'away',setpoint:18,cooldown_seconds:300}); links([price,occupied],and); link(and,action);
|
||||
} else if (key === 'peak_power_guard') {
|
||||
const power=add('ha_numeric',40,75,{entity_id:'sensor.house_power',operator:'gt',value:5000}), mode=add('house_mode',40,200,{operator:'neq',value:'off'}), and=add('logic_and',315,140), action=thermostat(570,140,{power:false,preset:'auto',cooldown_seconds:180}); links([power,mode],and); link(and,action);
|
||||
} else if (key === 'mild_weather_eco') {
|
||||
const low=add('outdoor_temperature',35,55,{operator:'gte',value:17}), high=add('outdoor_temperature',35,175,{operator:'lte',value:24}), window=add('ha_state',35,295,{entity_id:'binary_sensor.window',operator:'eq',value:'off'}), and=add('logic_and',310,175), action=thermostat(565,175,{power:false,preset:'auto',cooldown_seconds:300}); links([low,high,window],and); link(and,action);
|
||||
} else if (key === 'unoccupied_shutdown') {
|
||||
const away=add('ha_state',35,70,{entity_id:'person.someone',operator:'eq',value:'not_home'}), time=add('time_range',35,190,{start:'09:00',end:'16:00'}), and=add('logic_and',310,130), action=group ? add('group_action',565,130,{group_id:group,power:false,mode:'',preset:'',setpoint:21,cooldown_seconds:300}) : thermostat(565,130,{power:false,preset:'away',cooldown_seconds:300}); links([away,time],and); link(and,action);
|
||||
} else if (key === 'frost_guard') {
|
||||
const heat=add('house_mode',35,50,{operator:'eq',value:'heat'}), outside=add('outdoor_temperature',35,170,{operator:'lt',value:3}), room=add('zone_temperature',35,290,{zone_id:zone,operator:'lt',value:9}), and=add('logic_and',315,170), action=thermostat(575,170,{preset:'custom',setpoint:12,mode:'heat',cooldown_seconds:300}); links([heat,outside,room],and); link(and,action);
|
||||
} else if (key === 'ha_window_guard') {
|
||||
const open=add('ha_state',45,90,{entity_id:'binary_sensor.window',operator:'eq',value:'on'}), mode=add('house_mode',45,220,{operator:'neq',value:'off'}), and=add('logic_and',305,155), action=thermostat(560,155,{power:false,preset:'auto',cooldown_seconds:60}); links([open,mode],and); link(and,action);
|
||||
} else if (key === 'humidity_guard') {
|
||||
const humidity=add('ha_numeric',40,60,{entity_id:'sensor.living_room_humidity',operator:'gt',value:70}), cool=add('house_mode',40,180,{operator:'eq',value:'cool'}), occupied=add('ha_state',40,300,{entity_id:'person.someone',operator:'eq',value:'home'}), and=add('logic_and',315,180), action=thermostat(575,180,{preset:'custom',setpoint:22,mode:'cool',cooldown_seconds:180}); links([humidity,cool,occupied],and); link(and,action);
|
||||
} else if (key === 'overheat_guard') {
|
||||
const room=add('zone_temperature',35,65,{zone_id:zone,operator:'gt',value:28}), cool=add('house_mode',35,185,{operator:'eq',value:'cool'}), window=add('ha_state',35,305,{entity_id:'binary_sensor.window',operator:'eq',value:'off'}), and=add('logic_and',310,185), action=thermostat(570,185,{preset:'custom',setpoint:22,mode:'cool',cooldown_seconds:120}); links([room,cool,window],and); link(and,action);
|
||||
} else if (key === 'window_available_guard') {
|
||||
const available=add('ha_available',35,80,{entity_id:'binary_sensor.window'}), open=add('ha_state',35,210,{entity_id:'binary_sensor.window',operator:'eq',value:'on'}), and=add('logic_and',310,145), action=thermostat(565,145,{power:false,preset:'auto',cooldown_seconds:60}); links([available,open],and); link(and,action);
|
||||
} else if (key === 'night_group') {
|
||||
const time=add('time_range',50,100,{start:'22:30',end:'06:00'}), mode=add('house_mode',50,230,{operator:'neq',value:'off'}), and=add('logic_and',315,165), action=groupOrZone(570,165,{power:true,preset:'sleep',setpoint:20,cooldown_seconds:120}); links([time,mode],and); link(and,action);
|
||||
} else if (key === 'night_quiet') {
|
||||
const night=add('night_mode',45,90), and=add('logic_and',310,155), action=groupOrZone(565,155,{preset:'sleep',setpoint:20,cooldown_seconds:180}); link(night,and); if (group) { const on=add('group_state',45,225,{group_id:group,field:'power_enabled',operator:'eq',value:'true'}); link(on,and); } link(and,action);
|
||||
} else if (key === 'sleep_temperature_guard') {
|
||||
const night=add('night_mode',35,55), room=add('zone_temperature',35,175,{zone_id:zone,operator:'gt',value:23.5}), cool=add('house_mode',35,295,{operator:'eq',value:'cool'}), and=add('logic_and',310,175), action=thermostat(570,175,{preset:'sleep',setpoint:20,mode:'cool',cooldown_seconds:180}); links([night,room,cool],and); link(and,action);
|
||||
} else if (key === 'bedroom_window_night') {
|
||||
const night=add('night_mode',35,65), open=add('ha_state',35,185,{entity_id:'binary_sensor.bedroom_window',operator:'eq',value:'on'}), not=add('logic_not',275,185), and=add('logic_and',500,125), action=thermostat(745,125,{preset:'sleep',setpoint:20,cooldown_seconds:180}); link(open,not); links([night,not],and); link(and,action);
|
||||
} else if (key === 'device_resilience') {
|
||||
const online=add('device_state',40,55,{device_id:device,field:'online',operator:'eq',value:'true'}), enabled=add('device_state',40,175,{device_id:device,field:'enabled',operator:'eq',value:'true'}), mode=add('house_mode',40,295,{operator:'neq',value:'off'}), and=add('logic_and',315,175), action=thermostat(570,175,{preset:'auto'}); links([online,enabled,mode],and); link(and,action);
|
||||
} else if (key === 'sensor_availability_guard') {
|
||||
const available=add('ha_available',35,55,{entity_id:'sensor.room_temperature'}), temp=add('ha_numeric',35,175,{entity_id:'sensor.room_temperature',operator:'gt',value:26}), cool=add('house_mode',35,295,{operator:'eq',value:'cool'}), and=add('logic_and',310,175), action=thermostat(570,175,{preset:'comfort',mode:'cool',cooldown_seconds:120}); links([available,temp,cool],and); link(and,action);
|
||||
} else if (key === 'offline_safe_off') {
|
||||
const offline=add('device_state',35,85,{device_id:device,field:'online',operator:'eq',value:'false'}), enabled=add('zone_state',35,215,{zone_id:zone,field:'enabled',operator:'eq',value:'true'}), and=add('logic_and',310,150), action=thermostat(565,150,{power:false,preset:'auto',cooldown_seconds:300}); links([offline,enabled],and); link(and,action);
|
||||
} else if (key === 'thermostat_enabled_guard') {
|
||||
const enabled=add('zone_state',35,55,{zone_id:zone,field:'enabled',operator:'eq',value:'true'}), demand=add('zone_state',35,175,{zone_id:zone,field:'demand',operator:'eq',value:'true'}), mode=add('house_mode',35,295,{operator:'neq',value:'off'}), and=add('logic_and',310,175), action=thermostat(570,175,{preset:'auto',cooldown_seconds:120}); links([enabled,demand,mode],and); link(and,action);
|
||||
} else if (key === 'nested_guard') {
|
||||
const days=add('weekday',25,35), time=add('time_range',25,145,{start:'06:00',end:'22:30'}), outside=add('outdoor_temperature',25,255,{operator:'lt',value:8}), room=add('zone_temperature',25,365,{zone_id:zone,operator:'lt',value:20}), or=add('logic_or',275,310), available=add('ha_available',275,430,{entity_id:'binary_sensor.window'}), window=add('ha_state',275,540,{entity_id:'binary_sensor.window',operator:'eq',value:'on'}), not=add('logic_not',495,540), and=add('logic_and',510,235), action=thermostat(770,235); links([outside,room],or); link(window,not); links([days,time,or,available,not],and); link(and,action);
|
||||
} else if (key === 'occupancy_weather_matrix') {
|
||||
const home=add('ha_state',25,40,{entity_id:'person.someone',operator:'eq',value:'home'}), outside=add('outdoor_temperature',25,155,{operator:'lt',value:9}), room=add('zone_temperature',25,270,{zone_id:zone,operator:'lt',value:20}), need=add('logic_or',275,215), window=add('ha_state',275,345,{entity_id:'binary_sensor.window',operator:'eq',value:'on'}), not=add('logic_not',495,345), and=add('logic_and',505,150), action=thermostat(765,150); links([outside,room],need); link(window,not); links([home,need,not],and); link(and,action);
|
||||
} else if (key === 'dual_threshold_control') {
|
||||
const cold=add('zone_temperature',35,70,{zone_id:zone,operator:'lt',value:19}), hot=add('zone_temperature',35,245,{zone_id:zone,operator:'gt',value:25}), heat=add('house_mode',250,70,{operator:'eq',value:'heat'}), cool=add('house_mode',250,245,{operator:'eq',value:'cool'}), andHeat=add('logic_and',470,70), andCool=add('logic_and',470,245), heatAction=thermostat(715,70,{preset:'comfort',mode:'heat'}), coolAction=thermostat(715,245,{preset:'comfort',mode:'cool'}); links([cold,heat],andHeat); links([hot,cool],andCool); link(andHeat,heatAction); link(andCool,coolAction);
|
||||
} else if (key === 'multi_room_group_guard') {
|
||||
const roomA=add('zone_temperature',30,55,{zone_id:zone,operator:'gt',value:25}), roomB=add('zone_temperature',30,175,{zone_id:zone2,operator:'gt',value:25}), need=add('logic_or',280,115), cool=add('house_mode',280,245,{operator:'eq',value:'cool'}), and=add('logic_and',505,175), action=groupOrZone(760,175,{power:true,preset:'comfort',setpoint:22,cooldown_seconds:120}); links([roomA,roomB],need); links([need,cool],and); link(and,action);
|
||||
} else if (key === 'ha_attribute_mode_guard') {
|
||||
const running=add('ha_attribute',35,60,{entity_id:'climate.living_room',attribute:'hvac_action',operator:'neq',value:'idle'}), window=add('ha_state',35,180,{entity_id:'binary_sensor.window',operator:'eq',value:'on'}), available=add('ha_available',35,300,{entity_id:'climate.living_room'}), and=add('logic_and',315,180), action=thermostat(575,180,{power:false,preset:'auto',cooldown_seconds:60}); links([running,window,available],and); link(and,action);
|
||||
} else if (key === 'ha_gas_heating_off') {
|
||||
const available=add('ha_available',35,70,{entity_id:'climate.gas_boiler'}), heating=add('ha_attribute',35,200,{entity_id:'climate.gas_boiler',attribute:'hvac_action',operator:'eq',value:'heating'}), and=add('logic_and',315,135), action=thermostat(575,135,{power:false,preset:'auto',cooldown_seconds:120}); links([available,heating],and); link(and,action);
|
||||
} else if (key === 'ha_gas_heating_boost') {
|
||||
const available=add('ha_available',25,35,{entity_id:'climate.gas_boiler'}), heating=add('ha_attribute',25,145,{entity_id:'climate.gas_boiler',attribute:'hvac_action',operator:'eq',value:'heating'}), cold=add('zone_temperature',25,255,{zone_id:zone,operator:'lt',value:20}), heat=add('house_mode',25,365,{operator:'eq',value:'heat'}), and=add('logic_and',320,200), action=thermostat(590,200,{power:true,preset:'custom',setpoint:23.5,mode:'heat',cooldown_seconds:180}); links([available,heating,cold,heat],and); link(and,action);
|
||||
} else if (key === 'ha_gas_heating_reduce') {
|
||||
const available=add('ha_available',35,50,{entity_id:'climate.gas_boiler'}), heating=add('ha_attribute',35,165,{entity_id:'climate.gas_boiler',attribute:'hvac_action',operator:'eq',value:'heating'}), warm=add('zone_temperature',35,280,{zone_id:zone,operator:'gte',value:21}), and=add('logic_and',315,165), action=thermostat(575,165,{power:true,preset:'custom',setpoint:18,mode:'heat',cooldown_seconds:180}); links([available,heating,warm],and); link(and,action);
|
||||
} else if (key === 'ha_gas_backup_heat') {
|
||||
const available=add('ha_available',25,40,{entity_id:'climate.gas_boiler'}), idle=add('ha_attribute',25,155,{entity_id:'climate.gas_boiler',attribute:'hvac_action',operator:'neq',value:'heating'}), cold=add('zone_temperature',25,270,{zone_id:zone,operator:'lt',value:19}), heat=add('house_mode',25,385,{operator:'eq',value:'heat'}), and=add('logic_and',320,210), action=thermostat(590,210,{power:true,preset:'custom',setpoint:22,mode:'heat',cooldown_seconds:180}); links([available,idle,cold,heat],and); link(and,action);
|
||||
} else if (key === 'ha_external_heat_source_off') {
|
||||
const available=add('ha_available',35,70,{entity_id:'binary_sensor.external_heat_source'}), active=add('ha_state',35,200,{entity_id:'binary_sensor.external_heat_source',operator:'eq',value:'on'}), and=add('logic_and',315,135), action=groupOrZone(575,135,{power:false,preset:'auto',cooldown_seconds:120}); links([available,active],and); link(and,action);
|
||||
} else if (key === 'ha_external_heat_source_assist') {
|
||||
const available=add('ha_available',25,40,{entity_id:'binary_sensor.external_heat_source'}), active=add('ha_state',25,155,{entity_id:'binary_sensor.external_heat_source',operator:'eq',value:'on'}), cold=add('zone_temperature',25,270,{zone_id:zone,operator:'lt',value:20}), heat=add('house_mode',25,385,{operator:'eq',value:'heat'}), and=add('logic_and',320,210), action=thermostat(590,210,{power:true,preset:'custom',setpoint:23,mode:'heat',cooldown_seconds:180}); links([available,active,cold,heat],and); link(and,action);
|
||||
} else if (key === 'ha_heating_demand_follow') {
|
||||
const available=add('ha_available',35,60,{entity_id:'binary_sensor.heating_demand'}), demand=add('ha_state',35,180,{entity_id:'binary_sensor.heating_demand',operator:'eq',value:'on'}), heat=add('house_mode',35,300,{operator:'eq',value:'heat'}), and=add('logic_and',315,180), action=thermostat(575,180,{power:true,preset:'custom',setpoint:22.5,mode:'heat',cooldown_seconds:120}); links([available,demand,heat],and); link(and,action);
|
||||
} else if (key === 'ha_boiler_supply_boost') {
|
||||
const available=add('ha_available',25,45,{entity_id:'sensor.boiler_supply_temperature'}), supply=add('ha_numeric',25,160,{entity_id:'sensor.boiler_supply_temperature',operator:'gt',value:45}), cold=add('zone_temperature',25,275,{zone_id:zone,operator:'lt',value:20}), heat=add('house_mode',25,390,{operator:'eq',value:'heat'}), and=add('logic_and',320,215), action=thermostat(590,215,{power:true,preset:'custom',setpoint:23.5,mode:'heat',cooldown_seconds:180}); links([available,supply,cold,heat],and); link(and,action);
|
||||
} else if (key === 'ha_thermostat_idle_fallback') {
|
||||
const available=add('ha_available',25,40,{entity_id:'climate.gas_boiler'}), idle=add('ha_attribute',25,155,{entity_id:'climate.gas_boiler',attribute:'hvac_action',operator:'eq',value:'idle'}), cold=add('zone_temperature',25,270,{zone_id:zone,operator:'lt',value:19}), heat=add('house_mode',25,385,{operator:'eq',value:'heat'}), and=add('logic_and',320,210), action=thermostat(590,210,{power:true,preset:'custom',setpoint:21.5,mode:'heat',cooldown_seconds:240}); links([available,idle,cold,heat],and); link(and,action);
|
||||
|
||||
function flowPresetText(value) {
|
||||
if (typeof value === 'string') return value;
|
||||
if (!value || typeof value !== 'object') return '';
|
||||
return value[app.language] || value.en || value.pl || Object.values(value).find(item => typeof item === 'string') || '';
|
||||
}
|
||||
|
||||
async function loadFlowPresets({ force = false } = {}) {
|
||||
if (!force && Array.isArray(app.flowPresets)) return app.flowPresets;
|
||||
if (!force && flowPresetLoadPromise) return flowPresetLoadPromise;
|
||||
flowPresetLoadPromise = (async () => {
|
||||
const indexResponse = await fetch(withBase('/presets/index.json'), { headers: { Accept: 'application/json' }, cache: 'no-store' });
|
||||
if (!indexResponse.ok) throw new Error(`Presets HTTP ${indexResponse.status}`);
|
||||
const manifest = await indexResponse.json();
|
||||
const entries = Array.isArray(manifest?.presets) ? manifest.presets : [];
|
||||
const presets = await Promise.all(entries.map(async entry => {
|
||||
const filename = String(entry?.file || '');
|
||||
if (!filename || !/^[a-zA-Z0-9_-]+\.json$/.test(filename)) throw new Error('Invalid preset filename');
|
||||
const response = await fetch(withBase(`/presets/${encodeURIComponent(filename)}`), { headers: { Accept: 'application/json' }, cache: 'no-store' });
|
||||
if (!response.ok) throw new Error(`${filename}: HTTP ${response.status}`);
|
||||
const preset = await response.json();
|
||||
if (!preset?.id || !preset?.flow || !Array.isArray(preset.flow.nodes) || !Array.isArray(preset.flow.edges)) throw new Error(`${filename}: invalid preset`);
|
||||
return preset;
|
||||
}));
|
||||
app.flowPresets = presets;
|
||||
return presets;
|
||||
})();
|
||||
try { return await flowPresetLoadPromise; }
|
||||
finally { flowPresetLoadPromise = null; }
|
||||
}
|
||||
|
||||
function materializeFlowPreset(preset) {
|
||||
const zone1 = app.zones[0]?.id || '';
|
||||
const variables = {
|
||||
'$zone1': zone1,
|
||||
'$zone2': app.zones[1]?.id || zone1,
|
||||
'$device1': app.devices[0]?.id || '',
|
||||
'$group1': app.groups[0]?.id || '',
|
||||
'$shared1': app.flowSharedInputs?.[0]?.id || '',
|
||||
};
|
||||
const replaceValue = value => {
|
||||
if (typeof value === 'string' && Object.prototype.hasOwnProperty.call(variables, value)) return variables[value];
|
||||
if (Array.isArray(value)) return value.map(replaceValue);
|
||||
if (value && typeof value === 'object') return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, replaceValue(item)]));
|
||||
return value;
|
||||
};
|
||||
const sourceNodes = Array.isArray(preset?.flow?.nodes) ? preset.flow.nodes : [];
|
||||
const sourceEdges = Array.isArray(preset?.flow?.edges) ? preset.flow.edges : [];
|
||||
const skipped = new Set();
|
||||
const idMap = new Map();
|
||||
const nodes = [];
|
||||
sourceNodes.forEach(source => {
|
||||
const originalConfig = source.config || {};
|
||||
if (source.kind === 'group_state' && originalConfig.group_id === '$group1' && !variables.$group1) { skipped.add(source.id); return; }
|
||||
const node = { ...source, id: newFlowId('node'), config: replaceValue(originalConfig) };
|
||||
if (source.kind === 'group_action' && originalConfig.group_id === '$group1' && !variables.$group1) {
|
||||
node.kind = 'zone_thermostat';
|
||||
node.config = {
|
||||
zone_id: zone1,
|
||||
preset: node.config.preset || 'comfort',
|
||||
setpoint: Number(node.config.setpoint ?? 21),
|
||||
mode: ['heat','cool'].includes(node.config.mode) ? node.config.mode : 'auto',
|
||||
cooldown_seconds: Number(node.config.cooldown_seconds || 60),
|
||||
power: node.config.power ?? null,
|
||||
};
|
||||
}
|
||||
return { titleKey, descriptionKey, nodes, edges };
|
||||
idMap.set(source.id, node.id);
|
||||
nodes.push(node);
|
||||
});
|
||||
const edges = sourceEdges
|
||||
.filter(edge => !skipped.has(edge.from) && !skipped.has(edge.to) && idMap.has(edge.from) && idMap.has(edge.to))
|
||||
.map(edge => ({ id:newFlowId('edge'), from:idMap.get(edge.from), to:idMap.get(edge.to) }));
|
||||
return { nodes, edges };
|
||||
}
|
||||
|
||||
const FLOW_TEMPLATE_CATEGORIES = [
|
||||
['comfort', ['workday_comfort','weather_comfort','smart_demand','morning_boost','weekend_comfort']],
|
||||
['energy', ['presence_eco','energy_price_eco','peak_power_guard','mild_weather_eco','unoccupied_shutdown']],
|
||||
['safety', ['frost_guard','ha_window_guard','humidity_guard','overheat_guard','window_available_guard']],
|
||||
['night', ['night_group','night_quiet','sleep_temperature_guard','bedroom_window_night']],
|
||||
['reliability', ['device_resilience','sensor_availability_guard','offline_safe_off','thermostat_enabled_guard']],
|
||||
['home_assistant', ['ha_gas_heating_off','ha_gas_heating_boost','ha_gas_heating_reduce','ha_gas_backup_heat','ha_external_heat_source_off','ha_external_heat_source_assist','ha_heating_demand_follow','ha_boiler_supply_boost','ha_thermostat_idle_fallback']],
|
||||
['advanced', ['nested_guard','occupancy_weather_matrix','dual_threshold_control','multi_room_group_guard','ha_attribute_mode_guard']],
|
||||
];
|
||||
function openFlowTemplates() {
|
||||
if (!app.flowDraft) return;
|
||||
const host = $('#flowTemplateList');
|
||||
host.innerHTML = FLOW_TEMPLATE_CATEGORIES.map(([category, keys]) => `<section class="flow-template-category"><div class="flow-template-category-head"><strong>${esc(tr(`flow.templateCategory.${category}`))}</strong><span>${esc(tr(`flow.templateCategory.${category}.hint`))}</span></div><div class="flow-template-category-grid">${keys.map(key => `<button type="button" class="flow-template-card" data-flow-template="${esc(key)}"><strong>${esc(tr(`flow.template.${key}.title`))}</strong><span>${esc(tr(`flow.template.${key}.description`))}</span></button>`).join('')}</div></section>`).join('');
|
||||
$('#flowTemplateDialog')?.showModal();
|
||||
function renderFlowPresetBrowser(category = '') {
|
||||
const tabs = $('#flowTemplateTabs'), host = $('#flowTemplateList');
|
||||
if (!tabs || !host) return;
|
||||
const presets = Array.isArray(app.flowPresets) ? app.flowPresets : [];
|
||||
const byCategory = new Map();
|
||||
presets.forEach(preset => {
|
||||
const key = preset.category || 'advanced';
|
||||
if (!byCategory.has(key)) byCategory.set(key, []);
|
||||
byCategory.get(key).push(preset);
|
||||
});
|
||||
const categories = [...new Set([...FLOW_PRESET_CATEGORY_ORDER, ...byCategory.keys()])].filter(key => byCategory.has(key));
|
||||
if (!categories.length) { tabs.innerHTML = ''; host.innerHTML = ''; return; }
|
||||
flowPresetActiveCategory = categories.includes(category) ? category : (categories.includes(flowPresetActiveCategory) ? flowPresetActiveCategory : categories[0]);
|
||||
tabs.innerHTML = categories.map(key => `<button type="button" class="flow-template-tab ${key === flowPresetActiveCategory ? 'active' : ''}" role="tab" aria-selected="${key === flowPresetActiveCategory}" data-flow-template-category="${esc(key)}">${esc(tr(`flow.templateCategory.${key}`) || key)} <span class="badge">${byCategory.get(key).length}</span></button>`).join('');
|
||||
const active = byCategory.get(flowPresetActiveCategory) || [];
|
||||
host.innerHTML = `<section class="flow-template-category-single"><div class="flow-template-category-head"><strong>${esc(tr(`flow.templateCategory.${flowPresetActiveCategory}`) || flowPresetActiveCategory)}</strong><span>${esc(tr(`flow.templateCategory.${flowPresetActiveCategory}.hint`) || '')}</span></div><div class="flow-template-category-grid">${active.map(preset => `<button type="button" class="flow-template-card" data-flow-template="${esc(preset.id)}"><strong>${esc(flowPresetText(preset.name) || preset.id)}</strong><span>${esc(flowPresetText(preset.description))}</span></button>`).join('')}</div></section>`;
|
||||
}
|
||||
|
||||
async function openFlowTemplates() {
|
||||
if (!app.flowDraft) return;
|
||||
const host = $('#flowTemplateList'), tabs = $('#flowTemplateTabs');
|
||||
if (!host) return;
|
||||
if (tabs) tabs.innerHTML = '';
|
||||
host.innerHTML = `<p class="field-note">${esc(tr('common.loading'))}</p>`;
|
||||
$('#flowTemplateDialog')?.showModal();
|
||||
try {
|
||||
await loadFlowPresets();
|
||||
renderFlowPresetBrowser(flowPresetActiveCategory);
|
||||
} catch (error) {
|
||||
if (tabs) tabs.innerHTML = '';
|
||||
host.innerHTML = `<div class="empty compact"><strong>${esc(tr('flow.templatesLoadFailed') || 'Unable to load presets')}</strong><span>${esc(error.message)}</span></div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function applyFlowTemplate(key) {
|
||||
if (!app.flowDraft) return;
|
||||
const preset = (app.flowPresets || []).find(item => item.id === key);
|
||||
if (!preset) return toast(tr('flow.templatesLoadFailed') || 'Preset not found', true);
|
||||
if (app.flowDraft.nodes.length && !confirm(tr('flow.templateReplaceConfirm'))) return;
|
||||
const template = flowTemplateGraph(key); app.flowDraft.nodes = template.nodes; app.flowDraft.edges = template.edges;
|
||||
app.flowDraft.description = tr(template.descriptionKey); app.flowSelectedNodeId = null; app.flowSelectedNodeIds = []; app.flowDirty = true;
|
||||
if (!app.flowDraft.id || $('#flowName').value === tr('flow.newDefaultName')) $('#flowName').value = tr(template.titleKey);
|
||||
const graph = materializeFlowPreset(preset);
|
||||
app.flowDraft.nodes = graph.nodes; app.flowDraft.edges = graph.edges;
|
||||
app.flowDraft.description = flowPresetText(preset.description); app.flowSelectedNodeId = null; app.flowSelectedNodeIds = []; app.flowDirty = true;
|
||||
if (!app.flowDraft.id || $('#flowName').value === tr('flow.newDefaultName')) $('#flowName').value = flowPresetText(preset.name) || preset.id;
|
||||
$('#flowTemplateDialog')?.close(); renderFlowEditor();
|
||||
}
|
||||
|
||||
@@ -585,6 +596,7 @@ document.addEventListener('keydown', event => {
|
||||
document.addEventListener('click', event => {
|
||||
const edge = event.target.closest?.('[data-flow-edge]'); if (edge) { removeFlowEdge(edge.dataset.flowEdge); return; }
|
||||
const add = event.target.closest?.('[data-flow-add]'); if (add) { addFlowNode(add.dataset.flowAdd); return; }
|
||||
const templateCategory = event.target.closest?.('[data-flow-template-category]'); if (templateCategory) { renderFlowPresetBrowser(templateCategory.dataset.flowTemplateCategory); return; }
|
||||
const template = event.target.closest?.('[data-flow-template]'); if (template) { applyFlowTemplate(template.dataset.flowTemplate); return; }
|
||||
const remove = event.target.closest?.('[data-flow-remove]'); if (remove) { removeFlowNode(remove.dataset.flowRemove); return; }
|
||||
const output = event.target.closest?.('[data-flow-output]'); if (output) { app.flowConnectFrom = output.dataset.flowOutput; renderFlowEditor(); return; }
|
||||
@@ -603,6 +615,16 @@ document.addEventListener('click', event => {
|
||||
else if (action === 'flow-logs') openFlowLogs();
|
||||
else if (action === 'flow-select-all') selectAllFlowNodes();
|
||||
else if (action === 'flow-clear-selection') clearFlowSelection();
|
||||
else if (action === 'flow-shared-input-settings') {
|
||||
if (!showView('homeassistant')) return;
|
||||
requestAnimationFrame(() => {
|
||||
const target = $('#flowSharedInputsSettings');
|
||||
if (!target) return;
|
||||
target.scrollIntoView({ behavior:'smooth', block:'start' });
|
||||
target.classList.add('is-linked-target');
|
||||
setTimeout(() => target.classList.remove('is-linked-target'), 1800);
|
||||
});
|
||||
}
|
||||
else if (action === 'close-flow-editor') closeFlowEditor();
|
||||
});
|
||||
document.addEventListener('change', event => {
|
||||
|
||||
@@ -6259,3 +6259,23 @@ body.flow-editor-open { overflow:hidden; }
|
||||
.flow-shared-input-actions button { flex:1; }
|
||||
.flow-shared-input-fields .two { grid-template-columns:1fr; }
|
||||
}
|
||||
|
||||
/* v0.9.9: Flow shared-input navigation and preset category tabs */
|
||||
.flow-shared-settings-head { justify-content:space-between; align-items:flex-start; }
|
||||
.flow-shared-settings-head > div { min-width:0; }
|
||||
.flow-shared-add-button { flex:0 0 auto; align-self:flex-start; margin-left:auto; }
|
||||
.flow-shared-dialog-actions { display:flex; align-items:center; justify-content:space-between; gap:24px; padding-top:14px; margin-top:4px; border-top:1px solid var(--line); }
|
||||
.flow-shared-dialog-actions > button { min-width:112px; }
|
||||
.flow-shared-settings-link { margin-top:12px; width:max-content; max-width:100%; }
|
||||
.flow-shared-settings.is-linked-target { outline:2px solid var(--accent); outline-offset:3px; }
|
||||
.flow-template-tabs { display:flex; gap:8px; overflow-x:auto; padding:4px 0 10px; margin-top:14px; border-bottom:1px solid var(--line); scrollbar-width:thin; }
|
||||
.flow-template-tab { flex:0 0 auto; border:1px solid var(--line); border-radius:999px; background:var(--surface-2); color:var(--muted); padding:8px 12px; white-space:nowrap; }
|
||||
.flow-template-tab.active { border-color:var(--accent-border); background:var(--accent-soft); color:var(--accent); }
|
||||
.flow-template-list { margin-top:14px; }
|
||||
.flow-template-category-single { display:grid; gap:12px; }
|
||||
.flow-template-category-single .flow-template-category-head { padding-bottom:2px; }
|
||||
@media (max-width:760px) {
|
||||
.flow-shared-settings-head { gap:12px; }
|
||||
.flow-shared-add-button { width:auto; }
|
||||
.flow-shared-dialog-actions { gap:16px; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user