Инструменты пользователя

Инструменты сайта


iot:software:node-red:flows:network_monitoring

Мониторинг локальной сети в Node-RED

Небольшой поток для мониторинга произвольных устройств в локальной сети или Интернете версия 2.x, полностью переосмысленная и переписанная – меньше ложных срабатываний1), меньше обращений к базе данных, более компактная, линейная и логичная! В общем, конфетка, а не… то, что было2). LOL

:!: Архивные версии 1.0, 1.1, 2.0.

Нестандартные узлы

В этой цепочке используются следующие узлы, которых нет в стандартной поставке:

Дополнительные подпотоки

Этот подпоток входит в состав кода ниже и загружать отдельно его не надо!

Описание работы цепочки

Цепочка запускается автоматически каждую минуту3), при необходимости или каком-то сбое, можно запустить вручную. Далее из базы данных читаются все устройства, проверяются командой ping и записываются результаты в БД. Если есть устройства, которые не ответили, они попадают в цикл с заданным числом витков и временем между попытками4). Прочие устройства ожидают завершения всех циклов, после чего все сообщения собираются в одно, которое и передается дальше.

Далее подсчитывается количество тех или иных статусов5) и сообщение вновь разбивается на части для объединения по статусам и сортировки. В конце, если необходимо6), формируется и отправляется письмо.

Примеры писем от мониторинга сети.

История изменений

  • В версии 2.1 добавлена отправка периодической сводки7) по недоступным хостам.

Создание таблицы

:!: Для работы этого потока, необходимо вручную создать таблицу, выполнив SQL-запрос:

CREATE TABLE nw_status (_id INTEGER PRIMARY KEY, name TEXT, host TEXT, timeout INTEGER, response INTEGER, sent INTEGER DEFAULT 0, cycles INTEGER)

Пример цепочки:

[
    {
        "id": "28be5e5d.cb7442",
        "type": "inject",
        "z": "66d1b95c.cf90f8",
        "name": "Подготовка запроса",
        "props": [
            {
                "p": "topic",
                "vt": "str"
            },
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": 0.1,
        "topic": "CREATE TABLE nw_status (_id INTEGER PRIMARY KEY, name TEXT, host TEXT, timeout INTEGER, response INTEGER, sent INTEGER DEFAULT 0, cycles INTEGER)",
        "payload": "",
        "payloadType": "date",
        "x": 350,
        "y": 240,
        "wires": [
            [
                "d089a31b.a5805"
            ]
        ]
    },
    {
        "id": "758cd73a.9cf318",
        "type": "debug",
        "z": "66d1b95c.cf90f8",
        "name": "Вывод команды",
        "active": true,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 350,
        "y": 360,
        "wires": []
    },
    {
        "id": "d089a31b.a5805",
        "type": "sqlite",
        "z": "66d1b95c.cf90f8",
        "mydb": "2bc4c6d.cf1f03a",
        "sqlquery": "msg.topic",
        "sql": "",
        "name": "Создание таблицы",
        "x": 350,
        "y": 300,
        "wires": [
            [
                "758cd73a.9cf318"
            ]
        ]
    },
    {
        "id": "2bc4c6d.cf1f03a",
        "type": "sqlitedb",
        "db": "c:\\noderedDB\\nw_status.db",
        "mode": "RWC"
    }
]

Полезные SQL-запросы

Все эти запросы можно вставлять в msg.topic узла «inject» из примера цепочки в предыдущем пункте.

Добавление устройства

INSERT INTO nw_status (name, host, timeout) VALUES ("Устройство 1", "192.168.0.5", 10000)

Если таймаут необходимо установить по умолчанию, вместо цифр указать NULL8) или не использовать его в запросе:

INSERT INTO nw_status (name, host) VALUES ("Устройство 1", "192.168.0.5")

Массовое добавление

INSERT INTO nw_status (name, host, timeout) VALUES ("Устройство 1", "192.168.0.5", NULL), ("Устройство 2", "192.168.0.6", 7000), ("Устройство 3", "192.168.0.7", 2000)

