Пришла весна, потом пришло лето… и все это подряд, да еще и в один и тот же город Владивосток! Было бы смешно, если не сезонная влажность, которая в этот период на улице может неделями держаться на уровне 100%, а в квартире… Ну, вот сейчас, 67%!
В ванной комнате, как это не печально, тоже… А там установлен Sonoff TH10, работающий под Tasmota в автоматическом режиме – влажность поднялась, он включился, влажность упала – выключился. Удобно, все привыкли, а тут – ну не выключается1), хоть ты тресни!
Сперва вручную поправил пороги в соответствующем правиле, потом почесал, где обычно чешут, и родил этот поток.
В этой цепочке используются следующие узлы, которых нет в стандартной поставке:
Этот подпоток входит в состав кода ниже и загружать отдельно его не надо!
Цепочка запускается по таймеру – сейчас установлено 15 минут, но после тестирования планирую увеличить промежуток до 6-12 часов. Данные получаются и передаются по MQTT.
Сперва проверяется, включена или выключена вентиляция, т.к. в первом случае ни о какой корректировке порогов влажности не может идти речи. Если включена, ничего не делается, кроме отправки письма с предупреждением. Если выключена, вводятся настройки и сравнивается уровень текущей влажности с предыдущим, если он не выходит за рамки установленной погрешности, опять же, ничего, кроме письма не делается. Если влажность изменилась больше порога погрешности, проверяется уровень порога включения вентиляции на предмет превышения максимального значения в 100% – если при грядущем изменении порогов он может быть превышен, отправляется соответствующее письмо с предупреждением, если нет, т.е. все нормально и легендарных 146% случайно не выйдет, то подготавливается MQTT-сообщение с новыми порогами и отправляется. Дополнительно, как обычно, отправляется письмо.
После полной отладки, можно отключить узел «link out», чтобы было меньше писем, или вовсе подпоток «sendmail», чтобы писем не было вообще.
Профит.
Если в web-интерфес модуля добавить дополнительную кнопку для ручной коррекции, то для ее работы понадобится такая логика:
Узел «mqtt in» подписывается на соответствующий топик и при смене его статуса включает описанный выше поток минуя таймер.
Помимо добавления новых узлов, нужно изменить настройки следующих узлов:
ventilation_000457/stat/POWER1
;"ON SI7021#Humidity>=" & threshold.on & " DO Power1 on ENDON ON SI7021#Humidity<=" & threshold.off & " DO Power1 off ENDON"
.Измененные узлы входят в код, указанный ниже в соответствующем разделе!
Аналогичные изменения нужно внести в код конфигурации аксессуаров Homebridge!
Важное дополнение ко всему вышеуказанному – для правильной работы корректировок в большую сторону2) необходимо заменить узлы «Статус вентиляции» и «Сохранение статуса» этим кодом.
Эта цепочка, помимо своего исконного предназначения, запускает таймер, по истечению которого, если вентиляция не выключится автоматически, запустится принудительная коррекция.
[ { "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": "d1e5566a.2c1c08", "type": "tab", "label": "Коррекция влажности", "disabled": false, "info": "Корректирует пороги включения и выключения вентиляции периодически измеряя текущую влажность в ванной комнате." }, { "id": "44f5cbc9.ce1e74", "type": "mqtt in", "z": "d1e5566a.2c1c08", "name": "Телеметрия вентиляции", "topic": "ventilation_000457/tele/SENSOR", "qos": "2", "datatype": "json", "broker": "8745b931.133868", "x": 170, "y": 160, "wires": [ [ "ad93fb8a.450a08" ] ] }, { "id": "ad93fb8a.450a08", "type": "switch", "z": "d1e5566a.2c1c08", "name": "Фильтр запуска", "property": "status.start", "propertyType": "flow", "rules": [ { "t": "eq", "v": "YES", "vt": "str" } ], "checkall": "false", "repair": false, "outputs": 1, "x": 140, "y": 220, "wires": [ [ "719cb63c.ea11d8" ] ] }, { "id": "aab004d1.b3b2a8", "type": "inject", "z": "d1e5566a.2c1c08", "name": "Периодический запуск", "props": [ { "p": "payload" } ], "repeat": "900", "crontab": "", "once": true, "onceDelay": "0", "topic": "", "payload": "YES", "payloadType": "str", "x": 170, "y": 40, "wires": [ [ "c7164be0.cce398" ] ] }, { "id": "437d65a8.782aac", "type": "change", "z": "d1e5566a.2c1c08", "name": "Сохранение метки", "rules": [ { "t": "move", "p": "payload", "pt": "msg", "to": "status.start", "tot": "flow" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 710, "y": 100, "wires": [ [] ] }, { "id": "c67e2442.ddbd18", "type": "mqtt out", "z": "d1e5566a.2c1c08", "name": "Установка нового правила", "topic": "ventilation_000457/cmnd/rule1", "qos": "0", "retain": "false", "broker": "8745b931.133868", "x": 680, "y": 340, "wires": [] }, { "id": "719cb63c.ea11d8", "type": "change", "z": "d1e5566a.2c1c08", "name": "Ввод настроек и подготовка", "rules": [ { "t": "set", "p": "settings.shift", "pt": "flow", "to": "2", "tot": "num" }, { "t": "set", "p": "settings.gap", "pt": "flow", "to": "10", "tot": "num" }, { "t": "set", "p": "settings.inaccuracy", "pt": "flow", "to": "2", "tot": "num" }, { "t": "set", "p": "humidity.current", "pt": "flow", "to": "$ceil(payload.SI7021.Humidity)", "tot": "jsonata" }, { "t": "set", "p": "threshold", "pt": "msg", "to": "\"{ \\\"on\\\": \\\"\" & ($flowContext(\"humidity.current\")+$flowContext(\"settings.shift\")+$flowContext(\"settings.gap\")) & \"\\\", \\\"off\\\": \\\"\" & ($flowContext(\"humidity.current\")+$flowContext(\"settings.shift\")) & \"\\\"}\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 440, "y": 220, "wires": [ [ "4886a5d2.c29a5c" ] ], "info": "Свойство **shift** отвечает за положительный (2) или отрицательный (-1) сдвиг, относительно измеренной влажности. Свойство **gap** - промежуток между порогами. Свойство **inaccuracy** - погрешность (2)." }, { "id": "fca1d16.e7d153", "type": "subflow:38c9a069.18cd6", "z": "d1e5566a.2c1c08", "name": "Отправка писем", "env": [], "x": 710, "y": 520, "wires": [] }, { "id": "5b177dfc.05bd54", "type": "template", "z": "d1e5566a.2c1c08", "name": "Шаблон тела письма", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "Новый порог включеня и выключения: {{{threshold.on}}}/{{{threshold.off}}}%, т.к. текущая влажность составляет {{{flow.humidity.current}}}% (установленный сдвиг и промежуток - {{{flow.settings.shift}}}/{{{flow.settings.gap}}}%, погрешность ±{{{flow.settings.inaccuracy}}}%).\n\nОтпрвленное правило: \"{{{payload}}}\"", "output": "str", "x": 700, "y": 460, "wires": [ [ "f5422743.499978" ] ] }, { "id": "f5422743.499978", "type": "change", "z": "d1e5566a.2c1c08", "name": "Установка темы и времени", "rules": [ { "t": "set", "p": "topic", "pt": "msg", "to": "\"Коррекция порогов вентиляции (\" & $now('[H01]:[m01]:[s01] [D01].[M01].[Y0001]', '+1000') & \")\"", "tot": "jsonata" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 340, "y": 520, "wires": [ [ "fca1d16.e7d153" ] ] }, { "id": "e10baa27.f6d9a8", "type": "change", "z": "d1e5566a.2c1c08", "name": "Подготовка правила и сброс метки", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "\"ON SI7021#Humidity>=\" & threshold.on & \" DO power on ENDON ON SI7021#Humidity<=\" & threshold.off & \" DO power off ENDON\"", "tot": "jsonata" }, { "t": "set", "p": "status.start", "pt": "flow", "to": "NO", "tot": "str" }, { "t": "set", "p": "humidity.previous", "pt": "flow", "to": "humidity.current", "tot": "flow" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 650, "y": 400, "wires": [ [ "c67e2442.ddbd18", "5b177dfc.05bd54" ] ], "info": "Свойство flow.humshift отвечает за положительный (2) или отрицательный (-1) сдвиг, относительно измеренной влажности." }, { "id": "2ba1e0a7.ddf7", "type": "json", "z": "d1e5566a.2c1c08", "name": "Преобразование в объект", "property": "threshold", "action": "obj", "pretty": false, "x": 180, "y": 340, "wires": [ [ "b6098692.504858" ] ] }, { "id": "3093988.3fd9168", "type": "inject", "z": "d1e5566a.2c1c08", "name": "Задать влажность вручную", "props": [ { "p": "payload" } ], "repeat": "", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "payload": "{\"SI7021\":{\"Humidity\":24}}", "payloadType": "json", "x": 180, "y": 100, "wires": [ [ "719cb63c.ea11d8" ] ], "info": "Установите текущую влажность." }, { "id": "cab7bd9.198da4", "type": "mqtt in", "z": "d1e5566a.2c1c08", "name": "Статус вентиляции", "topic": "ventilation_000457/stat/POWER", "qos": "2", "datatype": "utf8", "broker": "8745b931.133868", "x": 450, "y": 40, "wires": [ [ "dd9d91a4.08a5a" ] ] }, { "id": "c7164be0.cce398", "type": "switch", "z": "d1e5566a.2c1c08", "name": "Фильтр статуса", "property": "status.power", "propertyType": "flow", "rules": [ { "t": "eq", "v": "OFF", "vt": "str" }, { "t": "null" }, { "t": "else" } ], "checkall": "false", "repair": false, "outputs": 3, "x": 440, "y": 100, "wires": [ [ "437d65a8.782aac" ], [ "dca29af2.bff068" ], [ "b12445af.833948" ] ], "outputLabels": [ "Выключена", "Ошибка", "Включена" ] }, { "id": "dd9d91a4.08a5a", "type": "change", "z": "d1e5566a.2c1c08", "name": "Сохранение статуса", "rules": [ { "t": "move", "p": "payload", "pt": "msg", "to": "status.power", "tot": "flow" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 700, "y": 40, "wires": [ [] ] }, { "id": "b12445af.833948", "type": "template", "z": "d1e5566a.2c1c08", "name": "Шаблон тела письма", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "Корректировка порогов влажности не выполнена, т.к. вентиляция была включена!", "output": "str", "x": 460, "y": 160, "wires": [ [ "6d2686f5.04aa08" ] ] }, { "id": "b6098692.504858", "type": "switch", "z": "d1e5566a.2c1c08", "name": "Ограничение верхнего порога", "property": "humidity.current", "propertyType": "flow", "rules": [ { "t": "lt", "v": "100-$flowContext(\"settings.shift\")-$flowContext(\"settings.gap\")", "vt": "jsonata" }, { "t": "else" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 190, "y": 400, "wires": [ [ "e10baa27.f6d9a8" ], [ "9df3c1f0.bae07" ] ], "outputLabels": [ "Не превышен", "Превышен" ], "info": "Отмена корректировки, если сумма текущей влажности, заданного сдвига и промежутка больше 100%." }, { "id": "490df473.7eb0cc", "type": "template", "z": "d1e5566a.2c1c08", "name": "Шаблон тела письма", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "Слишком высокая влажность для изменения порогов! Действие отменено!\n\nПри текущей влажности {{{flow.humidity.current}}}%, порог включения составит {{{threshold.on}}}%, т.к. сдвиг равняется {{{flow.settings.shift}}}%, а промежуток - {{{flow.settings.gap}}}%.", "output": "str", "x": 400, "y": 460, "wires": [ [ "f5422743.499978" ] ] }, { "id": "4886a5d2.c29a5c", "type": "switch", "z": "d1e5566a.2c1c08", "name": "Фильтр погрешности", "property": "humidity.current", "propertyType": "flow", "rules": [ { "t": "btwn", "v": "$flowContext(\"humidity.previous\")-$flowContext(\"settings.inaccuracy\")", "vt": "jsonata", "v2": "$flowContext(\"humidity.previous\")+$flowContext(\"settings.inaccuracy\")", "v2t": "jsonata" }, { "t": "else" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 160, "y": 280, "wires": [ [ "e7566d10.19a77" ], [ "2ba1e0a7.ddf7" ] ], "outputLabels": [ "Не изменилась", "Изменилась" ] }, { "id": "e7566d10.19a77", "type": "template", "z": "d1e5566a.2c1c08", "name": "Шаблон тела письма", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "Корректировка порогов влажности не была выполнена, т.к. влажность осталась на прежнем уровне!\n\nПредыдущее и последнее значение влажности - {{{flow.humidity.previous}}}/{{{flow.humidity.current}}}%, установленная погрешность ±{{{flow.settings.inaccuracy}}}%.", "output": "str", "x": 460, "y": 280, "wires": [ [ "38701419.cf46ac" ] ] }, { "id": "38701419.cf46ac", "type": "change", "z": "d1e5566a.2c1c08", "name": "Сброс метки", "rules": [ { "t": "set", "p": "status.start", "pt": "flow", "to": "NO", "tot": "str" }, { "t": "set", "p": "humidity.previous", "pt": "flow", "to": "humidity.current", "tot": "flow" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 730, "y": 280, "wires": [ [ "6d2686f5.04aa08" ] ], "info": "Свойство flow.humshift отвечает за положительный (2) или отрицательный (-1) сдвиг, относительно измеренной влажности." }, { "id": "9df3c1f0.bae07", "type": "change", "z": "d1e5566a.2c1c08", "name": "Сброс метки", "rules": [ { "t": "set", "p": "status.start", "pt": "flow", "to": "NO", "tot": "str" }, { "t": "set", "p": "humidity.previous", "pt": "flow", "to": "humidity.current", "tot": "flow" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 130, "y": 460, "wires": [ [ "490df473.7eb0cc" ] ], "info": "Свойство flow.humshift отвечает за положительный (2) или отрицательный (-1) сдвиг, относительно измеренной влажности." }, { "id": "a70165e6.d7ccd8", "type": "link in", "z": "d1e5566a.2c1c08", "name": "К письму", "links": [ "6d2686f5.04aa08", "d44ce687.cd78f8", "87333111.1a3a" ], "x": 75, "y": 520, "wires": [ [ "f5422743.499978" ] ] }, { "id": "6d2686f5.04aa08", "type": "link out", "z": "d1e5566a.2c1c08", "name": "От статуса", "links": [ "a70165e6.d7ccd8" ], "x": 655, "y": 220, "wires": [] }, { "id": "62ea660f.b98de8", "type": "comment", "z": "d1e5566a.2c1c08", "name": "Настройки", "info": "Ввод настроек осуществляется в узле \"**Ввод настроек и подготовка**\" выше в первых трех правилах (смотрите комментарии в нем).", "x": 420, "y": 340, "wires": [] }, { "id": "dca29af2.bff068", "type": "template", "z": "d1e5566a.2c1c08", "name": "Шаблон тела письма", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "Корректировка порогов влажности не выполнена, т.к. отсутствует значение \"status.power\" в потоковом контексте Node-RED, вызванное перезагрузкой устройства.\n\nЭто не является ошибкой! Просто подождите, когда вентиляция сама включится или включите\\выключите ее вручную.", "output": "str", "x": 700, "y": 160, "wires": [ [ "6d2686f5.04aa08" ] ] }, { "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": "" } ]
[ { "id": "d0efd2d4.1584f", "type": "template", "z": "d1e5566a.2c1c08", "name": "Шаблон тела письма", "field": "payload", "fieldType": "msg", "format": "handlebars", "syntax": "mustache", "template": "Коррекция порогов запущена вручную из web-интерфейса!", "output": "str", "x": 160, "y": 520, "wires": [ [ "f5422743.499978" ] ] }, { "id": "6a09a4c1.ce2acc", "type": "mqtt in", "z": "d1e5566a.2c1c08", "name": "Статус ручной коррекции", "topic": "ventilation_000457/stat/POWER2", "qos": "2", "datatype": "utf8", "broker": "8745b931.133868", "x": 170, "y": 580, "wires": [ [ "d5a73a92.fd1ab8" ] ] }, { "id": "d5a73a92.fd1ab8", "type": "switch", "z": "d1e5566a.2c1c08", "name": "Фильтр статуса", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "ON", "vt": "str" } ], "checkall": "false", "repair": false, "outputs": 1, "x": 440, "y": 580, "wires": [ [ "6076425.d1fdfbc" ] ] }, { "id": "6076425.d1fdfbc", "type": "change", "z": "d1e5566a.2c1c08", "name": "Сохранение метки", "rules": [ { "t": "set", "p": "status.start", "pt": "flow", "to": "YES", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 710, "y": 580, "wires": [ [ "d0efd2d4.1584f" ] ] }, { "id": "e10baa27.f6d9a8", "type": "change", "z": "d1e5566a.2c1c08", "name": "Подготовка правила и сброс метки", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "\"ON SI7021#Humidity>=\" & threshold.on & \" DO Power1 on ENDON ON SI7021#Humidity<=\" & threshold.off & \" DO Power1 off ENDON\"", "tot": "jsonata" }, { "t": "set", "p": "status.start", "pt": "flow", "to": "NO", "tot": "str" }, { "t": "set", "p": "humidity.previous", "pt": "flow", "to": "humidity.current", "tot": "flow" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 650, "y": 400, "wires": [ [ "c67e2442.ddbd18", "5b177dfc.05bd54" ] ], "info": "Свойство flow.humshift отвечает за положительный (2) или отрицательный (-1) сдвиг, относительно измеренной влажности." }, { "id": "cab7bd9.198da4", "type": "mqtt in", "z": "d1e5566a.2c1c08", "name": "Статус вентиляции", "topic": "ventilation_000457/stat/POWER1", "qos": "2", "datatype": "utf8", "broker": "8745b931.133868", "x": 450, "y": 40, "wires": [ [ "dd9d91a4.08a5a" ] ] }, { "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": "" } ]
[ { "id": "cab7bd9.198da4", "type": "mqtt in", "z": "d1e5566a.2c1c08", "name": "Статус работы вентиляции", "topic": "ventilation_000457/stat/POWER1", "qos": "2", "datatype": "utf8", "broker": "8745b931.133868", "x": 180, "y": 580, "wires": [ [ "dd9d91a4.08a5a" ] ] }, { "id": "dd9d91a4.08a5a", "type": "change", "z": "d1e5566a.2c1c08", "name": "Сохранение статуса", "rules": [ { "t": "set", "p": "status.power", "pt": "flow", "to": "payload", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 460, "y": 580, "wires": [ [ "ca2cb356.08fbf" ] ] }, { "id": "ca2cb356.08fbf", "type": "switch", "z": "d1e5566a.2c1c08", "name": "Маршрутизация", "property": "payload", "propertyType": "msg", "rules": [ { "t": "eq", "v": "ON", "vt": "str" }, { "t": "eq", "v": "OFF", "vt": "str" } ], "checkall": "false", "repair": false, "outputs": 2, "x": 150, "y": 640, "wires": [ [ "ed82b8.ba997d48" ], [ "5d2821b8.6e178" ] ], "outputLabels": [ "Включена", "Выключена" ] }, { "id": "5d2821b8.6e178", "type": "change", "z": "d1e5566a.2c1c08", "name": "Сброс триггера", "rules": [ { "t": "set", "p": "reset", "pt": "msg", "to": "true", "tot": "bool" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 140, "y": 700, "wires": [ [ "ed82b8.ba997d48" ] ] }, { "id": "ed82b8.ba997d48", "type": "trigger", "z": "d1e5566a.2c1c08", "name": "Максимальное время работы", "op1": "", "op2": "true", "op1type": "nul", "op2type": "bool", "duration": "3", "extend": false, "overrideDelay": false, "units": "hr", "reset": "", "bytopic": "all", "topic": "topic", "outputs": 1, "x": 430, "y": 640, "wires": [ [ "9b8b6e17.b3521" ] ], "info": "Максимальное время непрерывной работы, по истечению которого считается, что порог выключения вентиляции выше минимально возможной влажности в помещении - требуется принудительная корректировка порогов." }, { "id": "9b8b6e17.b3521", "type": "change", "z": "d1e5566a.2c1c08", "name": "Установка сообщения", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "ON", "tot": "str" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 700, "y": 640, "wires": [ [ "53dc503a.78c4" ] ] }, { "id": "53dc503a.78c4", "type": "mqtt out", "z": "d1e5566a.2c1c08", "name": "Запуск коррекции по порогу времени", "topic": "ventilation_000457/cmnd/POWER2", "qos": "0", "retain": "false", "broker": "8745b931.133868", "x": 650, "y": 700, "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": "" } ]
Этот код содержит все изменения и дополнения указанные выше. Однако, при его использовании, все равно необходимо внести изменения в конфигурацию Tasmota и применить соответствующий конфиг для Homebridge.
Обсуждение