Это старая версия документа!
Этот небольшой поток услужливо включает свет, когда ты приходишь домой, а там достаточно темно и выключает, когда уходишь. Удобно, стильно, современно.
Поток-то небольшой, а вот железок для реализации необходимо много:
Помимо этого нужен, понятно, Node-RED, а еще Zigbee2MQTT и MQTT-брокер! От так.
В этой цепочке используются следующие узлы, которых нет в стандартной поставке:
Этот подпоток входит в состав кода ниже и загружать отдельно его не надо!
Узлы «mqtt in»2) подключаются к брокеру и подписываются на соответствующие темы. При получении сообщений, сохраняют их в потоковый контекст. Все датчики подключены к сторожевому таймеру, который срабатывает при отсутствии диагностических сообщений в течение 60-и минут.
Основная цепочка запускается при срабатывании датчика присутствия, расположенного между дверьми в предбаннике, при этом учитывается освещенность в коридоре и направление прохода – домой или из дома. При выходе, если освещение было выключено, оно не включается, а при входе, включается только, если в коридоре недостаточная освещенность3). Освещение выключается с настраиваемой задержкой.
[ { "id": "38c9a069.18cd6", "type": "subflow", "name": "sendmail", "info": "Отправляет почту по настроенным реквизитам.", "category": "", "in": [ { "x": 60, "y": 60, "wires": [ { "id": "be1032f6.e2b02" } ] } ], "out": [], "env": [], "color": "#C7E9C0", "icon": "node-red/envelope.svg" }, { "id": "be1032f6.e2b02", "type": "e-mail", "z": "38c9a069.18cd6", "server": "smtp.beget.com", "port": "465", "secure": true, "tls": true, "name": "nikolay@soloshin.su", "dname": "Отправка сообщения", "x": 240, "y": 60, "wires": [] }, { "id": "98ba2d02.5ee68", "type": "subflow", "name": "watchdog", "info": "Ожидает поступление сообщений в установленный интервал, если сообщения нет, генерирует письмо с предупреждением.\n\nПринимает **msg.topic** в качестве ID датчика и **msg.payload** в качестве названия, которые будут указаны в теле письма.", "category": "", "in": [ { "x": 80, "y": 40, "wires": [ { "id": "fee5d855.a15048" } ] } ], "out": [], "env": [ { "name": "msgnote35634", "type": "str", "value": "", "ui": { "label": { "en-US": "Укажите задержку срабатывания таймера в миллисекундах." }, "type": "none" } }, { "name": "msgdelay", "type": "num", "value": "3600000", "ui": { "icon": "font-awesome/fa-clock-o", "label": { "en-US": "Задержка (мс)" }, "type": "input", "opts": { "types": [ "num" ] } } } ], "color": "#FFAAAA", "icon": "font-awesome/fa-clock-o" }, { "id": "7cada431.44b94c", "type": "trigger", "z": "98ba2d02.5ee68", "name": "Таймер", "op1": "", "op2": "", "op1type": "pay", "op2type": "date", "duration": "10", "extend": true, "overrideDelay": true, "units": "s", "reset": "", "bytopic": "topic", "topic": "topic", "outputs": 2, "x": 540, "y": 40, "wires": [ [ "536fe262.24fb2c" ], [ "27141a53.5a2246" ] ], "outputLabels": [ "Первое", "Ошибка" ] }, { "id": "3cfc87ed.72e3d8", "type": "subflow:38c9a069.18cd6", "z": "98ba2d02.5ee68", "name": "Отправка почты", "env": [], "x": 710, "y": 580, "wires": [] }, { "id": "ca1cc7d1.c86308", "type": "change", "z": "98ba2d02.5ee68", "name": "Установка текстовых полей письма", "rules": [ { "t": "move", "p": "firstline", "pt": "msg", "to": "payload", "tot": "msg" }, { "t": "set", "p": "topic", "pt": "msg", "to": "\"Изменился статус датчика (\" & $now('[H01]:[m01]:[s01] [D01].[M01].[Y0001]', '+1000') & \")\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 210, "y": 580, "wires": [ [ "3cfc87ed.72e3d8" ] ] }, { "id": "fee5d855.a15048", "type": "change", "z": "98ba2d02.5ee68", "name": "Установка задержки таймера", "rules": [ { "t": "set", "p": "delay", "pt": "msg", "to": "msgdelay", "tot": "env" }, { "t": "set", "p": "savedtopic", "pt": "msg", "to": "topic", "tot": "msg" }, { "t": "set", "p": "savedpayload", "pt": "msg", "to": "payload", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 290, "y": 40, "wires": [ [ "7cada431.44b94c" ] ] }, { "id": "6fcd49c4.ba53c8", "type": "comment", "z": "98ba2d02.5ee68", "name": "SQL запросы", "info": "Создание таблицы:\nCREATE TABLE watchdog (topic TEXT PRIMARY KEY, name TEXT, sent INTEGER DEFAULT 0)", "x": 730, "y": 40, "wires": [] }, { "id": "536fe262.24fb2c", "type": "change", "z": "98ba2d02.5ee68", "name": "Подготовка запроса", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "\"SELECT * FROM watchdog WHERE topic = \\\"\" & savedtopic & \"\\\"\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 160, "y": 100, "wires": [ [ "25c0b13d.61990e" ] ] }, { "id": "25c0b13d.61990e", "type": "sqlite", "z": "98ba2d02.5ee68", "mydb": "abf4792e.cd5078", "sqlquery": "msg.topic", "sql": "", "name": "Запрос на наличие записи в БД", "x": 200, "y": 160, "wires": [ [ "43ffca62.b3b554" ] ] }, { "id": "43ffca62.b3b554", "type": "switch", "z": "98ba2d02.5ee68", "name": "Маршрутизация", "property": "payload", "propertyType": "msg", "rules": [ { "t": "nempty" }, { "t": "else" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 650, "y": 160, "wires": [ [ "2557a088.c4251" ], [ "90a4953e.e690a8" ] ] }, { "id": "90a4953e.e690a8", "type": "change", "z": "98ba2d02.5ee68", "name": "Подготовка запроса", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "\"INSERT INTO watchdog (topic, name) VALUES (\\\"\" & savedtopic & \"\\\", \\\"\" & savedpayload & \"\\\")\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 160, "y": 220, "wires": [ [ "235c7484.7cd52c" ] ] }, { "id": "235c7484.7cd52c", "type": "sqlite", "z": "98ba2d02.5ee68", "mydb": "abf4792e.cd5078", "sqlquery": "msg.topic", "sql": "", "name": "Добавление отсутствующей записи", "x": 210, "y": 280, "wires": [ [ "2557a088.c4251" ] ] }, { "id": "2557a088.c4251", "type": "change", "z": "98ba2d02.5ee68", "name": "Подготовка запроса", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "\"SELECT * FROM watchdog WHERE topic = \\\"\" & savedtopic & \"\\\" AND sent = false\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 540, "y": 280, "wires": [ [ "b903c102.384fe" ] ] }, { "id": "b903c102.384fe", "type": "sqlite", "z": "98ba2d02.5ee68", "mydb": "abf4792e.cd5078", "sqlquery": "msg.topic", "sql": "", "name": "Выборка записей, которые не отправлялись", "x": 240, "y": 340, "wires": [ [ "2d7a7c9c.c9c0a4" ] ] }, { "id": "2d7a7c9c.c9c0a4", "type": "switch", "z": "98ba2d02.5ee68", "name": "Отсечка пустых сообщений", "property": "payload", "propertyType": "msg", "rules": [ { "t": "nempty" } ], "checkall": "false", "repair": false, "outputs": 1, "x": 180, "y": 400, "wires": [ [ "29c18b99.2c4044" ] ] }, { "id": "27141a53.5a2246", "type": "change", "z": "98ba2d02.5ee68", "name": "Настройка текста письма (false)", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "false", "tot": "bool" }, { "t": "set", "p": "firstline", "pt": "msg", "to": "\"Датчик \\\"\" & savedpayload & \"\\\" не передает показания уже \" & $ceil(delay/1000/60) & \" мин!\\n\\nИдентификатор устройства \\\"\" & savedtopic & \"\\\".\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 660, "y": 100, "wires": [ [ "b13655cc.bdf9d8" ] ] }, { "id": "b13655cc.bdf9d8", "type": "change", "z": "98ba2d02.5ee68", "name": "Подготовка запроса", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "\"UPDATE watchdog SET sent = \" & topic & \" WHERE topic = \\\"\" & savedtopic & \"\\\"\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 700, "y": 460, "wires": [ [ "b4d28c09.f2007" ] ] }, { "id": "b4d28c09.f2007", "type": "sqlite", "z": "98ba2d02.5ee68", "mydb": "abf4792e.cd5078", "sqlquery": "msg.topic", "sql": "", "name": "Установка флага отправки", "x": 180, "y": 520, "wires": [ [ "ca1cc7d1.c86308" ] ] }, { "id": "29c18b99.2c4044", "type": "change", "z": "98ba2d02.5ee68", "name": "Настройка текста письма (true)", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "true", "tot": "bool" }, { "t": "set", "p": "firstline", "pt": "msg", "to": "\"Датчик \\\"\" & savedpayload & \"\\\" передал показания! Интервал проверки \" & $ceil(delay/1000/60) & \" мин.\\n\\nИдентификатор устройства \\\"\" & savedtopic & \"\\\".\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 190, "y": 460, "wires": [ [ "b13655cc.bdf9d8" ] ] }, { "id": "abf4792e.cd5078", "type": "sqlitedb", "z": "98ba2d02.5ee68", "db": "c:\\noderedDB\\watchdog.db", "mode": "RWC" }, { "id": "e0364aba.751a08", "type": "tab", "label": "Управление освещением", "disabled": false, "info": "" }, { "id": "2baeac32.ea77b4", "type": "subflow:98ba2d02.5ee68", "z": "e0364aba.751a08", "name": "Сторожевой таймер", "env": [], "x": 700, "y": 280, "wires": [] }, { "id": "23568c39.ad9054", "type": "mqtt in", "z": "e0364aba.751a08", "name": "Датчик движения между дверьми", "topic": "zigbee2mqtt/0x00124b0023acf684", "qos": "2", "datatype": "json", "broker": "8745b931.133868", "x": 200, "y": 220, "wires": [ [ "17adca3f.942eb6", "232f3b69.b9e994" ] ] }, { "id": "17adca3f.942eb6", "type": "change", "z": "e0364aba.751a08", "name": "Установка названий датчиков", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "topic", "tot": "msg" }, { "t": "change", "p": "payload", "pt": "msg", "from": "zigbee2mqtt/0x00124b0023acf684", "fromt": "str", "to": "Датчик движения между дверьми", "tot": "str" }, { "t": "change", "p": "payload", "pt": "msg", "from": "zigbee2mqtt/0x54ef4410000c1819", "fromt": "str", "to": "Датчик освещенности в коридоре", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 670, "y": 220, "wires": [ [ "2baeac32.ea77b4" ] ] }, { "id": "bef06898.a69968", "type": "link in", "z": "e0364aba.751a08", "name": "Датчик открытия входной двери", "links": [ "677e2f02.bc1e3" ], "x": 190, "y": 340, "wires": [ [ "2d2c4e3f.0a3f22" ] ], "l": true }, { "id": "a503e788.260478", "type": "change", "z": "e0364aba.751a08", "name": "Сохранение статуса", "rules": [ { "t": "set", "p": "status.occupancy", "pt": "flow", "to": "payload.occupancy", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 400, "y": 280, "wires": [ [ "a2236fb3.2b9a1" ] ] }, { "id": "95e6238a.3cb9b", "type": "mqtt out", "z": "e0364aba.751a08", "name": "Передача команды", "topic": "corridorlighting_0F7B7C/cmnd/POWER1", "qos": "", "retain": "", "broker": "8745b931.133868", "x": 700, "y": 520, "wires": [], "info": "Необходимая команда устанавливается в узле \"Сохранение статуса\"." }, { "id": "e6f3432e.e12d5", "type": "change", "z": "e0364aba.751a08", "name": "Включение", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "true", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 390, "y": 460, "wires": [ [ "95e6238a.3cb9b" ] ] }, { "id": "b9e40431.e91b78", "type": "mqtt in", "z": "e0364aba.751a08", "name": "Статус освещения в коридоре", "topic": "corridorlighting_0F7B7C/stat/POWER1", "qos": "2", "datatype": "utf8", "broker": "8745b931.133868", "x": 190, "y": 100, "wires": [ [ "84601baf.bce798" ] ] }, { "id": "84601baf.bce798", "type": "change", "z": "e0364aba.751a08", "name": "Сохранение статуса", "rules": [ { "t": "set", "p": "status.power", "pt": "flow", "to": "payload = \"ON\" ? true : false", "tot": "jsonata" }, { "t": "set", "p": "reset", "pt": "msg", "to": "true", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 480, "y": 100, "wires": [ [ "f9dc1c77.7e32c" ] ] }, { "id": "2d2c4e3f.0a3f22", "type": "change", "z": "e0364aba.751a08", "name": "Сохранение статуса", "rules": [ { "t": "set", "p": "status.contact", "pt": "flow", "to": "payload.contact", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 480, "y": 340, "wires": [ [] ] }, { "id": "f9dc1c77.7e32c", "type": "switch", "z": "e0364aba.751a08", "name": "Сброс триггера", "property": "status.power", "propertyType": "flow", "rules": [ { "t": "false" }, { "t": "true" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 720, "y": 100, "wires": [ [ "4dfc4c0c.c25944" ], [ "71a8b946.591148" ] ], "outputLabels": [ "Освещение выключилось", "Освещение включилось" ] }, { "id": "232f3b69.b9e994", "type": "switch", "z": "e0364aba.751a08", "name": "Отсечка диагностики", "property": "payload.occupancy", "propertyType": "msg", "rules": [ { "t": "neq", "v": "status.occupancy", "vt": "flow" } ], "checkall": "false", "repair": false, "outputs": 1, "x": 160, "y": 280, "wires": [ [ "a503e788.260478" ] ] }, { "id": "f32f3687.ceadf8", "type": "switch", "z": "e0364aba.751a08", "name": "Маршрутизация", "property": "payload", "propertyType": "msg", "rules": [ { "t": "jsonata_exp", "v": "$flowContext(\"status.power\") = true and $flowContext(\"status.contact\") = false", "vt": "jsonata" }, { "t": "jsonata_exp", "v": "$flowContext(\"status.power\") = false and $flowContext(\"status.occupancy\") = true and $flowContext(\"status.contact\") = true and $flowContext(\"status.illuminance\") <= ($type($flowContext(\"settings.illuminance.min\")) = 'number' ? $flowContext(\"settings.illuminance.min\") : $flowContext(\"status.illuminance\"))", "vt": "jsonata" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 210, "y": 400, "wires": [ [ "486c4396.05f45c" ], [ "c7d8380f.2bc108" ] ], "outputLabels": [ "Можно выключать освещение", "Нужно включить освещение" ] }, { "id": "486c4396.05f45c", "type": "switch", "z": "e0364aba.751a08", "name": "Условия для выключения", "property": "payload", "propertyType": "msg", "rules": [ { "t": "jsonata_exp", "v": "$flowContext(\"status.occupancy\") = false and $flowContext(\"status.contact\") = true", "vt": "jsonata" }, { "t": "jsonata_exp", "v": "$flowContext(\"status.occupancy\") = true", "vt": "jsonata" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 480, "y": 400, "wires": [ [ "e5b34c28.b4ffd" ], [ "b1ebb537.74c5c8" ] ], "outputLabels": [ "Условия соблюдены", "Условия не соблюдены" ], "info": "Цикл автоматически сбрасывается, когда датчик движения восстанавливается, в текущей модели, это 60 секунд." }, { "id": "b1ebb537.74c5c8", "type": "trigger", "z": "e0364aba.751a08", "name": "Цикл, 10 сек.", "op1": "", "op2": "", "op1type": "nul", "op2type": "pay", "duration": "10", "extend": true, "overrideDelay": false, "units": "s", "reset": "", "bytopic": "all", "topic": "topic", "outputs": 1, "x": 640, "y": 460, "wires": [ [ "486c4396.05f45c" ] ], "info": "\"msg.reset\" устанавливается в узле \"Сохранение статуса\"." }, { "id": "e5b34c28.b4ffd", "type": "change", "z": "e0364aba.751a08", "name": "Выключение", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "false", "tot": "bool" }, { "t": "set", "p": "delay", "pt": "msg", "to": "( $flowContext(\"settings.delay\") - 1 ) * 60000", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 730, "y": 400, "wires": [ [ "24d18ed.11a2f72" ] ] }, { "id": "8c2c31bf.9ecb5", "type": "mqtt in", "z": "e0364aba.751a08", "name": "Освещенность в коридоре", "topic": "zigbee2mqtt/0x54ef4410000c1819", "qos": "2", "datatype": "json", "broker": "8745b931.133868", "x": 180, "y": 160, "wires": [ [ "fe98e862.2a4968" ] ] }, { "id": "fe98e862.2a4968", "type": "change", "z": "e0364aba.751a08", "name": "Сохранение освещенности", "rules": [ { "t": "set", "p": "status.illuminance", "pt": "flow", "to": "payload.illuminance_lux", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 460, "y": 160, "wires": [ [ "17adca3f.942eb6" ] ] }, { "id": "6fac3528.c9031c", "type": "inject", "z": "e0364aba.751a08", "name": "Инициализация потока", "props": [], "repeat": "", "crontab": "", "once": true, "onceDelay": "0.5", "topic": "", "payloadType": "str", "x": 170, "y": 40, "wires": [ [ "16a86705.16d229" ] ] }, { "id": "16a86705.16d229", "type": "change", "z": "e0364aba.751a08", "name": "Ввод настроек", "rules": [ { "t": "set", "p": "settings.illuminance.min", "pt": "flow", "to": "6", "tot": "num" }, { "t": "set", "p": "settings.delay", "pt": "flow", "to": "5", "tot": "num" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 720, "y": 40, "wires": [ [] ], "info": "Описание настроек:\n\n - **settings.illuminance.min** -- минимальная освещенность для включения освещения;\n - **settings.delay** -- задержка выключения света в минутах." }, { "id": "c7d8380f.2bc108", "type": "switch", "z": "e0364aba.751a08", "name": "Условия для включения", "property": "payload", "propertyType": "msg", "rules": [ { "t": "jsonata_exp", "v": "$flowContext(\"status.occupancy\") = true and $flowContext(\"status.contact\") = false", "vt": "jsonata" }, { "t": "jsonata_exp", "v": "$flowContext(\"status.occupancy\") = true and $flowContext(\"status.contact\") = true", "vt": "jsonata" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 170, "y": 460, "wires": [ [ "e6f3432e.e12d5" ], [ "7b6b6c70.fe2254" ] ], "outputLabels": [ "Условия соблюдены", "Условия не соблюдены" ], "info": "Цикл автоматически сбрасывается, когда датчик движения восстанавливается, в текущей модели, это 60 секунд." }, { "id": "7b6b6c70.fe2254", "type": "trigger", "z": "e0364aba.751a08", "name": "Цикл, 0,5 сек.", "op1": "", "op2": "", "op1type": "nul", "op2type": "pay", "duration": "500", "extend": true, "overrideDelay": false, "units": "ms", "reset": "", "bytopic": "all", "topic": "topic", "outputs": 1, "x": 240, "y": 520, "wires": [ [ "c7d8380f.2bc108" ] ], "info": "\"msg.reset\" устанавливается в узле \"Сохранение статуса\"." }, { "id": "a2236fb3.2b9a1", "type": "link out", "z": "e0364aba.751a08", "name": "", "links": [ "2e4850fe.13963" ], "x": 555, "y": 280, "wires": [] }, { "id": "2e4850fe.13963", "type": "link in", "z": "e0364aba.751a08", "name": "", "links": [ "a2236fb3.2b9a1" ], "x": 75, "y": 400, "wires": [ [ "f32f3687.ceadf8" ] ] }, { "id": "dd171ff0.71df", "type": "trigger", "z": "e0364aba.751a08", "name": "Задержка", "op1": "", "op2": "", "op1type": "nul", "op2type": "pay", "duration": "1", "extend": true, "overrideDelay": true, "units": "min", "reset": "", "bytopic": "all", "topic": "topic", "outputs": 1, "x": 480, "y": 520, "wires": [ [ "95e6238a.3cb9b" ] ] }, { "id": "9eb1c1f9.94ab", "type": "link in", "z": "e0364aba.751a08", "name": "", "links": [ "4dfc4c0c.c25944", "71a8b946.591148", "24d18ed.11a2f72" ], "x": 375, "y": 520, "wires": [ [ "dd171ff0.71df" ] ] }, { "id": "4dfc4c0c.c25944", "type": "link out", "z": "e0364aba.751a08", "name": "", "links": [ "9eb1c1f9.94ab", "a56146c.fba80b8" ], "x": 675, "y": 160, "wires": [] }, { "id": "71a8b946.591148", "type": "link out", "z": "e0364aba.751a08", "name": "", "links": [ "9eb1c1f9.94ab", "de30c54b.be7a68" ], "x": 775, "y": 160, "wires": [] }, { "id": "a56146c.fba80b8", "type": "link in", "z": "e0364aba.751a08", "name": "", "links": [ "4dfc4c0c.c25944" ], "x": 515, "y": 460, "wires": [ [ "b1ebb537.74c5c8" ] ] }, { "id": "de30c54b.be7a68", "type": "link in", "z": "e0364aba.751a08", "name": "", "links": [ "71a8b946.591148" ], "x": 75, "y": 520, "wires": [ [ "7b6b6c70.fe2254" ] ] }, { "id": "24d18ed.11a2f72", "type": "link out", "z": "e0364aba.751a08", "name": "", "links": [ "9eb1c1f9.94ab" ], "x": 775, "y": 460, "wires": [] }, { "id": "8745b931.133868", "type": "mqtt-broker", "name": "localhost", "broker": "localhost", "port": "1883", "clientid": "", "usetls": false, "compatmode": false, "keepalive": "60", "cleansession": true, "birthTopic": "", "birthQos": "0", "birthPayload": "", "closeTopic": "", "closeQos": "0", "closePayload": "", "willTopic": "", "willQos": "0", "willPayload": "" } ]
Обсуждение