Просмотр всех устройств

SELECT * FROM nw_status

Удаление устройства

Запрос для удаления устройства с номером 2.

DELETE FROM nw_status WHERE _id = 2

:!: Во второй версии потока есть ограничение – ряд _id должен быть цельным, без пропусков9), т.е. нельзя просто так удалить устройство – его необходимо заменить другим или присвоить его номер последнему устройству в списке!

Обновление последней записи

Для замены _id в последней строке базы данных можно использовать такой запрос:

UPDATE nw_status SET _id = 2 WHERE _rowid_ = ( SELECT MAX( _rowid_ ) FROM nw_status )

Код для загрузки

network-monitoring.json
[
    {
        "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": "bf63e9a3.a5b928",
        "type": "tab",
        "label": "Мониторинг сети",
        "disabled": false,
        "info": ""
    },
    {
        "id": "817060ef.2b843",
        "type": "inject",
        "z": "bf63e9a3.a5b928",
        "name": "Автозапуск",
        "props": [],
        "repeat": "60",
        "crontab": "",
        "once": true,
        "onceDelay": "1",
        "topic": "",
        "payloadType": "str",
        "x": 130,
        "y": 100,
        "wires": [
            [
                "ad444795.a7b668"
            ]
        ]
    },
    {
        "id": "f27932db.06f1e",
        "type": "sqlite",
        "z": "bf63e9a3.a5b928",
        "mydb": "2bc4c6d.cf1f03a",
        "sqlquery": "msg.topic",
        "sql": "",
        "name": "Выборка всех устройств",
        "x": 690,
        "y": 40,
        "wires": [
            [
                "5ace9ea9.1497d"
            ]
        ]
    },
    {
        "id": "f41fa10e.39756",
        "type": "ping",
        "z": "bf63e9a3.a5b928",
        "protocol": "Automatic",
        "mode": "triggered",
        "name": "Проверка связи",
        "host": "",
        "timer": "60",
        "inputs": 1,
        "x": 460,
        "y": 160,
        "wires": [
            [
                "425962de.576a5c"
            ]
        ]
    },
    {
        "id": "cbb6faf8.027568",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Установка счетчика цикла",
        "rules": [
            {
                "t": "set",
                "p": "ping.count",
                "pt": "msg",
                "to": "$exists( ping.count ) = true ? ( ping.count + 1 ) : 0",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "delay",
                "pt": "msg",
                "to": "settings.delay",
                "tot": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 180,
        "y": 220,
        "wires": [
            [
                "25c3af02.51d2c"
            ]
        ]
    },
    {
        "id": "25c3af02.51d2c",
        "type": "switch",
        "z": "bf63e9a3.a5b928",
        "name": "Проверка счетчика",
        "property": "ping.count",
        "propertyType": "msg",
        "rules": [
            {
                "t": "neq",
                "v": "settings.cycles",
                "vt": "flow"
            },
            {
                "t": "eq",
                "v": "settings.cycles",
                "vt": "flow"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 460,
        "y": 220,
        "wires": [
            [
                "202cf843.0c54a8"
            ],
            [
                "73733ff5.013f9"
            ]
        ],
        "outputLabels": [
            "Повторить цикл",
            "Завершить цикл"
        ]
    },
    {
        "id": "425962de.576a5c",
        "type": "switch",
        "z": "bf63e9a3.a5b928",
        "name": "Доступность устройства",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "false"
            },
            {
                "t": "else"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 690,
        "y": 160,
        "wires": [
            [
                "cbb6faf8.027568"
            ],
            [
                "47244dcf.c20b34"
            ]
        ],
        "outputLabels": [
            "Не отвечает",
            "Отвечает"
        ]
    },
    {
        "id": "202cf843.0c54a8",
        "type": "template",
        "z": "bf63e9a3.a5b928",
        "name": "Восстановление структуры",
        "field": "payload",
        "fieldType": "msg",
        "format": "handlebars",
        "syntax": "mustache",
        "template": "[{\n\"_id\": {{{ping._id}}},\n\"name\": \"{{{ping.name}}}\",\n\"host\": \"{{{ping.host}}}\",\n\"timeout\": {{{ping.timeout}}},\n\"sent\": {{{ping.sent}}},\n\"count\": {{{ping.count}}}\n}]",
        "output": "json",
        "x": 680,
        "y": 280,
        "wires": [
            [
                "d2b39ab6.0c64f8"
            ]
        ]
    },
    {
        "id": "73733ff5.013f9",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Установка св-в",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "\"UPDATE \\\"\" & $flowContext( \"settings.table\" ) & \"\\\" SET response = \" & payload & \", cycles = \" & ( $exists( ping.count ) = false ? 0 : ping.count ) & \" WHERE _id = \" & ping._id",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "parts.index",
                "pt": "msg",
                "to": "ping._id - 1",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "parts.count",
                "pt": "msg",
                "to": "parts.count",
                "tot": "flow"
            },
            {
                "t": "set",
                "p": "parts.id",
                "pt": "msg",
                "to": "parts.id",
                "tot": "flow"
            },
            {
                "t": "move",
                "p": "payload",
                "pt": "msg",
                "to": "ping.response",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 220,
        "y": 280,
        "wires": [
            [
                "5d114f5c.32a04"
            ]
        ]
    },
    {
        "id": "5d114f5c.32a04",
        "type": "sqlite",
        "z": "bf63e9a3.a5b928",
        "mydb": "2bc4c6d.cf1f03a",
        "sqlquery": "msg.topic",
        "sql": "",
        "name": "Запись ответов",
        "x": 420,
        "y": 280,
        "wires": [
            [
                "8961f0c.35b121"
            ]
        ]
    },
    {
        "id": "5ace9ea9.1497d",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Сохранение переменных",
        "rules": [
            {
                "t": "set",
                "p": "parts.count",
                "pt": "flow",
                "to": "$count( payload )\t",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "parts.id",
                "pt": "flow",
                "to": "",
                "tot": "date"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 680,
        "y": 100,
        "wires": [
            [
                "f41fa10e.39756"
            ]
        ]
    },
    {
        "id": "93dadf2f.1e905",
        "type": "join",
        "z": "bf63e9a3.a5b928",
        "name": "Объединение",
        "mode": "auto",
        "build": "string",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "num",
        "reduceFixup": "",
        "x": 480,
        "y": 340,
        "wires": [
            [
                "d763f5eb.4a1378"
            ]
        ],
        "info": "Восстанавливается и объединяется последовательность для того, чтобы достоверно узнать завершение операции тестирования связи."
    },
    {
        "id": "8961f0c.35b121",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Установка статусов",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "$type( payload ) = \"array\" ? ping : payload",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "payload.status",
                "pt": "msg",
                "to": "( payload.sent = 0 and payload.response = false ) ? \"died\" : ( payload.sent = 1 and payload.response = false ) ? \"dead\" : ( payload.sent = 1 and payload.response > 0 ) ? \"revived\" : ( payload.sent = 0 and payload.response > 0 ) ? \"alive\"",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 240,
        "y": 340,
        "wires": [
            [
                "93dadf2f.1e905"
            ]
        ]
    },
    {
        "id": "51891d56.192d94",
        "type": "delay",
        "z": "bf63e9a3.a5b928",
        "name": "Задержка проверки",
        "pauseType": "delayv",
        "timeout": "1",
        "timeoutUnits": "seconds",
        "rate": "1",
        "nbRateUnits": "1",
        "rateUnits": "second",
        "randomFirst": "1",
        "randomLast": "5",
        "randomUnits": "seconds",
        "drop": false,
        "x": 220,
        "y": 160,
        "wires": [
            [
                "f41fa10e.39756"
            ]
        ]
    },
    {
        "id": "6ccc324d.f380bc",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Ввод настроек",
        "rules": [
            {
                "t": "set",
                "p": "settings.cycles",
                "pt": "flow",
                "to": "3",
                "tot": "num"
            },
            {
                "t": "set",
                "p": "settings.delay",
                "pt": "flow",
                "to": "10000",
                "tot": "num"
            },
            {
                "t": "set",
                "p": "settings.table",
                "pt": "flow",
                "to": "nw_status_test",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "\"SELECT _id, name, host, timeout, sent FROM \\\"\" & $flowContext( \"settings.table\" ) & \"\\\"\"",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "status.run",
                "pt": "flow",
                "to": "true",
                "tot": "bool"
            },
            {
                "t": "set",
                "p": "status.sent",
                "pt": "flow",
                "to": "false",
                "tot": "bool"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 440,
        "y": 40,
        "wires": [
            [
                "f27932db.06f1e"
            ]
        ],
        "info": "**flow.settings.cycles** -- количество дополнительных попыток проверки связи (при установке \"0\" будет проведена 1 попытка; при установке \"1\", соответственно, 2, т.е. одна основная, и одна дополнительная);\n\n**flow.settings.delay** -- задержка между дополнительными попытками проверки;\n\n**flow.settings.table** -- название таблицы в базе данных."
    },
    {
        "id": "dbabb4a5.093288",
        "type": "link in",
        "z": "bf63e9a3.a5b928",
        "name": "",
        "links": [
            "d2b39ab6.0c64f8"
        ],
        "x": 75,
        "y": 160,
        "wires": [
            [
                "51891d56.192d94"
            ]
        ]
    },
    {
        "id": "d2b39ab6.0c64f8",
        "type": "link out",
        "z": "bf63e9a3.a5b928",
        "name": "",
        "links": [
            "dbabb4a5.093288"
        ],
        "x": 675,
        "y": 220,
        "wires": []
    },
    {
        "id": "721310f6.a461a",
        "type": "link in",
        "z": "bf63e9a3.a5b928",
        "name": "",
        "links": [
            "47244dcf.c20b34"
        ],
        "x": 75,
        "y": 280,
        "wires": [
            [
                "73733ff5.013f9"
            ]
        ]
    },
    {
        "id": "47244dcf.c20b34",
        "type": "link out",
        "z": "bf63e9a3.a5b928",
        "name": "",
        "links": [
            "721310f6.a461a"
        ],
        "x": 775,
        "y": 220,
        "wires": []
    },
    {
        "id": "ad444795.a7b668",
        "type": "switch",
        "z": "bf63e9a3.a5b928",
        "name": "Проверка метки",
        "property": "status.run",
        "propertyType": "flow",
        "rules": [
            {
                "t": "jsonata_exp",
                "v": "$exists( $flowContext( \"status.run\" ) ) = false or $flowContext( \"status.run\" ) = false",
                "vt": "jsonata"
            },
            {
                "t": "jsonata_exp",
                "v": "( $exists( $flowContext( \"status.sent\" ) ) = false or $flowContext( \"status.sent\" ) = false) and $flowContext( \"status.run\" ) = true",
                "vt": "jsonata"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 2,
        "x": 330,
        "y": 100,
        "wires": [
            [
                "6ccc324d.f380bc"
            ],
            [
                "65cbf7fe.7357d8"
            ]
        ],
        "info": "Фильтр запуска цепочки до завершения предыдущей задачи."
    },
    {
        "id": "d763f5eb.4a1378",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Подсчет статусов",
        "rules": [
            {
                "t": "set",
                "p": "result.alive",
                "pt": "msg",
                "to": "payload.$sift( function( $v, $k ) { $k = \"status\" and $v = \"alive\" } ) ~> $count()",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "result.dead",
                "pt": "msg",
                "to": "payload.$sift( function( $v, $k ) { $k = \"status\" and $v = \"dead\" } ) ~> $count()",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "result.revived",
                "pt": "msg",
                "to": "payload.$sift( function( $v, $k ) { $k = \"status\" and $v = \"revived\" } ) ~> $count()",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "result.died",
                "pt": "msg",
                "to": "payload.$sift( function( $v, $k ) { $k = \"status\" and $v = \"died\" } ) ~> $count()",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "status.run",
                "pt": "flow",
                "to": "false",
                "tot": "bool"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 710,
        "y": 340,
        "wires": [
            [
                "71abee18.7fdf4"
            ]
        ]
    },
    {
        "id": "2aa2153.fed7bea",
        "type": "subflow:38c9a069.18cd6",
        "z": "bf63e9a3.a5b928",
        "name": "Отправка писем",
        "env": [],
        "x": 710,
        "y": 640,
        "wires": []
    },
    {
        "id": "38565f85.6837e",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Наложение проверок",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "\"Уведомление системы мониторинга от \" & $now( '[H01]:[m01]:[s01] [D01].[M01].[Y0001]', '+1000' ) & \"!\"",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "Запущен новый цикл проверки, тогда как предыдущий еще не завершен! Текущая проверка отменена. Возможно, необходимо увеличить интервал запуска.",
                "tot": "str"
            },
            {
                "t": "set",
                "p": "status.sent",
                "pt": "flow",
                "to": "true",
                "tot": "bool"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 700,
        "y": 700,
        "wires": [
            [
                "2aa2153.fed7bea"
            ]
        ]
    },
    {
        "id": "49762568.343b6c",
        "type": "link in",
        "z": "bf63e9a3.a5b928",
        "name": "",
        "links": [
            "65cbf7fe.7357d8"
        ],
        "x": 555,
        "y": 700,
        "wires": [
            [
                "38565f85.6837e"
            ]
        ]
    },
    {
        "id": "65cbf7fe.7357d8",
        "type": "link out",
        "z": "bf63e9a3.a5b928",
        "name": "",
        "links": [
            "49762568.343b6c"
        ],
        "x": 495,
        "y": 100,
        "wires": []
    },
    {
        "id": "924e62cc.f20bf",
        "type": "csv",
        "z": "bf63e9a3.a5b928",
        "name": "Преобразование в текст",
        "sep": ",",
        "hdrin": "",
        "hdrout": "none",
        "multi": "one",
        "ret": "\\r\\n",
        "temp": "string",
        "skip": "0",
        "strings": true,
        "include_empty_strings": "",
        "include_null_values": "",
        "x": 430,
        "y": 520,
        "wires": [
            [
                "6d923a0c.dfcda4"
            ]
        ]
    },
    {
        "id": "dd59e694.b8b688",
        "type": "split",
        "z": "bf63e9a3.a5b928",
        "name": "Разделение пос-и",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 430,
        "y": 400,
        "wires": [
            [
                "15fa5ef7.8a6351",
                "5a977cdd.89d1a4"
            ]
        ]
    },
    {
        "id": "5a977cdd.89d1a4",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Подготовка свойств",
        "rules": [
            {
                "t": "set",
                "p": "parts.id",
                "pt": "msg",
                "to": "payload.status",
                "tot": "msg"
            },
            {
                "t": "set",
                "p": "parts.count",
                "pt": "msg",
                "to": "parts.id = \"alive\" ? result.alive : parts.id = \"dead\" ? result.dead : parts.id = \"revived\" ? result.revived : parts.id = \"died\" ? result.died",
                "tot": "jsonata"
            },
            {
                "t": "delete",
                "p": "parts.index",
                "pt": "msg"
            },
            {
                "t": "set",
                "p": "payload.string",
                "pt": "msg",
                "to": "( payload.response = false ? \"\" : payload.response ) & \" мс (\" & ( $exists( payload.count ) = false ? 0 : payload.count ) & \") - \" & payload.name & \" (\" & payload.host & \")\"",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 160,
        "y": 460,
        "wires": [
            [
                "3e710520.472cea"
            ]
        ]
    },
    {
        "id": "3e710520.472cea",
        "type": "join",
        "z": "bf63e9a3.a5b928",
        "name": "Группировка по статусу",
        "mode": "auto",
        "build": "string",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "accumulate": false,
        "timeout": "",
        "count": "",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "",
        "reduceFixup": "",
        "x": 410,
        "y": 460,
        "wires": [
            [
                "5f8d8b50.4b7204"
            ]
        ],
        "info": "Создает до двух отдельных сообщений в зависимости от статуса -- отвечает устройство или нет."
    },
    {
        "id": "5f8d8b50.4b7204",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Подготовка нагрузки",
        "rules": [
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "$type( payload[0].response ) = \"number\" ? $sort( payload, function( $l, $r ) { $l.response < $r.response } ) : payload",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "result.status",
                "pt": "msg",
                "to": "payload[0].status",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 160,
        "y": 520,
        "wires": [
            [
                "924e62cc.f20bf"
            ]
        ]
    },
    {
        "id": "15fa5ef7.8a6351",
        "type": "switch",
        "z": "bf63e9a3.a5b928",
        "name": "Фильтрация статусов",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "jsonata_exp",
                "v": "payload.status = \"died\" or payload.status = \"revived\"",
                "vt": "jsonata"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 1,
        "x": 700,
        "y": 400,
        "wires": [
            [
                "663cca43.d8dff4"
            ]
        ]
    },
    {
        "id": "a07661e9.dc5b5",
        "type": "sqlite",
        "z": "bf63e9a3.a5b928",
        "mydb": "2bc4c6d.cf1f03a",
        "sqlquery": "msg.topic",
        "sql": "",
        "name": "Запись статусов",
        "x": 710,
        "y": 520,
        "wires": [
            []
        ]
    },
    {
        "id": "663cca43.d8dff4",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Подготовка изменений",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "\"UPDATE \"& $flowContext( \"settings.table\" ) & \" SET sent = \" & ( ( payload.status = \"died\" and payload.sent = 0 ) ? 1 : ( payload.status = \"revived\" and payload.sent = 1 ) ? 0 ) & \" WHERE _id = \" & payload._id",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 690,
        "y": 460,
        "wires": [
            [
                "a07661e9.dc5b5"
            ]
        ]
    },
    {
        "id": "71abee18.7fdf4",
        "type": "switch",
        "z": "bf63e9a3.a5b928",
        "name": "Фильтрация изменений",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "jsonata_exp",
                "v": "( result.revived > 0 or result.died > 0 ) or ( result.dead > 0 and periodical = true)",
                "vt": "jsonata"
            }
        ],
        "checkall": "false",
        "repair": false,
        "outputs": 1,
        "x": 170,
        "y": 400,
        "wires": [
            [
                "dd59e694.b8b688"
            ]
        ]
    },
    {
        "id": "6d923a0c.dfcda4",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Сохранение текста",
        "rules": [
            {
                "t": "set",
                "p": "status.texts",
                "pt": "flow",
                "to": "$merge( [ $flowContext( \"status.texts\" ), { $.result.status : payload } ] )",
                "tot": "jsonata"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 160,
        "y": 580,
        "wires": [
            [
                "2fb8a144.23e9ee"
            ]
        ]
    },
    {
        "id": "2fb8a144.23e9ee",
        "type": "trigger",
        "z": "bf63e9a3.a5b928",
        "name": "Ожидание всех частей",
        "op1": "",
        "op2": "true",
        "op1type": "nul",
        "op2type": "bool",
        "duration": "2",
        "extend": true,
        "overrideDelay": false,
        "units": "s",
        "reset": "",
        "bytopic": "all",
        "topic": "topic",
        "outputs": 1,
        "x": 430,
        "y": 580,
        "wires": [
            [
                "13bfd89.8a76c27"
            ]
        ]
    },
    {
        "id": "13bfd89.8a76c27",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Подготовка письма",
        "rules": [
            {
                "t": "set",
                "p": "topic",
                "pt": "msg",
                "to": "( periodical = true ? \"Сводка системы мониторинга от \" : \"Уведомление системы мониторинга от \" ) & $now( '[H01]:[m01]:[s01] [D01].[M01].[Y0001]', '+1000' ) & \"!\"",
                "tot": "jsonata"
            },
            {
                "t": "set",
                "p": "payload",
                "pt": "msg",
                "to": "( $exists( $flowContext( \"status.texts.revived\" ) ) = true ? \"Устройства начали отвечать:\\n\" ) & ( $exists( $flowContext( \"status.texts.revived\" ) ) = true ? ( $flowContext( \"status.texts.revived\" ) & \"\\n\" ) ) & ( $exists( $flowContext( \"status.texts.died\" ) ) = true ? \"Устройства перестали отвечать: \\n\" ) & ( $exists( $flowContext( \"status.texts.died\" ) ) = true ? ( $flowContext( \"status.texts.died\" ) & \"\\n\" ) ) & ( $exists( $flowContext( \"status.texts.dead\" ) ) = true ? \"Устройства не отвечают:\\n\" ) & ( $exists( $flowContext( \"status.texts.dead\" ) ) = true ? ( $flowContext( \"status.texts.dead\" ) & \"\\n\" ) ) & ( $exists( $flowContext( \"status.texts.alive\" ) ) = true ? \"Диагностические данные:\\n\" ) & ( $exists( $flowContext( \"status.texts.alive\" ) ) = true ? $flowContext( \"status.texts.alive\" ) )",
                "tot": "jsonata"
            },
            {
                "t": "delete",
                "p": "status.texts",
                "pt": "flow"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 700,
        "y": 580,
        "wires": [
            [
                "2aa2153.fed7bea"
            ]
        ]
    },
    {
        "id": "172accf.e425333",
        "type": "inject",
        "z": "bf63e9a3.a5b928",
        "name": "Запустить и сбросить метку",
        "props": [],
        "repeat": "",
        "crontab": "",
        "once": false,
        "onceDelay": "1",
        "topic": "",
        "payloadType": "str",
        "x": 180,
        "y": 40,
        "wires": [
            [
                "6ccc324d.f380bc"
            ]
        ],
        "info": "Сбросить метку `flow.status.run` и запустить поток. Полезно при сбоях, когда цепочка повисла в режиме ожидания."
    },
    {
        "id": "d45c7cea.9b2c4",
        "type": "inject",
        "z": "bf63e9a3.a5b928",
        "name": "Периодическая сводка",
        "props": [
            {
                "p": "topic",
                "v": "\"SELECT _id, name, host, response, sent, cycles FROM \\\"\" & $flowContext( \"settings.table\" ) & \"\\\"\"",
                "vt": "jsonata"
            },
            {
                "p": "periodical",
                "v": "true",
                "vt": "bool"
            }
        ],
        "repeat": "21600",
        "crontab": "",
        "once": true,
        "onceDelay": "60",
        "topic": "",
        "payloadType": "str",
        "x": 170,
        "y": 640,
        "wires": [
            [
                "994ffc21.74839"
            ]
        ],
        "info": "Отправляется только, если есть \"мертвые\" устройства."
    },
    {
        "id": "994ffc21.74839",
        "type": "sqlite",
        "z": "bf63e9a3.a5b928",
        "mydb": "2bc4c6d.cf1f03a",
        "sqlquery": "msg.topic",
        "sql": "",
        "name": "Выборка устройств",
        "x": 440,
        "y": 640,
        "wires": [
            [
                "f97471ca.36e7d"
            ]
        ]
    },
    {
        "id": "f97471ca.36e7d",
        "type": "split",
        "z": "bf63e9a3.a5b928",
        "name": "Разделение пос-и",
        "splt": "\\n",
        "spltType": "str",
        "arraySplt": 1,
        "arraySpltType": "len",
        "stream": false,
        "addname": "",
        "x": 150,
        "y": 700,
        "wires": [
            [
                "a11064c5.7b4778"
            ]
        ]
    },
    {
        "id": "f9033d4c.c67e1",
        "type": "link in",
        "z": "bf63e9a3.a5b928",
        "name": "",
        "links": [
            "d76d9726.edb0b8"
        ],
        "x": 75,
        "y": 340,
        "wires": [
            [
                "8961f0c.35b121"
            ]
        ]
    },
    {
        "id": "d76d9726.edb0b8",
        "type": "link out",
        "z": "bf63e9a3.a5b928",
        "name": "",
        "links": [
            "f9033d4c.c67e1"
        ],
        "x": 495,
        "y": 700,
        "wires": []
    },
    {
        "id": "a11064c5.7b4778",
        "type": "change",
        "z": "bf63e9a3.a5b928",
        "name": "Подготовка св-в",
        "rules": [
            {
                "t": "set",
                "p": "payload.response",
                "pt": "msg",
                "to": "payload.response = 0 ? false : payload.response",
                "tot": "jsonata"
            },
            {
                "t": "move",
                "p": "payload.cycles",
                "pt": "msg",
                "to": "payload.count",
                "tot": "msg"
            }
        ],
        "action": "",
        "property": "",
        "from": "",
        "to": "",
        "reg": false,
        "x": 350,
        "y": 700,
        "wires": [
            [
                "d76d9726.edb0b8"
            ]
        ]
    },
    {
        "id": "2bc4c6d.cf1f03a",
        "type": "sqlitedb",
        "db": "c:\\noderedDB\\nw_status.db",
        "mode": "RWC"
    }
]

Дисклеймер

  • Использование материалов данной базы знаний разрешено на условиях лицензии, указанной внизу каждой страницы! При использовании материалов активная гиперссылка на соответствующую страницу данной базы знаний обязательна!
  • Автор не несет и не может нести какую либо ответственность за последствия использования материалов, размещенных в данной базе знаний. Все материалы предоставляются по принципу «как есть». Используйте их исключительно на свой страх и риск.
  • Все высказывания, мысли или идеи автора, размещенные в материалах данной базе знаний, являются исключительно его личным субъективным мнением и могут не совпадать с мнением читателей!
  • При размещении ссылок в данной базе знаний на интернет-страницы третьих лиц автор не несет ответственности за их техническую функциональность (особенно отсутствие вирусов) и содержание! При обнаружении таких ссылок, можно и желательно сообщить о них в комментариях к соответствующей статье.
1)
Для беспроводных устройств оптимальным оказалось 3 дополнительных цикла с задержкой 10 секунд.
2)
Можно простить, т.к. это практические первое, что я когда-то собрал на Node-RED.
3)
Настраивается в узле «Автозапуск».
4)
Настраивается в узле «Ввод настроек».
5)
«Умерло», «ожило», «мертвое» и «живое» устройство.
6)
Есть устройства со статусами «умерло» или «ожило».
7)
По умолчанию раз в 6 часов.
8)
По умолчанию 5000/(5 сек.), диапазон 1000-30000.
9)
Т.е. «1, 2, 3, 4», а не «1, 2, 4, 5»!

Обсуждение

SeKam, 2021/12/15 04:33
Если результат запроса "Выборка: устройство отвечает" пустой (ни одно из устройств не пингуется), нода "Преобразование 2-й секции" не отрабатывает. В итоге при отключении устройств дело до письма не доходит.
Николай Солошин, 2021/12/15 12:10
Да, действительно... Ни разу не сталкивался, ибо устройств много. ))) Добавил два узла - "Фильтрация пустой нагрузки" и "Сообщение о пустой нагрузке". Теперь, если все устройства не отвечают, во второй секции пишется "Ни одно устройство не отвечает!". Благодарю! ))
Николай Солошин, 2021/12/26 21:56
Опубликовал вторую версию мониторинга.
Ваш комментарий:
D B O E M I D᠎ P Q​ B​ Q H G X I Z
 
Последнее изменение: 2022/02/16 21:20 — Николай Солошин