[ { "id": "46892ced77481340", "type": "tab", "label": "Flow 1", "disabled": false, "info": "", "env": [] }, { "id": "7de41d810b04d992", "type": "tab", "label": "Living Room", "disabled": false, "info": "", "env": [] }, { "id": "480553bb6f5b2b51", "type": "tab", "label": "Notifications", "disabled": false, "info": "", "env": [] }, { "id": "f9a2fb576f0d360d", "type": "tab", "label": "Zigbee ", "disabled": false, "info": "", "env": [] }, { "id": "6722d185624fd57a", "type": "tab", "label": "Scheduler", "disabled": false, "info": "", "env": [] }, { "id": "7eef035843cf87db", "type": "tab", "label": "Flow 2", "disabled": false, "info": "", "env": [] }, { "id": "31693504fcbbd954", "type": "tab", "label": "Flow 3", "disabled": false, "info": "", "env": [] }, { "id": "50971c50479dfd7a", "type": "tab", "label": "Flow 4", "disabled": false, "info": "", "env": [] }, { "id": "a6a28d6b6c0b4f4a", "type": "tab", "label": "Flow 5", "disabled": false, "info": "", "env": [] }, { "id": "b673e10beab091ff", "type": "tab", "label": "Flow 6", "disabled": false, "info": "", "env": [] }, { "id": "24e9a56732cfa6f1", "type": "tab", "label": "Flow 7", "disabled": false, "info": "", "env": [] }, { "id": "57bd1b149526fcee", "type": "subflow", "name": "Room Lights", "info": "", "category": "", "in": [ { "x": 260, "y": 220, "wires": [ { "id": "ee7c2a47d6441c26" } ] } ], "out": [ { "x": 560, "y": 120, "wires": [ { "id": "ee7c2a47d6441c26", "port": 0 } ] }, { "x": 560, "y": 160, "wires": [ { "id": "ee7c2a47d6441c26", "port": 1 } ] }, { "x": 560, "y": 200, "wires": [ { "id": "ee7c2a47d6441c26", "port": 2 } ] }, { "x": 560, "y": 240, "wires": [ { "id": "ee7c2a47d6441c26", "port": 3 } ] }, { "x": 560, "y": 280, "wires": [ { "id": "ee7c2a47d6441c26", "port": 4 } ] }, { "x": 560, "y": 320, "wires": [ { "id": "ee7c2a47d6441c26", "port": 5 } ] } ], "env": [ { "name": "room_name", "type": "str", "value": "" } ], "meta": {}, "color": "#DDAA99" }, { "id": "d0de479f6b80ab6c", "type": "subflow", "name": "Subflow 1", "info": "", "in": [ { "x": 60, "y": 80, "wires": [ { "id": "f9557fd9a8b2eee2" } ] } ], "out": [ { "x": 340, "y": 80, "wires": [ { "id": "f9557fd9a8b2eee2", "port": 0 } ] } ] }, { "id": "4dc13919bcc9d676", "type": "subflow", "name": "Room filter", "info": "", "category": "", "in": [ { "x": 60, "y": 80, "wires": [ { "id": "d2a3760f36aa6f41" } ] } ], "out": [ { "x": 640, "y": 100, "wires": [ { "id": "0ce841560c8c4087", "port": 0 }, { "id": "64b045db5a4541fa", "port": 0 }, { "id": "4a891a7505b5fd00", "port": 0 }, { "id": "258a84ec1d54a43a", "port": 0 }, { "id": "5532273136423869", "port": 0 } ] } ], "env": [ { "name": "switch_1", "type": "str", "value": ".sw_1" }, { "name": "switch_2", "type": "str", "value": ".sw_2" }, { "name": "switch_3", "type": "str", "value": ".sw_3" }, { "name": "switch_4", "type": "str", "value": ".sw_4" }, { "name": "single", "type": "str", "value": ".sw_1" } ], "meta": {}, "color": "#DDAA99" }, { "id": "664de832a54bc4e0", "type": "group", "z": "46892ced77481340", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "039e1be0cfe8e630", "740b766e9bdc0d2a" ], "x": 1934, "y": 179, "w": 292, "h": 82 }, { "id": "f27a48975d61e376", "type": "group", "z": "46892ced77481340", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "e37aa132859c1ea8", "d3f0c80e0188aabf", "1a534f2c5be60889" ], "x": 2244, "y": 179, "w": 502, "h": 152 }, { "id": "9113c5ebf5c089e3", "type": "group", "z": "480553bb6f5b2b51", "name": "Door Sensor Notifications", "style": { "fill": "#addb7b", "fill-opacity": "0.89", "label": true, "stroke": "#ffffff", "stroke-opacity": "0" }, "nodes": [ "0385d24efa18d698", "9d611c0ff2a0b1ca", "10448f46514c1406", "a9d786b1ba52704b", "e250cc2f901bea9f", "5e94eb39aec6e82d", "8b8cce25637907b1", "3f9797c13c3a11a1", "7301d71523d87e94", "4055425d6c42dd13", "ada6fe8339eab29b", "8e0d5ec04f029b9a", "eb25ece689ea1045", "63cb264d89898c6a", "bd4b7dd437c1aaaf", "f6adcaa35a793e58" ], "x": 34, "y": -1, "w": 1562, "h": 302 }, { "id": "91b1f4cb0e1ffa84", "type": "group", "z": "480553bb6f5b2b51", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "d592161c8e50638a", "2a218aee475ce267", "f5ef8cb0a1bc7def" ], "x": 2234, "y": 39, "w": 412, "h": 122 }, { "id": "d24bcb9ea3d9711c", "type": "group", "z": "46892ced77481340", "name": "", "style": { "fill": "#ffdf7f", "label": true }, "nodes": [ "925b79f58f75e449", "b88648a578b60cb8", "4a9361ba088ba046", "0271d58953459100", "4b360c7d54e39e0a", "62cc8431c77a4797", "2d6eb3ac6de382be", "af99b05ba44c6741", "3c7f8838aa2349b9", "0b0b27deacee2bfc" ], "x": 38, "y": 653, "w": 1634, "h": 684 }, { "id": "7c29230c98070fd5", "type": "group", "z": "46892ced77481340", "name": "", "style": { "fill": "#bfdbef", "label": true, "color": "#000000" }, "nodes": [ "ff517137dc8eb4e5", "2b9f0ac7a58d6e99", "007a0818e00b6e8a", "42040eb51b6909d2", "888d856dae38ce27", "2ba7fb1e189ec017", "3cc3b21e7b1f7b13", "f16b851b413f0d32", "1a348789bcd14214", "8044f4e5402ca464", "f83a4ef2662f4f11", "48b019b444db2a5a", "639e1c2545c2de96" ], "x": 48, "y": 133, "w": 1764, "h": 494 }, { "id": "41609eab5db77f0a", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "36d1d2c1e10100e7", "4c584ffba6a17ccb", "c53543186fd45d8b", "33eb6e0725214c0b", "5df52e7f8217a6d9", "6dd69a9285fc9583", "3e5fabb6aa93449c", "aadcf8d1921d77e6" ], "x": 94, "y": 2019, "w": 1272, "h": 162 }, { "id": "b6271f4a3284f8d9", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "46517eb4342b3d18", "a3d5be29d6effa34", "d23c32a704af639d", "68f7d3015de2dbab", "701c1cd70874e615" ], "x": 94, "y": 1879, "w": 1272, "h": 122 }, { "id": "3db6f7ccc63a5f8b", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "1633e8e6861be2e0", "9c36d1335b0f8ebb", "fe5612a41399f1f5", "7f48ed25c8ec1fce", "ab17cf6a7d65fcb9" ], "x": 94, "y": 1699, "w": 1272, "h": 162 }, { "id": "5270af8a6312b29d", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "25cf5d71108cbbb4", "cbcd3d741247b12b", "07e63813fb04b906", "4d3d4a82a512ca10", "0bf96ec77f6d1809" ], "x": 94, "y": 1459, "w": 1272, "h": 122 }, { "id": "6809b1c79783ab0c", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "a330bf2f4d26c536", "398c06a48e4daa13" ], "x": 94, "y": 1599, "w": 1272, "h": 82 }, { "id": "1166ae03751d953e", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "ef6df11582a22110", "774c15def7e6cf96" ], "x": 94, "y": 1359, "w": 1272, "h": 82 }, { "id": "fb2d97888a83fc98", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "6f028b285108ff17", "82c1d5f7ae54b348" ], "x": 94, "y": 1259, "w": 1272, "h": 82 }, { "id": "5b22d521e762f0da", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "6e30880884a2cdb2", "da7ab159be01b35c" ], "x": 94, "y": 1159, "w": 1272, "h": 82 }, { "id": "74596bdef53b62cf", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "0bd6051323b66072", "6aac621e2a9acf79" ], "x": 94, "y": 1059, "w": 1272, "h": 82 }, { "id": "5d202845936f0275", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "becbc51cb810ff3d", "4673e2e3f2c0626f" ], "x": 94, "y": 959, "w": 1272, "h": 82 }, { "id": "68db2262f7c7313e", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "675ba75711ef84e7", "84272551b322cde2" ], "x": 94, "y": 859, "w": 1272, "h": 82 }, { "id": "39f557d8eec2fbae", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "a6cf1bd4ae01ee56", "16eaca15570ff092", "109c390c131b09a8", "d02a9d4e0468bc67", "2d6bcc49a2785fd6" ], "x": 94, "y": 379, "w": 1272, "h": 122 }, { "id": "795d604329d51272", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "1aa9e0ff37d1afee", "b9c07d22cbaae6a2" ], "x": 94, "y": 279, "w": 1272, "h": 82 }, { "id": "4b06cbc568091f6f", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "6654c150377ed2bb", "83bbabef65831016" ], "x": 94, "y": 179, "w": 1272, "h": 82 }, { "id": "b5ffb4a4212da258", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "ca1a1f7f8b90cfc9", "b8f3d3242fb39bdd" ], "x": 94, "y": 79, "w": 1272, "h": 82 }, { "id": "5c95d99a679a5e00", "type": "group", "z": "480553bb6f5b2b51", "name": "Water Leak Notifications", "style": { "label": true, "fill": "#0070c0", "fill-opacity": "0.54", "stroke": "#000000", "color": "#000000" }, "nodes": [ "8f42e8fdfef40579", "58ee1ac91f379cb9", "a1f1e1ea2cf90f61", "3242605bce7f6f92", "22740e52f6cc3399", "53799a37bb6cf7c6", "8b9761ea2f86b4f1", "70f797398b0e6783", "2157cdd444dfec91", "8b2f06afcf0d773e", "e31ec1ce332c4c99", "1164cfc4fd2e5382", "748c39a404648158", "a73395db2426b4fc" ], "x": 54, "y": 379, "w": 1562, "h": 288 }, { "id": "1c73b8aaec035f06", "type": "group", "z": "480553bb6f5b2b51", "name": "Battery notifications", "style": { "fill": "#ffbfbf", "label": true, "color": "#000000" }, "nodes": [ "eb721beae24b271b", "41f1e9feaf1ea6aa", "c60307d3b68ebe34", "81d16e7a5307e9cc", "209d79611a5414cc", "e6a93b0cbc48af98", "a9f755806e4e8a75", "5c2272c244ffc8b0", "6d60df5c0c6920d2" ], "x": 54, "y": 699, "w": 1562, "h": 162 }, { "id": "bd16cebc90c528e9", "type": "group", "z": "46892ced77481340", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "b4e49387d80fa951", "860779317fad91b5", "2ae3fedce613ecfe", "1a8d95afd537e151", "d1c2e1ee1fba88c6" ], "x": 1944, "y": 319, "w": 482, "h": 232 }, { "id": "507ca4f1b82ad9c2", "type": "group", "z": "46892ced77481340", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "66255b06a0d4a4c9", "9c99ecea6e4aefd8" ], "x": 1954, "y": 559, "w": 292, "h": 82 }, { "id": "cc230a0894b116d3", "type": "group", "z": "6722d185624fd57a", "name": "", "style": { "fill": "#7fb7df", "label": true }, "nodes": [ "05ecf6f492d4a8cf", "ad81a0918c31a862", "7049d2e629127b0e", "e44fa1b081b4aba7", "532476a808456423", "9e01966beafd582b", "301e955ac79a9326", "54161a78e09f85c3", "0fdf497d70900d11", "434ef7e821c63223" ], "x": 134, "y": 939, "w": 992, "h": 277 }, { "id": "b73455843d7a5a9f", "type": "group", "z": "6722d185624fd57a", "name": "Watering Schedule", "style": { "label": true, "fill": "#b797cf" }, "nodes": [ "905629455f4dd222", "33e972f98673a6b6", "ab7182ad5c37be48", "d51ae77e82bb86f0", "b43dc5183a67d128", "2896d687417bbc1d", "1199fd928d0abd32", "86153b2dba01756f" ], "x": 54, "y": 379, "w": 1432, "h": 242 }, { "id": "ef555db28dba4c46", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "0b112f9f314fa0bb", "a1f5a94baf1fbcd7", "ae314d3d3457b679", "0c35b08a3c7d347f", "f0de9c882920d07c" ], "x": 94, "y": 519, "w": 1272, "h": 122 }, { "id": "1756bd5d4ff2c23b", "type": "group", "z": "f9a2fb576f0d360d", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "310f749a07eded9d", "d0febe343ef897ac", "e1965a78e430acad", "8cce4a0a7061ac87", "d5cad6d8ca5fe08c" ], "x": 94, "y": 2199, "w": 1272, "h": 162 }, { "id": "860e99939cf4fb5c", "type": "group", "z": "6722d185624fd57a", "name": "Christmas Light", "style": { "label": true }, "nodes": [ "d97b1b86e0e0040e", "3737a8c897de2221", "ca74d224370a0b5a", "3a8262144b91d661", "d20a28e1dea2fcde", "01df5278eead8a98", "1460ed0d062f8b73", "6fdd0a95dd76a2e8", "bb1639973b4a6a05", "800cb2f6a21c882f", "893d9228d166c0d2", "be86177040153c9f" ], "x": 654, "y": 1679, "w": 1272, "h": 382 }, { "id": "ce79bea4667a77e2", "type": "group", "z": "480553bb6f5b2b51", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "8656a450e0ae020d", "7ff8359abb38dca4", "doorbell_state_check", "bd7fed2198a7b950", "78a1c2a40934ef20", "05f0d77a9b605f22", "19d0e8d8c5addb1f", "eff49303c6d84242", "c74ddf6b84ef7a95", "d496d62222d1a073", "48bfe0ad8a973a84", "88d855e525ab78f0", "a4752681740af47e", "7e88e31d094e343d", "365adc2679063bc8", "842a49fa21a0587a", "bedee5f9397c27f1", "3f9c2db4dfea3095", "0446448ed8c8da8a", "d241b1f4991cfc05" ], "x": 14, "y": 1129, "w": 2362, "h": 272 }, { "id": "9da6393897881dca", "type": "group", "z": "46892ced77481340", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "5351a670ea3bcf15", "8dd17125d6bb49f7", "9b4f318fa5f438aa" ], "x": 1764, "y": 839, "w": 522, "h": 152 }, { "id": "ff517137dc8eb4e5", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Office ", "style": { "label": true }, "nodes": [ "a91dcb332bae2807", "11f594c5b9f0fce8" ], "x": 354, "y": 379, "w": 312, "h": 102 }, { "id": "2b9f0ac7a58d6e99", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Shower", "style": { "label": true }, "nodes": [ "a2eceb1ef60667cb", "102d7d54a45e3f18", "a024d8a903074aa4", "d680ff6c7ac109cf", "9dc26f31e8b58f14" ], "x": 1034, "y": 259, "w": 402, "h": 222 }, { "id": "007a0818e00b6e8a", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Master Bedroom", "style": { "label": true }, "nodes": [ "67149a39f56c5694", "d5dacec70d47b2e5", "28d2293b97a7b72b", "a6493ad8864f2b68" ], "x": 354, "y": 159, "w": 312, "h": 202 }, { "id": "42040eb51b6909d2", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Kitchen", "style": { "label": true, "fill": "#d1d1d1", "color": "#000000" }, "nodes": [ "e9aa8b33edf056f6", "eda94d52e6cf650a", "188a3b16710467e7", "2dc64fabc1602ec8", "a1f44cc63b77a2c3" ], "x": 74, "y": 159, "w": 262, "h": 422 }, { "id": "888d856dae38ce27", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Veranda", "style": { "label": true }, "nodes": [ "f714485f125865af", "2565695beaa14d76", "9594045be414b84c" ], "x": 1434, "y": 159, "w": 352, "h": 142 }, { "id": "2ba7fb1e189ec017", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Living Room ", "style": { "label": true }, "nodes": [ "58525896ff637a27", "beeb512081d25291" ], "x": 694, "y": 379, "w": 312, "h": 82 }, { "id": "3cc3b21e7b1f7b13", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Dining Room", "style": { "label": true }, "nodes": [ "66cafcf3b261e8b5", "04e183fcfe9e9f6d", "1f3ba1a73e155da9", "6190a90971a43aba" ], "x": 694, "y": 159, "w": 312, "h": 202 }, { "id": "f16b851b413f0d32", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Guest WC", "style": { "label": true }, "nodes": [ "f1cf19264e9957f3", "0d7f6d11034f98ee" ], "x": 1034, "y": 499, "w": 342, "h": 82 }, { "id": "1a348789bcd14214", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Back yard", "style": { "label": true }, "nodes": [ "518a9fd6f52bfc23", "839bb9d987729d16" ], "x": 1434, "y": 419, "w": 352, "h": 82 }, { "id": "8044f4e5402ca464", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Master Bathroom", "style": { "label": true }, "nodes": [ "0f93e95f3e92150a", "ed3b84f4d63a8bd5" ], "x": 1034, "y": 159, "w": 342, "h": 82 }, { "id": "f83a4ef2662f4f11", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Front Yard", "style": { "label": true }, "nodes": [ "194c35655de1a128", "45e37c698b0b2e5a" ], "x": 1434, "y": 319, "w": 352, "h": 82 }, { "id": "48b019b444db2a5a", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "name": "Drive ways", "style": { "label": true }, "nodes": [ "bbda8fd42d8aa120", "01da9e8ebba7f592" ], "x": 1434, "y": 519, "w": 352, "h": 82 }, { "id": "925b79f58f75e449", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "40fd804bb4acf519", "b9ab51a28b433f94", "0d1a60ec03adac5c" ], "x": 64, "y": 999, "w": 522, "h": 152 }, { "id": "b88648a578b60cb8", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "1feb11ab8be3ef2e", "01b4eb4b91f9c9e2", "1ee2b22951639d6b" ], "x": 64, "y": 839, "w": 522, "h": 152 }, { "id": "4a9361ba088ba046", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "3c894953f414add5", "7ec85095958da9f5", "566e5b2ec261934f", "89762968e1556a42" ], "x": 64, "y": 679, "w": 522, "h": 152 }, { "id": "0271d58953459100", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "af7220d8f5bb9bf2", "b51586d393da96cd", "e8db33fc81400531", "e0739e7f8c82e487", "1530556181903c3a" ], "x": 624, "y": 1099, "w": 482, "h": 202 }, { "id": "4b360c7d54e39e0a", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "53178ccb3f691dad", "b2641f71595c1d2d", "ba2859e1aa882eee" ], "x": 624, "y": 919, "w": 482, "h": 152 }, { "id": "62cc8431c77a4797", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "b664207011dd548a", "39d435c6a32d4f09", "5f7ffd82e5200d9a", "f0bc3094d4af717e", "0a4414fc667405b4", "22c73018f4564256" ], "x": 624, "y": 679, "w": 482, "h": 262 }, { "id": "2d6eb3ac6de382be", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "e6e67dc471f2ecb3", "fc5020edbd894baa", "29af11e532f234d4" ], "x": 1164, "y": 839, "w": 482, "h": 152 }, { "id": "af99b05ba44c6741", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "b7e6812909ef1051", "37cdfd56758051ef", "280e6cc7a9de62b5" ], "x": 1164, "y": 679, "w": 482, "h": 152 }, { "id": "3c7f8838aa2349b9", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "806720bc7ab2d4e8", "3b5e1f4f9ccd9c74", "07bae699fea75512" ], "x": 1164, "y": 999, "w": 482, "h": 152 }, { "id": "0b0b27deacee2bfc", "type": "group", "z": "46892ced77481340", "g": "d24bcb9ea3d9711c", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "3ec8968914e324f5", "2b29c71c180a50df", "197fc35230069190" ], "x": 64, "y": 1159, "w": 522, "h": 152 }, { "id": "639e1c2545c2de96", "type": "group", "z": "46892ced77481340", "g": "7c29230c98070fd5", "style": { "stroke": "#999999", "stroke-opacity": "1", "fill": "none", "fill-opacity": "1", "label": true, "label-position": "nw", "color": "#a4a4a4" }, "nodes": [ "a8ac75d5944a28b9", "f11fa2bedfc41e41" ], "x": 354, "y": 499, "w": 292, "h": 82 }, { "id": "a73395db2426b4fc", "type": "group", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Watering Schedule Notification", "style": { "label": true, "fill": "#c8e7a7", "color": "#000000" }, "nodes": [ "c57ea029ee569428", "fe7372c7f33d96f3", "c1d2a4dc34b63730", "141f635c6c9d380f", "18454d6cad2042dc" ], "x": 474, "y": 499, "w": 622, "h": 142 }, { "id": "4e20fc347c658518", "type": "zigbee2mqtt-server", "name": "", "host": "mqtt.paraskeva.net", "mqtt_port": 1883, "mqtt_username": "nodered", "mqtt_password": "sh1pb0x1", "mqtt_qos": "0", "tls": "", "usetls": false, "base_topic": "zigbee2mqtt" }, { "id": "29eb84a2708d96e0", "type": "server", "name": "Home Assistant", "version": 6, "addon": false, "rejectUnauthorizedCerts": true, "ha_boolean": [ "y", "yes", "true", "on", "home", "open" ], "connectionDelay": true, "cacheJson": true, "heartbeat": false, "heartbeatInterval": 30, "areaSelector": "friendlyName", "deviceSelector": "friendlyName", "entitySelector": "friendlyName", "statusSeparator": ": ", "statusYear": "hidden", "statusMonth": "short", "statusDay": "numeric", "statusHourCycle": "default", "statusTimeFormat": "h:m", "enableGlobalContextStore": false }, { "id": "70fca1d2a3467c93", "type": "ha-device-config", "name": "Office", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "7fe55db85a29f18c", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "70fca1d2a3467c93", "name": "Office Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Office Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "4f23c8e7043f542b", "type": "ha-device-config", "name": "Master Bedroom", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "5e7f6287035ecc94", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "4f23c8e7043f542b", "name": "Master Bedroom Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Master Bedroom Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "b2c7564cfe776a2d", "type": "nvl-datatypes", "name": "Example types", "datatypes": "//Structure definition\nTYPE ST_MyStruct:\nSTRUCT\n xBool: BOOL;\n bByte: BYTE;\nEND_STRUCT\nEND_TYPE\n\n//Enumeration definition\nTYPE ENUM_Light: (\n Red,\n Orange,\n Green := 10\n);\nEND_TYPE" }, { "id": "17b3adc633ee3394", "type": "ha-device-config", "name": "Shower", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "88f51f9c233f4cc3", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Shower Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Shower Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "3cec5437caacb905", "type": "ha-device-config", "name": "Kitchen", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "29592d5555367344", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3cec5437caacb905", "name": "Kitchen Island", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Kitchen Island Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "cc2640502094371a", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3cec5437caacb905", "name": "Kitchen Main Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Kitchen Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "8e22cfb83ec013d1", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3cec5437caacb905", "name": "Fridge Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Fridge Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "085d42240f91eec2", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3cec5437caacb905", "name": "Pantry Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Pantry Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "451e5988101b1aac", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "4f23c8e7043f542b", "name": "Master Bedroom Door Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Master Bedroom Door Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "c21001f594a359c9", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "4f23c8e7043f542b", "name": "Master Bedroom Dresser Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Master Bedroom Dresser Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "29f5afd91874c0b8", "type": "ha-device-config", "name": "Veranda", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "2a94bae266d9423d", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "29f5afd91874c0b8", "name": "Veranda Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Veranda Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "d721225e966ecf1b", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "29f5afd91874c0b8", "name": "Veranda BBQ Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Veranda BBQ Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "2380526f974b097d", "type": "ha-device-config", "name": "Living Room", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "eca0cca02aabd143", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "2380526f974b097d", "name": "Living Room Main Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Living Room Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "5d56cc73c39843cc", "type": "ha-device-config", "name": "Dining Room", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "8c493a05a6971f90", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "5d56cc73c39843cc", "name": "Dining Room Main Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Dining Room Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "9f0f51223282478b", "type": "ha-device-config", "name": "Guest WC", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "85fe098bb4010c10", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "9f0f51223282478b", "name": "Guest WC Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Guest WC Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "87957c9f7179fe85", "type": "ha-device-config", "name": "Master Bathroom", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "ac7e5f5dfeb9ce54", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "87957c9f7179fe85", "name": "Master Bathroom Main Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Master Bathroom Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "d46352482122dfe6", "type": "ha-device-config", "name": "Front Yard", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "aa9cf2e1dc39616f", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "d46352482122dfe6", "name": "Front Entrance Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Front Entrance Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "be89dbc3425f9cc0", "type": "ha-device-config", "name": "Back Yard", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "a3fb2a27c9896974", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "be89dbc3425f9cc0", "name": "Flood Light 1", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Flood Light 1" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "a1743637a1619654", "type": "ha-device-config", "name": "Driveways", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "a97f2813611faac8", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "a1743637a1619654", "name": "Driveway Flood Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Driveway Flood Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "f744459771e70676", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "70fca1d2a3467c93", "name": "Office Light", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Office Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "2b453fcb286e51f5", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "4f23c8e7043f542b", "name": "Master Bedroom Main Light", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Master Bedroom Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "edf39a33a28182ca", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "87957c9f7179fe85", "name": "Master Bathroom Main Light", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Master Bathroom Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "16560fc93e9523d4", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Shower Main Light", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Shower Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "9b2dc1266b7513da", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Shower Fan", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Shower Fan" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "12e315808eced5db", "type": "ha-device-config", "name": "Bedroom", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "ac2dba905819562f", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Shower Fan Switch", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Shower Fan Switch" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "c494e187e88c3208", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3cec5437caacb905", "name": "Pantry Light", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Pantry Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "293fc06a888710c5", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "12e315808eced5db", "name": "Bedroom Main Light", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Bedroom Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "1a22f89094ea7b38", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "29f5afd91874c0b8", "name": "Veranda BBQ Light", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Veranda BBQ Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "8b4d5408fdcd8c0d", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "12e315808eced5db", "name": "Bedroom Main Light", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Bedroom Main Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "f190a69cf72af140", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "5d56cc73c39843cc", "name": "Dining Room Main", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Dining Room Main" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "b43c6846b0baeeec", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "2380526f974b097d", "name": "Living Room Main", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Living Room Main" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "be947f3b20336437", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3cec5437caacb905", "name": "Kitchen Main", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Kitchen Main" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "9b99cd4af3bdb9a9", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3cec5437caacb905", "name": "Kitchen Island", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Kitchen Island" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "d75c31dd7a1edcbf", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3cec5437caacb905", "name": "Fridge Light", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Fridge Light" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "3dbb887330025103", "type": "telegram bot", "botname": "spito_robot", "usernames": "nearxos", "chatids": "4747176681", "baseapiurl": "", "testenvironment": false, "updatemode": "polling", "addressfamily": "0", "pollinterval": 300, "usesocks": false, "sockshost": "", "socksprotocol": "socks5", "socksport": 6667, "socksusername": "anonymous", "sockspassword": "", "bothost": "", "botpath": "", "localbothost": "0.0.0.0", "localbotport": 8443, "publicbotport": 8443, "privatekey": "", "certificate": "", "useselfsignedcertificate": false, "sslterminated": false, "verboselogging": true }, { "id": "fe79cfd2fda112db", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "d46352482122dfe6", "name": "Front Lights", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Front Lights" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "311d801ad1f1bc0f", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "d46352482122dfe6", "name": "Front Lights", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Front Lights" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "a1235a09a8d34dea", "type": "mqtt-broker", "name": "", "broker": "10.20.30.6", "port": 1883, "clientid": "", "autoConnect": true, "usetls": false, "protocolVersion": 4, "keepalive": 60, "cleansession": true, "autoUnsubscribe": true, "birthTopic": "", "birthQos": "0", "birthRetain": "false", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closeRetain": "false", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willRetain": "false", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "telegram_bot_config", "type": "telegram bot", "botname": "Your Bot Name", "usernames": "", "chatids": "", "baseapiurl": "", "updatemode": "polling", "pollinterval": "300", "usesocks": false, "sockshost": "", "socksprotocol": "socks5", "socksport": "6667", "socksusername": "", "sockspassword": "", "bothost": "", "botpath": "", "localbotport": "8443", "publicbotport": "8443", "privatekey": "", "certificate": "", "useselfsignedcertificate": false, "sslterminated": false, "verboselogging": false }, { "id": "0d71a45029c6da27", "type": "ui_tab", "name": "Lights", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "7df2b0bd19b6ef42", "type": "ui_base", "theme": { "name": "theme-light", "lightTheme": { "default": "#0094CE", "baseColor": "#0094CE", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "edited": true, "reset": false }, "darkTheme": { "default": "#097479", "baseColor": "#097479", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif", "edited": false }, "customTheme": { "name": "Untitled Theme 1", "default": "#4B7930", "baseColor": "#4B7930", "baseFont": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" }, "themeState": { "base-color": { "default": "#0094CE", "value": "#0094CE", "edited": false }, "page-titlebar-backgroundColor": { "value": "#0094CE", "edited": false }, "page-backgroundColor": { "value": "#fafafa", "edited": false }, "page-sidebar-backgroundColor": { "value": "#ffffff", "edited": false }, "group-textColor": { "value": "#1bbfff", "edited": false }, "group-borderColor": { "value": "#ffffff", "edited": false }, "group-backgroundColor": { "value": "#ffffff", "edited": false }, "widget-textColor": { "value": "#111111", "edited": false }, "widget-backgroundColor": { "value": "#0094ce", "edited": false }, "widget-borderColor": { "value": "#ffffff", "edited": false }, "base-font": { "value": "-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen-Sans,Ubuntu,Cantarell,Helvetica Neue,sans-serif" } }, "angularTheme": { "primary": "indigo", "accents": "blue", "warn": "red", "background": "grey", "palette": "light" } }, "site": { "name": "Node-RED Dashboard", "hideToolbar": "false", "allowSwipe": "false", "lockMenu": "false", "allowTempTheme": "true", "dateFormat": "DD/MM/YYYY", "sizes": { "sx": 48, "sy": 48, "gx": 6, "gy": 6, "cx": 6, "cy": 6, "px": 0, "py": 0 } } }, { "id": "f0dee03e196ee8bc", "type": "ui_group", "name": "Default", "tab": "0d71a45029c6da27", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_masterBedroom", "type": "ui_tab", "name": "masterBedroom", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_masterBedroom", "type": "ui_group", "name": "masterBedroom", "tab": "tab_masterBedroom", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_masterBathroom", "type": "ui_tab", "name": "masterBathroom", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_masterBathroom", "type": "ui_group", "name": "masterBathroom", "tab": "tab_masterBathroom", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_bedroom_1", "type": "ui_tab", "name": "bedroom_1", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_bedroom_1", "type": "ui_group", "name": "bedroom_1", "tab": "tab_bedroom_1", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_bedroom_2", "type": "ui_tab", "name": "bedroom_2", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_bedroom_2", "type": "ui_group", "name": "bedroom_2", "tab": "tab_bedroom_2", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_bathroom", "type": "ui_tab", "name": "bathroom", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_bathroom", "type": "ui_group", "name": "bathroom", "tab": "tab_bathroom", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_hallway", "type": "ui_tab", "name": "hallway", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_hallway", "type": "ui_group", "name": "hallway", "tab": "tab_hallway", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_pantry", "type": "ui_tab", "name": "pantry", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_pantry", "type": "ui_group", "name": "pantry", "tab": "tab_pantry", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_kitchen", "type": "ui_tab", "name": "kitchen", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_kitchen", "type": "ui_group", "name": "kitchen", "tab": "tab_kitchen", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_livingRoom", "type": "ui_tab", "name": "livingRoom", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_livingRoom", "type": "ui_group", "name": "livingRoom", "tab": "tab_livingRoom", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_dinningRoom", "type": "ui_tab", "name": "dinningRoom", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_dinningRoom", "type": "ui_group", "name": "dinningRoom", "tab": "tab_dinningRoom", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_entrance", "type": "ui_tab", "name": "entrance", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_entrance", "type": "ui_group", "name": "entrance", "tab": "tab_entrance", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_guestWc", "type": "ui_tab", "name": "guestWc", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_guestWc", "type": "ui_group", "name": "guestWc", "tab": "tab_guestWc", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_outVeranda", "type": "ui_tab", "name": "outVeranda", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_outVeranda", "type": "ui_group", "name": "outVeranda", "tab": "tab_outVeranda", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_outFront", "type": "ui_tab", "name": "outFront", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_outFront", "type": "ui_group", "name": "outFront", "tab": "tab_outFront", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_outSide", "type": "ui_tab", "name": "outSide", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_outSide", "type": "ui_group", "name": "outSide", "tab": "tab_outSide", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "tab_outBack", "type": "ui_tab", "name": "outBack", "icon": "dashboard", "disabled": false, "hidden": false }, { "id": "group_outBack", "type": "ui_group", "name": "outBack", "tab": "tab_outBack", "order": 1, "disp": true, "width": 6, "collapse": false, "className": "" }, { "id": "0c9a4c8d912d0a38", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Water_boiler", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Water_boiler" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "8166d41aaab8a32a", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Water_boiler", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Water_boiler" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "timer30min_config", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Timer_30_Min", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Timer 30 Min" }, { "property": "icon", "value": "mdi:timer" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "timer1hour_config", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Timer_1_Hour", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Timer 1 Hour" }, { "property": "icon", "value": "mdi:timer" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "timer2hours_config", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Timer_2_Hours", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Timer 2 Hours" }, { "property": "icon", "value": "mdi:timer" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "timerstop_config", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Stop_Timer", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Stop Timer" }, { "property": "icon", "value": "mdi:timer-off" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "timer_remaining_config", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "17b3adc633ee3394", "name": "Timer_Remaining", "version": 6, "entityType": "sensor", "haConfig": [ { "property": "name", "value": "Water Boiler Timer Remaining" }, { "property": "icon", "value": "mdi:timer-sand" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" }, { "property": "unit_of_measurement", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "c5b6375b9e419298", "type": "ha-device-config", "name": "Entrance", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "c1b8d65524acbab3", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "c5b6375b9e419298", "name": "Entrance Mirror", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Entrance Mirror" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "72e9fc1709b9891c", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "c5b6375b9e419298", "name": "Entrance Mirror", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Entrance Mirror" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "121b1dead369ae82", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "c5b6375b9e419298", "name": "Entrance Light In", "version": 6, "entityType": "button", "haConfig": [ { "property": "name", "value": "Entrance Light In" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "395ea43be3b0e20c", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "c5b6375b9e419298", "name": "Entrance Light In", "version": 6, "entityType": "binary_sensor", "haConfig": [ { "property": "name", "value": "Entrance Light In" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "3e00db06a8f6a759", "type": "ha-device-config", "name": "Living_Room_New", "hwVersion": "", "manufacturer": "Node-RED", "model": "", "swVersion": "" }, { "id": "6d1793815598b149", "type": "ha-entity-config", "server": "29eb84a2708d96e0", "deviceConfig": "3e00db06a8f6a759", "name": "Living_room_Lights", "version": 6, "entityType": "switch", "haConfig": [ { "property": "name", "value": "" }, { "property": "icon", "value": "" }, { "property": "entity_picture", "value": "" }, { "property": "entity_category", "value": "" }, { "property": "device_class", "value": "" } ], "resend": false, "debugEnabled": false }, { "id": "ee7c2a47d6441c26", "type": "function", "z": "57bd1b149526fcee", "name": "function 1", "func": "// Get the room name from the environment variable\nconst roomName = env.get(\"room_name\");\n\n// Access Node-RED context for state storage\nlet contextState = context.get(roomName) || {};\n\n// Check if the payload contains the specified room\nif (msg.payload.hasOwnProperty(roomName)) {\n // Get the lights status for the specified room\n let lights = msg.payload[roomName];\n\n // Check if this is the first run (initial state)\n // Context is empty or missing expected light keys\n const expectedLights = ['l_1', 'l_2', 'l_3', 'l_4', 'l_5', 'l_6'];\n const isInitialState = Object.keys(contextState).length === 0 || \n expectedLights.some(light => !(light in contextState));\n\n // Create an output array for the 6 ports\n let outputs = [null, null, null, null, null, null];\n\n // Check each light status and detect changes\n for (let light in lights) {\n let lightStatus = lights[light];\n\n // On initial state, send ALL states to initialize binary sensors\n // Otherwise, only send changed states\n if (isInitialState || contextState[light] !== lightStatus) {\n // Update the context with the new status\n contextState[light] = lightStatus;\n\n // Create a new message preserving original metadata\n let newMsg = {\n payload: lightStatus,\n topic: msg.topic,\n _msgid: msg._msgid\n };\n\n // Assign the message to the correct output port\n switch (light) {\n case 'l_1':\n outputs[0] = newMsg;\n break;\n case 'l_2':\n outputs[1] = newMsg;\n break;\n case 'l_3':\n outputs[2] = newMsg;\n break;\n case 'l_4':\n outputs[3] = newMsg;\n break;\n case 'l_5':\n outputs[4] = newMsg;\n break;\n case 'l_6':\n outputs[5] = newMsg;\n break;\n default:\n // Ignore any unexpected light keys\n break;\n }\n }\n }\n\n // Store the updated state in context\n context.set(roomName, contextState);\n\n // Send states to the respective ports (all on initial, only changes otherwise)\n return outputs;\n\n} else {\n // If the specified room does not exist in the payload, clean up stored context\n context.set(roomName, null); // Remove stored state for the room\n return [null, null, null, null, null, null]; // Return array instead of null\n}\n\n", "outputs": 6, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 400, "y": 220, "wires": [ [], [], [], [], [], [] ] }, { "id": "f9557fd9a8b2eee2", "type": "function", "z": "d0de479f6b80ab6c", "name": "function 2", "func": "// Define the masterBedroom and sw_1 variables\nvar masterBedroom = \"bedroom_1\"; // Example variable for masterBedroom\nvar sw_1 = \"sw_1\"; // Example variable for sw_1\n\n// Create a message object to set the value to true\nvar msgTrue = {\n payload: {}\n};\nmsgTrue.payload[masterBedroom] = {};\nmsgTrue.payload[masterBedroom][sw_1] = true;\n\n// Create a message object to set the value to false\nvar msgFalse = {\n payload: {}\n};\nmsgFalse.payload[masterBedroom] = {};\nmsgFalse.payload[masterBedroom][sw_1] = false;\n\n// Send the message to set the value to true\nnode.send(msgTrue);\n\n// Delay for 1 second\nsetTimeout(function() {\n // Send the message to set the value to false after 1 second\n node.send(msgFalse);\n}, 1000); // 1000 milliseconds = 1 second\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 200, "y": 80, "wires": [ [] ] }, { "id": "d2a3760f36aa6f41", "type": "switch", "z": "4dc13919bcc9d676", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "1_single", "vt": "str" }, { "t": "eq", "v": "2_single", "vt": "str" }, { "t": "eq", "v": "3_single", "vt": "str" }, { "t": "eq", "v": "4_single", "vt": "str" }, { "t": "eq", "v": "single", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 5, "x": 190, "y": 80, "wires": [ [ "0ce841560c8c4087" ], [ "64b045db5a4541fa" ], [ "4a891a7505b5fd00" ], [ "258a84ec1d54a43a" ], [ "5532273136423869" ] ] }, { "id": "0ce841560c8c4087", "type": "function", "z": "4dc13919bcc9d676", "name": "Switch 1", "func": "// Retrieve the combined device variable (e.g., \"bedroom_1.sw1\")\nvar switch_1 = env.get(\"switch_1\");\n\n// Split the string into room and switch name parts using the dot as a delimiter\nvar parts = switch_1.split(\".\");\nvar room = parts[0];\nvar switchName = parts[1];\n\n// Create a message object to set the switch to true\nvar msgTrue = {\n payload: {}\n};\nmsgTrue.payload[room] = {};\nmsgTrue.payload[room][switchName] = true;\n\n// Create a message object to set the switch to false\nvar msgFalse = {\n payload: {}\n};\nmsgFalse.payload[room] = {};\nmsgFalse.payload[room][switchName] = false;\n\n// Send the message to set the switch to true\nnode.send(msgTrue);\n\n// Delay for 1 second before setting the switch to false\nsetTimeout(function () {\n node.send(msgFalse);\n}, 1000);\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 380, "y": 60, "wires": [ [] ] }, { "id": "64b045db5a4541fa", "type": "function", "z": "4dc13919bcc9d676", "name": "Switch 2", "func": "// Retrieve the combined device variable (e.g., \"bedroom_1.sw1\")\nvar switch_2 = env.get(\"switch_2\");\n\n// Split the string into room and switch name parts using the dot as a delimiter\nvar parts = switch_2.split(\".\");\nvar room = parts[0];\nvar switchName = parts[1];\n\n// Create a message object to set the switch to true\nvar msgTrue = {\n payload: {}\n};\nmsgTrue.payload[room] = {};\nmsgTrue.payload[room][switchName] = true;\n\n// Create a message object to set the switch to false\nvar msgFalse = {\n payload: {}\n};\nmsgFalse.payload[room] = {};\nmsgFalse.payload[room][switchName] = false;\n\n// Send the message to set the switch to true\nnode.send(msgTrue);\n\n// Delay for 1 second before setting the switch to false\nsetTimeout(function () {\n node.send(msgFalse);\n}, 1000);\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 380, "y": 100, "wires": [ [] ] }, { "id": "4a891a7505b5fd00", "type": "function", "z": "4dc13919bcc9d676", "name": "Switch 3", "func": "// Retrieve the combined device variable (e.g., \"bedroom_1.sw1\")\nvar switch_3 = env.get(\"switch_3\");\n\n// Split the string into room and switch name parts using the dot as a delimiter\nvar parts = switch_3.split(\".\");\nvar room = parts[0];\nvar switchName = parts[1];\n\n// Create a message object to set the switch to true\nvar msgTrue = {\n payload: {}\n};\nmsgTrue.payload[room] = {};\nmsgTrue.payload[room][switchName] = true;\n\n// Create a message object to set the switch to false\nvar msgFalse = {\n payload: {}\n};\nmsgFalse.payload[room] = {};\nmsgFalse.payload[room][switchName] = false;\n\n// Send the message to set the switch to true\nnode.send(msgTrue);\n\n// Delay for 1 second before setting the switch to false\nsetTimeout(function () {\n node.send(msgFalse);\n}, 1000);\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 380, "y": 140, "wires": [ [] ] }, { "id": "258a84ec1d54a43a", "type": "function", "z": "4dc13919bcc9d676", "name": "Switch 4", "func": "// Retrieve the combined device variable (e.g., \"bedroom_1.sw1\")\nvar switch_4 = env.get(\"switch_4\");\n\n// Split the string into room and switch name parts using the dot as a delimiter\nvar parts = switch_4.split(\".\");\nvar room = parts[0];\nvar switchName = parts[1];\n\n// Create a message object to set the switch to true\nvar msgTrue = {\n payload: {}\n};\nmsgTrue.payload[room] = {};\nmsgTrue.payload[room][switchName] = true;\n\n// Create a message object to set the switch to false\nvar msgFalse = {\n payload: {}\n};\nmsgFalse.payload[room] = {};\nmsgFalse.payload[room][switchName] = false;\n\n// Send the message to set the switch to true\nnode.send(msgTrue);\n\n// Delay for 1 second before setting the switch to false\nsetTimeout(function () {\n node.send(msgFalse);\n}, 1000);\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 380, "y": 180, "wires": [ [] ] }, { "id": "5532273136423869", "type": "function", "z": "4dc13919bcc9d676", "name": "Switch 4", "func": "// Retrieve the combined device variable (e.g., \"bedroom_1.sw1\")\nvar single = env.get(\"single\");\n\n// Split the string into room and switch name parts using the dot as a delimiter\nvar parts = single.split(\".\");\nvar room = parts[0];\nvar switchName = parts[1];\n\n// Create a message object to set the switch to true\nvar msgTrue = {\n payload: {}\n};\nmsgTrue.payload[room] = {};\nmsgTrue.payload[room][switchName] = true;\n\n// Create a message object to set the switch to false\nvar msgFalse = {\n payload: {}\n};\nmsgFalse.payload[room] = {};\nmsgFalse.payload[room][switchName] = false;\n\n// Send the message to set the switch to true\nnode.send(msgTrue);\n\n// Delay for 1 second before setting the switch to false\nsetTimeout(function () {\n node.send(msgFalse);\n}, 1000);\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 380, "y": 220, "wires": [ [] ] }, { "id": "030bba61776bd099", "type": "nvl-send", "z": "46892ced77481340", "name": "", "definition": "VAR_GLOBAL\n\tmasterBedroom \t:\tstruct_switches;\n\tmasterBathroom\t:\tstruct_switches;\n\tbedroom_1\t\t:\tstruct_switches;\n\tbedroom_2\t\t:\tstruct_switches;\n\tbathroom\t\t:\tstruct_switches;\n\thallway\t\t\t:\tstruct_switches;\n\tpantry\t\t\t:\tstruct_switches;\n\tkitchen\t\t\t:\tstruct_switches;\n\tlivingRoom\t\t:\tstruct_switches;\n\tdinningRoom\t\t:\tstruct_switches;\n\tentrance\t\t:\tstruct_switches;\n\tguestWc\t\t\t:\tstruct_switches;\n\toutVeranda\t\t:\tstruct_switches;\n\toutFront\t\t:\tstruct_switches;\n\toutSide\t\t\t:\tstruct_switches;\n\toutBack\t\t\t:\tstruct_switches;\n\tcmd_livingroom\t:\tstruct_room_cmds;\nEND_VAR\n\nTYPE struct_switches :\nSTRUCT\n\tall_off:BOOL;\n\tall_on:BOOL;\t\n\tsw_1:BOOL;\n\tsw_2:BOOL;\n\tsw_3:BOOL;\n\tsw_4:BOOL;\n\tsw_5:BOOL;\n\tsw_6:BOOL;\t\nEND_STRUCT\nEND_TYPE\n\nTYPE struct_room_cmds :\nSTRUCT\n // Home Assistant Commands (set/reset)\n ha_l1_on: BOOL;\n ha_l1_off: BOOL;\n ha_l2_on: BOOL;\n ha_l2_off: BOOL;\n ha_l3_on: BOOL;\n ha_l3_off: BOOL;\n ha_l4_on: BOOL;\n ha_l4_off: BOOL;\n ha_l5_on: BOOL;\n ha_l5_off: BOOL;\n ha_l6_on: BOOL;\n ha_l6_off: BOOL;\n \n // Zigbee Switch Inputs (edge detection for toggle)\n zigbee_sw1: BOOL; \n zigbee_sw2: BOOL;\n zigbee_sw3: BOOL;\n zigbee_sw4: BOOL;\n zigbee_sw5: BOOL;\n zigbee_sw6: BOOL;\n \n // Global Commands\n ha_all_on: BOOL;\n ha_all_off: BOOL;\nEND_STRUCT\nEND_TYPE", "listId": "3", "globaltypes": "", "pack": "true", "port": "", "x": 400, "y": 40, "wires": [ [ "040e9ff14df4a326", "f48d2c10e183fb95" ] ] }, { "id": "a18b0ead6d0e88cb", "type": "nvl-receive", "z": "46892ced77481340", "name": "", "definition": "\nVAR_GLOBAL\n\n\tl_masterBedroom \t:\tstruct_lights;\n\tl_masterBathroom\t:\tstruct_lights;\n\tl_bedroom_1\t\t\t:\tstruct_lights;\n\tl_bedroom_2\t\t\t:\tstruct_lights;\n\tl_bathroom\t\t\t:\tstruct_lights;\n\tl_hallway\t\t\t:\tstruct_lights;\n\tl_pantry\t\t\t:\tstruct_lights;\n\tl_kitchen\t\t\t:\tstruct_lights;\n\tl_livingRoom\t\t:\tstruct_lights;\n\tl_dinningRoom\t\t:\tstruct_lights;\n\tl_entrance\t\t\t:\tstruct_lights;\n\tl_guestWc\t\t\t:\tstruct_lights;\n\tl_outVeranda\t\t:\tstruct_lights;\n\tl_outFront\t\t\t:\tstruct_lights;\n\tl_outSide\t\t\t:\tstruct_lights;\n\tl_outBack\t\t\t:\tstruct_lights;\n\tlight_livingRoom\t\t:\tstruct_room_outs;\nEND_VAR\n\n\nTYPE struct_lights:\nSTRUCT\n l_1 \t\t: BOOL;\n\tl_2 \t\t: BOOL;\n\tl_3 \t\t: BOOL;\n\tl_4 \t\t: BOOL;\n\tl_5 \t\t: BOOL;\n\tl_6 \t\t: BOOL;\t\nEND_STRUCT\nEND_TYPE\n\nTYPE struct_room_outs :\nSTRUCT\n l_1: BOOL; // Light 1 control output\n l_2: BOOL; // Light 2 control output\n l_3: BOOL; // Light 3 control output\n l_4: BOOL; // Light 4 control output\n l_5: BOOL; // Light 5 control output\n l_6: BOOL; // Light 6 control output\n \n // Status feedback (read from actual relay outputs)\n l_1_status: BOOL; // Actual relay 1 state\n l_2_status: BOOL; // Actual relay 2 state\n l_3_status: BOOL; // Actual relay 3 state\n l_4_status: BOOL; // Actual relay 4 state\n l_5_status: BOOL; // Actual relay 5 state\n l_6_status: BOOL; // Actual relay 6 state\nEND_STRUCT\nEND_TYPE", "listId": "1", "globaltypes": "", "pack": "true", "x": 990, "y": 40, "wires": [ [ "e059a9fd1da3c3fd", "9672723b593ef966" ] ] }, { "id": "040e9ff14df4a326", "type": "udp out", "z": "46892ced77481340", "name": "", "addr": "plc.paraskeva.net", "iface": "", "port": "1202", "ipv": "udp4", "outport": "", "base64": false, "multicast": "false", "x": 640, "y": 40, "wires": [] }, { "id": "67f7ec38bbf87e95", "type": "udp in", "z": "46892ced77481340", "name": "", "iface": "", "port": "1202", "ipv": "udp4", "multicast": "false", "group": "", "datatype": "buffer", "x": 820, "y": 40, "wires": [ [ "a18b0ead6d0e88cb" ] ] }, { "id": "a91dcb332bae2807", "type": "ha-button", "z": "46892ced77481340", "g": "ff517137dc8eb4e5", "name": "Office", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "7fe55db85a29f18c", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "bedroom_1", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 430, "y": 420, "wires": [ [ "11f594c5b9f0fce8" ] ] }, { "id": "67149a39f56c5694", "type": "ha-button", "z": "46892ced77481340", "g": "007a0818e00b6e8a", "name": "Main Light", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "5e7f6287035ecc94", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "masterBedroom", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 440, "y": 200, "wires": [ [ "a6493ad8864f2b68" ] ] }, { "id": "40fd804bb4acf519", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "925b79f58f75e449", "name": "Office", "env": [ { "name": "room_name", "value": "l_bedroom_1", "type": "str" } ], "x": 230, "y": 1080, "wires": [ [ "b9ab51a28b433f94" ], [], [], [], [], [] ] }, { "id": "123bb560d193b3aa", "type": "function", "z": "46892ced77481340", "name": "function 3", "func": "// Retrieve room and switch from the input message\nvar room = msg.topic; // e.g., \"masterBedroom\"\nvar switchName = msg.payload; // e.g., \"sw_1\"\n\n// Create a message object to set the value to true\nvar msgTrue = {\n payload: {}\n};\nmsgTrue.payload[room] = {};\nmsgTrue.payload[room][switchName] = true;\n\n// Create a message object to set the value to false\nvar msgFalse = {\n payload: {}\n};\nmsgFalse.payload[room] = {};\nmsgFalse.payload[room][switchName] = false;\n\n// Send the message to set the value to true\nnode.send(msgTrue);\n\n// Delay for 1 second\nsetTimeout(function() {\n // Send the message to set the value to false after 1 second\n node.send(msgFalse);\n}, 1000); // 1000 milliseconds = 1 second\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 200, "y": 40, "wires": [ [ "030bba61776bd099", "438b13c5cdbb5f1c" ] ] }, { "id": "c6162cb59e21491f", "type": "link in", "z": "46892ced77481340", "name": "from zigbee", "links": [ "629cbd7ce15bb9e3", "6fb9cc41c7b14fac", "74c2640db1c8bd3e", "bcf5055c45c97cc3" ], "x": 245, "y": 100, "wires": [ [ "030bba61776bd099" ] ] }, { "id": "a2eceb1ef60667cb", "type": "ha-button", "z": "46892ced77481340", "g": "2b9f0ac7a58d6e99", "name": "Shower Light", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "88f51f9c233f4cc3", "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" }, { "property": "topic", "propertyType": "msg", "value": "bathroom", "valueType": "str" } ], "x": 1130, "y": 300, "wires": [ [ "102d7d54a45e3f18" ] ] }, { "id": "e9aa8b33edf056f6", "type": "ha-button", "z": "46892ced77481340", "g": "42040eb51b6909d2", "name": "Kitchen Island", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "29592d5555367344", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "kitchen", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_2", "valueType": "str" } ], "x": 170, "y": 220, "wires": [ [ "a1f44cc63b77a2c3" ] ] }, { "id": "eda94d52e6cf650a", "type": "ha-button", "z": "46892ced77481340", "g": "42040eb51b6909d2", "name": "Main", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "cc2640502094371a", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "kitchen", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 150, "y": 280, "wires": [ [ "a1f44cc63b77a2c3" ] ] }, { "id": "188a3b16710467e7", "type": "ha-button", "z": "46892ced77481340", "g": "42040eb51b6909d2", "name": "Fridge", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "8e22cfb83ec013d1", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "kitchen", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_3", "valueType": "str" } ], "x": 150, "y": 340, "wires": [ [ "a1f44cc63b77a2c3" ] ] }, { "id": "f714485f125865af", "type": "ha-button", "z": "46892ced77481340", "g": "888d856dae38ce27", "name": "outVeranda", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "2a94bae266d9423d", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "outVeranda", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_2", "valueType": "str" } ], "x": 1530, "y": 200, "wires": [ [ "9594045be414b84c" ] ] }, { "id": "2dc64fabc1602ec8", "type": "ha-button", "z": "46892ced77481340", "g": "42040eb51b6909d2", "name": "Pantry", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "085d42240f91eec2", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "pantry", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 210, "y": 540, "wires": [ [ "a1f44cc63b77a2c3" ] ] }, { "id": "58525896ff637a27", "type": "ha-button", "z": "46892ced77481340", "g": "2ba7fb1e189ec017", "name": "Main", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "eca0cca02aabd143", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "livingRoom", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 770, "y": 420, "wires": [ [ "beeb512081d25291" ] ] }, { "id": "d5dacec70d47b2e5", "type": "ha-button", "z": "46892ced77481340", "g": "007a0818e00b6e8a", "name": "Door", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "451e5988101b1aac", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "masterBedroom", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_2", "valueType": "str" } ], "x": 430, "y": 260, "wires": [ [ "a6493ad8864f2b68" ] ] }, { "id": "28d2293b97a7b72b", "type": "ha-button", "z": "46892ced77481340", "g": "007a0818e00b6e8a", "name": "Dresser", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "c21001f594a359c9", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "", "valueType": "str" } ], "x": 430, "y": 320, "wires": [ [ "a6493ad8864f2b68" ] ] }, { "id": "2565695beaa14d76", "type": "ha-button", "z": "46892ced77481340", "g": "888d856dae38ce27", "name": "BBQ", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "d721225e966ecf1b", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "outSide", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 1510, "y": 260, "wires": [ [ "9594045be414b84c" ] ] }, { "id": "66cafcf3b261e8b5", "type": "ha-button", "z": "46892ced77481340", "g": "3cc3b21e7b1f7b13", "name": "Main", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "8c493a05a6971f90", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "dinningRoom", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 770, "y": 200, "wires": [ [ "04e183fcfe9e9f6d" ] ] }, { "id": "0bbcb269da9b75c7", "type": "link in", "z": "46892ced77481340", "name": "From HA Entities", "links": [ "11f594c5b9f0fce8", "102d7d54a45e3f18", "a6493ad8864f2b68", "9594045be414b84c", "beeb512081d25291", "04e183fcfe9e9f6d", "0d7f6d11034f98ee", "839bb9d987729d16", "ed3b84f4d63a8bd5", "45e37c698b0b2e5a", "01da9e8ebba7f592", "740b766e9bdc0d2a", "a1f44cc63b77a2c3", "f11fa2bedfc41e41", "33eb6e0725214c0b", "9c99ecea6e4aefd8", "e44fa1b081b4aba7", "1d0a46b9d5255560" ], "x": 75, "y": 40, "wires": [ [ "123bb560d193b3aa", "e4d5c7b8295b4251" ] ] }, { "id": "11f594c5b9f0fce8", "type": "link out", "z": "46892ced77481340", "g": "ff517137dc8eb4e5", "name": "to PLC Function", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 625, "y": 440, "wires": [] }, { "id": "102d7d54a45e3f18", "type": "link out", "z": "46892ced77481340", "g": "2b9f0ac7a58d6e99", "name": "link out 2", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1335, "y": 300, "wires": [] }, { "id": "a6493ad8864f2b68", "type": "link out", "z": "46892ced77481340", "g": "007a0818e00b6e8a", "name": "link out 3", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 625, "y": 200, "wires": [] }, { "id": "a1f44cc63b77a2c3", "type": "link out", "z": "46892ced77481340", "g": "42040eb51b6909d2", "name": "link out 4", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 295, "y": 200, "wires": [] }, { "id": "9594045be414b84c", "type": "link out", "z": "46892ced77481340", "g": "888d856dae38ce27", "name": "link out 5", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1745, "y": 200, "wires": [] }, { "id": "beeb512081d25291", "type": "link out", "z": "46892ced77481340", "g": "2ba7fb1e189ec017", "name": "link out 6", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 965, "y": 420, "wires": [] }, { "id": "04e183fcfe9e9f6d", "type": "link out", "z": "46892ced77481340", "g": "3cc3b21e7b1f7b13", "name": "link out 7", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 965, "y": 200, "wires": [] }, { "id": "f1cf19264e9957f3", "type": "ha-button", "z": "46892ced77481340", "g": "f16b851b413f0d32", "name": "Guest WC Light", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "85fe098bb4010c10", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "guestWc", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 1140, "y": 540, "wires": [ [ "0d7f6d11034f98ee" ] ] }, { "id": "0d7f6d11034f98ee", "type": "link out", "z": "46892ced77481340", "g": "f16b851b413f0d32", "name": "link out 8", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1335, "y": 540, "wires": [] }, { "id": "518a9fd6f52bfc23", "type": "ha-button", "z": "46892ced77481340", "g": "1a348789bcd14214", "name": "Flood Light 1", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "a3fb2a27c9896974", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "outBack", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "", "valueType": "str" } ], "x": 1530, "y": 460, "wires": [ [ "839bb9d987729d16" ] ] }, { "id": "839bb9d987729d16", "type": "link out", "z": "46892ced77481340", "g": "1a348789bcd14214", "name": "link out 9", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1745, "y": 460, "wires": [] }, { "id": "0f93e95f3e92150a", "type": "ha-button", "z": "46892ced77481340", "g": "8044f4e5402ca464", "name": "Main", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "ac7e5f5dfeb9ce54", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "masterBathroom", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 1110, "y": 200, "wires": [ [ "ed3b84f4d63a8bd5" ] ] }, { "id": "ed3b84f4d63a8bd5", "type": "link out", "z": "46892ced77481340", "g": "8044f4e5402ca464", "name": "link out 10", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1335, "y": 200, "wires": [] }, { "id": "194c35655de1a128", "type": "ha-button", "z": "46892ced77481340", "g": "f83a4ef2662f4f11", "name": "Entrance Light out", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "aa9cf2e1dc39616f", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "outFront", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "", "valueType": "str" } ], "x": 1550, "y": 360, "wires": [ [ "45e37c698b0b2e5a" ] ] }, { "id": "45e37c698b0b2e5a", "type": "link out", "z": "46892ced77481340", "g": "f83a4ef2662f4f11", "name": "link out 11", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1745, "y": 360, "wires": [] }, { "id": "bbda8fd42d8aa120", "type": "ha-button", "z": "46892ced77481340", "g": "48b019b444db2a5a", "name": "Driveway Flood Light", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "a97f2813611faac8", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "", "valueType": "str" } ], "x": 1560, "y": 560, "wires": [ [ "01da9e8ebba7f592" ] ] }, { "id": "01da9e8ebba7f592", "type": "link out", "z": "46892ced77481340", "g": "48b019b444db2a5a", "name": "link out 12", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1745, "y": 560, "wires": [] }, { "id": "039e1be0cfe8e630", "type": "ha-button", "z": "46892ced77481340", "d": true, "g": "664de832a54bc4e0", "name": "", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "", "valueType": "str" } ], "x": 2010, "y": 220, "wires": [ [ "740b766e9bdc0d2a" ] ] }, { "id": "740b766e9bdc0d2a", "type": "link out", "z": "46892ced77481340", "g": "664de832a54bc4e0", "name": "link out 13", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 2185, "y": 220, "wires": [] }, { "id": "b9ab51a28b433f94", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "925b79f58f75e449", "name": "Office Light", "entityConfig": "f744459771e70676", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 490, "y": 1040, "wires": [ [] ] }, { "id": "e059a9fd1da3c3fd", "type": "link out", "z": "46892ced77481340", "name": "from PLC states", "mode": "link", "links": [ "0d1a60ec03adac5c", "01b4eb4b91f9c9e2", "7ec85095958da9f5", "b51586d393da96cd", "b2641f71595c1d2d", "39d435c6a32d4f09", "fc5020edbd894baa", "37cdfd56758051ef", "d3f0c80e0188aabf", "3b5e1f4f9ccd9c74", "2b29c71c180a50df", "860779317fad91b5", "8dd17125d6bb49f7", "7c4268195123e319", "032f98ab9d5085b8" ], "x": 1205, "y": 100, "wires": [] }, { "id": "0d1a60ec03adac5c", "type": "link in", "z": "46892ced77481340", "g": "925b79f58f75e449", "name": "link in 1", "links": [ "e059a9fd1da3c3fd" ], "x": 105, "y": 1080, "wires": [ [ "40fd804bb4acf519" ] ] }, { "id": "1feb11ab8be3ef2e", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "b88648a578b60cb8", "name": "Living Room", "env": [ { "name": "room_name", "value": "l_livingRoom", "type": "str" } ], "x": 250, "y": 920, "wires": [ [ "1ee2b22951639d6b" ], [], [], [], [], [] ] }, { "id": "01b4eb4b91f9c9e2", "type": "link in", "z": "46892ced77481340", "g": "b88648a578b60cb8", "name": "link in 2", "links": [ "e059a9fd1da3c3fd" ], "x": 105, "y": 920, "wires": [ [ "1feb11ab8be3ef2e" ] ] }, { "id": "3c894953f414add5", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "4a9361ba088ba046", "name": "Dining Room", "env": [ { "name": "room_name", "value": "l_dinningRoom", "type": "str" } ], "x": 250, "y": 760, "wires": [ [ "566e5b2ec261934f" ], [], [ "89762968e1556a42" ], [], [], [] ] }, { "id": "7ec85095958da9f5", "type": "link in", "z": "46892ced77481340", "g": "4a9361ba088ba046", "name": "link in 3", "links": [ "e059a9fd1da3c3fd" ], "x": 105, "y": 760, "wires": [ [ "3c894953f414add5" ] ] }, { "id": "af7220d8f5bb9bf2", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "0271d58953459100", "name": "Kitchen", "env": [ { "name": "room_name", "value": "l_kitchen", "type": "str" } ], "x": 800, "y": 1180, "wires": [ [ "e8db33fc81400531" ], [ "e0739e7f8c82e487" ], [ "1530556181903c3a" ], [], [], [] ] }, { "id": "b51586d393da96cd", "type": "link in", "z": "46892ced77481340", "g": "0271d58953459100", "name": "link in 4", "links": [ "e059a9fd1da3c3fd" ], "x": 665, "y": 1180, "wires": [ [ "af7220d8f5bb9bf2" ] ] }, { "id": "53178ccb3f691dad", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "4b360c7d54e39e0a", "name": "Bedroom", "env": [ { "name": "room_name", "value": "l_bedroom_2", "type": "str" } ], "x": 800, "y": 1000, "wires": [ [ "ba2859e1aa882eee" ], [], [], [], [], [] ] }, { "id": "b2641f71595c1d2d", "type": "link in", "z": "46892ced77481340", "g": "4b360c7d54e39e0a", "name": "link in 5", "links": [ "e059a9fd1da3c3fd" ], "x": 665, "y": 1000, "wires": [ [ "53178ccb3f691dad" ] ] }, { "id": "b664207011dd548a", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "62cc8431c77a4797", "name": "Shower", "env": [ { "name": "room_name", "value": "l_bathroom", "type": "str" } ], "x": 800, "y": 760, "wires": [ [ "5f7ffd82e5200d9a" ], [ "f0bc3094d4af717e" ], [], [], [], [ "0a4414fc667405b4", "22c73018f4564256" ] ] }, { "id": "39d435c6a32d4f09", "type": "link in", "z": "46892ced77481340", "g": "62cc8431c77a4797", "name": "link in 6", "links": [ "e059a9fd1da3c3fd" ], "x": 665, "y": 760, "wires": [ [ "b664207011dd548a" ] ] }, { "id": "1ee2b22951639d6b", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "b88648a578b60cb8", "name": "Living Room Main", "entityConfig": "b43c6846b0baeeec", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 470, "y": 880, "wires": [ [] ] }, { "id": "566e5b2ec261934f", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "4a9361ba088ba046", "name": "Dining Room Main", "entityConfig": "f190a69cf72af140", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 470, "y": 720, "wires": [ [] ] }, { "id": "5f7ffd82e5200d9a", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "62cc8431c77a4797", "name": "Main", "entityConfig": "16560fc93e9523d4", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 1030, "y": 720, "wires": [ [] ] }, { "id": "ba2859e1aa882eee", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "4b360c7d54e39e0a", "name": "Main", "entityConfig": "293fc06a888710c5", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 1030, "y": 960, "wires": [ [] ] }, { "id": "e8db33fc81400531", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "0271d58953459100", "name": "Kitchen Main", "entityConfig": "be947f3b20336437", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 990, "y": 1140, "wires": [ [] ] }, { "id": "e6e67dc471f2ecb3", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "2d6eb3ac6de382be", "name": "Master Bathroom", "env": [ { "name": "room_name", "value": "l_masterBathroom", "type": "str" } ], "x": 1370, "y": 920, "wires": [ [ "29af11e532f234d4" ], [], [], [], [], [] ] }, { "id": "fc5020edbd894baa", "type": "link in", "z": "46892ced77481340", "g": "2d6eb3ac6de382be", "name": "link in 7", "links": [ "e059a9fd1da3c3fd" ], "x": 1205, "y": 920, "wires": [ [ "e6e67dc471f2ecb3" ] ] }, { "id": "29af11e532f234d4", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "2d6eb3ac6de382be", "name": "Main", "entityConfig": "edf39a33a28182ca", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 1570, "y": 880, "wires": [ [] ] }, { "id": "b7e6812909ef1051", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "af99b05ba44c6741", "name": "Master Bedroom", "env": [ { "name": "room_name", "value": "l_masterBedroom", "type": "str" } ], "x": 1360, "y": 760, "wires": [ [ "280e6cc7a9de62b5" ], [], [], [], [], [] ] }, { "id": "37cdfd56758051ef", "type": "link in", "z": "46892ced77481340", "g": "af99b05ba44c6741", "name": "link in 8", "links": [ "e059a9fd1da3c3fd" ], "x": 1205, "y": 760, "wires": [ [ "b7e6812909ef1051" ] ] }, { "id": "280e6cc7a9de62b5", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "af99b05ba44c6741", "name": "Main", "entityConfig": "2b453fcb286e51f5", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 1570, "y": 720, "wires": [ [] ] }, { "id": "e0739e7f8c82e487", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "0271d58953459100", "name": "Kitchen Island", "entityConfig": "9b99cd4af3bdb9a9", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 1000, "y": 1200, "wires": [ [] ] }, { "id": "1530556181903c3a", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "0271d58953459100", "name": "Fridge", "entityConfig": "d75c31dd7a1edcbf", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 970, "y": 1260, "wires": [ [] ] }, { "id": "e37aa132859c1ea8", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "d": true, "g": "f27a48975d61e376", "name": "Bedroom", "env": [ { "name": "room_name", "value": "l_bedroom_2", "type": "str" } ], "x": 2420, "y": 260, "wires": [ [ "1a534f2c5be60889" ], [], [], [], [], [] ] }, { "id": "d3f0c80e0188aabf", "type": "link in", "z": "46892ced77481340", "g": "f27a48975d61e376", "name": "link in 9", "links": [ "e059a9fd1da3c3fd" ], "x": 2285, "y": 260, "wires": [ [ "e37aa132859c1ea8" ] ] }, { "id": "1a534f2c5be60889", "type": "ha-binary-sensor", "z": "46892ced77481340", "d": true, "g": "f27a48975d61e376", "name": "", "entityConfig": "", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 2640, "y": 220, "wires": [ [] ] }, { "id": "f0bc3094d4af717e", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "62cc8431c77a4797", "name": "Fan", "entityConfig": "9b2dc1266b7513da", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 1030, "y": 780, "wires": [ [] ] }, { "id": "a024d8a903074aa4", "type": "ha-button", "z": "46892ced77481340", "g": "2b9f0ac7a58d6e99", "name": "Fan", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "ac2dba905819562f", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "bathroom", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_2", "valueType": "str" } ], "x": 1110, "y": 360, "wires": [ [ "102d7d54a45e3f18" ] ] }, { "id": "07bae699fea75512", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "3c7f8838aa2349b9", "name": "Pantry", "entityConfig": "c494e187e88c3208", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 1570, "y": 1040, "wires": [ [] ] }, { "id": "806720bc7ab2d4e8", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "3c7f8838aa2349b9", "name": "Pantry", "env": [ { "name": "room_name", "value": "l_pantry", "type": "str" } ], "x": 1330, "y": 1080, "wires": [ [ "07bae699fea75512" ], [], [], [], [], [] ] }, { "id": "3b5e1f4f9ccd9c74", "type": "link in", "z": "46892ced77481340", "g": "3c7f8838aa2349b9", "name": "link in 10", "links": [ "e059a9fd1da3c3fd" ], "x": 1205, "y": 1080, "wires": [ [ "806720bc7ab2d4e8" ] ] }, { "id": "9672723b593ef966", "type": "debug", "z": "46892ced77481340", "name": "debug 1", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1340, "y": 40, "wires": [] }, { "id": "3ec8968914e324f5", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "0b0b27deacee2bfc", "name": "Bedroom", "env": [ { "name": "room_name", "value": "l_outSide", "type": "str" } ], "x": 240, "y": 1240, "wires": [ [ "197fc35230069190" ], [], [], [], [], [] ] }, { "id": "2b29c71c180a50df", "type": "link in", "z": "46892ced77481340", "g": "0b0b27deacee2bfc", "name": "link in 11", "links": [ "e059a9fd1da3c3fd" ], "x": 105, "y": 1240, "wires": [ [ "3ec8968914e324f5" ] ] }, { "id": "197fc35230069190", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "0b0b27deacee2bfc", "name": "Veranda BBQ Light", "entityConfig": "1a22f89094ea7b38", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 470, "y": 1200, "wires": [ [] ] }, { "id": "a8ac75d5944a28b9", "type": "ha-button", "z": "46892ced77481340", "g": "639e1c2545c2de96", "name": "Baby Bedroom", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "8b4d5408fdcd8c0d", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "bedroom_2", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 460, "y": 540, "wires": [ [ "f11fa2bedfc41e41" ] ] }, { "id": "f11fa2bedfc41e41", "type": "link out", "z": "46892ced77481340", "g": "639e1c2545c2de96", "name": "link out 14", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 605, "y": 540, "wires": [] }, { "id": "f785dab1a0f37204", "type": "comment", "z": "46892ced77481340", "name": "", "info": "VAR_GLOBAL\n\tmasterBedroom \t:\tstruct_switches;\n\tmasterBathroom\t:\tstruct_switches;\n\tbedroom_1\t\t:\tstruct_switches;\n\tbedroom_2\t\t:\tstruct_switches;\n\tbathroom\t\t:\tstruct_switches;\n\thallway\t\t\t:\tstruct_switches;\n\tpantry\t\t\t:\tstruct_switches;\n\tkitchen\t\t\t:\tstruct_switches;\n\tlivingRoom\t\t:\tstruct_switches;\n\tdinningRoom\t\t:\tstruct_switches;\n\tentrance\t\t:\tstruct_switches;\n\tguestWc\t\t\t:\tstruct_switches;\n\toutVeranda\t\t:\tstruct_switches;\n\toutFront\t\t:\tstruct_switches;\n\toutSide\t\t\t:\tstruct_switches;\n\toutBack\t\t\t:\tstruct_switches;\nEND_VAR\n\nTYPE struct_switches :\nSTRUCT\n\tall_off:BOOL;\n\tall_on:BOOL;\t\n\tsw_1:BOOL;\n\tsw_2:BOOL;\n\tsw_3:BOOL;\n\tsw_4:BOOL;\n\tsw_5:BOOL;\n\tsw_6:BOOL;\t\nEND_STRUCT\nEND_TYPE", "x": 1560, "y": 40, "wires": [] }, { "id": "b4e49387d80fa951", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "bd16cebc90c528e9", "name": "Out", "env": [ { "name": "room_name", "value": "l_outVeranda", "type": "str" } ], "x": 2110, "y": 480, "wires": [ [ "2ae3fedce613ecfe", "d1c2e1ee1fba88c6" ], [], [], [], [], [] ] }, { "id": "860779317fad91b5", "type": "link in", "z": "46892ced77481340", "g": "bd16cebc90c528e9", "name": "link in 12", "links": [ "e059a9fd1da3c3fd" ], "x": 1985, "y": 480, "wires": [ [ "b4e49387d80fa951", "1a8d95afd537e151" ] ] }, { "id": "2ae3fedce613ecfe", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "bd16cebc90c528e9", "name": "Front Lights", "entityConfig": "fe79cfd2fda112db", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 2330, "y": 440, "wires": [ [] ] }, { "id": "66255b06a0d4a4c9", "type": "ha-button", "z": "46892ced77481340", "g": "507ca4f1b82ad9c2", "name": "Front Lights", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "311d801ad1f1bc0f", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "outVeranda", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 2050, "y": 600, "wires": [ [ "9c99ecea6e4aefd8" ] ] }, { "id": "9c99ecea6e4aefd8", "type": "link out", "z": "46892ced77481340", "g": "507ca4f1b82ad9c2", "name": "link out 20", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 2205, "y": 600, "wires": [] }, { "id": "f48d2c10e183fb95", "type": "debug", "z": "46892ced77481340", "name": "debug 15", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 600, "y": 80, "wires": [] }, { "id": "438b13c5cdbb5f1c", "type": "debug", "z": "46892ced77481340", "name": "debug 16", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 380, "y": 100, "wires": [] }, { "id": "d680ff6c7ac109cf", "type": "ha-button", "z": "46892ced77481340", "g": "2b9f0ac7a58d6e99", "name": "Water Boiler", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "0c9a4c8d912d0a38", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "bathroom", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_6", "valueType": "str" } ], "x": 1130, "y": 420, "wires": [ [ "102d7d54a45e3f18", "9dc26f31e8b58f14" ] ] }, { "id": "0a4414fc667405b4", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "62cc8431c77a4797", "name": "Water_boiler", "entityConfig": "8166d41aaab8a32a", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 1010, "y": 840, "wires": [ [] ] }, { "id": "9dc26f31e8b58f14", "type": "debug", "z": "46892ced77481340", "g": "2b9f0ac7a58d6e99", "name": "debug 29", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1330, "y": 440, "wires": [] }, { "id": "1a8d95afd537e151", "type": "debug", "z": "46892ced77481340", "g": "bd16cebc90c528e9", "name": "debug 31", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 2090, "y": 360, "wires": [] }, { "id": "d1c2e1ee1fba88c6", "type": "debug", "z": "46892ced77481340", "g": "bd16cebc90c528e9", "name": "debug 32", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 2250, "y": 400, "wires": [] }, { "id": "e4d5c7b8295b4251", "type": "debug", "z": "46892ced77481340", "name": "debug 27", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 120, "y": 100, "wires": [] }, { "id": "22c73018f4564256", "type": "debug", "z": "46892ced77481340", "g": "62cc8431c77a4797", "name": "debug 34", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 980, "y": 900, "wires": [] }, { "id": "1f3ba1a73e155da9", "type": "ha-button", "z": "46892ced77481340", "g": "3cc3b21e7b1f7b13", "name": "Entrance Mirror", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "c1b8d65524acbab3", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "dinningRoom", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_3", "valueType": "str" } ], "x": 800, "y": 260, "wires": [ [ "04e183fcfe9e9f6d" ] ] }, { "id": "89762968e1556a42", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "4a9361ba088ba046", "name": "Entrance Miror", "entityConfig": "72e9fc1709b9891c", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 460, "y": 780, "wires": [ [] ] }, { "id": "6190a90971a43aba", "type": "ha-button", "z": "46892ced77481340", "g": "3cc3b21e7b1f7b13", "name": "Entrance Light in", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "121b1dead369ae82", "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "entrance", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "x": 800, "y": 320, "wires": [ [ "04e183fcfe9e9f6d" ] ] }, { "id": "5351a670ea3bcf15", "type": "subflow:57bd1b149526fcee", "z": "46892ced77481340", "g": "9da6393897881dca", "name": "Entrance", "env": [ { "name": "room_name", "value": "l_entrance", "type": "str" } ], "x": 1940, "y": 920, "wires": [ [ "9b4f318fa5f438aa" ], [], [], [], [], [] ] }, { "id": "8dd17125d6bb49f7", "type": "link in", "z": "46892ced77481340", "g": "9da6393897881dca", "name": "link in 13", "links": [ "e059a9fd1da3c3fd" ], "x": 1805, "y": 920, "wires": [ [ "5351a670ea3bcf15" ] ] }, { "id": "9b4f318fa5f438aa", "type": "ha-binary-sensor", "z": "46892ced77481340", "g": "9da6393897881dca", "name": "Entrance Light In", "entityConfig": "395ea43be3b0e20c", "version": 0, "state": "payload", "stateType": "msg", "attributes": [], "inputOverride": "allow", "outputProperties": [], "x": 2170, "y": 880, "wires": [ [] ] }, { "id": "61d0351b6a2d43cc", "type": "link in", "z": "46892ced77481340", "name": "to UDP", "links": [], "x": 285, "y": 20, "wires": [ [ "040e9ff14df4a326" ] ] }, { "id": "4045239f675b77d2", "type": "function", "z": "7de41d810b04d992", "name": "HA to NVL", "func": "// Writes to state.rooms.. Room from entity_id via global roomConfig.entityToRoom. See /root/.node-red/room-config.js.\nconst entityId = (msg.topic || '').toString();\nconst config = global.get('roomConfig');\nconst entityToRoom = (config && config.entityToRoom) ? config.entityToRoom : { open_plan_living_room_main: 'open_plan_living_room' };\n// Parse entity_id e.g. input_boolean.open_plan_living_room_main_1 → base \"open_plan_living_room_main_1\", then room + light\nconst base = (entityId.split('.')[1] || '').replace(/\\s/g, '');\nconst numMatch = base.match(/_(\\d+)$/);\nconst lightNum = (numMatch && parseInt(numMatch[1], 10) >= 1) ? Math.min(6, parseInt(numMatch[1], 10)) : 1;\nconst baseWithoutNum = base.replace(/_?\\d+$/, '') || base;\nconst ROOM_NAME = entityToRoom[baseWithoutNum] || entityToRoom[base] || 'open_plan_living_room';\n\n// Normalize state: HA / trigger-state can send payload as string, object with .state, or data.new_state.state\nlet rawState = msg.payload;\nif (rawState !== null && typeof rawState === 'object' && rawState.state !== undefined) rawState = rawState.state;\nif (msg.data && msg.data.new_state && msg.data.new_state.state !== undefined) rawState = msg.data.new_state.state;\nconst isOn = (rawState === 'on' || rawState === true);\n\nnode.warn('[HA to NVL] topic=' + entityId + ' rawState=' + JSON.stringify(rawState) + ' → lightNum=' + lightNum + ' isOn=' + isOn);\n\nif (!flow.get('nvlInState')) flow.set('nvlInState', { rooms: {}, boiler: {} });\nconst state = flow.get('nvlInState');\nif (!state.rooms[ROOM_NAME]) state.rooms[ROOM_NAME] = {};\nconst r = state.rooms[ROOM_NAME];\nr['ha_l' + lightNum + '_on'] = false;\nr['ha_l' + lightNum + '_off'] = false;\nif (isOn) r['ha_l' + lightNum + '_on'] = true;\nelse r['ha_l' + lightNum + '_off'] = true;\nflow.set('nvlInState', state);\n\nnode.warn('[HA to NVL] set ' + ROOM_NAME + ' ha_l' + lightNum + '_' + (isOn ? 'on' : 'off') + '=true, buildAndSend');\n\n// PLC uses R_TRIG (rising edge). If \"off\" still doesn’t work, add a flow: after this node, 80ms delay then clear ha_l*_off and buildAndSend again (pulse).\nmsg.payload = { buildAndSend: true };\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1170, "y": 320, "wires": [ [ "75212a4bc3d085db" ] ] }, { "id": "718ba68ae647874f", "type": "function", "z": "7de41d810b04d992", "name": "Zigbee to NVL", "func": "// Each button maps to (room, light) via global roomConfig.switchBindings. See /root/.node-red/room-config.js.\n// Supports single-device payload (action, friendly_name at top level) and multi-device payload (keyed by IEEE address).\nconst actionToSwitch = { single: 1, double: 2, hold: 3, release: 4, triple: 5, quad: 6 };\nconst config = global.get('roomConfig');\nconst switchBindings = (config && config.switchBindings) ? config.switchBindings : {};\nconst deviceToRoom = (config && config.deviceToRoom) ? config.deviceToRoom : { 'Office Switch': 'open_plan_living_room' };\n// Optional: map IEEE address to friendly name when multi-device node doesn't provide it. e.g. deviceIdToName: { '0xa4c138a5b9771b05': 'Office Switch' }\nconst deviceIdToName = (config && config.deviceIdToName) ? config.deviceIdToName : {};\n\nconst payload = msg.payload != null ? msg.payload : {};\n// Payload can be: single-device { action, friendly_name }, multi-device { \"0x...\": { ... } }, or plain action string \"1_single\"\nlet friendlyName = (typeof payload === 'object' && payload.friendly_name != null) ? payload.friendly_name.toString() : '';\nlet actionRaw = (typeof payload === 'string' ? payload : (payload.action || payload.click || msg.action || (payload && payload.action)) || '').toString().toLowerCase();\n\n// Multi-device payload: prefer the device that has an action AND a configured binding (so we don't pick another device's stale action)\nif (!actionRaw && typeof payload === 'object' && !Array.isArray(payload)) {\n const keys = Object.keys(payload);\n let fallback = null;\n for (let i = 0; i < keys.length; i++) {\n const key = keys[i];\n const v = payload[key];\n if (key && key.toLowerCase().indexOf('0x') === 0 && v && typeof v === 'object') {\n const inner = v.payload || v.message || v.state || v;\n const a = (inner.action || inner.click || v.action || v.click || '').toString().toLowerCase();\n if (!a) continue;\n const name = (v.friendly_name || v.name || (v.item && (v.item.friendly_name || v.item.name)) || deviceIdToName[key] || key).toString();\n if (switchBindings[name] || deviceToRoom[name]) {\n actionRaw = a;\n friendlyName = name;\n break;\n }\n if (!fallback) fallback = { actionRaw: a, friendlyName: name };\n }\n }\n if (!actionRaw && fallback) {\n actionRaw = fallback.actionRaw;\n friendlyName = fallback.friendlyName;\n }\n}\n// If still no action, try msg.data or msg.topic (some nodes put action in topic, e.g. \"1_single\")\nif (!actionRaw && msg.data && msg.data.action) actionRaw = msg.data.action.toString().toLowerCase();\nif (!actionRaw && typeof msg.topic === 'string' && /^\\d_[a-z_]+$/.test(msg.topic.trim())) actionRaw = msg.topic.trim().toLowerCase();\n// If payload was the action string, get friendly_name from topic e.g. zigbee2mqtt/Office Switch/action\nif (actionRaw && !friendlyName && typeof msg.topic === 'string') {\n const parts = msg.topic.split('/');\n if (parts.length >= 2) friendlyName = parts[1].trim(); // zigbee2mqtt/Office Switch/action → Office Switch\n}\n\nif (!actionRaw) {\n node.warn('[Zigbee to NVL] no action in payload. Keys: ' + (typeof payload === 'object' ? Object.keys(payload).join(', ') : 'n/a'));\n return null;\n}\n\nconst parts = actionRaw.split('_');\nlet buttonIndex = null;\nif (parts.length >= 2) {\n const n = parseInt(parts[0], 10);\n if (n >= 1 && n <= 6) buttonIndex = n;\n}\nif (buttonIndex == null) buttonIndex = actionToSwitch[actionRaw];\nif (buttonIndex == null && parts.length >= 2) buttonIndex = actionToSwitch[parts.slice(1).join('_')];\nif (buttonIndex == null) buttonIndex = actionToSwitch[parts[parts.length - 1]];\n\nif (buttonIndex == null) {\n node.warn('[Zigbee to NVL] unknown action: ' + JSON.stringify(actionRaw));\n return null;\n}\n\nnode.warn('[Zigbee to NVL] action=' + actionRaw + ' buttonIndex=' + buttonIndex + ' device=' + friendlyName);\n\n// Prefer switchBindings by friendly name; fallback by device ID (IEEE) if we have switchBindingsByDeviceId\nconst bindingByDeviceId = (config && config.switchBindingsByDeviceId) ? config.switchBindingsByDeviceId : null;\nlet targets = [];\nlet binding = switchBindings[friendlyName] && switchBindings[friendlyName][buttonIndex];\nif ((binding === undefined || binding === null) && bindingByDeviceId) {\n const deviceId = typeof payload === 'object' && Object.keys(payload).some(function (k) { return k.indexOf('0x') === 0; })\n ? Object.keys(payload).find(function (k) { return k.indexOf('0x') === 0; })\n : null;\n if (deviceId) binding = bindingByDeviceId[deviceId] && bindingByDeviceId[deviceId][buttonIndex];\n}\nif (binding !== undefined && binding !== null) {\n targets = Array.isArray(binding) ? binding : [binding];\n targets = targets.filter(function (t) { return t && t.room && t.light >= 1 && t.light <= 6; });\n}\nif (targets.length === 0) {\n const room = deviceToRoom[friendlyName] || 'open_plan_living_room';\n targets = [{ room: room, light: buttonIndex }];\n}\n\nif (!flow.get('nvlInState')) flow.set('nvlInState', { rooms: {}, boiler: {} });\nconst state = flow.get('nvlInState');\nconst clearList = [];\n\nfor (const t of targets) {\n const key = 'zigbee_sw' + t.light;\n if (!state.rooms[t.room]) state.rooms[t.room] = {};\n state.rooms[t.room][key] = true;\n clearList.push({ room: t.room, key: key });\n}\n\nflow.set('nvlInState', state);\n\nnode.warn('[Zigbee to NVL] ' + (friendlyName || 'device') + ' btn' + buttonIndex + ' → ' + targets.map(function (t) { return t.room + ' L' + t.light; }).join(', '));\n\nmsg.payload = { buildAndSend: true };\nmsg.zigbeeClear = clearList;\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1160, "y": 380, "wires": [ [ "886c1334e909e2cd", "75212a4bc3d085db" ] ] }, { "id": "886c1334e909e2cd", "type": "delay", "z": "7de41d810b04d992", "name": "80ms", "pauseType": "delay", "timeout": "80", "timeoutUnits": "milliseconds", "rate": "1", "nbRateUnits": "1", "rateUnits": "seconds", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": true, "outputs": 1, "x": 1350, "y": 380, "wires": [ [ "44822e048dbaee31" ] ] }, { "id": "44822e048dbaee31", "type": "function", "z": "7de41d810b04d992", "name": "Clear zigbee edge", "func": "// Paste into the \"Clear zigbee edge\" Function node (after 80 ms delay).\n// Clears zigbee_swN in nvlInState so the PLC sees one pulse. Supports one room or many (switchBindings).\n// msg.zigbeeClear can be: { room, key } or [ { room, key }, ... ]\n\nif (msg.zigbeeClear) {\n const state = flow.get('nvlInState') || { rooms: {}, boiler: {} };\n const list = Array.isArray(msg.zigbeeClear) ? msg.zigbeeClear : [msg.zigbeeClear];\n for (const item of list) {\n const r = state.rooms[item.room];\n if (r && item.key) r[item.key] = false;\n }\n flow.set('nvlInState', state);\n}\nmsg.payload = { buildAndSend: true };\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1550, "y": 380, "wires": [ [ "75212a4bc3d085db" ] ] }, { "id": "17814d6d1beda546", "type": "zigbee2mqtt-in", "z": "7de41d810b04d992", "name": "", "server": "4e20fc347c658518", "friendly_name": "2 selected", "device_id": [ "0xa4c138a5b9771b05", "0xa4c138112a12d55f" ], "state": null, "outputAtStartup": true, "filterChanges": false, "enableMultiple": true, "x": 680, "y": 380, "wires": [ [ "718ba68ae647874f", "2edb29caf874a91e" ] ] }, { "id": "74c2640db1c8bd3e", "type": "link out", "z": "7de41d810b04d992", "name": "link out 26", "mode": "link", "links": [ "c6162cb59e21491f" ], "x": 1570, "y": 320, "wires": [], "l": true }, { "id": "95b626ea6980446e", "type": "trigger-state", "z": "7de41d810b04d992", "name": "", "server": "29eb84a2708d96e0", "version": 5, "inputs": 1, "outputs": 2, "exposeAsEntityConfig": "", "entities": { "entity": [ "input_boolean.open_plan_living_room_main_1" ], "substring": [], "regex": [] }, "debugEnabled": true, "constraints": [], "customOutputs": [], "outputInitially": false, "stateType": "str", "enableInput": true, "x": 830, "y": 320, "wires": [ [ "4045239f675b77d2" ], [] ] }, { "id": "75212a4bc3d085db", "type": "function", "z": "7de41d810b04d992", "name": "STATE TO NVL", "func": "// Build the payload for nvl-send from flow.nvlInState.\n// Room list comes from global roomConfig (single source of truth). See /root/.node-red/room-config.js.\n// Wire: HA to NVL / Zigbee to NVL → this function → nvl-send → udp out\n\nconst struct_room_cmds_default = {\n ha_l1_on: false, ha_l1_off: false, ha_l2_on: false, ha_l2_off: false,\n ha_l3_on: false, ha_l3_off: false, ha_l4_on: false, ha_l4_off: false,\n ha_l5_on: false, ha_l5_off: false, ha_l6_on: false, ha_l6_off: false,\n zigbee_sw1: false, zigbee_sw2: false, zigbee_sw3: false,\n zigbee_sw4: false, zigbee_sw5: false, zigbee_sw6: false,\n ha_all_on: false, ha_all_off: false\n};\n\nconst config = global.get('roomConfig');\nconst roomNames = (config && config.roomNames && config.roomNames.length) ? config.roomNames : ['open_plan_living_room'];\n\nconst state = flow.get('nvlInState') || { rooms: {}, boiler: {} };\nconst rooms = state.rooms || {};\nconst payload = {};\n\nfor (const name of roomNames) {\n const cmd = rooms[name] || {};\n payload[name] = { ...struct_room_cmds_default };\n for (const k of Object.keys(struct_room_cmds_default)) {\n if (cmd[k] !== undefined) payload[name][k] = !!cmd[k];\n }\n}\n\nmsg.payload = payload;\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1380, "y": 320, "wires": [ [ "74c2640db1c8bd3e", "561398f1884392c1" ] ] }, { "id": "d5cdc38171230744", "type": "function", "z": "7de41d810b04d992", "name": "NVL to HA Sync", "func": "// Run this AFTER nvl-receive. Syncs all mapped lights from PLC state to HA entities.\n// Map comes from global roomConfig (single source of truth). See /root/.node-red/room-config.js.\n// Connect output 1 → Action node (turn_on), output 2 → Action node (turn_off).\n\nconst config = global.get('roomConfig');\nconst LIGHT_ENTITY_MAP = (config && config.lightEntityMap && config.lightEntityMap.length) ? config.lightEntityMap : [\n { room: 'l_open_plan_living_room', light: 1, entityId: 'input_boolean.open_plan_living_room_main_1' },\n];\n\nconst payload = msg.payload || {};\nconst onMsgs = [];\nconst offMsgs = [];\n\nfor (const entry of LIGHT_ENTITY_MAP) {\n const room = payload[entry.room] || {};\n const isOn = !!(room['l_' + entry.light] || room['l' + entry.light]);\n\n const flowKey = 'nvlToHa_' + entry.entityId.replace(/\\./g, '_');\n const last = flow.get(flowKey);\n if (last === isOn) continue;\n flow.set(flowKey, isOn);\n\n const domain = entry.entityId.split('.')[0] || 'input_boolean';\n const action = domain + '.' + (isOn ? 'turn_on' : 'turn_off');\n const out = { payload: { action: action, target: { entity_id: [entry.entityId] } } };\n if (isOn) onMsgs.push(out); else offMsgs.push(out);\n}\n\nif (onMsgs.length === 0 && offMsgs.length === 0) return null;\nreturn [onMsgs, offMsgs];\n", "outputs": 2, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1240, "y": 220, "wires": [ [ "566f142b2e6e841f" ], [ "5789f9ce23be8782" ] ] }, { "id": "7c4268195123e319", "type": "link in", "z": "7de41d810b04d992", "name": "link in 14", "links": [ "e059a9fd1da3c3fd" ], "x": 1015, "y": 220, "wires": [ [ "d5cdc38171230744" ] ] }, { "id": "566f142b2e6e841f", "type": "api-call-service", "z": "7de41d810b04d992", "name": "", "server": "29eb84a2708d96e0", "version": 7, "debugenabled": false, "action": "input_boolean.turn_on", "floorId": [], "areaId": [], "deviceId": [], "entityId": [ "input_boolean.living_room_new" ], "labelId": [], "data": "", "dataType": "jsonata", "mergeContext": "", "mustacheAltTags": false, "outputProperties": [], "queue": "none", "blockInputOverrides": false, "domain": "input_boolean", "service": "turn_on", "x": 1540, "y": 200, "wires": [ [] ] }, { "id": "5789f9ce23be8782", "type": "api-call-service", "z": "7de41d810b04d992", "name": "", "server": "29eb84a2708d96e0", "version": 7, "debugenabled": false, "action": "input_boolean.turn_off", "floorId": [], "areaId": [], "deviceId": [], "entityId": [ "input_boolean.living_room_new" ], "labelId": [], "data": "", "dataType": "jsonata", "mergeContext": "", "mustacheAltTags": false, "outputProperties": [], "queue": "none", "blockInputOverrides": false, "domain": "input_boolean", "service": "turn_off", "x": 1540, "y": 260, "wires": [ [] ] }, { "id": "3b1ea5253e0fbf22", "type": "function", "z": "7de41d810b04d992", "d": true, "name": "HA to NVL", "func": "// Writes to state.rooms.cmd_livingroom (NVL variable cmd_livingroom).\nconst ROOM_NAME = 'cmd_livingroom';\nconst entityId = (msg.topic || '').toString();\nconst parts = entityId.split('_');\nconst last = parts[parts.length - 1] || '';\nconst num = parseInt(last, 10);\nconst lightNum = (!isNaN(num) && num >= 1) ? Math.min(6, num) : 1;\n\n// Normalize state: HA / trigger-state can send payload as string, object with .state, or data.new_state.state\nlet rawState = msg.payload;\nif (rawState !== null && typeof rawState === 'object' && rawState.state !== undefined) rawState = rawState.state;\nif (msg.data && msg.data.new_state && msg.data.new_state.state !== undefined) rawState = msg.data.new_state.state;\nconst isOn = (rawState === 'on' || rawState === true);\n\nnode.warn('[HA to NVL] topic=' + entityId + ' rawState=' + JSON.stringify(rawState) + ' → lightNum=' + lightNum + ' isOn=' + isOn);\n\nif (!flow.get('nvlInState')) flow.set('nvlInState', { rooms: {}, boiler: {} });\nconst state = flow.get('nvlInState');\nif (!state.rooms[ROOM_NAME]) state.rooms[ROOM_NAME] = {};\nconst r = state.rooms[ROOM_NAME];\nr['ha_l' + lightNum + '_on'] = false;\nr['ha_l' + lightNum + '_off'] = false;\nif (isOn) r['ha_l' + lightNum + '_on'] = true;\nelse r['ha_l' + lightNum + '_off'] = true;\nflow.set('nvlInState', state);\n\nnode.warn('[HA to NVL] set cmd_livingroom ha_l' + lightNum + '_' + (isOn ? 'on' : 'off') + '=true, buildAndSend');\n\n// PLC uses R_TRIG (rising edge). If \"off\" still doesn’t work, add a flow: after this node, 80ms delay then clear ha_l*_off and buildAndSend again (pulse).\nmsg.payload = { buildAndSend: true };\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1130, "y": 740, "wires": [ [ "3e962e16c44a4b8a" ] ] }, { "id": "1957eb3666681641", "type": "function", "z": "7de41d810b04d992", "d": true, "name": "Zigbee to NVL", "func": "// Writes to state.rooms.cmd_livingroom (same as HA to NVL). Zigbee action → zigbee_sw1..6.\nconst ROOM_NAME = 'cmd_livingroom';\nconst actionToSwitch = { single: 1, double: 2, hold: 3, release: 4, triple: 5, quad: 6 };\nconst payload = msg.payload || {};\nconst actionRaw = (payload.action || payload.click || '').toLowerCase();\n// Support \"1_single\", \"2_double\" etc. (button_number + action) or plain \"single\", \"double\"\nconst parts = actionRaw.split('_');\nlet swIndex = null;\nif (parts.length >= 2) {\n const buttonNum = parseInt(parts[0], 10);\n if (buttonNum >= 1 && buttonNum <= 6) swIndex = buttonNum;\n}\nif (swIndex == null) swIndex = actionToSwitch[actionRaw];\nif (swIndex == null && parts.length >= 2) swIndex = actionToSwitch[parts.slice(1).join('_')];\nif (swIndex == null) swIndex = actionToSwitch[parts[parts.length - 1]];\n\nif (swIndex == null) {\n node.warn('[Zigbee to NVL] unknown action: ' + JSON.stringify(actionRaw) + ' payload=' + JSON.stringify(payload));\n return null;\n}\n\nif (!flow.get('nvlInState')) flow.set('nvlInState', { rooms: {}, boiler: {} });\nconst state = flow.get('nvlInState');\nif (!state.rooms[ROOM_NAME]) state.rooms[ROOM_NAME] = {};\nstate.rooms[ROOM_NAME]['zigbee_sw' + swIndex] = true;\nflow.set('nvlInState', state);\n\nnode.warn('[Zigbee to NVL] cmd_livingroom zigbee_sw' + swIndex + '=true (action=' + actionRaw + '), buildAndSend + zigbeeClear');\n\nmsg.payload = { buildAndSend: true };\nmsg.zigbeeClear = { room: ROOM_NAME, key: 'zigbee_sw' + swIndex };\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1120, "y": 800, "wires": [ [ "30fab57c9aad15eb", "3e962e16c44a4b8a" ] ] }, { "id": "30fab57c9aad15eb", "type": "delay", "z": "7de41d810b04d992", "d": true, "name": "80ms", "pauseType": "delay", "timeout": "80", "timeoutUnits": "milliseconds", "rate": "1", "nbRateUnits": "1", "rateUnits": "seconds", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": true, "outputs": 1, "x": 1310, "y": 800, "wires": [ [ "ef18cce9c468177c" ] ] }, { "id": "ef18cce9c468177c", "type": "function", "z": "7de41d810b04d992", "d": true, "name": "Clear zigbee edge", "func": "if (msg.zigbeeClear) {\n const state = flow.get('nvlInState') || { rooms: {}, boiler: {} };\n const r = state.rooms[msg.zigbeeClear.room];\n if (r) r[msg.zigbeeClear.key] = false;\n flow.set('nvlInState', state);\n}\nmsg.payload = { buildAndSend: true };\nreturn msg;", "outputs": 1, "x": 1510, "y": 800, "wires": [ [ "3e962e16c44a4b8a" ] ] }, { "id": "79c6501879706e27", "type": "zigbee2mqtt-in", "z": "7de41d810b04d992", "d": true, "name": "", "server": "4e20fc347c658518", "friendly_name": "Office Switch (TS0042)", "device_id": "0xa4c138a5b9771b05", "state": "0", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 900, "y": 800, "wires": [ [ "1957eb3666681641" ] ] }, { "id": "bcf5055c45c97cc3", "type": "link out", "z": "7de41d810b04d992", "d": true, "name": "link out 27", "mode": "link", "links": [ "c6162cb59e21491f" ], "x": 1530, "y": 740, "wires": [], "l": true }, { "id": "96ed40d44eeab413", "type": "trigger-state", "z": "7de41d810b04d992", "d": true, "name": "", "server": "29eb84a2708d96e0", "version": 5, "inputs": 1, "outputs": 2, "exposeAsEntityConfig": "", "entities": { "entity": [ "input_boolean.living_room_new" ], "substring": [], "regex": [] }, "debugEnabled": true, "constraints": [], "customOutputs": [], "outputInitially": false, "stateType": "str", "enableInput": true, "x": 850, "y": 740, "wires": [ [ "3b1ea5253e0fbf22" ], [] ] }, { "id": "3e962e16c44a4b8a", "type": "function", "z": "7de41d810b04d992", "d": true, "name": "NVL SEND", "func": "// Build the payload for nvl-send from flow.nvlInState.\n// Redesign: all rooms use struct_room_cmds. Add more names to roomNames when you add rooms.\n// Wire: HA to NVL / Zigbee to NVL → this function → nvl-send → udp out\n\nconst struct_room_cmds_default = {\n ha_l1_on: false, ha_l1_off: false, ha_l2_on: false, ha_l2_off: false,\n ha_l3_on: false, ha_l3_off: false, ha_l4_on: false, ha_l4_off: false,\n ha_l5_on: false, ha_l5_off: false, ha_l6_on: false, ha_l6_off: false,\n zigbee_sw1: false, zigbee_sw2: false, zigbee_sw3: false,\n zigbee_sw4: false, zigbee_sw5: false, zigbee_sw6: false,\n ha_all_on: false, ha_all_off: false\n};\n\n// NVL variable names per room (struct_room_cmds). Add more when you add rooms.\nconst roomNames = ['open_plan_living_room'];\n\nconst state = flow.get('nvlInState') || { rooms: {}, boiler: {} };\nconst rooms = state.rooms || {};\nconst payload = {};\n\nfor (const name of roomNames) {\n const cmd = rooms[name] || {};\n payload[name] = { ...struct_room_cmds_default };\n for (const k of Object.keys(struct_room_cmds_default)) {\n if (cmd[k] !== undefined) payload[name][k] = !!cmd[k];\n }\n}\n\nmsg.payload = payload;\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1330, "y": 740, "wires": [ [ "bcf5055c45c97cc3" ] ] }, { "id": "747c5e9bf3763dac", "type": "function", "z": "7de41d810b04d992", "d": true, "name": "NVL to HA Sync", "func": "// Run this AFTER nvl-receive. Syncs all mapped lights from PLC state to HA entities.\n// Connect output 1 → api-call-service (input_boolean.turn_on / light.turn_on), output 2 → api-call-service (turn_off).\n// Only outputs when state changed (per entity). Add more entries to LIGHT_ENTITY_MAP as you add rooms/lights.\n\n// Map: NVL room key (in payload) + light index 1..6 → HA entity_id\nconst LIGHT_ENTITY_MAP = [\n { room: 'l_open_plan_living_room', light: 1, entityId: 'input_boolean.open_plan_living_room_main_1' },\n // { room: 'l_open_plan_living_room', light: 2, entityId: 'input_boolean.open_plan_living_room_spots_1' },\n // { room: 'l_kitchen_kitchen', light: 1, entityId: 'input_boolean.kitchen_kitchen_main_1' },\n];\n\nconst payload = msg.payload || {};\nconst onMsgs = [];\nconst offMsgs = [];\n\nfor (const entry of LIGHT_ENTITY_MAP) {\n const room = payload[entry.room] || {};\n const isOn = !!(room['l_' + entry.light] || room['l' + entry.light]);\n\n const flowKey = 'nvlToHa_' + entry.entityId.replace(/\\./g, '_');\n const last = flow.get(flowKey);\n if (last === isOn) continue;\n flow.set(flowKey, isOn);\n\n const out = { payload: { entity_id: entry.entityId } };\n if (isOn) onMsgs.push(out); else offMsgs.push(out);\n}\n\nif (onMsgs.length === 0 && offMsgs.length === 0) return null;\nreturn [onMsgs, offMsgs];\n", "outputs": 2, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1200, "y": 640, "wires": [ [ "320ececfad817f94" ], [ "577d462afbb43835" ] ] }, { "id": "032f98ab9d5085b8", "type": "link in", "z": "7de41d810b04d992", "d": true, "name": "link in 15", "links": [ "e059a9fd1da3c3fd" ], "x": 975, "y": 640, "wires": [ [ "747c5e9bf3763dac" ] ] }, { "id": "320ececfad817f94", "type": "api-call-service", "z": "7de41d810b04d992", "d": true, "name": "", "server": "29eb84a2708d96e0", "version": 7, "debugenabled": false, "action": "input_boolean.turn_on", "floorId": [], "areaId": [], "deviceId": [], "entityId": [ "input_boolean.living_room_new" ], "labelId": [], "data": "", "dataType": "jsonata", "mergeContext": "", "mustacheAltTags": false, "outputProperties": [], "queue": "none", "blockInputOverrides": false, "domain": "input_boolean", "service": "turn_on", "x": 1500, "y": 620, "wires": [ [] ] }, { "id": "577d462afbb43835", "type": "api-call-service", "z": "7de41d810b04d992", "d": true, "name": "", "server": "29eb84a2708d96e0", "version": 7, "debugenabled": false, "action": "input_boolean.turn_off", "floorId": [], "areaId": [], "deviceId": [], "entityId": [ "input_boolean.living_room_new" ], "labelId": [], "data": "", "dataType": "jsonata", "mergeContext": "", "mustacheAltTags": false, "outputProperties": [], "queue": "none", "blockInputOverrides": false, "domain": "input_boolean", "service": "turn_off", "x": 1500, "y": 680, "wires": [ [] ] }, { "id": "9f25a0709e29f737", "type": "function", "z": "7de41d810b04d992", "d": true, "name": "Zigbee to NVL", "func": "// Writes to state.rooms.. Room from Zigbee device via global roomConfig.deviceToRoom. See /root/.node-red/room-config.js.\nconst actionToSwitch = { single: 1, double: 2, hold: 3, release: 4, triple: 5, quad: 6 };\nconst config = global.get('roomConfig');\nconst deviceToRoom = (config && config.deviceToRoom) ? config.deviceToRoom : { 'Office Switch': 'cmd_livingroom' };\nconst friendlyName = (msg.payload && msg.payload.friendly_name) ? msg.payload.friendly_name : '';\nconst ROOM_NAME = deviceToRoom[friendlyName] || 'cmd_livingroom';\nconst payload = msg.payload || {};\nconst actionRaw = (payload.action || payload.click || '').toLowerCase();\n// Support \"1_single\", \"2_double\" etc. (button_number + action) or plain \"single\", \"double\"\nconst parts = actionRaw.split('_');\nlet swIndex = null;\nif (parts.length >= 2) {\n const buttonNum = parseInt(parts[0], 10);\n if (buttonNum >= 1 && buttonNum <= 6) swIndex = buttonNum;\n}\nif (swIndex == null) swIndex = actionToSwitch[actionRaw];\nif (swIndex == null && parts.length >= 2) swIndex = actionToSwitch[parts.slice(1).join('_')];\nif (swIndex == null) swIndex = actionToSwitch[parts[parts.length - 1]];\n\nif (swIndex == null) {\n node.warn('[Zigbee to NVL] unknown action: ' + JSON.stringify(actionRaw) + ' payload=' + JSON.stringify(payload));\n return null;\n}\n\nif (!flow.get('nvlInState')) flow.set('nvlInState', { rooms: {}, boiler: {} });\nconst state = flow.get('nvlInState');\nif (!state.rooms[ROOM_NAME]) state.rooms[ROOM_NAME] = {};\nstate.rooms[ROOM_NAME]['zigbee_sw' + swIndex] = true;\nflow.set('nvlInState', state);\n\nnode.warn('[Zigbee to NVL] ' + ROOM_NAME + ' zigbee_sw' + swIndex + '=true (action=' + actionRaw + '), buildAndSend + zigbeeClear');\n\nmsg.payload = { buildAndSend: true };\nmsg.zigbeeClear = { room: ROOM_NAME, key: 'zigbee_sw' + swIndex };\nreturn msg;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1200, "y": 540, "wires": [ [] ] }, { "id": "a0b2279b89ef6f15", "type": "function", "z": "7de41d810b04d992", "d": true, "name": "Load room config", "func": "// Paste this into a Function node named \"Load room config\".\n// Connect an Inject node (once after 0.5 s) to it so it runs at startup.\n//\n// Since functionExternalModules is true in settings.js, you can require files.\n// room-config.js must be on the Node-RED server at /root/.node-red/room-config.js\n\n// Delete cached version so changes to the file are picked up on redeploy\ndelete require.cache[require.resolve('/root/.node-red/room-config.js')];\nconst ROOM_CONFIG = require('/root/.node-red/room-config.js');\n\nglobal.set('roomConfig', ROOM_CONFIG);\nnode.warn('[Load room config] loaded: ' + ROOM_CONFIG.roomNames.length + ' rooms, ' + ROOM_CONFIG.lightEntityMap.length + ' light mappings');\nreturn null;\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 850, "y": 140, "wires": [ [ "8150e2ee9131f8b9" ] ] }, { "id": "7667d77649229573", "type": "inject", "z": "7de41d810b04d992", "d": true, "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": true, "onceDelay": "0.5", "topic": "", "payload": "", "payloadType": "date", "x": 650, "y": 140, "wires": [ [ "a0b2279b89ef6f15" ] ] }, { "id": "8150e2ee9131f8b9", "type": "debug", "z": "7de41d810b04d992", "d": true, "name": "debug 36", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1040, "y": 140, "wires": [] }, { "id": "a4e26ffa4890dced", "type": "watch", "z": "7de41d810b04d992", "name": "Watch room-config.js", "files": "/root/.node-red/room-config.js", "recursive": "", "x": 780, "y": 80, "wires": [ [ "9b42b7c654e069ab", "5f1f1b1d56c0c6cc" ] ] }, { "id": "9b42b7c654e069ab", "type": "exec", "z": "7de41d810b04d992", "command": "node -e \"console.log(JSON.stringify(require('/root/.node-red/room-config.js')))\"", "addpay": "payload", "append": "", "useSpawn": "false", "timer": "", "winHide": false, "oldrc": false, "name": "Read room-config as JSON", "x": 1120, "y": 80, "wires": [ [ "8fcbcdbb7ce4c8e5", "2744d5e479e716b2" ], [ "c59934f4f1db0826" ], [ "1b367a15a867effc" ] ] }, { "id": "8fcbcdbb7ce4c8e5", "type": "function", "z": "7de41d810b04d992", "name": "Reload room config", "func": "// Paste into a Function node named \"Reload room config from payload\".\n// Input: msg.payload = JSON string (from Exec node that runs the script below).\n// Sets global roomConfig so all flows see the new config without restarting Node-RED.\n\nconst raw = msg.payload;\nif (typeof raw !== 'string') {\n node.warn('[Reload config] expected string payload, got ' + typeof raw);\n return null;\n}\ntry {\n const config = JSON.parse(raw.trim());\n if (!config.roomNames || !Array.isArray(config.roomNames)) {\n node.error('[Reload config] invalid config: missing roomNames');\n return null;\n }\n global.set('roomConfig', config);\n node.warn('[Reload config] OK: ' + config.roomNames.length + ' rooms, ' + (config.lightEntityMap ? config.lightEntityMap.length : 0) + ' light mappings');\n return msg;\n} catch (e) {\n node.error('[Reload config] parse error: ' + e.message);\n return null;\n}\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1430, "y": 80, "wires": [ [] ] }, { "id": "5f1f1b1d56c0c6cc", "type": "debug", "z": "7de41d810b04d992", "name": "debug 37", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 950, "y": 40, "wires": [] }, { "id": "2744d5e479e716b2", "type": "debug", "z": "7de41d810b04d992", "name": "debug 39", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1420, "y": 40, "wires": [] }, { "id": "c59934f4f1db0826", "type": "debug", "z": "7de41d810b04d992", "name": "debug 40", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1420, "y": 120, "wires": [] }, { "id": "1b367a15a867effc", "type": "debug", "z": "7de41d810b04d992", "name": "debug 41", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1350, "y": 160, "wires": [] }, { "id": "561398f1884392c1", "type": "debug", "z": "7de41d810b04d992", "name": "debug 42", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1710, "y": 540, "wires": [] }, { "id": "2edb29caf874a91e", "type": "debug", "z": "7de41d810b04d992", "name": "debug 43", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1070, "y": 460, "wires": [] }, { "id": "d592161c8e50638a", "type": "debug", "z": "480553bb6f5b2b51", "g": "91b1f4cb0e1ffa84", "name": "debug 7", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 2540, "y": 80, "wires": [] }, { "id": "2a218aee475ce267", "type": "debug", "z": "480553bb6f5b2b51", "g": "91b1f4cb0e1ffa84", "name": "debug 10", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 2540, "y": 120, "wires": [] }, { "id": "f5ef8cb0a1bc7def", "type": "telegram receiver", "z": "480553bb6f5b2b51", "g": "91b1f4cb0e1ffa84", "name": "", "bot": "3dbb887330025103", "saveDataDir": "", "filterCommands": false, "inputs": 0, "x": 2350, "y": 80, "wires": [ [ "d592161c8e50638a" ], [ "2a218aee475ce267" ] ] }, { "id": "0385d24efa18d698", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "", "server": "4e20fc347c658518", "friendly_name": "Hallway Door Sensor (TS0203)", "device_id": "0xa4c138eb9239e0de", "state": "contact", "outputAtStartup": true, "filterChanges": true, "enableMultiple": false, "x": 190, "y": 120, "wires": [ [ "4055425d6c42dd13" ] ] }, { "id": "9d611c0ff2a0b1ca", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "", "server": "4e20fc347c658518", "friendly_name": "Basement Door Sensor (E2013)", "device_id": "0x048727fffea28deb", "state": "contact", "outputAtStartup": true, "filterChanges": true, "enableMultiple": false, "x": 190, "y": 160, "wires": [ [ "4055425d6c42dd13" ] ] }, { "id": "10448f46514c1406", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "", "server": "4e20fc347c658518", "friendly_name": "Front Door Sensor (TS0203)", "device_id": "0xa4c138f4b1035c1d", "state": "contact", "outputAtStartup": true, "filterChanges": true, "enableMultiple": false, "x": 180, "y": 200, "wires": [ [ "4055425d6c42dd13" ] ] }, { "id": "a9d786b1ba52704b", "type": "function", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "Generate Message with snapshot", "func": "let contact = msg.payload;\nlet topic = msg.topic || '';\nlet rawName = topic.split('/')[1] || 'Unknown';\nlet cleanName = rawName.replace(/sensor/i, '').trim();\n\n// Mapping between sensor names (or topic parts) and their camera IPs\nconst cameraMap = {\n \"Hallway\": \"10.20.30.33\",\n \"Basement\": \"10.20.30.30\",\n \"Front\": \"10.20.30.30\",\n \"Veranda\": \"10.20.30.32\"\n};\n\n// Find matching camera IP based on topic\nlet cameraIP = Object.keys(cameraMap).find(key => topic.includes(key));\nlet ip = cameraMap[cameraIP] || \"10.20.30.30\"; // fallback to Hallway if not matched\n\n// Construct URL\nmsg.url = `http://${ip}/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=${Math.random().toString(36).substring(7)}&user=admin&password=sh1pb0x1`;\n\n// Final message structure\nmsg.payload = null; // clear previous payload\nmsg.friendly_name = cleanName;\nmsg.door_status = contact === true ? \"CLOSED\" : \"OPENED\";\n\nreturn msg;\n\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 920, "y": 120, "wires": [ [ "5e94eb39aec6e82d", "8b8cce25637907b1" ] ] }, { "id": "e250cc2f901bea9f", "type": "function", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "Send Message to group", "func": "// Check that the snapshot came in as a binary buffer\nif (!Buffer.isBuffer(msg.payload)) {\n node.warn(\"āŒ Snapshot fetch failed — not a binary image buffer\");\n return null;\n}\n\nmsg.payload = {\n chatId: -4747176681,\n type: 'photo',\n content: msg.payload, // this is the buffer\n caption: `🚪 ${msg.friendly_name} just ${msg.door_status}`\n};\n\nreturn msg;\n\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1410, "y": 120, "wires": [ [ "7301d71523d87e94" ] ] }, { "id": "5e94eb39aec6e82d", "type": "debug", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "debug 6", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "statusVal": "", "statusType": "auto", "x": 1160, "y": 60, "wires": [] }, { "id": "8b8cce25637907b1", "type": "http request", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "", "method": "GET", "ret": "bin", "paytoqs": "query", "url": "", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 1190, "y": 120, "wires": [ [ "e250cc2f901bea9f" ] ] }, { "id": "3f9797c13c3a11a1", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "9113c5ebf5c089e3", "name": "Door Status Message", "func": "// Extract contact state and sensor name\nlet contact = msg.payload;\nlet topic = msg.topic || '';\nlet rawName = topic.split('/')[1] || 'Unknown';\nlet cleanName = rawName.replace(/sensor/i, '').trim();\n\n// Create message\nmsg.payload = {\n chatId: -4747176681,\n type: 'message',\n content: `🚪 ${cleanName} just ${contact === true ? \"CLOSED\" : \"OPENED\"}`\n};\n\nreturn msg;\n\n\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 940, "y": 60, "wires": [ [] ] }, { "id": "c57ea029ee569428", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "a73395db2426b4fc", "name": "", "server": "4e20fc347c658518", "friendly_name": "Front Water Valve (SWV)", "device_id": "0x0ceff6fffe84e4bc", "state": "state", "outputAtStartup": false, "filterChanges": true, "enableMultiple": false, "x": 610, "y": 540, "wires": [ [ "fe7372c7f33d96f3" ] ] }, { "id": "fe7372c7f33d96f3", "type": "function", "z": "480553bb6f5b2b51", "g": "a73395db2426b4fc", "name": "Status Message", "func": "let state = msg.payload;\nlet status = state === 'ON' ? \"OPENED\" : \"CLOSED\";\n\nmsg.payload = {\n chatId: -4747176681, // your group chat ID\n type: 'message',\n content: `šŸ’§ Front Water Valve is now ${status}`\n};\n\nreturn msg;\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 840, "y": 540, "wires": [ [ "18454d6cad2042dc" ] ] }, { "id": "c1d2a4dc34b63730", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "a73395db2426b4fc", "name": "", "server": "4e20fc347c658518", "friendly_name": "Back Water Valve (SWV)", "device_id": "0x7cc6b6fffe38a415", "state": "state", "outputAtStartup": false, "filterChanges": true, "enableMultiple": false, "x": 610, "y": 600, "wires": [ [ "141f635c6c9d380f" ] ] }, { "id": "141f635c6c9d380f", "type": "function", "z": "480553bb6f5b2b51", "g": "a73395db2426b4fc", "name": "Status Message", "func": "let state = msg.payload;\nlet status = state === 'ON' ? \"OPENED\" : \"CLOSED\";\n\nmsg.payload = {\n chatId: -4747176681, // your group chat ID\n type: 'message',\n content: `šŸ’§ Back Water Valve is now ${status}`\n};\n\nreturn msg;\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 840, "y": 600, "wires": [ [ "18454d6cad2042dc" ] ] }, { "id": "77f3053cbdcdb875", "type": "debug", "z": "480553bb6f5b2b51", "name": "debug 9", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 2540, "y": 260, "wires": [] }, { "id": "55c50c70b3d0a0bb", "type": "telegram sender", "z": "480553bb6f5b2b51", "name": "", "bot": "3dbb887330025103", "haserroroutput": false, "outputs": 1, "x": 2330, "y": 260, "wires": [ [ "77f3053cbdcdb875" ] ] }, { "id": "41d29e978759e26e", "type": "link in", "z": "480553bb6f5b2b51", "name": "telegram sender", "links": [ "7301d71523d87e94", "18454d6cad2042dc", "70f797398b0e6783", "81d16e7a5307e9cc", "bd7fed2198a7b950", "8f15067daf678e66", "1ba4ee81e40e5c51" ], "x": 2145, "y": 260, "wires": [ [ "55c50c70b3d0a0bb" ] ] }, { "id": "7301d71523d87e94", "type": "link out", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "link out 16", "mode": "link", "links": [ "41d29e978759e26e" ], "x": 1555, "y": 120, "wires": [] }, { "id": "18454d6cad2042dc", "type": "link out", "z": "480553bb6f5b2b51", "g": "a73395db2426b4fc", "name": "link out 17", "mode": "link", "links": [ "41d29e978759e26e" ], "x": 1055, "y": 540, "wires": [] }, { "id": "4055425d6c42dd13", "type": "api-current-state", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "", "server": "29eb84a2708d96e0", "version": 3, "outputs": 2, "halt_if": "home", "halt_if_type": "str", "halt_if_compare": "is", "entity_id": "person.nearchos_paraskeva", "state_type": "str", "blockInputOverrides": false, "outputProperties": [], "for": "", "forType": "num", "forUnits": "seconds", "override_topic": false, "state_location": "payload", "override_payload": "msg", "entity_location": "data", "override_data": "msg", "x": 570, "y": 120, "wires": [ [], [ "a9d786b1ba52704b", "f6adcaa35a793e58" ] ] }, { "id": "ada6fe8339eab29b", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "", "server": "4e20fc347c658518", "friendly_name": "Veranda Door Sensor (E2013)", "device_id": "0x048727fffea287ba", "state": "contact", "outputAtStartup": true, "filterChanges": true, "enableMultiple": false, "x": 180, "y": 260, "wires": [ [ "4055425d6c42dd13" ] ] }, { "id": "8f42e8fdfef40579", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "", "server": "4e20fc347c658518", "friendly_name": "Pantry water leak Sensor (ZG-222ZA)", "device_id": "0xa4c138aeed18e61c", "state": "water_leak", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 230, "y": 620, "wires": [ [ "1164cfc4fd2e5382" ] ] }, { "id": "58ee1ac91f379cb9", "type": "function", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Status Message", "func": "let state = msg.payload;\n\nif (state === true) {\n msg.payload = {\n chatId: -4747176681, // your group chat ID\n type: 'animation',\n content: 'https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExeWoxNjV6Z2Fna3MxMjcxd3RsaWxjMTA3cWhraW9kbGYzbGFtNzUzYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/lVBtp4SRW6rvDHf1b6/giphy.gif', // Replace with your preferred GIF URL\n caption: '🚨 WATER LEAK DETECTED in Pantry Sink!'\n };\n return msg;\n}\n\nreturn null;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1000, "y": 460, "wires": [ [ "70f797398b0e6783" ] ] }, { "id": "a1f1e1ea2cf90f61", "type": "inject", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Simulate Leak (true)", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "true", "payloadType": "bool", "x": 290, "y": 420, "wires": [ [ "22740e52f6cc3399" ] ] }, { "id": "3242605bce7f6f92", "type": "inject", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Simulate No Leak (false)", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "false", "payloadType": "bool", "x": 270, "y": 460, "wires": [ [ "22740e52f6cc3399" ] ] }, { "id": "22740e52f6cc3399", "type": "function", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Prepare trigger/reset", "func": "// Pass through leak state\n// Add reset flag when false\n\nif (msg.payload === false) {\n msg.reset = true;\n}\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 420, "wires": [ [ "53799a37bb6cf7c6" ] ] }, { "id": "53799a37bb6cf7c6", "type": "trigger", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Repeat every 1 min", "op1": "true", "op2": "true", "op1type": "bool", "op2type": "bool", "duration": "1", "extend": true, "overrideDelay": false, "units": "min", "reset": "reset", "bytopic": "all", "topic": "topic", "outputs": 1, "x": 780, "y": 420, "wires": [ [ "8b9761ea2f86b4f1" ] ] }, { "id": "8b9761ea2f86b4f1", "type": "function", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Status Message", "func": "let state = msg.payload;\n\nif (state === true) {\n msg.payload = {\n chatId: -4747176681, // your group chat ID\n type: 'animation',\n content: 'https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExeWoxNjV6Z2Fna3MxMjcxd3RsaWxjMTA3cWhraW9kbGYzbGFtNzUzYiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/lVBtp4SRW6rvDHf1b6/giphy.gif', // Replace with your preferred GIF URL\n caption: '🚨 WATER LEAK DETECTED in Kitchen Sink!'\n };\n return msg;\n}\n\nreturn null;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1000, "y": 420, "wires": [ [ "70f797398b0e6783" ] ] }, { "id": "70f797398b0e6783", "type": "link out", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "link out 19", "mode": "link", "links": [ "41d29e978759e26e" ], "x": 1575, "y": 440, "wires": [] }, { "id": "2157cdd444dfec91", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "", "server": "4e20fc347c658518", "friendly_name": "kitchen water leak sensor (E2202)", "device_id": "0xf84477fffeec19e9", "state": "water_leak", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 240, "y": 500, "wires": [ [ "22740e52f6cc3399" ] ] }, { "id": "8b2f06afcf0d773e", "type": "inject", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Simulate Leak (true)", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "true", "payloadType": "bool", "x": 290, "y": 540, "wires": [ [ "1164cfc4fd2e5382" ] ] }, { "id": "e31ec1ce332c4c99", "type": "inject", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Simulate No Leak (false)", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "false", "payloadType": "bool", "x": 270, "y": 580, "wires": [ [ "1164cfc4fd2e5382" ] ] }, { "id": "1164cfc4fd2e5382", "type": "function", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Prepare trigger/reset", "func": "// Pass through leak state\n// Add reset flag when false\n\nif (msg.payload === false) {\n msg.reset = true;\n}\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 560, "y": 460, "wires": [ [ "748c39a404648158" ] ] }, { "id": "748c39a404648158", "type": "trigger", "z": "480553bb6f5b2b51", "g": "5c95d99a679a5e00", "name": "Repeat every 1 min", "op1": "true", "op2": "true", "op1type": "bool", "op2type": "bool", "duration": "1", "extend": true, "overrideDelay": false, "units": "min", "reset": "reset", "bytopic": "all", "topic": "topic", "outputs": 1, "x": 790, "y": 460, "wires": [ [ "58ee1ac91f379cb9" ] ] }, { "id": "eb721beae24b271b", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "1c73b8aaec035f06", "name": "", "server": "4e20fc347c658518", "friendly_name": "27 selected", "device_id": [ "0xa4c138ff324b5b7e", "0xa4c138a5b9771b05", "0xa4c13873de3faa66", "0xa4c138cc9b54cec9", "0xa4c138112a12d55f", "0xa4c13854734f3a20", "0xa4c1387dd1c2d40e", "0xa4c138332cc3da08", "0xa4c1388b74d83cfa", "0xa4c138c2ae9ed430", "0xa4c1380bab38d546", "0xa4c1383b7c24483a", "0x8c65a3fffee879a6", "0xa4c138ceaa5681d5", "0xa4c138d65f53037c", "0xa4c1383d7921827a", "0xa4c138eb9239e0de", "0xa4c13891821386eb", "0xa4c138f4b1035c1d", "0x0ceff6fffe84e4bc", "0x7cc6b6fffe38a415", "0x048727fffea28deb", "0x6cfd22fffe2cc318", "0x6cfd22fffe66db44", "0xa4c138aeed18e61c", "0xf84477fffeec19e9", "0x048727fffea287ba" ], "state": null, "outputAtStartup": false, "filterChanges": false, "enableMultiple": true, "x": 150, "y": 820, "wires": [ [ "41f1e9feaf1ea6aa", "a9f755806e4e8a75" ] ] }, { "id": "41f1e9feaf1ea6aa", "type": "function", "z": "480553bb6f5b2b51", "g": "1c73b8aaec035f06", "name": "function 5", "func": "let result = [];\nlet devices = msg.payload;\nlet now = Date.now();\nlet dayMs = 24 * 60 * 60 * 1000;\n\n// Use flow context to track last alerts\nlet lastAlerts = flow.get(\"battery_alerts\") || {};\n\nfor (let ieee in devices) {\n let dev = devices[ieee];\n let battery = dev.payload?.battery ?? dev.item?.current_values?.battery;\n let name = dev.item?.friendly_name || dev.topic || ieee;\n\n if (typeof battery === 'number' && battery < 15) {\n let lastAlert = lastAlerts[ieee];\n\n if (!lastAlert || now - lastAlert > dayMs) {\n result.push(`šŸ”‹ ${name} is at ${battery}%`);\n lastAlerts[ieee] = now; // update timestamp\n }\n }\n}\n\n// Save updated state\nflow.set(\"battery_alerts\", lastAlerts);\n\nif (result.length > 0) {\n let time = new Date().toLocaleString();\n msg.payload = `Low battery alert(s) [${time}]:\\n` + result.join('\\n');\n return msg;\n}\n\nreturn null;\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 600, "y": 740, "wires": [ [ "c60307d3b68ebe34", "5c2272c244ffc8b0" ] ] }, { "id": "c60307d3b68ebe34", "type": "function", "z": "480553bb6f5b2b51", "g": "1c73b8aaec035f06", "name": "function 6", "func": "let battery = msg.payload;\n\n\nmsg.payload = {\n chatId: -4747176681, // your group chat ID\n type: 'message',\n content: `${battery}`\n};\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1040, "y": 740, "wires": [ [ "81d16e7a5307e9cc", "6d60df5c0c6920d2" ] ] }, { "id": "81d16e7a5307e9cc", "type": "link out", "z": "480553bb6f5b2b51", "g": "1c73b8aaec035f06", "name": "link out 18", "mode": "link", "links": [ "41d29e978759e26e" ], "x": 1575, "y": 740, "wires": [] }, { "id": "209d79611a5414cc", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "1c73b8aaec035f06", "name": "function 7", "func": "let result = [];\nlet devices = msg.payload;\n\nfor (let ieee in devices) {\n let dev = devices[ieee];\n\n // Try to get battery from payload or fallback to item.current_values\n let battery = dev.payload?.battery ?? dev.item?.current_values?.battery;\n\n // Get friendly name or fallback to topic or IEEE\n let name = dev.item?.friendly_name || dev.topic || ieee;\n // if (typeof battery === 'number') {\n if (typeof battery === 'number' && battery < 15) {\n result.push(`šŸ”‹ ${name} is at ${battery}%`);\n }\n}\n\nif (result.length > 0) {\n msg.payload = `Low battery alert(s):\\n` + result.join('\\n');\n return msg;\n}\n\nreturn null;\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 600, "y": 780, "wires": [ [] ] }, { "id": "e6a93b0cbc48af98", "type": "inject", "z": "480553bb6f5b2b51", "g": "1c73b8aaec035f06", "name": "Test Device", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "zigbee2mqtt/Test Device", "payload": "{\"0xdeadbeef00000001\":{\"item\":{\"friendly_name\":\"Low Battery Sensor\"},\"topic\":\"zigbee2mqtt/Low Battery Sensor\",\"payload\":{\"battery\":9}},\"0xdeadbeef00000002\":{\"item\":{\"friendly_name\":\"Good Battery Sensor\"},\"topic\":\"zigbee2mqtt/Good Battery Sensor\",\"payload\":{\"battery\":87}}}", "payloadType": "json", "x": 170, "y": 740, "wires": [ [ "41f1e9feaf1ea6aa", "a9f755806e4e8a75" ] ] }, { "id": "a9f755806e4e8a75", "type": "debug", "z": "480553bb6f5b2b51", "g": "1c73b8aaec035f06", "name": "debug 2", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 160, "y": 780, "wires": [] }, { "id": "5c2272c244ffc8b0", "type": "debug", "z": "480553bb6f5b2b51", "g": "1c73b8aaec035f06", "name": "debug 3", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 760, "y": 760, "wires": [] }, { "id": "6d60df5c0c6920d2", "type": "debug", "z": "480553bb6f5b2b51", "g": "1c73b8aaec035f06", "name": "debug 4", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1200, "y": 760, "wires": [] }, { "id": "8e0d5ec04f029b9a", "type": "zigbee2mqtt-in", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "Door Sensors", "server": "4e20fc347c658518", "friendly_name": "4 selected", "device_id": [ "0xa4c138eb9239e0de", "0xa4c138f4b1035c1d", "0x048727fffea28deb", "0x048727fffea287ba" ], "state": null, "outputAtStartup": false, "filterChanges": false, "enableMultiple": true, "x": 130, "y": 80, "wires": [ [ "eb25ece689ea1045", "63cb264d89898c6a" ] ] }, { "id": "eb25ece689ea1045", "type": "rbe", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "", "func": "rbe", "gap": "", "start": "", "inout": "out", "septopics": true, "property": "payload", "topi": "topic", "x": 350, "y": 80, "wires": [ [ "bd4b7dd437c1aaaf" ] ] }, { "id": "63cb264d89898c6a", "type": "debug", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "debug 5", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 270, "y": 40, "wires": [] }, { "id": "bd4b7dd437c1aaaf", "type": "debug", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "debug 8", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 470, "y": 60, "wires": [] }, { "id": "f6adcaa35a793e58", "type": "debug", "z": "480553bb6f5b2b51", "g": "9113c5ebf5c089e3", "name": "debug 11", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 850, "y": 200, "wires": [] }, { "id": "8656a450e0ae020d", "type": "mqtt in", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "", "topic": "#", "qos": "2", "datatype": "auto-detect", "broker": "a1235a09a8d34dea", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 150, "y": 1200, "wires": [ [ "7ff8359abb38dca4" ] ] }, { "id": "7ff8359abb38dca4", "type": "switch", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "", "property": "topic", "propertyType": "msg", "rules": [ { "t": "cont", "v": "zigbee2mqtt", "vt": "str" }, { "t": "eq", "v": "frigate/doorbell/person", "vt": "str" }, { "t": "eq", "v": "frigate/veranda_door/person", "vt": "str" }, { "t": "eq", "v": "frigate/basement_driveway/person", "vt": "str" }, { "t": "cont", "v": "frigate", "vt": "str" }, { "t": "else" } ], "checkall": "true", "repair": false, "outputs": 6, "x": 330, "y": 1200, "wires": [ [], [ "doorbell_state_check" ], [ "48bfe0ad8a973a84" ], [ "365adc2679063bc8" ], [], [] ] }, { "id": "doorbell_state_check", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Check State Change", "func": "// Get current payload value\nvar currentValue = parseInt(msg.payload);\n\n// Get previous state from context (default to 0 if not set)\nvar previousValue = context.get('previousDoorbellState') || 0;\n\n// Store current value for next comparison\ncontext.set('previousDoorbellState', currentValue);\n\n// Only proceed if current value is 1 AND previous value was 0\nif (currentValue === 1 && previousValue === 0) {\n msg.payload = \"🚪 Person detected at doorbell!\";\n return msg;\n}\n\n// Don't send message for other cases\nreturn null;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 700, "y": 1200, "wires": [ [ "78a1c2a40934ef20" ] ] }, { "id": "bd7fed2198a7b950", "type": "link out", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "link out 22", "mode": "link", "links": [ "41d29e978759e26e" ], "x": 2335, "y": 1200, "wires": [] }, { "id": "78a1c2a40934ef20", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Generate Doorbell Camera URL", "func": "// Hardcoded doorbell camera IP\nconst doorbellCameraIP = \"10.20.30.30\";\n\n// Generate random string for cache busting\nconst randomString = Math.random().toString(36).substring(7);\n\n// Construct camera snapshot URL\nmsg.url = `http://${doorbellCameraIP}/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=${randomString}&user=admin&password=sh1pb0x1`;\n\n// Clear payload for HTTP request\nmsg.payload = null;\n\n// Add camera info to message\nmsg.camera_ip = doorbellCameraIP;\nmsg.camera_location = \"Doorbell Camera\";\n\nnode.status({fill:\"blue\", shape:\"dot\", text:`URL: ${doorbellCameraIP}`});\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 990, "y": 1200, "wires": [ [ "05f0d77a9b605f22" ] ] }, { "id": "05f0d77a9b605f22", "type": "http request", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Fetch Camera Snapshot", "method": "GET", "ret": "bin", "paytoqs": "query", "url": "", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 1270, "y": 1200, "wires": [ [ "19d0e8d8c5addb1f" ] ] }, { "id": "19d0e8d8c5addb1f", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Send Doorbell Alert to Telegram", "func": "// Validate that we received a proper image buffer\nif (!Buffer.isBuffer(msg.payload)) {\n node.warn(\"āŒ Doorbell snapshot fetch failed — not a binary image buffer\");\n node.status({fill:\"red\", shape:\"ring\", text:\"Snapshot failed\"});\n return null;\n}\n\n// Check if buffer has reasonable size (basic validation)\nif (msg.payload.length < 1000) {\n node.warn(\"āŒ Doorbell snapshot too small — likely corrupted\");\n node.status({fill:\"red\", shape:\"ring\", text:\"Image too small\"});\n return null;\n}\n\n// Format timestamp for display\nconst timestamp = new Date(msg.timestamp).toLocaleString();\n\n// Prepare Telegram message payload\nmsg.payload = {\n chatId: -4747176681, // Telegram group chat ID\n type: 'photo',\n content: msg.payload, // Binary image buffer\n caption: `šŸ”” DOORBELL ALERT! šŸ””\\n\\nšŸ“ Someone is at the ${msg.location}\\nā° Time: ${timestamp}\\nšŸ“· Camera: ${msg.camera_location} (${msg.camera_ip})`\n};\n\nnode.status({fill:\"green\", shape:\"dot\", text:\"Alert sent!\"});\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1540, "y": 1200, "wires": [ [ "bd7fed2198a7b950" ] ] }, { "id": "eff49303c6d84242", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Send Doorbell Alert to Telegram", "func": "// Validate that we received a proper image buffer\nif (!Buffer.isBuffer(msg.payload)) {\n node.warn(\"āŒ Doorbell snapshot fetch failed — not a binary image buffer\");\n node.status({fill:\"red\", shape:\"ring\", text:\"Snapshot failed\"});\n return null;\n}\n\n// Check if buffer has reasonable size (basic validation)\nif (msg.payload.length < 1000) {\n node.warn(\"āŒ Doorbell snapshot too small — likely corrupted\");\n node.status({fill:\"red\", shape:\"ring\", text:\"Image too small\"});\n return null;\n}\n\n// Format timestamp for display\nconst timestamp = new Date(msg.timestamp).toLocaleString();\n\n// Prepare Telegram message payload\nmsg.payload = {\n chatId: -4747176681, // Telegram group chat ID\n type: 'photo',\n content: msg.payload, // Binary image buffer\n caption: `šŸ”” Veranda ALERT! šŸ””\\n\\nšŸ“ Someone is at the ${msg.location}\\nā° Time: ${timestamp}\\nšŸ“· Camera: ${msg.camera_location} (${msg.camera_ip})`\n};\n\nnode.status({fill:\"green\", shape:\"dot\", text:\"Alert sent!\"});\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1550, "y": 1260, "wires": [ [ "bd7fed2198a7b950" ] ] }, { "id": "c74ddf6b84ef7a95", "type": "http request", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Fetch Camera Snapshot", "method": "GET", "ret": "bin", "paytoqs": "query", "url": "", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 1270, "y": 1260, "wires": [ [ "eff49303c6d84242", "88d855e525ab78f0" ] ] }, { "id": "d496d62222d1a073", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Generate Doorbell Camera URL", "func": "// Hardcoded doorbell camera IP\nconst CameraIP = \"10.20.30.33\";\n\n// Generate random string for cache busting\nconst randomString = Math.random().toString(36).substring(7);\n\n// Construct camera snapshot URL\nmsg.url = `http://${CameraIP}/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=${randomString}&user=admin&password=sh1pb0x1`;\n\n// Clear payload for HTTP request\nmsg.payload = null;\n\n// Add camera info to message\nmsg.camera_ip = CameraIP;\nmsg.camera_location = \"Veranda Door Camera\";\n\nnode.status({fill:\"blue\", shape:\"dot\", text:`URL: ${CameraIP}`});\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 990, "y": 1260, "wires": [ [ "c74ddf6b84ef7a95" ] ] }, { "id": "48bfe0ad8a973a84", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Check State Change", "func": "// Get current payload value\nvar currentValue = parseInt(msg.payload);\n\n// Get previous state from context (default to 0 if not set)\nvar previousValue = context.get('previousDoorbellState') || 0;\n\n// Store current value for next comparison\ncontext.set('previousDoorbellState', currentValue);\n\n// Only proceed if current value is 1 AND previous value was 0\nif (currentValue === 1 && previousValue === 0) {\n msg.payload = \"🚪 Person detected at Veranda Door!\";\n return msg;\n}\n\n// Don't send message for other cases\nreturn null;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 700, "y": 1260, "wires": [ [ "d496d62222d1a073" ] ] }, { "id": "88d855e525ab78f0", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "function 8", "func": "// Try decoding buffer into string so we can read JSON errors\ntry {\n msg.debug_text = msg.payload.toString();\n node.warn(\"Camera returned text: \" + msg.debug_text);\n} catch (e) {\n node.warn(\"Could not decode payload\");\n}\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1620, "y": 1300, "wires": [ [] ] }, { "id": "a4752681740af47e", "type": "inject", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Simulate Person Detected", "props": [ { "p": "payload", "v": "1", "vt": "num" }, { "p": "timestamp", "v": "", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "x": 170, "y": 1300, "wires": [ [ "7e88e31d094e343d" ] ] }, { "id": "7e88e31d094e343d", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Add Current Timestamp", "func": "// Add timestamp\nmsg.timestamp = Date.now();\nreturn msg;", "outputs": 1, "x": 170, "y": 1360, "wires": [ [ "365adc2679063bc8" ] ] }, { "id": "365adc2679063bc8", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Check Doorbell State", "func": "// Get previous state from context\nvar prev = context.get('prev') || 0;\nvar curr = parseInt(msg.payload);\ncontext.set('prev', curr);\n\nif(curr===1 && prev===0){\n msg.payload = \"🚪 Person detected at Basement Driveway!\";\n return msg;\n}\nreturn null;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 700, "y": 1360, "wires": [ [ "842a49fa21a0587a" ] ] }, { "id": "842a49fa21a0587a", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Reolink Login", "func": "const ip = '10.20.30.34';\nconst username = 'admin';\nconst password = 'sh1pb0x1';\nmsg.url = `http://${ip}/cgi-bin/api.cgi?cmd=Login&token=null`;\nmsg.method = 'POST';\nmsg.headers = { 'Content-Type': 'application/json' };\nmsg.payload = JSON.stringify([\n { cmd: 'Login', param: { User: { userName: username, password: password } } }\n]);\nmsg.camera_ip = ip;\nmsg.camera_location = 'Basement Driveway Camera';\nmsg.nextRandom = Math.random().toString(36).substring(7);\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 950, "y": 1360, "wires": [ [ "bedee5f9397c27f1" ] ] }, { "id": "bedee5f9397c27f1", "type": "http request", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Send Login Request", "method": "use", "ret": "obj", "url": "", "tls": "", "persist": false, "proxy": "", "x": 1190, "y": 1360, "wires": [ [ "3f9c2db4dfea3095" ] ] }, { "id": "3f9c2db4dfea3095", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Fetch Snapshot", "func": "// Extract token from login response\nif(!msg.payload || !msg.payload[0] || !msg.payload[0].value){\n node.error('Login failed');\n return null;\n}\nconst token = msg.payload[0].value.Token.name;\nif(!token){ node.error('Token missing'); return null; }\n\n// Build snapshot URL\nmsg.url = `http://${msg.camera_ip}/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=${msg.nextRandom}&token=${token}`;\nmsg.method = 'GET';\nmsg.headers = {};\nmsg.payload = null;\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1430, "y": 1360, "wires": [ [ "0446448ed8c8da8a" ] ] }, { "id": "0446448ed8c8da8a", "type": "http request", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Get Camera Snapshot", "method": "use", "ret": "bin", "url": "", "tls": "", "persist": false, "proxy": "", "x": 1670, "y": 1360, "wires": [ [ "d241b1f4991cfc05" ] ] }, { "id": "d241b1f4991cfc05", "type": "function", "z": "480553bb6f5b2b51", "d": true, "g": "ce79bea4667a77e2", "name": "Send Doorbell Alert to Telegram", "func": "// Validate that we received a proper image buffer\nif (!Buffer.isBuffer(msg.payload)) {\n node.warn(\"āŒ Basement Driveway snapshot fetch failed — not a binary image buffer\");\n node.status({fill:\"red\", shape:\"ring\", text:\"Snapshot failed\"});\n return null;\n}\n\n// Check if buffer has reasonable size (basic validation)\nif (msg.payload.length < 1000) {\n node.warn(\"āŒ Basement Driveway snapshot too small — likely corrupted\");\n node.status({fill:\"red\", shape:\"ring\", text:\"Image too small\"});\n return null;\n}\n\n// Format timestamp for display\nconst timestamp = new Date(msg.timestamp).toLocaleString();\n\n// Prepare Telegram message payload\nmsg.payload = {\n chatId: -4747176681, // Telegram group chat ID\n type: 'photo',\n content: msg.payload, // Binary image buffer\n caption: `šŸ”” Basement Driveway ALERT! šŸ””\\n\\nšŸ“ Someone is at the ${msg.location}\\nā° Time: ${timestamp}\\nšŸ“· Camera: ${msg.camera_location} (${msg.camera_ip})`\n};\n\nnode.status({fill:\"green\", shape:\"dot\", text:\"Alert sent!\"});\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1950, "y": 1360, "wires": [ [ "bd7fed2198a7b950" ] ] }, { "id": "ca1a1f7f8b90cfc9", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "d": true, "g": "b5ffb4a4212da258", "name": "", "server": "4e20fc347c658518", "friendly_name": "Office Switch (TS0042)", "device_id": "0xa4c138a5b9771b05", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 220, "y": 120, "wires": [ [ "b8f3d3242fb39bdd" ] ] }, { "id": "b8f3d3242fb39bdd", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "d": true, "g": "b5ffb4a4212da258", "name": "", "env": [ { "name": "switch_1", "value": "bedroom_1.sw_1", "type": "str" } ], "x": 1270, "y": 120, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "629cbd7ce15bb9e3", "type": "link out", "z": "f9a2fb576f0d360d", "name": "link out 1", "mode": "link", "links": [ "c6162cb59e21491f" ], "x": 1785, "y": 1340, "wires": [] }, { "id": "6654c150377ed2bb", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "4b06cbc568091f6f", "name": "", "server": "4e20fc347c658518", "friendly_name": "Hallway Switch (TS0042)", "device_id": "0xa4c13873de3faa66", "state": "0", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 230, "y": 220, "wires": [ [ "83bbabef65831016" ] ] }, { "id": "1aa9e0ff37d1afee", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "795d604329d51272", "name": "", "server": "4e20fc347c658518", "friendly_name": "Hallway Door Switch (TS0042)", "device_id": "0xa4c138112a12d55f", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 250, "y": 320, "wires": [ [ "b9c07d22cbaae6a2" ] ] }, { "id": "a6cf1bd4ae01ee56", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "39f557d8eec2fbae", "name": "", "server": "4e20fc347c658518", "friendly_name": "Master Bedroom Switch (TS0044)", "device_id": "0xa4c13854734f3a20", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 260, "y": 420, "wires": [ [ "16eaca15570ff092", "2d6bcc49a2785fd6" ] ] }, { "id": "675ba75711ef84e7", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "68db2262f7c7313e", "name": "", "server": "4e20fc347c658518", "friendly_name": "Master bathroom switch (TS0042)", "device_id": "0xa4c1387dd1c2d40e", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 260, "y": 900, "wires": [ [ "84272551b322cde2" ] ] }, { "id": "becbc51cb810ff3d", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "5d202845936f0275", "name": "", "server": "4e20fc347c658518", "friendly_name": "Pantry Switch (TS0042)", "device_id": "0xa4c138c2ae9ed430", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 220, "y": 1000, "wires": [ [ "4673e2e3f2c0626f" ] ] }, { "id": "0bd6051323b66072", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "74596bdef53b62cf", "name": "", "server": "4e20fc347c658518", "friendly_name": "Kitchen Switch (TS0044)", "device_id": "0xa4c1380bab38d546", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 230, "y": 1100, "wires": [ [ "6aac621e2a9acf79" ] ] }, { "id": "6e30880884a2cdb2", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "5b22d521e762f0da", "name": "", "server": "4e20fc347c658518", "friendly_name": "Kitchen Veranda Switch (TS0043)", "device_id": "0xa4c1383b7c24483a", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 250, "y": 1200, "wires": [ [ "da7ab159be01b35c" ] ] }, { "id": "83bbabef65831016", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "4b06cbc568091f6f", "name": "", "env": [ { "name": "switch_1", "value": "hallway.sw_2", "type": "str" }, { "name": "switch_2", "value": "hallway.sw_1", "type": "str" } ], "x": 1270, "y": 220, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "b9c07d22cbaae6a2", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "795d604329d51272", "name": "", "env": [ { "name": "switch_1", "value": "outSide.sw_1", "type": "str" } ], "x": 1270, "y": 320, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "16eaca15570ff092", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "39f557d8eec2fbae", "name": "", "env": [ { "name": "switch_1", "value": "masterBedroom.sw_1", "type": "str" }, { "name": "switch_2", "value": "", "type": "str" }, { "name": "switch_3", "value": "masterBathroom.sw_1", "type": "str" }, { "name": "switch_4", "value": "masterBedroom.sw_2", "type": "str" } ], "x": 1270, "y": 420, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "84272551b322cde2", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "68db2262f7c7313e", "name": "", "env": [ { "name": "switch_1", "value": "masterBathroom.sw_1", "type": "str" }, { "name": "switch_2", "value": "masterBathroom.sw_2", "type": "str" } ], "x": 1270, "y": 900, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "4673e2e3f2c0626f", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "5d202845936f0275", "name": "", "env": [ { "name": "switch_1", "value": "hallway.sw_1", "type": "str" }, { "name": "switch_2", "value": "pantry.sw_1", "type": "str" } ], "x": 1270, "y": 1000, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "6aac621e2a9acf79", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "74596bdef53b62cf", "name": "", "env": [ { "name": "switch_1", "value": "kitchen.sw_1", "type": "str" }, { "name": "switch_2", "value": "kitchen.sw_2", "type": "str" }, { "name": "switch_3", "value": "kitchen.sw_3", "type": "str" } ], "x": 1270, "y": 1100, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "da7ab159be01b35c", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "5b22d521e762f0da", "name": "", "env": [ { "name": "switch_1", "value": "livingRoom.sw_1", "type": "str" }, { "name": "switch_3", "value": "outVeranda.sw_2", "type": "str" } ], "x": 1270, "y": 1200, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "6f028b285108ff17", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "fb2d97888a83fc98", "name": "", "env": [ { "name": "switch_1", "value": "bedroom_2.sw_1", "type": "str" } ], "x": 1270, "y": 1300, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "ef6df11582a22110", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "1166ae03751d953e", "name": "", "env": [ { "name": "switch_1", "value": "bathroom.sw_1", "type": "str" }, { "name": "single", "value": "bathroom.sw_1", "type": "str" } ], "x": 1270, "y": 1400, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "82c1d5f7ae54b348", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "fb2d97888a83fc98", "name": "", "server": "4e20fc347c658518", "friendly_name": "Bedroom (TS0042)", "device_id": "0xa4c1388b74d83cfa", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 210, "y": 1300, "wires": [ [ "6f028b285108ff17" ] ] }, { "id": "774c15def7e6cf96", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "1166ae03751d953e", "name": "", "server": "4e20fc347c658518", "friendly_name": "Shower Switch (TS0041)", "device_id": "0xa4c138cc9b54cec9", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 230, "y": 1400, "wires": [ [ "ef6df11582a22110" ] ] }, { "id": "25cf5d71108cbbb4", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "5270af8a6312b29d", "name": "", "env": [ { "name": "switch_1", "value": "dinningRoom.sw_1", "type": "str" }, { "name": "switch_3", "value": "entrance.sw_1", "type": "str" }, { "name": "switch_4", "value": "entrance.sw_2", "type": "str" } ], "x": 1270, "y": 1500, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "a330bf2f4d26c536", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "6809b1c79783ab0c", "name": "", "env": [ { "name": "single", "value": "guestWc.sw_1", "type": "str" } ], "x": 1270, "y": 1640, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "cbcd3d741247b12b", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "5270af8a6312b29d", "name": "", "server": "4e20fc347c658518", "friendly_name": "Entrance Switch (TS0044)", "device_id": "0xa4c138ceaa5681d5", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 230, "y": 1500, "wires": [ [ "25cf5d71108cbbb4", "0bf96ec77f6d1809" ] ] }, { "id": "398c06a48e4daa13", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "6809b1c79783ab0c", "name": "", "server": "4e20fc347c658518", "friendly_name": "Guest WC Switch (TS0041)", "device_id": "0xa4c138d65f53037c", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 240, "y": 1640, "wires": [ [ "a330bf2f4d26c536" ] ] }, { "id": "1633e8e6861be2e0", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "3db6f7ccc63a5f8b", "name": "", "server": "4e20fc347c658518", "friendly_name": "Basement Switch (TS0043)", "device_id": "0xa4c13891821386eb", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 230, "y": 1740, "wires": [ [ "9c36d1335b0f8ebb", "7f48ed25c8ec1fce" ] ] }, { "id": "9c36d1335b0f8ebb", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "3db6f7ccc63a5f8b", "name": "", "env": [ { "name": "switch_1", "value": "dinningRoom.sw_4", "type": "str" }, { "name": "single", "value": "guestWc.sw_1", "type": "str" } ], "x": 1270, "y": 1740, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "36d1d2c1e10100e7", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "41609eab5db77f0a", "name": "", "server": "4e20fc347c658518", "friendly_name": "Master Bedroom RODRET (E2201)", "device_id": "0x6cfd22fffe66db44", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 260, "y": 2060, "wires": [ [ "4c584ffba6a17ccb" ] ] }, { "id": "4c584ffba6a17ccb", "type": "switch", "z": "f9a2fb576f0d360d", "g": "41609eab5db77f0a", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "on", "vt": "str" }, { "t": "eq", "v": "off", "vt": "str" }, { "t": "eq", "v": "brightness_move_up", "vt": "str" }, { "t": "eq", "v": "brightness_move_down", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 4, "x": 590, "y": 2120, "wires": [ [ "6dd69a9285fc9583" ], [ "6dd69a9285fc9583" ], [ "c53543186fd45d8b" ], [ "aadcf8d1921d77e6" ] ] }, { "id": "c53543186fd45d8b", "type": "change", "z": "f9a2fb576f0d360d", "g": "41609eab5db77f0a", "name": "", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "masterBedroom", "tot": "str" }, { "t": "set", "p": "payload", "pt": "msg", "to": "sw_1", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 920, "y": 2100, "wires": [ [ "33eb6e0725214c0b" ] ] }, { "id": "33eb6e0725214c0b", "type": "link out", "z": "f9a2fb576f0d360d", "g": "41609eab5db77f0a", "name": "link out 15", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1325, "y": 2100, "wires": [] }, { "id": "5df52e7f8217a6d9", "type": "zigbee2mqtt-out", "z": "f9a2fb576f0d360d", "g": "41609eab5db77f0a", "name": "", "server": "4e20fc347c658518", "friendly_name": "Master Bedroom Spots (GL-C-006P)", "device_id": "0xa4c138883e5d795c", "command": "brightness", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1190, "y": 2060, "wires": [] }, { "id": "6dd69a9285fc9583", "type": "function", "z": "f9a2fb576f0d360d", "g": "41609eab5db77f0a", "name": "function 4", "func": "// Initialize the counter\nlet counter = context.get('counter') || 10;\n\nif (msg.payload === \"on\") {\n msg.payload = counter;\n counter += 10;\n context.set('counter', counter);\n return msg;\n}\n\nif (msg.payload === \"off\") {\n counter -= 10;\n msg.payload = counter;\n context.set('counter', counter);\n return msg;\n}\n\n// Ignore other payloads\nreturn null;\n", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 840, "y": 2060, "wires": [ [ "5df52e7f8217a6d9" ] ] }, { "id": "3e5fabb6aa93449c", "type": "zigbee2mqtt-out", "z": "f9a2fb576f0d360d", "g": "41609eab5db77f0a", "name": "", "server": "4e20fc347c658518", "friendly_name": "Master Bedroom Spots (GL-C-006P)", "device_id": "0xa4c138883e5d795c", "command": "state", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1190, "y": 2140, "wires": [] }, { "id": "aadcf8d1921d77e6", "type": "change", "z": "f9a2fb576f0d360d", "g": "41609eab5db77f0a", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "off", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 920, "y": 2140, "wires": [ [ "3e5fabb6aa93449c" ] ] }, { "id": "109c390c131b09a8", "type": "change", "z": "f9a2fb576f0d360d", "g": "39f557d8eec2fbae", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "toggle", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 880, "y": 460, "wires": [ [ "d02a9d4e0468bc67" ] ] }, { "id": "d02a9d4e0468bc67", "type": "zigbee2mqtt-out", "z": "f9a2fb576f0d360d", "g": "39f557d8eec2fbae", "name": "", "server": "4e20fc347c658518", "friendly_name": "Master Bedroom Spots (GL-C-006P)", "device_id": "0xa4c138883e5d795c", "command": "state", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1190, "y": 460, "wires": [] }, { "id": "07e63813fb04b906", "type": "change", "z": "f9a2fb576f0d360d", "g": "5270af8a6312b29d", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "toggle", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 820, "y": 1540, "wires": [ [ "4d3d4a82a512ca10" ] ] }, { "id": "4d3d4a82a512ca10", "type": "zigbee2mqtt-out", "z": "f9a2fb576f0d360d", "g": "5270af8a6312b29d", "name": "", "server": "4e20fc347c658518", "friendly_name": "Dining Room Spots (GL-C-009P)", "device_id": "0xa4c138df201f25a1", "command": "state", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1200, "y": 1540, "wires": [] }, { "id": "46517eb4342b3d18", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "b6271f4a3284f8d9", "name": "", "server": "4e20fc347c658518", "friendly_name": "Living Room Door Switch (TS0044)", "device_id": "0xa4c1383d7921827a", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 260, "y": 1920, "wires": [ [ "a3d5be29d6effa34", "701c1cd70874e615" ] ] }, { "id": "a3d5be29d6effa34", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "b6271f4a3284f8d9", "name": "", "env": [ { "name": "switch_1", "value": "livingRoom.sw_1", "type": "str" }, { "name": "switch_2", "value": "", "type": "str" }, { "name": "switch_3", "value": "", "type": "str" }, { "name": "switch_4", "value": "", "type": "str" }, { "name": "single", "value": "", "type": "str" } ], "x": 550, "y": 1920, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "d23c32a704af639d", "type": "change", "z": "f9a2fb576f0d360d", "g": "b6271f4a3284f8d9", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "toggle", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 720, "y": 1960, "wires": [ [ "68f7d3015de2dbab" ] ] }, { "id": "68f7d3015de2dbab", "type": "zigbee2mqtt-out", "z": "f9a2fb576f0d360d", "g": "b6271f4a3284f8d9", "name": "", "server": "4e20fc347c658518", "friendly_name": "Living Room Spots (GL-C-006P)", "device_id": "0xa4c13837f72f43ab", "command": "state", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1210, "y": 1960, "wires": [] }, { "id": "fe5612a41399f1f5", "type": "api-call-service", "z": "f9a2fb576f0d360d", "g": "3db6f7ccc63a5f8b", "name": "", "server": "29eb84a2708d96e0", "version": 7, "debugenabled": false, "action": "switch.toggle", "floorId": [], "areaId": [], "deviceId": [], "entityId": [ "switch.basement_lights_switch_1" ], "labelId": [], "data": "", "dataType": "jsonata", "mergeContext": "", "mustacheAltTags": false, "outputProperties": [], "queue": "none", "blockInputOverrides": true, "domain": "switch", "service": "toggle", "x": 1270, "y": 1780, "wires": [ [] ] }, { "id": "7f48ed25c8ec1fce", "type": "switch", "z": "f9a2fb576f0d360d", "g": "3db6f7ccc63a5f8b", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "2_single", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 850, "y": 1780, "wires": [ [ "fe5612a41399f1f5" ] ] }, { "id": "ab17cf6a7d65fcb9", "type": "inject", "z": "f9a2fb576f0d360d", "g": "3db6f7ccc63a5f8b", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 840, "y": 1820, "wires": [ [ "fe5612a41399f1f5" ] ] }, { "id": "0bf96ec77f6d1809", "type": "switch", "z": "f9a2fb576f0d360d", "g": "5270af8a6312b29d", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "2_single", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 550, "y": 1540, "wires": [ [ "07e63813fb04b906" ] ] }, { "id": "2d6bcc49a2785fd6", "type": "switch", "z": "f9a2fb576f0d360d", "g": "39f557d8eec2fbae", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "2_single", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 630, "y": 460, "wires": [ [ "109c390c131b09a8" ] ] }, { "id": "701c1cd70874e615", "type": "switch", "z": "f9a2fb576f0d360d", "g": "b6271f4a3284f8d9", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "2_single", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 530, "y": 1960, "wires": [ [ "d23c32a704af639d" ] ] }, { "id": "0b112f9f314fa0bb", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "ef555db28dba4c46", "name": "", "server": "4e20fc347c658518", "friendly_name": "0xa4c138332cc3da08 (TS0044)", "device_id": "0xa4c138332cc3da08", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 250, "y": 560, "wires": [ [ "a1f5a94baf1fbcd7", "f0de9c882920d07c" ] ] }, { "id": "a1f5a94baf1fbcd7", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "ef555db28dba4c46", "name": "", "env": [ { "name": "switch_1", "value": "masterBedroom.sw_1", "type": "str" }, { "name": "switch_2", "value": "", "type": "str" }, { "name": "switch_3", "value": "masterBedroom.sw_3", "type": "str" }, { "name": "switch_4", "value": "masterBedroom.sw_5", "type": "str" } ], "x": 1270, "y": 560, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "ae314d3d3457b679", "type": "change", "z": "f9a2fb576f0d360d", "g": "ef555db28dba4c46", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "toggle", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 880, "y": 600, "wires": [ [ "0c35b08a3c7d347f" ] ] }, { "id": "0c35b08a3c7d347f", "type": "zigbee2mqtt-out", "z": "f9a2fb576f0d360d", "g": "ef555db28dba4c46", "name": "", "server": "4e20fc347c658518", "friendly_name": "Master Bedroom Spots (GL-C-006P)", "device_id": [], "command": "state", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1190, "y": 600, "wires": [] }, { "id": "f0de9c882920d07c", "type": "switch", "z": "f9a2fb576f0d360d", "g": "ef555db28dba4c46", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "2_single", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 630, "y": 600, "wires": [ [ "ae314d3d3457b679" ] ] }, { "id": "310f749a07eded9d", "type": "zigbee2mqtt-in", "z": "f9a2fb576f0d360d", "g": "1756bd5d4ff2c23b", "name": "", "server": "4e20fc347c658518", "friendly_name": "basement_switch_2 (TS0043)", "device_id": "0xa4c138a1968db065", "state": "action", "outputAtStartup": true, "filterChanges": false, "enableMultiple": false, "x": 240, "y": 2240, "wires": [ [ "d0febe343ef897ac", "8cce4a0a7061ac87" ] ] }, { "id": "d0febe343ef897ac", "type": "subflow:4dc13919bcc9d676", "z": "f9a2fb576f0d360d", "g": "1756bd5d4ff2c23b", "name": "", "env": [ { "name": "switch_1", "value": "dinningRoom.sw_4", "type": "str" }, { "name": "single", "value": "guestWc.sw_1", "type": "str" } ], "x": 1270, "y": 2240, "wires": [ [ "629cbd7ce15bb9e3" ] ] }, { "id": "e1965a78e430acad", "type": "api-call-service", "z": "f9a2fb576f0d360d", "g": "1756bd5d4ff2c23b", "name": "", "server": "29eb84a2708d96e0", "version": 7, "debugenabled": false, "action": "switch.toggle", "floorId": [], "areaId": [], "deviceId": [], "entityId": [ "switch.basement_lights_switch_1" ], "labelId": [], "data": "", "dataType": "jsonata", "mergeContext": "", "mustacheAltTags": false, "outputProperties": [], "queue": "none", "blockInputOverrides": true, "domain": "switch", "service": "toggle", "x": 1270, "y": 2280, "wires": [ [] ] }, { "id": "8cce4a0a7061ac87", "type": "switch", "z": "f9a2fb576f0d360d", "g": "1756bd5d4ff2c23b", "name": "", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "2_single", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 1, "x": 850, "y": 2280, "wires": [ [ "e1965a78e430acad" ] ] }, { "id": "d5cad6d8ca5fe08c", "type": "inject", "z": "f9a2fb576f0d360d", "g": "1756bd5d4ff2c23b", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 840, "y": 2320, "wires": [ [ "e1965a78e430acad" ] ] }, { "id": "05ecf6f492d4a8cf", "type": "inject", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "name": "ON", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "ON", "payloadType": "str", "x": 230, "y": 1020, "wires": [ [ "301e955ac79a9326" ] ] }, { "id": "ad81a0918c31a862", "type": "inject", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "name": "OFF", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "OFF", "payloadType": "str", "x": 230, "y": 1140, "wires": [ [ "301e955ac79a9326" ] ] }, { "id": "7049d2e629127b0e", "type": "api-current-state", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "name": "", "server": "29eb84a2708d96e0", "version": 3, "outputs": 2, "halt_if": "off", "halt_if_type": "str", "halt_if_compare": "is", "entity_id": "binary_sensor.front_lights", "state_type": "str", "blockInputOverrides": true, "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "outVeranda", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "for": "0", "forType": "num", "forUnits": "minutes", "override_topic": false, "state_location": "payload", "override_payload": "msg", "entity_location": "data", "override_data": "msg", "x": 840, "y": 1040, "wires": [ [ "e44fa1b081b4aba7" ], [] ] }, { "id": "e44fa1b081b4aba7", "type": "link out", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "name": "link out 21", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1085, "y": 1060, "wires": [] }, { "id": "532476a808456423", "type": "api-current-state", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "name": "", "server": "29eb84a2708d96e0", "version": 3, "outputs": 2, "halt_if": "on", "halt_if_type": "str", "halt_if_compare": "is", "entity_id": "binary_sensor.front_lights", "state_type": "str", "blockInputOverrides": true, "outputProperties": [ { "property": "topic", "propertyType": "msg", "value": "outVeranda", "valueType": "str" }, { "property": "payload", "propertyType": "msg", "value": "sw_1", "valueType": "str" } ], "for": "0", "forType": "num", "forUnits": "minutes", "override_topic": false, "state_location": "payload", "override_payload": "msg", "entity_location": "data", "override_data": "msg", "x": 840, "y": 1100, "wires": [ [ "e44fa1b081b4aba7" ], [] ] }, { "id": "9e01966beafd582b", "type": "cronplus", "z": "6722d185624fd57a", "d": true, "g": "cc230a0894b116d3", "name": "", "outputField": "payload", "timeZone": "", "storeName": "", "commandResponseMsgOutput": "fanOut", "defaultLocation": "", "defaultLocationType": "default", "outputs": 4, "options": [ { "name": "ON", "topic": "topic1", "payloadType": "str", "payload": "on", "expressionType": "cron", "expression": "0 0 20 * * *", "location": "", "offset": "0", "solarType": "all", "solarEvents": "sunrise,sunset" }, { "name": "OFF", "topic": "topic2", "payloadType": "str", "payload": "off", "expressionType": "cron", "expression": "0 0 00 * * *", "location": "", "offset": "0", "solarType": "all", "solarEvents": "sunrise,sunset" } ], "x": 400, "y": 1160, "wires": [ [], [], [], [] ] }, { "id": "905629455f4dd222", "type": "zigbee2mqtt-out", "z": "6722d185624fd57a", "g": "b73455843d7a5a9f", "name": "", "server": "4e20fc347c658518", "friendly_name": "Front Water Valve (SWV)", "device_id": "0x0ceff6fffe84e4bc", "command": "state", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1350, "y": 460, "wires": [] }, { "id": "33e972f98673a6b6", "type": "cronplus", "z": "6722d185624fd57a", "g": "b73455843d7a5a9f", "name": "Olive Trees every 2 days at 19:00", "outputField": "payload", "timeZone": "", "storeName": "file", "commandResponseMsgOutput": "fanOut", "defaultLocation": "", "defaultLocationType": "default", "outputs": 4, "options": [ { "name": "ON", "topic": "front", "payloadType": "default", "payload": "", "expressionType": "cron", "expression": "20 6 */7 * *", "location": "", "offset": "0", "solarType": "all", "solarEvents": "sunrise,sunset" }, { "name": "OFF", "topic": "front", "payloadType": "default", "payload": "", "expressionType": "cron", "expression": "30 6 */7 * *", "location": "", "offset": "0", "solarType": "all", "solarEvents": "sunrise,sunset" } ], "x": 240, "y": 440, "wires": [ [ "ab7182ad5c37be48" ], [ "d51ae77e82bb86f0" ], [], [] ] }, { "id": "ab7182ad5c37be48", "type": "change", "z": "6722d185624fd57a", "g": "b73455843d7a5a9f", "name": "on", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "on", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 690, "y": 420, "wires": [ [ "905629455f4dd222" ] ] }, { "id": "d51ae77e82bb86f0", "type": "change", "z": "6722d185624fd57a", "g": "b73455843d7a5a9f", "name": "off", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "off", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 690, "y": 460, "wires": [ [ "905629455f4dd222" ] ] }, { "id": "b43dc5183a67d128", "type": "zigbee2mqtt-out", "z": "6722d185624fd57a", "g": "b73455843d7a5a9f", "name": "", "server": "4e20fc347c658518", "friendly_name": "Back Water Valve (SWV)", "device_id": "0x7cc6b6fffe38a415", "command": "state", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1350, "y": 540, "wires": [] }, { "id": "2896d687417bbc1d", "type": "cronplus", "z": "6722d185624fd57a", "g": "b73455843d7a5a9f", "name": "Citrus Trees every 2 days at 06:00", "outputField": "payload", "timeZone": "", "storeName": "file", "commandResponseMsgOutput": "fanOut", "defaultLocation": "", "defaultLocationType": "default", "outputs": 4, "options": [ { "name": "ON", "topic": "front", "payloadType": "default", "payload": "", "expressionType": "cron", "expression": "0 6 */2 * *", "location": "", "offset": "0", "solarType": "all", "solarEvents": "sunrise,sunset" }, { "name": "OFF", "topic": "front", "payloadType": "default", "payload": "", "expressionType": "cron", "expression": "15 6 */2 * *", "location": "", "offset": "0", "solarType": "all", "solarEvents": "sunrise,sunset" } ], "x": 240, "y": 560, "wires": [ [ "1199fd928d0abd32" ], [ "86153b2dba01756f" ], [], [] ] }, { "id": "1199fd928d0abd32", "type": "change", "z": "6722d185624fd57a", "g": "b73455843d7a5a9f", "name": "on", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "on", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 690, "y": 540, "wires": [ [ "b43dc5183a67d128" ] ] }, { "id": "86153b2dba01756f", "type": "change", "z": "6722d185624fd57a", "g": "b73455843d7a5a9f", "name": "off", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "off", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 690, "y": 580, "wires": [ [ "b43dc5183a67d128" ] ] }, { "id": "301e955ac79a9326", "type": "bigtimer", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "outtopic": "", "outpayload1": "", "outpayload2": "", "name": "Big Timer", "comment": "", "lat": "34.660694", "lon": "32.964306", "starttime": "5004", "endtime": "60", "starttime2": "0", "endtime2": "0", "startoff": 0, "endoff": 0, "startoff2": 0, "endoff2": 0, "offs": 0, "outtext1": "ON", "outtext2": "OFF", "timeout": 1440, "sun": true, "mon": true, "tue": true, "wed": true, "thu": true, "fri": true, "sat": true, "jan": true, "feb": true, "mar": true, "apr": true, "may": true, "jun": true, "jul": true, "aug": true, "sep": true, "oct": true, "nov": true, "dec": true, "day1": 0, "month1": 0, "day2": 0, "month2": 0, "day3": 0, "month3": 0, "day4": 0, "month4": 0, "day5": 0, "month5": 0, "day6": 0, "month6": 0, "day7": 0, "month7": 0, "day8": 0, "month8": 0, "day9": 0, "month9": 0, "day10": 0, "month10": 0, "day11": 0, "month11": 0, "day12": 0, "month12": 0, "d1": 0, "w1": 0, "d2": 0, "w2": 0, "d3": 0, "w3": 0, "d4": 0, "w4": 0, "d5": 0, "w5": 0, "d6": 0, "w6": 0, "xday1": 0, "xmonth1": 0, "xday2": 0, "xmonth2": 0, "xday3": 0, "xmonth3": 0, "xday4": 0, "xmonth4": 0, "xday5": 0, "xmonth5": 0, "xday6": 0, "xmonth6": 0, "xday7": 0, "xmonth7": 0, "xday8": 0, "xmonth8": 0, "xday9": 0, "xmonth9": 0, "xday10": 0, "xmonth10": 0, "xday11": 0, "xmonth11": 0, "xday12": 0, "xmonth12": 0, "xd1": 0, "xw1": 0, "xd2": 0, "xw2": 0, "xd3": 0, "xw3": 0, "xd4": 0, "xw4": 0, "xd5": 0, "xw5": 0, "xd6": 0, "xw6": 0, "suspend": false, "random": false, "randon1": false, "randoff1": false, "randon2": false, "randoff2": false, "repeat": true, "atstart": true, "odd": false, "even": false, "x": 400, "y": 1080, "wires": [ [ "7049d2e629127b0e", "532476a808456423", "434ef7e821c63223" ], [ "0fdf497d70900d11" ], [ "54161a78e09f85c3", "7049d2e629127b0e", "532476a808456423" ] ] }, { "id": "54161a78e09f85c3", "type": "debug", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "name": "debug 14", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 560, "y": 1140, "wires": [] }, { "id": "0fdf497d70900d11", "type": "debug", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "name": "debug 21", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 680, "y": 980, "wires": [] }, { "id": "434ef7e821c63223", "type": "debug", "z": "6722d185624fd57a", "g": "cc230a0894b116d3", "name": "debug 22", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 450, "y": 980, "wires": [] }, { "id": "d97b1b86e0e0040e", "type": "zigbee2mqtt-get", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "Get Current Plug State", "server": "4e20fc347c658518", "friendly_name": "Living Room Plug (TS011F_plug_3)", "device_id": "0xa4c138c205230a46", "state": "state", "enableMultiple": false, "x": 1080, "y": 1860, "wires": [ [ "6fdd0a95dd76a2e8", "be86177040153c9f" ] ] }, { "id": "3737a8c897de2221", "type": "function", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "Compare Desired vs Actual", "func": "let input = msg.input || null;\n\nif (input === 1) {\n // BigTimer sets desired state\n // Validate state value before storing\n if (msg.payload === \"ON\" || msg.payload === \"OFF\") {\n flow.set(\"desired_state\", msg.payload);\n node.status({fill:\"blue\", shape:\"dot\", text:`Desired: ${msg.payload}`});\n node.warn(`[BigTimer] Desired state set to: ${msg.payload}`);\n } else {\n node.error(`[BigTimer] Invalid state value: ${msg.payload}`);\n node.status({fill:\"red\", shape:\"ring\", text:\"Invalid state\"});\n }\n return null;\n}\n\nif (input === 2) {\n // Zigbee GET input - check and sync state\n let desired = flow.get(\"desired_state\");\n let current = msg.state || \n msg.payload || \n msg.payload?.state || \n msg.data?.state ||\n null;\n\n // Log current status\n node.warn(`[Zigbee Check] Desired: ${desired}, Current: ${current}`);\n\n // Check if states are available\n if (!desired) {\n node.warn(\"[Zigbee Check] No desired state set yet\");\n node.status({fill:\"yellow\", shape:\"ring\", text:\"No desired state\"});\n return null;\n }\n\n if (!current) {\n node.error(\"[Zigbee Check] Current state is undefined\");\n node.status({fill:\"red\", shape:\"ring\", text:\"No current state\"});\n return null;\n }\n\n // Check if sync is needed\n if (desired === \"ON\" && current !== \"ON\") {\n node.warn(`[Zigbee Check] State mismatch - sending ON command`);\n node.status({fill:\"green\", shape:\"dot\", text:\"Syncing → ON\"});\n return { payload: \"ON\" };\n }\n \n if (desired === \"OFF\" && current !== \"OFF\") {\n node.warn(`[Zigbee Check] State mismatch - sending OFF command`);\n node.status({fill:\"green\", shape:\"dot\", text:\"Syncing → OFF\"});\n return { payload: \"OFF\" };\n }\n\n // States match - no action needed\n node.status({fill:\"green\", shape:\"ring\", text:`Synced: ${current}`});\n node.warn(`[Zigbee Check] States match - no action needed`);\n return null;\n}\n\n// Invalid input\nnode.error(`Invalid input value: ${input}`);\nnode.status({fill:\"red\", shape:\"ring\", text:\"Invalid input\"});\nreturn null;\n", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1580, "y": 1880, "wires": [ [ "ca74d224370a0b5a", "893d9228d166c0d2" ] ] }, { "id": "ca74d224370a0b5a", "type": "zigbee2mqtt-out", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "Set Plug State", "server": "4e20fc347c658518", "friendly_name": "Living Room Plug (TS011F_plug_3)", "device_id": "0xa4c138c205230a46", "command": "state", "commandType": "z2m_cmd", "payload": "payload", "payloadType": "msg", "optionsValue": "", "optionsType": "nothing", "x": 1820, "y": 1880, "wires": [] }, { "id": "3a8262144b91d661", "type": "inject", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "OFF", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "OFF", "payloadType": "str", "x": 750, "y": 1960, "wires": [ [ "01df5278eead8a98" ] ] }, { "id": "d20a28e1dea2fcde", "type": "inject", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "ON", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "ON", "payloadType": "str", "x": 750, "y": 1840, "wires": [ [ "01df5278eead8a98" ] ] }, { "id": "01df5278eead8a98", "type": "bigtimer", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "outtopic": "", "outpayload1": "", "outpayload2": "", "name": "Big Timer", "comment": "", "lat": "34.660694", "lon": "32.964306", "starttime": "960", "endtime": "60", "starttime2": "0", "endtime2": "0", "startoff": 0, "endoff": 0, "startoff2": 0, "endoff2": 0, "offs": 0, "outtext1": "ON", "outtext2": "OFF", "timeout": 1440, "sun": true, "mon": true, "tue": true, "wed": true, "thu": true, "fri": true, "sat": true, "jan": true, "feb": true, "mar": true, "apr": true, "may": true, "jun": true, "jul": true, "aug": true, "sep": true, "oct": true, "nov": true, "dec": true, "day1": 0, "month1": 0, "day2": 0, "month2": 0, "day3": 0, "month3": 0, "day4": 0, "month4": 0, "day5": 0, "month5": 0, "day6": 0, "month6": 0, "day7": 0, "month7": 0, "day8": 0, "month8": 0, "day9": 0, "month9": 0, "day10": 0, "month10": 0, "day11": 0, "month11": 0, "day12": 0, "month12": 0, "d1": 0, "w1": 0, "d2": 0, "w2": 0, "d3": 0, "w3": 0, "d4": 0, "w4": 0, "d5": 0, "w5": 0, "d6": 0, "w6": 0, "xday1": 0, "xmonth1": 0, "xday2": 0, "xmonth2": 0, "xday3": 0, "xmonth3": 0, "xday4": 0, "xmonth4": 0, "xday5": 0, "xmonth5": 0, "xday6": 0, "xmonth6": 0, "xday7": 0, "xmonth7": 0, "xday8": 0, "xmonth8": 0, "xday9": 0, "xmonth9": 0, "xday10": 0, "xmonth10": 0, "xday11": 0, "xmonth11": 0, "xday12": 0, "xmonth12": 0, "xd1": 0, "xw1": 0, "xd2": 0, "xw2": 0, "xd3": 0, "xw3": 0, "xd4": 0, "xw4": 0, "xd5": 0, "xw5": 0, "xd6": 0, "xw6": 0, "suspend": false, "random": false, "randon1": false, "randoff1": false, "randon2": false, "randoff2": false, "repeat": true, "atstart": true, "odd": false, "even": false, "x": 880, "y": 1900, "wires": [ [], [], [ "d97b1b86e0e0040e", "1460ed0d062f8b73" ] ] }, { "id": "1460ed0d062f8b73", "type": "change", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "Tag BigTimer Input", "rules": [ { "t": "set", "p": "input", "pt": "msg", "to": "1", "tot": "num" } ], "x": 1310, "y": 1900, "wires": [ [ "3737a8c897de2221", "bb1639973b4a6a05" ] ] }, { "id": "6fdd0a95dd76a2e8", "type": "change", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "Tag Zigbee Input", "rules": [ { "t": "set", "p": "input", "pt": "msg", "to": "2", "tot": "num" } ], "x": 1310, "y": 1860, "wires": [ [ "3737a8c897de2221", "800cb2f6a21c882f" ] ] }, { "id": "bb1639973b4a6a05", "type": "debug", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "debug 23", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1560, "y": 2020, "wires": [] }, { "id": "800cb2f6a21c882f", "type": "debug", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "debug 24", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1540, "y": 1960, "wires": [] }, { "id": "893d9228d166c0d2", "type": "debug", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "debug 25", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1750, "y": 1980, "wires": [] }, { "id": "be86177040153c9f", "type": "debug", "z": "6722d185624fd57a", "g": "860e99939cf4fb5c", "name": "debug 26", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1230, "y": 1720, "wires": [] }, { "id": "6fb9cc41c7b14fac", "type": "link out", "z": "31693504fcbbd954", "name": "link out 23", "mode": "link", "links": [ "c6162cb59e21491f" ], "x": 2105, "y": 880, "wires": [] }, { "id": "func_node", "type": "function", "z": "31693504fcbbd954", "name": "Build JSON true/false", "func": "let input = msg.payload;\nlet parts = input.split(\".\");\nif (parts.length !== 2) {\n node.error(\"Invalid input format. Expected room.switch\", msg);\n return null;\n}\n\nlet room = parts[0];\nlet sw = parts[1];\n\nlet onMsg = { payload: { [room]: { [sw]: true } } };\nnode.send(onMsg);\n\nlet offMsg = { payload: { [room]: { [sw]: false } } };\nsetTimeout(() => { node.send(offMsg); }, 1000);\n\nreturn null;", "outputs": 1, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1920, "y": 880, "wires": [ [ "debug_node", "6fb9cc41c7b14fac" ] ] }, { "id": "debug_node", "type": "debug", "z": "31693504fcbbd954", "name": "Output", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "payload", "targetType": "msg", "x": 2110, "y": 920, "wires": [] }, { "id": "btn_masterBedroom_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBedroom all_off", "group": "group_masterBedroom", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "masterBedroom.all_off", "payloadType": "str", "topic": "", "x": 140, "y": 940, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBedroom_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBedroom all_on", "group": "group_masterBedroom", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "masterBedroom.all_on", "payloadType": "str", "topic": "", "x": 140, "y": 980, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBedroom_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBedroom sw_1", "group": "group_masterBedroom", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "masterBedroom.sw_1", "payloadType": "str", "topic": "", "x": 140, "y": 1020, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBedroom_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBedroom sw_2", "group": "group_masterBedroom", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "masterBedroom.sw_2", "payloadType": "str", "topic": "", "x": 140, "y": 1060, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBedroom_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBedroom sw_3", "group": "group_masterBedroom", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "masterBedroom.sw_3", "payloadType": "str", "topic": "", "x": 140, "y": 1100, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBedroom_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBedroom sw_4", "group": "group_masterBedroom", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "masterBedroom.sw_4", "payloadType": "str", "topic": "", "x": 140, "y": 1140, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBedroom_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBedroom sw_5", "group": "group_masterBedroom", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "masterBedroom.sw_5", "payloadType": "str", "topic": "", "x": 140, "y": 1180, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBedroom_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBedroom sw_6", "group": "group_masterBedroom", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "masterBedroom.sw_6", "payloadType": "str", "topic": "", "x": 140, "y": 1220, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBathroom_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBathroom all_off", "group": "group_masterBathroom", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "masterBathroom.all_off", "payloadType": "str", "topic": "", "x": 390, "y": 940, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBathroom_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBathroom all_on", "group": "group_masterBathroom", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "masterBathroom.all_on", "payloadType": "str", "topic": "", "x": 390, "y": 980, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBathroom_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBathroom sw_1", "group": "group_masterBathroom", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "masterBathroom.sw_1", "payloadType": "str", "topic": "", "x": 380, "y": 1020, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBathroom_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBathroom sw_2", "group": "group_masterBathroom", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "masterBathroom.sw_2", "payloadType": "str", "topic": "", "x": 380, "y": 1060, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBathroom_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBathroom sw_3", "group": "group_masterBathroom", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "masterBathroom.sw_3", "payloadType": "str", "topic": "", "x": 380, "y": 1100, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBathroom_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBathroom sw_4", "group": "group_masterBathroom", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "masterBathroom.sw_4", "payloadType": "str", "topic": "", "x": 380, "y": 1140, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBathroom_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBathroom sw_5", "group": "group_masterBathroom", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "masterBathroom.sw_5", "payloadType": "str", "topic": "", "x": 380, "y": 1180, "wires": [ [ "func_node" ] ] }, { "id": "btn_masterBathroom_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "masterBathroom sw_6", "group": "group_masterBathroom", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "masterBathroom.sw_6", "payloadType": "str", "topic": "", "x": 380, "y": 1220, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_1_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_1 all_off", "group": "group_bedroom_1", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "bedroom_1.all_off", "payloadType": "str", "topic": "", "x": 630, "y": 940, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_1_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_1 all_on", "group": "group_bedroom_1", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "bedroom_1.all_on", "payloadType": "str", "topic": "", "x": 630, "y": 980, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_1_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_1 sw_1", "group": "group_bedroom_1", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "bedroom_1.sw_1", "payloadType": "str", "topic": "", "x": 630, "y": 1020, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_1_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_1 sw_2", "group": "group_bedroom_1", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "bedroom_1.sw_2", "payloadType": "str", "topic": "", "x": 630, "y": 1060, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_1_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_1 sw_3", "group": "group_bedroom_1", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "bedroom_1.sw_3", "payloadType": "str", "topic": "", "x": 630, "y": 1100, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_1_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_1 sw_4", "group": "group_bedroom_1", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "bedroom_1.sw_4", "payloadType": "str", "topic": "", "x": 630, "y": 1140, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_1_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_1 sw_5", "group": "group_bedroom_1", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "bedroom_1.sw_5", "payloadType": "str", "topic": "", "x": 630, "y": 1180, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_1_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_1 sw_6", "group": "group_bedroom_1", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "bedroom_1.sw_6", "payloadType": "str", "topic": "", "x": 630, "y": 1220, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_2_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_2 all_off", "group": "group_bedroom_2", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "bedroom_2.all_off", "payloadType": "str", "topic": "", "x": 1050, "y": 940, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_2_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_2 all_on", "group": "group_bedroom_2", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "bedroom_2.all_on", "payloadType": "str", "topic": "", "x": 1050, "y": 980, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_2_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_2 sw_1", "group": "group_bedroom_2", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "bedroom_2.sw_1", "payloadType": "str", "topic": "", "x": 1050, "y": 1020, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_2_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_2 sw_2", "group": "group_bedroom_2", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "bedroom_2.sw_2", "payloadType": "str", "topic": "", "x": 1050, "y": 1060, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_2_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_2 sw_3", "group": "group_bedroom_2", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "bedroom_2.sw_3", "payloadType": "str", "topic": "", "x": 1050, "y": 1100, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_2_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_2 sw_4", "group": "group_bedroom_2", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "bedroom_2.sw_4", "payloadType": "str", "topic": "", "x": 1050, "y": 1140, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_2_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_2 sw_5", "group": "group_bedroom_2", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "bedroom_2.sw_5", "payloadType": "str", "topic": "", "x": 1050, "y": 1180, "wires": [ [ "func_node" ] ] }, { "id": "btn_bedroom_2_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "bedroom_2 sw_6", "group": "group_bedroom_2", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "bedroom_2.sw_6", "payloadType": "str", "topic": "", "x": 1050, "y": 1220, "wires": [ [ "func_node" ] ] }, { "id": "btn_bathroom_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "bathroom all_off", "group": "group_bathroom", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "bathroom.all_off", "payloadType": "str", "topic": "", "x": 1680, "y": 940, "wires": [ [ "func_node" ] ] }, { "id": "btn_bathroom_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "bathroom all_on", "group": "group_bathroom", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "bathroom.all_on", "payloadType": "str", "topic": "", "x": 1680, "y": 980, "wires": [ [ "func_node" ] ] }, { "id": "btn_bathroom_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "bathroom sw_1", "group": "group_bathroom", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "bathroom.sw_1", "payloadType": "str", "topic": "", "x": 1680, "y": 1020, "wires": [ [ "func_node" ] ] }, { "id": "btn_bathroom_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "bathroom sw_2", "group": "group_bathroom", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "bathroom.sw_2", "payloadType": "str", "topic": "", "x": 1680, "y": 1060, "wires": [ [ "func_node" ] ] }, { "id": "btn_bathroom_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "bathroom sw_3", "group": "group_bathroom", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "bathroom.sw_3", "payloadType": "str", "topic": "", "x": 1680, "y": 1100, "wires": [ [ "func_node" ] ] }, { "id": "btn_bathroom_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "bathroom sw_4", "group": "group_bathroom", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "bathroom.sw_4", "payloadType": "str", "topic": "", "x": 1680, "y": 1140, "wires": [ [ "func_node" ] ] }, { "id": "btn_bathroom_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "bathroom sw_5", "group": "group_bathroom", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "bathroom.sw_5", "payloadType": "str", "topic": "", "x": 1680, "y": 1180, "wires": [ [ "func_node" ] ] }, { "id": "btn_bathroom_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "bathroom sw_6", "group": "group_bathroom", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "bathroom.sw_6", "payloadType": "str", "topic": "", "x": 1680, "y": 1220, "wires": [ [ "func_node" ] ] }, { "id": "btn_hallway_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "hallway all_off", "group": "group_hallway", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "hallway.all_off", "payloadType": "str", "topic": "", "x": 840, "y": 940, "wires": [ [ "func_node" ] ] }, { "id": "btn_hallway_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "hallway all_on", "group": "group_hallway", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "hallway.all_on", "payloadType": "str", "topic": "", "x": 840, "y": 980, "wires": [ [ "func_node" ] ] }, { "id": "btn_hallway_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "hallway sw_1", "group": "group_hallway", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "hallway.sw_1", "payloadType": "str", "topic": "", "x": 830, "y": 1020, "wires": [ [ "func_node" ] ] }, { "id": "btn_hallway_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "hallway sw_2", "group": "group_hallway", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "hallway.sw_2", "payloadType": "str", "topic": "", "x": 830, "y": 1060, "wires": [ [ "func_node" ] ] }, { "id": "btn_hallway_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "hallway sw_3", "group": "group_hallway", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "hallway.sw_3", "payloadType": "str", "topic": "", "x": 830, "y": 1100, "wires": [ [ "func_node" ] ] }, { "id": "btn_hallway_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "hallway sw_4", "group": "group_hallway", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "hallway.sw_4", "payloadType": "str", "topic": "", "x": 830, "y": 1140, "wires": [ [ "func_node" ] ] }, { "id": "btn_hallway_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "hallway sw_5", "group": "group_hallway", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "hallway.sw_5", "payloadType": "str", "topic": "", "x": 830, "y": 1180, "wires": [ [ "func_node" ] ] }, { "id": "btn_hallway_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "hallway sw_6", "group": "group_hallway", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "hallway.sw_6", "payloadType": "str", "topic": "", "x": 830, "y": 1220, "wires": [ [ "func_node" ] ] }, { "id": "btn_pantry_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "pantry all_off", "group": "group_pantry", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "pantry.all_off", "payloadType": "str", "topic": "", "x": 1470, "y": 940, "wires": [ [ "func_node" ] ] }, { "id": "btn_pantry_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "pantry all_on", "group": "group_pantry", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "pantry.all_on", "payloadType": "str", "topic": "", "x": 1470, "y": 980, "wires": [ [ "func_node" ] ] }, { "id": "btn_pantry_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "pantry sw_1", "group": "group_pantry", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "pantry.sw_1", "payloadType": "str", "topic": "", "x": 1470, "y": 1020, "wires": [ [ "func_node" ] ] }, { "id": "btn_pantry_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "pantry sw_2", "group": "group_pantry", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "pantry.sw_2", "payloadType": "str", "topic": "", "x": 1470, "y": 1060, "wires": [ [ "func_node" ] ] }, { "id": "btn_pantry_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "pantry sw_3", "group": "group_pantry", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "pantry.sw_3", "payloadType": "str", "topic": "", "x": 1470, "y": 1100, "wires": [ [ "func_node" ] ] }, { "id": "btn_pantry_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "pantry sw_4", "group": "group_pantry", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "pantry.sw_4", "payloadType": "str", "topic": "", "x": 1470, "y": 1140, "wires": [ [ "func_node" ] ] }, { "id": "btn_pantry_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "pantry sw_5", "group": "group_pantry", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "pantry.sw_5", "payloadType": "str", "topic": "", "x": 1470, "y": 1180, "wires": [ [ "func_node" ] ] }, { "id": "btn_pantry_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "pantry sw_6", "group": "group_pantry", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "pantry.sw_6", "payloadType": "str", "topic": "", "x": 1470, "y": 1220, "wires": [ [ "func_node" ] ] }, { "id": "btn_kitchen_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "kitchen all_off", "group": "group_kitchen", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "kitchen.all_off", "payloadType": "str", "topic": "", "x": 1580, "y": 580, "wires": [ [ "func_node" ] ] }, { "id": "btn_kitchen_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "kitchen all_on", "group": "group_kitchen", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "kitchen.all_on", "payloadType": "str", "topic": "", "x": 1580, "y": 620, "wires": [ [ "func_node" ] ] }, { "id": "btn_kitchen_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "kitchen sw_1", "group": "group_kitchen", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "kitchen.sw_1", "payloadType": "str", "topic": "", "x": 1570, "y": 660, "wires": [ [ "func_node" ] ] }, { "id": "btn_kitchen_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "kitchen sw_2", "group": "group_kitchen", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "kitchen.sw_2", "payloadType": "str", "topic": "", "x": 1570, "y": 700, "wires": [ [ "func_node" ] ] }, { "id": "btn_kitchen_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "kitchen sw_3", "group": "group_kitchen", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "kitchen.sw_3", "payloadType": "str", "topic": "", "x": 1570, "y": 740, "wires": [ [ "func_node" ] ] }, { "id": "btn_kitchen_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "kitchen sw_4", "group": "group_kitchen", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "kitchen.sw_4", "payloadType": "str", "topic": "", "x": 1570, "y": 780, "wires": [ [ "func_node" ] ] }, { "id": "btn_kitchen_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "kitchen sw_5", "group": "group_kitchen", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "kitchen.sw_5", "payloadType": "str", "topic": "", "x": 1570, "y": 820, "wires": [ [ "func_node" ] ] }, { "id": "btn_kitchen_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "kitchen sw_6", "group": "group_kitchen", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "kitchen.sw_6", "payloadType": "str", "topic": "", "x": 1570, "y": 860, "wires": [ [ "func_node" ] ] }, { "id": "btn_livingRoom_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "livingRoom all_off", "group": "group_livingRoom", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "livingRoom.all_off", "payloadType": "str", "topic": "", "x": 1350, "y": 580, "wires": [ [ "func_node" ] ] }, { "id": "btn_livingRoom_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "livingRoom all_on", "group": "group_livingRoom", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "livingRoom.all_on", "payloadType": "str", "topic": "", "x": 1350, "y": 620, "wires": [ [ "func_node" ] ] }, { "id": "btn_livingRoom_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "livingRoom sw_1", "group": "group_livingRoom", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "livingRoom.sw_1", "payloadType": "str", "topic": "", "x": 1350, "y": 660, "wires": [ [ "func_node" ] ] }, { "id": "btn_livingRoom_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "livingRoom sw_2", "group": "group_livingRoom", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "livingRoom.sw_2", "payloadType": "str", "topic": "", "x": 1350, "y": 700, "wires": [ [ "func_node" ] ] }, { "id": "btn_livingRoom_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "livingRoom sw_3", "group": "group_livingRoom", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "livingRoom.sw_3", "payloadType": "str", "topic": "", "x": 1350, "y": 740, "wires": [ [ "func_node" ] ] }, { "id": "btn_livingRoom_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "livingRoom sw_4", "group": "group_livingRoom", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "livingRoom.sw_4", "payloadType": "str", "topic": "", "x": 1350, "y": 780, "wires": [ [ "func_node" ] ] }, { "id": "btn_livingRoom_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "livingRoom sw_5", "group": "group_livingRoom", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "livingRoom.sw_5", "payloadType": "str", "topic": "", "x": 1350, "y": 820, "wires": [ [ "func_node" ] ] }, { "id": "btn_livingRoom_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "livingRoom sw_6", "group": "group_livingRoom", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "livingRoom.sw_6", "payloadType": "str", "topic": "", "x": 1350, "y": 860, "wires": [ [ "func_node" ] ] }, { "id": "btn_dinningRoom_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "dinningRoom all_off", "group": "group_dinningRoom", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "dinningRoom.all_off", "payloadType": "str", "topic": "", "x": 1150, "y": 580, "wires": [ [ "func_node" ] ] }, { "id": "btn_dinningRoom_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "dinningRoom all_on", "group": "group_dinningRoom", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "dinningRoom.all_on", "payloadType": "str", "topic": "", "x": 1140, "y": 620, "wires": [ [ "func_node" ] ] }, { "id": "btn_dinningRoom_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "dinningRoom sw_1", "group": "group_dinningRoom", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "dinningRoom.sw_1", "payloadType": "str", "topic": "", "x": 1150, "y": 660, "wires": [ [ "func_node" ] ] }, { "id": "btn_dinningRoom_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "dinningRoom sw_2", "group": "group_dinningRoom", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "dinningRoom.sw_2", "payloadType": "str", "topic": "", "x": 1150, "y": 700, "wires": [ [ "func_node" ] ] }, { "id": "btn_dinningRoom_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "dinningRoom sw_3", "group": "group_dinningRoom", "order": 5, "width": 0, "height": 0, "passthru": false, "label": "sw_3", "tooltip": "", "color": "", "bgcolor": "", "className": "", "icon": "", "payload": "dinningRoom.sw_3", "payloadType": "str", "topic": "", "topicType": "str", "x": 1150, "y": 740, "wires": [ [ "func_node" ] ] }, { "id": "btn_dinningRoom_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "dinningRoom sw_4", "group": "group_dinningRoom", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "dinningRoom.sw_4", "payloadType": "str", "topic": "", "x": 1150, "y": 780, "wires": [ [ "func_node" ] ] }, { "id": "btn_dinningRoom_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "dinningRoom sw_5", "group": "group_dinningRoom", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "dinningRoom.sw_5", "payloadType": "str", "topic": "", "x": 1150, "y": 820, "wires": [ [ "func_node" ] ] }, { "id": "btn_dinningRoom_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "dinningRoom sw_6", "group": "group_dinningRoom", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "dinningRoom.sw_6", "payloadType": "str", "topic": "", "x": 1150, "y": 860, "wires": [ [ "func_node" ] ] }, { "id": "btn_entrance_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "entrance all_off", "group": "group_entrance", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "entrance.all_off", "payloadType": "str", "topic": "", "x": 1300, "y": 940, "wires": [ [ "func_node" ] ] }, { "id": "btn_entrance_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "entrance all_on", "group": "group_entrance", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "entrance.all_on", "payloadType": "str", "topic": "", "x": 1300, "y": 980, "wires": [ [ "func_node" ] ] }, { "id": "btn_entrance_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "entrance sw_1", "group": "group_entrance", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "entrance.sw_1", "payloadType": "str", "topic": "", "x": 1300, "y": 1020, "wires": [ [ "func_node" ] ] }, { "id": "btn_entrance_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "entrance sw_2", "group": "group_entrance", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "entrance.sw_2", "payloadType": "str", "topic": "", "x": 1300, "y": 1060, "wires": [ [ "func_node" ] ] }, { "id": "btn_entrance_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "entrance sw_3", "group": "group_entrance", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "entrance.sw_3", "payloadType": "str", "topic": "", "x": 1300, "y": 1100, "wires": [ [ "func_node" ] ] }, { "id": "btn_entrance_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "entrance sw_4", "group": "group_entrance", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "entrance.sw_4", "payloadType": "str", "topic": "", "x": 1300, "y": 1140, "wires": [ [ "func_node" ] ] }, { "id": "btn_entrance_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "entrance sw_5", "group": "group_entrance", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "entrance.sw_5", "payloadType": "str", "topic": "", "x": 1300, "y": 1180, "wires": [ [ "func_node" ] ] }, { "id": "btn_entrance_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "entrance sw_6", "group": "group_entrance", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "entrance.sw_6", "payloadType": "str", "topic": "", "x": 1300, "y": 1220, "wires": [ [ "func_node" ] ] }, { "id": "btn_guestWc_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "guestWc all_off", "group": "group_guestWc", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "guestWc.all_off", "payloadType": "str", "topic": "", "x": 940, "y": 580, "wires": [ [ "func_node" ] ] }, { "id": "btn_guestWc_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "guestWc all_on", "group": "group_guestWc", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "guestWc.all_on", "payloadType": "str", "topic": "", "x": 940, "y": 620, "wires": [ [ "func_node" ] ] }, { "id": "btn_guestWc_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "guestWc sw_1", "group": "group_guestWc", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "guestWc.sw_1", "payloadType": "str", "topic": "", "x": 940, "y": 660, "wires": [ [ "func_node" ] ] }, { "id": "btn_guestWc_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "guestWc sw_2", "group": "group_guestWc", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "guestWc.sw_2", "payloadType": "str", "topic": "", "x": 940, "y": 700, "wires": [ [ "func_node" ] ] }, { "id": "btn_guestWc_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "guestWc sw_3", "group": "group_guestWc", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "guestWc.sw_3", "payloadType": "str", "topic": "", "x": 940, "y": 740, "wires": [ [ "func_node" ] ] }, { "id": "btn_guestWc_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "guestWc sw_4", "group": "group_guestWc", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "guestWc.sw_4", "payloadType": "str", "topic": "", "x": 940, "y": 780, "wires": [ [ "func_node" ] ] }, { "id": "btn_guestWc_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "guestWc sw_5", "group": "group_guestWc", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "guestWc.sw_5", "payloadType": "str", "topic": "", "x": 940, "y": 820, "wires": [ [ "func_node" ] ] }, { "id": "btn_guestWc_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "guestWc sw_6", "group": "group_guestWc", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "guestWc.sw_6", "payloadType": "str", "topic": "", "x": 940, "y": 860, "wires": [ [ "func_node" ] ] }, { "id": "btn_outVeranda_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "outVeranda all_off", "group": "group_outVeranda", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "outVeranda.all_off", "payloadType": "str", "topic": "", "x": 730, "y": 580, "wires": [ [ "func_node" ] ] }, { "id": "btn_outVeranda_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "outVeranda all_on", "group": "group_outVeranda", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "outVeranda.all_on", "payloadType": "str", "topic": "", "x": 730, "y": 620, "wires": [ [ "func_node" ] ] }, { "id": "btn_outVeranda_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "outVeranda sw_1", "group": "group_outVeranda", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "outVeranda.sw_1", "payloadType": "str", "topic": "", "x": 730, "y": 660, "wires": [ [ "func_node" ] ] }, { "id": "btn_outVeranda_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "outVeranda sw_2", "group": "group_outVeranda", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "outVeranda.sw_2", "payloadType": "str", "topic": "", "x": 730, "y": 700, "wires": [ [ "func_node" ] ] }, { "id": "btn_outVeranda_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "outVeranda sw_3", "group": "group_outVeranda", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "outVeranda.sw_3", "payloadType": "str", "topic": "", "x": 730, "y": 740, "wires": [ [ "func_node" ] ] }, { "id": "btn_outVeranda_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "outVeranda sw_4", "group": "group_outVeranda", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "outVeranda.sw_4", "payloadType": "str", "topic": "", "x": 730, "y": 780, "wires": [ [ "func_node" ] ] }, { "id": "btn_outVeranda_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "outVeranda sw_5", "group": "group_outVeranda", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "outVeranda.sw_5", "payloadType": "str", "topic": "", "x": 730, "y": 820, "wires": [ [ "func_node" ] ] }, { "id": "btn_outVeranda_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "outVeranda sw_6", "group": "group_outVeranda", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "outVeranda.sw_6", "payloadType": "str", "topic": "", "x": 730, "y": 860, "wires": [ [ "func_node" ] ] }, { "id": "btn_outFront_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "outFront all_off", "group": "group_outFront", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "outFront.all_off", "payloadType": "str", "topic": "", "x": 520, "y": 580, "wires": [ [ "func_node" ] ] }, { "id": "btn_outFront_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "outFront all_on", "group": "group_outFront", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "outFront.all_on", "payloadType": "str", "topic": "", "x": 520, "y": 620, "wires": [ [ "func_node" ] ] }, { "id": "btn_outFront_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "outFront sw_1", "group": "group_outFront", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "outFront.sw_1", "payloadType": "str", "topic": "", "x": 520, "y": 660, "wires": [ [ "func_node" ] ] }, { "id": "btn_outFront_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "outFront sw_2", "group": "group_outFront", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "outFront.sw_2", "payloadType": "str", "topic": "", "x": 520, "y": 700, "wires": [ [ "func_node" ] ] }, { "id": "btn_outFront_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "outFront sw_3", "group": "group_outFront", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "outFront.sw_3", "payloadType": "str", "topic": "", "x": 520, "y": 740, "wires": [ [ "func_node" ] ] }, { "id": "btn_outFront_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "outFront sw_4", "group": "group_outFront", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "outFront.sw_4", "payloadType": "str", "topic": "", "x": 520, "y": 780, "wires": [ [ "func_node" ] ] }, { "id": "btn_outFront_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "outFront sw_5", "group": "group_outFront", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "outFront.sw_5", "payloadType": "str", "topic": "", "x": 520, "y": 820, "wires": [ [ "func_node" ] ] }, { "id": "btn_outFront_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "outFront sw_6", "group": "group_outFront", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "outFront.sw_6", "payloadType": "str", "topic": "", "x": 520, "y": 860, "wires": [ [ "func_node" ] ] }, { "id": "btn_outSide_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "outSide all_off", "group": "group_outSide", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "outSide.all_off", "payloadType": "str", "topic": "", "x": 340, "y": 580, "wires": [ [ "func_node" ] ] }, { "id": "btn_outSide_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "outSide all_on", "group": "group_outSide", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "outSide.all_on", "payloadType": "str", "topic": "", "x": 340, "y": 620, "wires": [ [ "func_node" ] ] }, { "id": "btn_outSide_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "outSide sw_1", "group": "group_outSide", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "outSide.sw_1", "payloadType": "str", "topic": "", "x": 340, "y": 660, "wires": [ [ "func_node" ] ] }, { "id": "btn_outSide_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "outSide sw_2", "group": "group_outSide", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "outSide.sw_2", "payloadType": "str", "topic": "", "x": 340, "y": 700, "wires": [ [ "func_node" ] ] }, { "id": "btn_outSide_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "outSide sw_3", "group": "group_outSide", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "outSide.sw_3", "payloadType": "str", "topic": "", "x": 340, "y": 740, "wires": [ [ "func_node" ] ] }, { "id": "btn_outSide_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "outSide sw_4", "group": "group_outSide", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "outSide.sw_4", "payloadType": "str", "topic": "", "x": 340, "y": 780, "wires": [ [ "func_node" ] ] }, { "id": "btn_outSide_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "outSide sw_5", "group": "group_outSide", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "outSide.sw_5", "payloadType": "str", "topic": "", "x": 340, "y": 820, "wires": [ [ "func_node" ] ] }, { "id": "btn_outSide_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "outSide sw_6", "group": "group_outSide", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "outSide.sw_6", "payloadType": "str", "topic": "", "x": 340, "y": 860, "wires": [ [ "func_node" ] ] }, { "id": "btn_outBack_all_off", "type": "ui_button", "z": "31693504fcbbd954", "name": "outBack all_off", "group": "group_outBack", "order": 1, "width": 0, "height": 0, "label": "all_off", "payload": "outBack.all_off", "payloadType": "str", "topic": "", "x": 120, "y": 580, "wires": [ [ "func_node" ] ] }, { "id": "btn_outBack_all_on", "type": "ui_button", "z": "31693504fcbbd954", "name": "outBack all_on", "group": "group_outBack", "order": 2, "width": 0, "height": 0, "label": "all_on", "payload": "outBack.all_on", "payloadType": "str", "topic": "", "x": 120, "y": 620, "wires": [ [ "func_node" ] ] }, { "id": "btn_outBack_sw_1", "type": "ui_button", "z": "31693504fcbbd954", "name": "outBack sw_1", "group": "group_outBack", "order": 3, "width": 0, "height": 0, "label": "sw_1", "payload": "outBack.sw_1", "payloadType": "str", "topic": "", "x": 120, "y": 660, "wires": [ [ "func_node" ] ] }, { "id": "btn_outBack_sw_2", "type": "ui_button", "z": "31693504fcbbd954", "name": "outBack sw_2", "group": "group_outBack", "order": 4, "width": 0, "height": 0, "label": "sw_2", "payload": "outBack.sw_2", "payloadType": "str", "topic": "", "x": 120, "y": 700, "wires": [ [ "func_node" ] ] }, { "id": "btn_outBack_sw_3", "type": "ui_button", "z": "31693504fcbbd954", "name": "outBack sw_3", "group": "group_outBack", "order": 5, "width": 0, "height": 0, "label": "sw_3", "payload": "outBack.sw_3", "payloadType": "str", "topic": "", "x": 120, "y": 740, "wires": [ [ "func_node" ] ] }, { "id": "btn_outBack_sw_4", "type": "ui_button", "z": "31693504fcbbd954", "name": "outBack sw_4", "group": "group_outBack", "order": 6, "width": 0, "height": 0, "label": "sw_4", "payload": "outBack.sw_4", "payloadType": "str", "topic": "", "x": 120, "y": 780, "wires": [ [ "func_node" ] ] }, { "id": "btn_outBack_sw_5", "type": "ui_button", "z": "31693504fcbbd954", "name": "outBack sw_5", "group": "group_outBack", "order": 7, "width": 0, "height": 0, "label": "sw_5", "payload": "outBack.sw_5", "payloadType": "str", "topic": "", "x": 120, "y": 820, "wires": [ [ "func_node" ] ] }, { "id": "btn_outBack_sw_6", "type": "ui_button", "z": "31693504fcbbd954", "name": "outBack sw_6", "group": "group_outBack", "order": 8, "width": 0, "height": 0, "label": "sw_6", "payload": "outBack.sw_6", "payloadType": "str", "topic": "", "x": 120, "y": 860, "wires": [ [ "func_node" ] ] }, { "id": "timer30min_btn", "type": "ha-button", "z": "50971c50479dfd7a", "name": "Timer 30 Min", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "timer30min_config", "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "30", "valueType": "num" } ], "x": 630, "y": 680, "wires": [ [ "260bf6fdd821f1b9" ] ] }, { "id": "timer1hour_btn", "type": "ha-button", "z": "50971c50479dfd7a", "name": "Timer 1 Hour", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "timer1hour_config", "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "60", "valueType": "num" } ], "x": 790, "y": 680, "wires": [ [ "260bf6fdd821f1b9" ] ] }, { "id": "timer2hours_btn", "type": "ha-button", "z": "50971c50479dfd7a", "name": "Timer 2 Hours", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "timer2hours_config", "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "120", "valueType": "num" } ], "x": 990, "y": 680, "wires": [ [ "260bf6fdd821f1b9" ] ] }, { "id": "timerstop_btn", "type": "ha-button", "z": "50971c50479dfd7a", "name": "Stop Timer", "version": 0, "debugenabled": false, "outputs": 1, "entityConfig": "timerstop_config", "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "stop", "valueType": "str" } ], "x": 980, "y": 740, "wires": [ [ "a57a98c852762ebf" ] ] }, { "id": "water_boiler_timer_handler", "type": "function", "z": "50971c50479dfd7a", "name": "Water Boiler Timer Handler", "func": "// Helper function to format remaining time\nfunction formatTime(remainingMs) {\n if (remainingMs <= 0) return '0m 0s';\n const totalSeconds = Math.floor(remainingMs / 1000);\n const minutes = Math.floor(totalSeconds / 60);\n const seconds = totalSeconds % 60;\n const hours = Math.floor(minutes / 60);\n const mins = minutes % 60;\n \n let timeStr = '';\n if (hours > 0) timeStr += hours + 'h ';\n if (mins > 0 || hours === 0) timeStr += mins + 'm ';\n timeStr += seconds + 's';\n return timeStr.trim();\n}\n\n// Check if this is a timer command (numeric payload or \"stop\")\nconst payload = msg.payload;\nconst isTimerCommand = typeof payload === 'number' || payload === 'stop';\n\nif (isTimerCommand) {\n // Cancel any existing timer and interval\n const existingTimer = flow.get('water_boiler_timer');\n if (existingTimer) {\n clearTimeout(existingTimer);\n flow.set('water_boiler_timer', null);\n }\n \n const existingInterval = flow.get('water_boiler_timer_interval');\n if (existingInterval) {\n clearInterval(existingInterval);\n flow.set('water_boiler_timer_interval', null);\n }\n \n if (payload === 'stop') {\n // Stop command - turn off water boiler immediately\n const msgFalse = {\n topic: \"bathroom\",\n payload: \"sw_6\",\n value: false\n };\n \n // Send 0 remaining time\n const msgTime = {\n payload: '0m 0s'\n };\n \n node.status({fill:\"yellow\", shape:\"dot\", text:\"Timer stopped\"});\n return [msgFalse, null, msgTime];\n } else {\n // Timer duration in minutes - convert to milliseconds\n const durationMs = payload * 60 * 1000;\n const startTime = Date.now();\n \n // Store start time and duration\n flow.set('water_boiler_timer_start', startTime);\n flow.set('water_boiler_timer_duration', durationMs);\n \n // Turn ON water boiler first\n const msgTrue = {\n topic: \"bathroom\",\n payload: \"sw_6\",\n value: true\n };\n \n // Function to send remaining time\n const sendRemainingTime = function() {\n const elapsed = Date.now() - startTime;\n const remaining = Math.max(0, durationMs - elapsed);\n const timeStr = formatTime(remaining);\n \n const msgTime = {\n payload: timeStr\n };\n node.send([null, null, msgTime]);\n \n // Update status\n node.status({fill:\"blue\", shape:\"dot\", text:`Timer: ${timeStr}`});\n \n // Clear interval if timer expired\n if (remaining <= 0) {\n const intervalId = flow.get('water_boiler_timer_interval');\n if (intervalId) {\n clearInterval(intervalId);\n flow.set('water_boiler_timer_interval', null);\n }\n }\n };\n \n // Send initial remaining time\n sendRemainingTime();\n \n // Set up interval to update remaining time every second (live refresh)\n const intervalId = setInterval(sendRemainingTime, 1000);\n flow.set('water_boiler_timer_interval', intervalId);\n \n // Set timer to turn OFF after duration\n const timerId = setTimeout(function() {\n const msgOff = {\n topic: \"bathroom\",\n payload: \"sw_6\",\n value: false\n };\n \n // Send final time (0m 0s)\n const msgTime = {\n payload: '0m 0s'\n };\n \n node.send([msgOff, null, msgTime]);\n flow.set('water_boiler_timer', null);\n flow.set('water_boiler_timer_start', null);\n flow.set('water_boiler_timer_duration', null);\n \n // Clear interval\n const intervalId = flow.get('water_boiler_timer_interval');\n if (intervalId) {\n clearInterval(intervalId);\n flow.set('water_boiler_timer_interval', null);\n }\n \n node.status({fill:\"green\", shape:\"ring\", text:\"Timer completed\"});\n }, durationMs);\n \n // Store timer ID\n flow.set('water_boiler_timer', timerId);\n \n const minutes = payload;\n const hours = Math.floor(minutes / 60);\n const mins = minutes % 60;\n let timeStr = '';\n if (hours > 0) timeStr += hours + 'h ';\n if (mins > 0 || hours === 0) timeStr += mins + 'm';\n \n // Return ON command on output 1, nothing on output 2, initial time on output 3\n const msgTime = {\n payload: formatTime(durationMs)\n };\n return [msgTrue, null, msgTime];\n }\n} else {\n // Regular button press - pass through to existing function on output 2\n return [null, msg, null];\n}\n\n", "outputs": 3, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1620, "y": 680, "wires": [ [ "1d0a46b9d5255560" ], [], [ "timer_remaining_sensor" ] ] }, { "id": "1d0a46b9d5255560", "type": "link out", "z": "50971c50479dfd7a", "name": "link out 24", "mode": "link", "links": [ "0bbcb269da9b75c7" ], "x": 1845, "y": 560, "wires": [] }, { "id": "timer_remaining_sensor", "type": "ha-sensor", "z": "50971c50479dfd7a", "name": "Timer Remaining", "entityConfig": "timer_remaining_config", "version": 1, "state": "payload", "stateType": "msg", "attributes": [], "x": 1890, "y": 620, "wires": [ [] ] }, { "id": "a57a98c852762ebf", "type": "api-current-state", "z": "50971c50479dfd7a", "name": "", "server": "29eb84a2708d96e0", "version": 3, "outputs": 2, "halt_if": "on", "halt_if_type": "str", "halt_if_compare": "is", "entity_id": "binary_sensor.water_boiler", "state_type": "str", "blockInputOverrides": false, "outputProperties": [], "for": "0", "forType": "num", "forUnits": "minutes", "override_topic": false, "state_location": "payload", "override_payload": "msg", "entity_location": "data", "override_data": "msg", "x": 1280, "y": 740, "wires": [ [ "water_boiler_timer_handler" ], [] ] }, { "id": "260bf6fdd821f1b9", "type": "api-current-state", "z": "50971c50479dfd7a", "name": "", "server": "29eb84a2708d96e0", "version": 3, "outputs": 2, "halt_if": "off", "halt_if_type": "str", "halt_if_compare": "is", "entity_id": "binary_sensor.water_boiler", "state_type": "str", "blockInputOverrides": false, "outputProperties": [], "for": "0", "forType": "num", "forUnits": "minutes", "override_topic": false, "state_location": "payload", "override_payload": "msg", "entity_location": "data", "override_data": "msg", "x": 1280, "y": 680, "wires": [ [ "water_boiler_timer_handler" ], [] ] }, { "id": "0ad5d7e5c99c2675", "type": "poll-state", "z": "50971c50479dfd7a", "name": "", "server": "29eb84a2708d96e0", "version": 3, "exposeAsEntityConfig": "", "updateInterval": "30", "updateIntervalType": "num", "updateIntervalUnits": "seconds", "outputInitially": true, "outputOnChanged": true, "entityId": "binary_sensor.water_boiler", "stateType": "str", "ifState": "on", "ifStateType": "str", "ifStateOperator": "is", "outputs": 2, "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "", "valueType": "entityState" }, { "property": "data", "propertyType": "msg", "value": "", "valueType": "entity" }, { "property": "topic", "propertyType": "msg", "value": "", "valueType": "triggerId" } ], "x": 1070, "y": 600, "wires": [ [ "2472daff4bc82fb2", "f12fa3448a1b5872" ], [] ] }, { "id": "2472daff4bc82fb2", "type": "function", "z": "50971c50479dfd7a", "name": "Safety Check Function", "func": "// Safety Check Function\n// This function checks the water boiler state on Node-RED startup ONLY\n// It's connected to the poll-state node which outputs initially when Node-RED starts\n// If the boiler is ON, it turns it off and clears timer state\n// Uses a flag to ensure it only runs once on startup, not on every poll\n\n// Check if safety check has already been performed (only runs once on startup)\nconst safetyCheckDone = flow.get('water_boiler_safety_check_done');\nif (safetyCheckDone === true) {\n // Safety check already performed, ignore this message (from periodic polls)\n // Return nothing to both outputs\n return [null, null];\n}\n\n// Mark safety check as done (so it won't run again until Node-RED restarts)\nflow.set('water_boiler_safety_check_done', true);\n\n// Get the current state from the poll-state node\nconst currentState = msg.payload; // 'on' or 'off'\n\n// Clear any timer state (safety measure on restart)\nflow.set('water_boiler_timer', null);\nflow.set('water_boiler_timer_interval', null);\nflow.set('water_boiler_timer_start', null);\nflow.set('water_boiler_timer_duration', null);\n\n// Only turn off if the boiler is currently ON\nif (currentState === 'on') {\n // Boiler is ON - turn it off for safety\n const msgOff = {\n topic: \"bathroom\",\n payload: \"sw_6\",\n value: false\n };\n \n const msgTime = {\n payload: '0m 0s'\n };\n \n node.status({fill:\"red\", shape:\"ring\", text:\"Safety: Boiler was ON, turned off\"});\n return [msgOff, msgTime];\n} else {\n // Boiler is already off, just reset timer display\n const msgTime = {\n payload: '0m 0s'\n };\n \n node.status({fill:\"green\", shape:\"ring\", text:\"Safety: Boiler already off\"});\n return [null, msgTime];\n}\n\n", "outputs": 2, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1600, "y": 620, "wires": [ [ "1d0a46b9d5255560" ], [ "timer_remaining_sensor" ] ] }, { "id": "f96bf3ff41b2e8f7", "type": "server-state-changed", "z": "50971c50479dfd7a", "d": true, "name": "Monitor Boiler (3h Safety)", "server": "29eb84a2708d96e0", "version": 6, "outputs": 1, "exposeAsEntityConfig": "", "entities": { "entity": [ "binary_sensor.water_boiler" ], "substring": [], "regex": [] }, "outputInitially": true, "stateType": "str", "ifState": "", "ifStateType": "str", "ifStateOperator": "is", "outputOnlyOnStateChange": true, "for": "0", "forType": "num", "forUnits": "minutes", "ignorePrevStateNull": true, "ignorePrevStateUnknown": true, "ignorePrevStateUnavailable": false, "ignoreCurrentStateUnknown": false, "ignoreCurrentStateUnavailable": false, "outputProperties": [ { "property": "payload", "propertyType": "msg", "value": "", "valueType": "entityState" }, { "property": "data", "propertyType": "msg", "value": "", "valueType": "eventData" }, { "property": "topic", "propertyType": "msg", "value": "", "valueType": "triggerId" } ], "x": 1030, "y": 560, "wires": [ [ "3hour_safety_function_events" ] ] }, { "id": "3hour_safety_function_events", "type": "function", "z": "50971c50479dfd7a", "d": true, "name": "3-Hour Safety Timer", "func": "// Water Boiler 3-Hour Safety Timer\n// Uses server-state-changed node which provides old_state and new_state in event data\n// Event-driven (real-time) - no polling needed!\n\n// Get state information from server-state-changed node\n// msg.data contains the full event object with old_state and new_state\nconst eventData = msg.data;\nconst newState = eventData.new_state ? eventData.new_state.state : msg.payload;\nconst oldState = eventData.old_state ? eventData.old_state.state : 'unknown';\n\n// Get existing safety timer if any\nconst safetyTimer = flow.get('water_boiler_3hour_timer');\n\n// Check if state changed from off/unknown to on\nif (newState === 'on' && oldState !== 'on') {\n // Boiler just turned ON - start 3-hour safety timer\n \n // Cancel any existing timer (safety measure)\n if (safetyTimer) {\n clearTimeout(safetyTimer);\n flow.set('water_boiler_3hour_timer', null);\n }\n \n // Start 3-hour timer (3 hours = 3 * 60 * 60 * 1000 milliseconds)\n const threeHours = 3 * 60 * 60 * 1000;\n const timerId = setTimeout(function() {\n // 3 hours elapsed - turn off boiler for safety\n const msgOff = {\n topic: \"bathroom\",\n payload: \"sw_6\",\n value: false\n };\n \n // Clear timer state\n flow.set('water_boiler_3hour_timer', null);\n flow.set('water_boiler_3hour_start_time', null);\n \n // Send turn-off command\n node.send(msgOff);\n node.status({fill:\"red\", shape:\"ring\", text:\"Safety: 3h limit reached, turned off\"});\n node.warn(\"Water boiler has been ON for 3 hours - automatically turned off for safety\");\n }, threeHours);\n \n // Store timer ID and start time\n flow.set('water_boiler_3hour_timer', timerId);\n flow.set('water_boiler_3hour_start_time', Date.now());\n \n // Update status\n node.status({fill:\"yellow\", shape:\"dot\", text:\"3h safety timer: 3h remaining\"});\n node.log(\"Water boiler turned ON - 3-hour safety timer started\");\n \n // Don't send any message (just monitoring)\n return null;\n \n} else if (newState === 'off' && oldState === 'on') {\n // Boiler just turned OFF - cancel safety timer\n \n if (safetyTimer) {\n clearTimeout(safetyTimer);\n flow.set('water_boiler_3hour_timer', null);\n \n const startTime = flow.get('water_boiler_3hour_start_time');\n if (startTime) {\n const runtime = Math.floor((Date.now() - startTime) / 1000 / 60); // minutes\n node.log(`Water boiler turned OFF - 3-hour safety timer cancelled (was on for ${runtime} minutes)`);\n }\n \n flow.set('water_boiler_3hour_start_time', null);\n node.status({fill:\"green\", shape:\"ring\", text:\"3h safety timer cancelled\"});\n } else {\n node.status({fill:\"grey\", shape:\"ring\", text:\"Boiler off\"});\n }\n \n // Don't send any message\n return null;\n \n} else {\n // Other state changes (on->on, off->off, initial state, etc.) - ignore\n return null;\n}", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1600, "y": 560, "wires": [ [ "1d0a46b9d5255560" ] ] }, { "id": "f12fa3448a1b5872", "type": "debug", "z": "50971c50479dfd7a", "name": "debug 28", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1290, "y": 460, "wires": [] }, { "id": "inject-person", "type": "inject", "z": "a6a28d6b6c0b4f4a", "name": "Simulate Person Detected", "props": [ { "p": "payload", "v": "1", "vt": "num" }, { "p": "timestamp", "v": "", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "x": 410, "y": 860, "wires": [ [ "function-add-timestamp" ] ] }, { "id": "function-add-timestamp", "type": "function", "z": "a6a28d6b6c0b4f4a", "name": "Add Current Timestamp", "func": "// Add timestamp\nmsg.timestamp = Date.now();\nreturn msg;", "outputs": 1, "x": 670, "y": 860, "wires": [ [ "function-check-state" ] ] }, { "id": "function-check-state", "type": "function", "z": "a6a28d6b6c0b4f4a", "name": "Check Doorbell State", "func": "// Get previous state from context\nvar prev = context.get('prev') || 0;\nvar curr = parseInt(msg.payload);\ncontext.set('prev', curr);\n\nif(curr===1 && prev===0){\n msg.payload = \"🚪 Person detected at Basement Driveway!\";\n return msg;\n}\nreturn null;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 910, "y": 860, "wires": [ [ "function-login" ] ] }, { "id": "function-login", "type": "function", "z": "a6a28d6b6c0b4f4a", "name": "Reolink Login", "func": "const ip = '10.20.30.34';\nconst username = 'admin';\nconst password = 'sh1pb0x1';\nmsg.url = `http://${ip}/cgi-bin/api.cgi?cmd=Login&token=null`;\nmsg.method = 'POST';\nmsg.headers = { 'Content-Type': 'application/json' };\nmsg.payload = JSON.stringify([\n { cmd: 'Login', param: { User: { userName: username, password: password } } }\n]);\nmsg.camera_ip = ip;\nmsg.camera_location = 'Basement Driveway Camera';\nmsg.nextRandom = Math.random().toString(36).substring(7);\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1150, "y": 860, "wires": [ [ "http-login" ] ] }, { "id": "http-login", "type": "http request", "z": "a6a28d6b6c0b4f4a", "name": "Send Login Request", "method": "use", "ret": "obj", "url": "", "tls": "", "persist": false, "proxy": "", "x": 1390, "y": 860, "wires": [ [ "function-snap" ] ] }, { "id": "function-snap", "type": "function", "z": "a6a28d6b6c0b4f4a", "name": "Fetch Snapshot", "func": "// Extract token from login response\nif(!msg.payload || !msg.payload[0] || !msg.payload[0].value){\n node.error('Login failed');\n return null;\n}\nconst token = msg.payload[0].value.Token.name;\nif(!token){ node.error('Token missing'); return null; }\n\n// Build snapshot URL\nmsg.url = `http://${msg.camera_ip}/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=${msg.nextRandom}&token=${token}`;\nmsg.method = 'GET';\nmsg.headers = {};\nmsg.payload = null;\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1630, "y": 860, "wires": [ [ "http-snap" ] ] }, { "id": "http-snap", "type": "http request", "z": "a6a28d6b6c0b4f4a", "name": "Get Camera Snapshot", "method": "use", "ret": "bin", "url": "", "tls": "", "persist": false, "proxy": "", "x": 1870, "y": 860, "wires": [ [ "b95aab8dab0c2fb4" ] ] }, { "id": "b95aab8dab0c2fb4", "type": "function", "z": "a6a28d6b6c0b4f4a", "name": "Send Doorbell Alert to Telegram", "func": "// Validate that we received a proper image buffer\nif (!Buffer.isBuffer(msg.payload)) {\n node.warn(\"āŒ Basement Driveway snapshot fetch failed — not a binary image buffer\");\n node.status({fill:\"red\", shape:\"ring\", text:\"Snapshot failed\"});\n return null;\n}\n\n// Check if buffer has reasonable size (basic validation)\nif (msg.payload.length < 1000) {\n node.warn(\"āŒ Basement Driveway snapshot too small — likely corrupted\");\n node.status({fill:\"red\", shape:\"ring\", text:\"Image too small\"});\n return null;\n}\n\n// Format timestamp for display\nconst timestamp = new Date(msg.timestamp).toLocaleString();\n\n// Prepare Telegram message payload\nmsg.payload = {\n chatId: -4747176681, // Telegram group chat ID\n type: 'photo',\n content: msg.payload, // Binary image buffer\n caption: `šŸ”” Basement Driveway ALERT! šŸ””\\n\\nšŸ“ Someone is at the ${msg.location}\\nā° Time: ${timestamp}\\nšŸ“· Camera: ${msg.camera_location} (${msg.camera_ip})`\n};\n\nnode.status({fill:\"green\", shape:\"dot\", text:\"Alert sent!\"});\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 2150, "y": 860, "wires": [ [ "8f15067daf678e66" ] ] }, { "id": "8f15067daf678e66", "type": "link out", "z": "a6a28d6b6c0b4f4a", "name": "link out 25", "mode": "link", "links": [ "41d29e978759e26e" ], "x": 2365, "y": 860, "wires": [] }, { "id": "dbea7ee9936e4747", "type": "mqtt in", "z": "b673e10beab091ff", "name": "MQTT Input", "topic": "#", "qos": "2", "datatype": "auto-detect", "broker": "a1235a09a8d34dea", "nl": false, "rap": true, "rh": 0, "inputs": 0, "x": 330, "y": 1040, "wires": [ [ "b10d3c44bca37652" ] ] }, { "id": "b10d3c44bca37652", "type": "function", "z": "b673e10beab091ff", "name": "Camera Config & Topic Parser", "func": "// Camera configuration - Add/remove cameras here\n// authMethod: 'url' for URL-based auth, 'reolink' for Reolink API login\nconst cameras = [\n {\n name: \"Doorbell Camera\",\n ip: \"10.20.30.30\",\n mqttTopic: \"frigate/doorbell/person\",\n username: \"admin\",\n password: \"sh1pb0x1\",\n authMethod: \"url\"\n },\n {\n name: \"Veranda Door Camera\",\n ip: \"10.20.30.33\",\n mqttTopic: \"frigate/veranda_door/person\",\n username: \"admin\",\n password: \"sh1pb0x1\",\n authMethod: \"url\"\n },\n {\n name: \"Basement Driveway Camera\",\n ip: \"10.20.30.34\",\n mqttTopic: \"frigate/basement_driveway/person\",\n username: \"admin\",\n password: \"sh1pb0x1\",\n authMethod: \"reolink\"\n }\n];\n\n// Find matching camera based on MQTT topic\nconst topic = msg.topic;\nconst camera = cameras.find(cam => topic === cam.mqttTopic);\n\n// Only process if it's a person detection topic for a known camera\nif (!camera) {\n return null; // Not a camera we care about\n}\n\n// Store camera config in message\nmsg.camera_name = camera.name;\nmsg.camera_ip = camera.ip;\nmsg.camera_username = camera.username;\nmsg.camera_password = camera.password;\nmsg.camera_location = camera.name;\nmsg.authMethod = camera.authMethod;\n\n// Add timestamp if not present\nif (!msg.timestamp) {\n msg.timestamp = Date.now();\n}\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 670, "y": 1040, "wires": [ [ "a1e7837147954108", "50b554a0642ab4e4" ] ] }, { "id": "a1e7837147954108", "type": "function", "z": "b673e10beab091ff", "name": "Check State Change", "func": "// Get current payload value\nvar currentValue = parseInt(msg.payload);\n\n// Use camera name as unique key for state tracking\nvar stateKey = 'previousState_' + msg.camera_name.replace(/\\s+/g, '_');\n\n// Get previous state from context (default to 0 if not set)\nvar previousValue = context.get(stateKey) || 0;\n\n// Store current value for next comparison\ncontext.set(stateKey, currentValue);\n\n// Only proceed if current value is 1 AND previous value was 0\nif (currentValue === 1 && previousValue === 0) {\n node.status({fill:\"blue\", shape:\"dot\", text:`${msg.camera_name}: Person detected!`});\n return msg;\n}\n\n// Don't send message for other cases\nreturn null;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 930, "y": 1040, "wires": [ [ "90f6a26b7b04cc23", "ec7ded527bfe8ef2" ] ] }, { "id": "90f6a26b7b04cc23", "type": "switch", "z": "b673e10beab091ff", "name": "Route by Auth Method", "property": "authMethod", "propertyType": "msg", "rules": [ { "t": "eq", "v": "url", "vt": "str" }, { "t": "eq", "v": "reolink", "vt": "str" } ], "checkall": "true", "repair": false, "outputs": 2, "x": 1180, "y": 1040, "wires": [ [ "d723df03bdda6ca5", "43983177055e72b1" ], [ "0339e277385e3213", "6cafa4c162199702" ] ] }, { "id": "d723df03bdda6ca5", "type": "function", "z": "b673e10beab091ff", "name": "URL Auth Snapshot", "func": "// Validate camera info\nif (!msg.camera_ip || !msg.camera_username || !msg.camera_password) {\n node.error(`Missing camera credentials for ${msg.camera_name || 'unknown'}`);\n node.status({fill:\"red\", shape:\"ring\", text:\"Missing credentials\"});\n return null;\n}\n\n// Generate random string for cache busting\nconst randomString = Math.random().toString(36).substring(7);\n\n// URL encode credentials to handle special characters safely\nconst encodedUser = encodeURIComponent(msg.camera_username);\nconst encodedPassword = encodeURIComponent(msg.camera_password);\n\n// Construct camera snapshot URL with credentials\nmsg.url = `http://${msg.camera_ip}/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=${randomString}&user=${encodedUser}&password=${encodedPassword}`;\nmsg.method = 'GET';\nmsg.headers = {};\nmsg.payload = null;\n\nnode.status({fill:\"blue\", shape:\"dot\", text:`Fetching ${msg.camera_name}...`});\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1450, "y": 960, "wires": [ [ "267ea942b61eb093", "7b685fbbf92cce4f" ] ] }, { "id": "0339e277385e3213", "type": "function", "z": "b673e10beab091ff", "name": "Reolink Login", "func": "// Prepare login request for Reolink API\nconst ip = msg.camera_ip;\nconst username = msg.camera_username;\nconst password = msg.camera_password;\n\n// Build login URL\nmsg.url = `http://${ip}/cgi-bin/api.cgi?cmd=Login&token=null`;\nmsg.method = 'POST';\nmsg.headers = { 'Content-Type': 'application/json' };\nmsg.payload = JSON.stringify([\n { cmd: 'Login', param: { User: { userName: username, password: password } } }\n]);\n\n// Generate random string for cache busting (for snapshot request)\nmsg.nextRandom = Math.random().toString(36).substring(7);\n\n// Preserve camera info\n// msg.camera_ip, msg.camera_name, msg.camera_location already set\n\nnode.status({fill:\"yellow\", shape:\"dot\", text:`Logging in to ${msg.camera_name}...`});\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1290, "y": 1160, "wires": [ [ "36ef8809abd6c068", "ad8ae18947a58945" ] ] }, { "id": "36ef8809abd6c068", "type": "http request", "z": "b673e10beab091ff", "name": "Send Login Request", "method": "use", "ret": "obj", "url": "", "tls": "", "persist": false, "proxy": "", "senderr": true, "x": 1450, "y": 1040, "wires": [ [ "e24c5bb10ec49f08" ] ] }, { "id": "e24c5bb10ec49f08", "type": "function", "z": "b673e10beab091ff", "name": "Fetch Snapshot", "func": "// Check for HTTP errors first\nif (msg.statusCode && msg.statusCode !== 200) {\n node.error(`HTTP ${msg.statusCode} - Login failed for ${msg.camera_name}`);\n node.status({fill:\"red\", shape:\"ring\", text:\"HTTP Error\"});\n return null;\n}\n\n// Extract token from login response\nif(!msg.payload || !msg.payload[0] || !msg.payload[0].value){\n node.error('Login failed for ' + msg.camera_name + ' - Invalid response');\n node.status({fill:\"red\", shape:\"ring\", text:\"Login failed\"});\n return null;\n}\n\nconst token = msg.payload[0].value.Token.name;\nif(!token){ \n node.error('Token missing for ' + msg.camera_name); \n node.status({fill:\"red\", shape:\"ring\", text:\"Token missing\"});\n return null; \n}\n\n// Build snapshot URL\nmsg.url = `http://${msg.camera_ip}/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=${msg.nextRandom}&token=${token}`;\nmsg.method = 'GET';\nmsg.headers = {};\nmsg.payload = null;\n\nnode.status({fill:\"blue\", shape:\"dot\", text:`Fetching snapshot from ${msg.camera_name}...`});\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1660, "y": 1040, "wires": [ [ "267ea942b61eb093" ] ] }, { "id": "267ea942b61eb093", "type": "http request", "z": "b673e10beab091ff", "name": "Get Camera Snapshot", "method": "use", "ret": "bin", "url": "", "tls": "", "persist": false, "proxy": "", "senderr": true, "x": 1910, "y": 1040, "wires": [ [ "c52d97f3e3de82d8" ] ] }, { "id": "b9939417e38d7ffa", "type": "function", "z": "b673e10beab091ff", "name": "Error Handler", "func": "// Handle HTTP errors\nconst cameraName = msg.camera_name || 'Unknown Camera';\nconst errorMsg = msg.error || msg.statusCode || msg.message || 'Unknown error';\n\n// Check if it's a timeout\nif (msg.error && (msg.error.message && msg.error.message.includes('timeout') || msg.error.code === 'ETIMEDOUT')) {\n node.error(`ā±ļø ${cameraName} request timed out`);\n node.status({fill:\"red\", shape:\"ring\", text:\"Timeout\"});\n} else {\n node.error(`āŒ ${cameraName} error: ${errorMsg}`);\n node.status({fill:\"red\", shape:\"ring\", text:\"Error\"});\n}\n\n// Pass error info to debug\nmsg.error_details = {\n camera: cameraName,\n error: errorMsg,\n statusCode: msg.statusCode,\n url: msg.url,\n timestamp: new Date().toISOString()\n};\n\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1700, "y": 1200, "wires": [ [ "df63eb3ba1bbfb73" ] ] }, { "id": "df63eb3ba1bbfb73", "type": "debug", "z": "b673e10beab091ff", "name": "Error Debug", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "error_details", "statusVal": "", "statusType": "auto", "x": 1910, "y": 1200, "wires": [] }, { "id": "c52d97f3e3de82d8", "type": "function", "z": "b673e10beab091ff", "name": "Send Alert to Telegram", "func": "// Validate that we received a proper image buffer\nif (!Buffer.isBuffer(msg.payload)) {\n node.warn(`āŒ ${msg.camera_name} snapshot fetch failed — not a binary image buffer`);\n node.status({fill:\"red\", shape:\"ring\", text:\"Snapshot failed\"});\n return null;\n}\n\n// Check if buffer has reasonable size (basic validation)\nif (msg.payload.length < 1000) {\n node.warn(`āŒ ${msg.camera_name} snapshot too small — likely corrupted`);\n node.status({fill:\"red\", shape:\"ring\", text:\"Image too small\"});\n return null;\n}\n\n// Format timestamp for display\nconst timestamp = new Date(msg.timestamp).toLocaleString();\n\n// Prepare Telegram message payload\nmsg.payload = {\n chatId: -4747176681, // Telegram group chat ID\n type: 'photo',\n content: msg.payload, // Binary image buffer\n caption: `šŸ”” ${msg.camera_name.toUpperCase()} ALERT! šŸ””\\n\\nšŸ“ Someone detected at ${msg.camera_location}\\nā° Time: ${timestamp}\\nšŸ“· Camera: ${msg.camera_name} (${msg.camera_ip})`\n};\n\nnode.status({fill:\"green\", shape:\"dot\", text:\"Alert sent!\"});\n\nreturn msg;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 2190, "y": 1040, "wires": [ [ "1ba4ee81e40e5c51", "8df5c69617ed9e92" ] ] }, { "id": "1ba4ee81e40e5c51", "type": "link out", "z": "b673e10beab091ff", "name": "link out 22", "mode": "link", "links": [ "41d29e978759e26e" ], "x": 2325, "y": 860, "wires": [] }, { "id": "8df5c69617ed9e92", "type": "debug", "z": "b673e10beab091ff", "name": "debug 12", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 2330, "y": 1120, "wires": [] }, { "id": "50b554a0642ab4e4", "type": "debug", "z": "b673e10beab091ff", "name": "debug 13", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 830, "y": 1160, "wires": [] }, { "id": "ad8ae18947a58945", "type": "debug", "z": "b673e10beab091ff", "name": "debug 17", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1430, "y": 1260, "wires": [] }, { "id": "9618c8df3ea2d338", "type": "inject", "z": "b673e10beab091ff", "name": "Test Veranda Door", "props": [ { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "frigate/veranda_door/person", "x": 210, "y": 1180, "wires": [ [ "498fac7ac1d2e87b" ] ] }, { "id": "43983177055e72b1", "type": "debug", "z": "b673e10beab091ff", "name": "debug 18", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1300, "y": 880, "wires": [] }, { "id": "7b685fbbf92cce4f", "type": "debug", "z": "b673e10beab091ff", "name": "debug 19", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1700, "y": 880, "wires": [] }, { "id": "6cafa4c162199702", "type": "debug", "z": "b673e10beab091ff", "name": "debug 20", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1100, "y": 1240, "wires": [] }, { "id": "ec7ded527bfe8ef2", "type": "debug", "z": "b673e10beab091ff", "name": "debug 30", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1080, "y": 960, "wires": [] }, { "id": "498fac7ac1d2e87b", "type": "function", "z": "b673e10beab091ff", "name": "function 9", "func": "// Send payload 0 first, then payload 1 after a short delay\n// This tests the state change detection (0 -> 1)\n\n// Get topic from incoming message (set in inject node)\nconst topic = msg.topic;\n\n// Send payload 0 immediately\nconst msg0 = {\n topic: topic,\n payload: 0,\n timestamp: Date.now()\n};\n\n// Send payload 1 after 500ms delay\nsetTimeout(() => {\n const msg1 = {\n topic: topic,\n payload: 1,\n timestamp: Date.now()\n };\n node.send(msg1);\n}, 500);\n\n// Return the first message (payload 0)\nreturn msg0;", "outputs": 1, "timeout": 0, "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 420, "y": 1180, "wires": [ [ "b10d3c44bca37652" ] ] }, { "id": "85ca22727431531a", "type": "inject", "z": "b673e10beab091ff", "name": "Test Veranda Door", "props": [ { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "frigate/basement_driveway/person", "x": 210, "y": 1220, "wires": [ [ "498fac7ac1d2e87b" ] ] }, { "id": "lr-ha-to-nvl", "type": "function", "z": "24e9a56732cfa6f1", "name": "HA to NVL", "func": "const ROOM_NAME = 'livingRoom';\nconst entityId = (msg.topic || '').toString();\nconst parts = entityId.split('_');\nconst last = parts[parts.length - 1] || '';\nconst num = parseInt(last, 10);\nconst lightNum = (!isNaN(num) && num >= 1) ? Math.min(6, num) : 1;\nconst isOn = (msg.payload === 'on' || msg.payload === true);\nif (!flow.get('nvlInState')) flow.set('nvlInState', { rooms: {}, boiler: {} });\nconst state = flow.get('nvlInState');\nif (!state.rooms[ROOM_NAME]) state.rooms[ROOM_NAME] = {};\nconst r = state.rooms[ROOM_NAME];\nr['ha_l' + lightNum + '_on'] = false;\nr['ha_l' + lightNum + '_off'] = false;\nif (isOn) r['ha_l' + lightNum + '_on'] = true;\nelse r['ha_l' + lightNum + '_off'] = true;\nflow.set('nvlInState', state);\nmsg.payload = { buildAndSend: true };\nreturn msg;", "outputs": 1, "x": 540, "y": 220, "wires": [ [ "lr-build-nvl", "59ce11298eda23b6" ] ] }, { "id": "lr-zigbee-to-nvl", "type": "function", "z": "24e9a56732cfa6f1", "name": "Zigbee to NVL", "func": "const ROOM_NAME = 'livingRoom';\nconst actionToSwitch = { single: 1, double: 2, hold: 3, release: 4, triple: 5, quad: 6 };\nconst payload = msg.payload || {};\nconst action = (payload.action || payload.click || '').toLowerCase();\nconst swIndex = actionToSwitch[action];\nif (swIndex == null) return null;\nif (!flow.get('nvlInState')) flow.set('nvlInState', { rooms: {}, boiler: {} });\nconst state = flow.get('nvlInState');\nif (!state.rooms[ROOM_NAME]) state.rooms[ROOM_NAME] = {};\nstate.rooms[ROOM_NAME]['zigbee_sw' + swIndex] = true;\nflow.set('nvlInState', state);\nmsg.payload = { buildAndSend: true };\nmsg.zigbeeClear = { room: ROOM_NAME, key: 'zigbee_sw' + swIndex };\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 540, "y": 320, "wires": [ [ "lr-build-nvl", "lr-delay" ] ] }, { "id": "lr-delay", "type": "delay", "z": "24e9a56732cfa6f1", "name": "80ms", "pauseType": "delay", "timeout": "80", "timeoutUnits": "milliseconds", "rate": "1", "nbRateUnits": "1", "rateUnits": "seconds", "randomFirst": "1", "randomLast": "5", "randomUnits": "seconds", "drop": true, "outputs": 1, "x": 760, "y": 320, "wires": [ [ "lr-clear-zigbee" ] ] }, { "id": "lr-clear-zigbee", "type": "function", "z": "24e9a56732cfa6f1", "name": "Clear zigbee edge", "func": "if (msg.zigbeeClear) {\n const state = flow.get('nvlInState') || { rooms: {}, boiler: {} };\n const r = state.rooms[msg.zigbeeClear.room];\n if (r) r[msg.zigbeeClear.key] = false;\n flow.set('nvlInState', state);\n}\nmsg.payload = { buildAndSend: true };\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 970, "y": 320, "wires": [ [ "lr-build-nvl" ] ] }, { "id": "lr-build-nvl", "type": "function", "z": "24e9a56732cfa6f1", "name": "Build NVL_In", "func": "const roomSize = 20;\nconst roomNames = ['masterBedroom','masterBathroom','bedroom_1','bedroom_2','bathroom','guestWc','kitchen','pantry','livingRoom','dinningRoom','entrance','hallway','outVeranda','outFront','outBack','outSide'];\nconst state = flow.get('nvlInState') || { rooms: {}, boiler: {} };\nconst rooms = state.rooms || {};\nconst boiler = state.boiler || {};\nconst buf = Buffer.alloc(328);\nfor (let r = 0; r < 16; r++) {\n const c = rooms[roomNames[r]] || {};\n const base = r * roomSize;\n buf[base+0]=c.ha_l1_on?1:0;buf[base+1]=c.ha_l1_off?1:0;buf[base+2]=c.ha_l2_on?1:0;buf[base+3]=c.ha_l2_off?1:0;buf[base+4]=c.ha_l3_on?1:0;buf[base+5]=c.ha_l3_off?1:0;buf[base+6]=c.ha_l4_on?1:0;buf[base+7]=c.ha_l4_off?1:0;buf[base+8]=c.ha_l5_on?1:0;buf[base+9]=c.ha_l5_off?1:0;buf[base+10]=c.ha_l6_on?1:0;buf[base+11]=c.ha_l6_off?1:0;\n for (let i = 0; i < 6; i++) buf[base+12+i] = c['zigbee_sw'+(i+1)] ? 1 : 0;\n buf[base+18]=c.ha_all_on?1:0;buf[base+19]=c.ha_all_off?1:0;\n}\nconst bo = 320;\nbuf[bo+0]=boiler.ha_on?1:0;buf[bo+1]=boiler.ha_off?1:0;buf[bo+2]=boiler.schedule_on?1:0;buf[bo+3]=boiler.schedule_off?1:0;buf[bo+4]=boiler.emergency_stop?1:0;buf.writeInt16LE(boiler.max_on_time_minutes??480,bo+6);\nmsg.payload = buf;\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 790, "y": 260, "wires": [ [ "9d20e54acf4079aa" ] ] }, { "id": "59ce11298eda23b6", "type": "debug", "z": "24e9a56732cfa6f1", "name": "debug 33", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 730, "y": 200, "wires": [] }, { "id": "9d20e54acf4079aa", "type": "debug", "z": "24e9a56732cfa6f1", "name": "debug 35", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 950, "y": 200, "wires": [] }, { "id": "5925b9fedc7dc1e1", "type": "debug", "z": "24e9a56732cfa6f1", "name": "debug 38", "active": true, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 750, "y": 560, "wires": [] }, { "id": "ed2071aadf923b50", "type": "inject", "z": "24e9a56732cfa6f1", "name": "", "props": [ { "p": "payload" }, { "p": "topic", "vt": "str" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "", "payloadType": "date", "x": 140, "y": 520, "wires": [ [] ] } ]