
Типичная история при работе с промышленными датчиками выглядит примерно так. Есть RS485- датчик, нашли документацию с картой регистров. Написали Python-скрипт, который раз в 10 секунд опрашивает Modbus, парсит регистры и пишет строчку в CSV. Через неделю скрипт падает — оказывается, что порт занят другим процессом, или systemd не поднял его после перезагрузки, или датчик не ответил три раза подряд и скрипт завис в ожидании. Чиним, причесываем, добавляем watchdog. Потом понимаем, что CSV — плохая идея и надо куда-то писать данные нормально. Этот путь знаком многим в промышленной инженерии, но есть и другой путь.
Суть идеи: Telegraf умеет опрашивать Modbus-устройства напрямую — и сразу писать временные ряды в InfluxDB. Никакого промежуточного кода. Grafana строит графики поверх InfluxDB. Весь стек открытый, работает локально, не требует интернета.
ОГЛАВЛЕНИЕ СТАТЬИ:
Про работу стека
Как выглядит “делай раз, делай два” при физическом подключении
Шаг 0. Убедиться, что датчик вообще отвечает
Шаг 1. Конфиг Telegraf — Modbus TCP
Шаг 2. Конфиг для Modbus RTU (датчик напрямую по RS485)
Шаг 3. Тестовый запуск до перезапуска службы
Шаг 4. Grafana — дашборд
А если несколько датчиков на одной шине
Что делать с датчиком без документации
Графический интерфейс NapiConfig — то же самое без консоли
Выводы и ссылки
Про инструментарий:
Telegraf — это агент сбора метрик от компании InfluxData. Программа-демон, которая работает в фоне на Linux-хосте, по расписанию читает данные из разных источников и пишет их куда скажешь — в данном случае в InfluxDB. Один из плагинов называется inputs.modbus — он умеет опрашивать Modbus-устройства по TCP или RS-485 напрямую.
Grafana — это open-source платформа для аналитики, мониторинга и визуализации данных. Она собирает информацию из разных источников (базы данных, облачные сервисы) и отображает в виде графиков и дашбордов.
Дальше — конкретный пример с датчиком DL-303 (температура, влажность, CO, CO2). В качестве железа — компактный ARM-сборщик NAPI-C на RK3308 с предустановленной ОС NapiLinux, там Telegraf и InfluxDB 2.x есть из коробки. Все команды и конфиги работают на любом Linux-хосте с тем же стеком.
Про работу стека
Рассмотрим комплектность такого решения:
Железо:
-
Любой Linux-сборщик с портом RS485 и Ethernet. В примере — NAPI-C (RK3308), компактный ARM-компьютер с NapiLinux, где Telegraf и InfluxDB 2.x предустановлены. На любом другом Linux-хосте все команды те же самые.
-
Датчик с интерфейсом Modbus RTU (RS485) или Modbus TCP.
Программный стек:
-
Telegraf >= 1.20 (плагин inputs.modbus)
-
InfluxDB 2.x
-
Grafana (любая свежая версия)
Для более общего случая, когда ваша ОС не NapiLinux (о ней ниже еще есть раздел) — установите стек вручную или через Docker. Compose-файл с тремя сервисами (telegraf, influxdb, grafana) — это условные 10 минут работы для опытного админа.
Как выглядит “делай раз, делай два” при физическом подключении
Датчик DL-303 подключается по RS-485 двумя проводами к соответствующим клеммам сборщика. Полярность важна — при перепутанных проводах датчик не ответит. На самом датчике через встроенный дисплей выставляются Modbus-адрес (по умолчанию 1), скорость порта (по умолчанию 9600) и параметры 8N1. Запишите эти значения — они понадобятся в конфиге.
На шину RS-485 можно подключить до 32 устройств без дополнительного оборудования. Каждому датчику — уникальный адрес (slave_id). Telegraf опрашивает их последовательно.
Шаг 0. Убедиться, что датчик вообще отвечает
Прежде чем трогать Telegraf, стоит опросить датчик вручную. Для этого подходит modpoll. Если на сборщике уже запущен шлюз mbusd:
modpoll -m tcp -0 -a 1 -r 0 -c 10 127.0.0.1
Флаги здесь важны. -m tcp — транспорт Modbus TCP. -0 включает PDU-адресацию, то есть нумерацию регистров с нуля. -a 1 — Modbus-адрес датчика. -r 0 -c 10 — читать 10 регистров начиная с нулевого.
При успешном ответе вывод будет примерно таким:
root@napi-rk3308b-s:~# modpoll -m tcp -0 -a 1 -r 0 -c 10 127.0.0.1modpoll 3.11 - FieldTalk(tm) Modbus(R) Master Simulator Protocol configuration: MODBUS/TCP, FC3Slave configuration...: address = 1, start reference = 0 (PDU), count = 10 -- Polling slave...[0]: 0[1]: 815[2]: 3881[3]: 2639[4]: 7950[5]: 1124[6]: 5223[7]: 0[8]: 0[9]: 0
По документации на DL-303 (или прямо по дисплею датчика — у него есть встроенный экран) расшифровываем регистры:
|
Регистр |
Параметр |
Множитель (scale) |
|
0 |
CO (ppm) |
1.0 |
|
1 |
CO2 (ppm) |
1.0 |
|
2 |
Влажность (%) |
0.1 |
|
3 |
Температура |
0.1 |
|
5 |
Точка росы |
0.1 |
Значение 2639 в регистре 3 — это 263.9, то есть 26.39 C при scale=0.1. Регистр 4 в этой документации не используется, регистр 5 — точка росы.
Если modpoll вернул данные — датчик отвечает. Если нет — проблема в физике (провода A/B, полярность, терминирование) или в адресе. Разбираемся там, потом идем к Telegraf.
Шаг 1. Конфиг Telegraf — Modbus TCP
Создаем файл /etc/telegraf/telegraf.d/dl303.conf. На NapiLinux шаблон можно загрузить через веб-интерфейс NapiConfig — раздел «Датчики» -> «Управление датчиками» -> «Загрузить шаблон». На любом другом хосте это просто текстовый файл.
Полный конфиг с секцией output:
## DL-303 (CO, CO2, температура, влажность) — Modbus TCP[[inputs.modbus]] name = "DL-303" slave_id = 1 timeout = "1s" # mbusd слушает на 127.0.0.1:502 controller = "tcp://127.0.0.1:502" input_registers = [{ measurement="DL-303", name="CO", byte_order="AB", data_type="UINT16", scale=1.0, address=[0] },{ measurement="DL-303", name="CO2", byte_order="AB", data_type="UINT16", scale=1.0, address=[1] },{ measurement="DL-303", name="Humidity", byte_order="AB", data_type="UINT16", scale=0.1, address=[2] },{ measurement="DL-303", name="Temp", byte_order="AB", data_type="UINT16", scale=0.1, address=[3] },{ measurement="DL-303", name="DewPoint", byte_order="AB", data_type="UINT16", scale=0.1, address=[5] }, ][[outputs.influxdb_v2]] urls = ["http://127.0.0.1:8086"] token = "ВАШ_ТОКЕН" organization = "myorg" bucket = "sensors"
Пройдемся по полям, которые вызывают вопросы чаще всего.
byte_order = «AB» — Порядок байт big-endian. Стандарт для большинства Modbus-устройств. Если значения выглядят бессмысленно — попробуйте «BA». Правильный порядок всегда есть в паспорте датчика.
data_type = «UINT16» — Беззнаковое 16-битное целое. DL-303 отдает данные именно так. Для датчиков с отрицательными значениями нужен INT16. Некоторые устройства отдают float — тогда FLOAT32 или FLOAT32-IEEE, и address принимает два регистра: address = [3, 4].
scale — Множитель, применяется к сырому значению. Для Humidity и Temp ставим 0.1, потому что датчик умножает значение на 10 перед записью в регистр.
address = [N] — PDU-адрес регистра, считается с нуля. Если документация использует нотацию 40001, 40002 (Modbus-нотация) — вычтите 1 и уберите ведущую цифру 4.
Шаг 2. Конфиг для Modbus RTU (датчик напрямую по RS485)
Если шлюза RTU -> TCP нет и датчик подключен физически к порту RS-485 сборщика, меняем секцию подключения:
[[inputs.modbus]] name = "DL-303" slave_id = 1 timeout = "1s" controller = "file:///dev/ttyS3" # RS485-порт на NAPI-C transmission_mode = "RTU" baud_rate = 9600 data_bits = 8 parity = "N" stop_bits = 1 # input_registers — те же, что в TCP-варианте input_registers = [{ measurement="DL-303", name="CO", byte_order="AB", data_type="UINT16", scale=1.0, address=[0] },{ measurement="DL-303", name="CO2", byte_order="AB", data_type="UINT16", scale=1.0, address=[1] },{ measurement="DL-303", name="Humidity", byte_order="AB", data_type="UINT16", scale=0.1, address=[2] },{ measurement="DL-303", name="Temp", byte_order="AB", data_type="UINT16", scale=0.1, address=[3] },{ measurement="DL-303", name="DewPoint", byte_order="AB", data_type="UINT16", scale=0.1, address=[5] }, ]
Имя порта зависит от платформы:
• /dev/ttyS3 — NAPI-C (RK3308)
• /dev/ttyUSB0 — USB-адаптер RS485 на любом хосте
• /dev/ttyAMA0 — Raspberry Pi (аппаратный UART)
Параметры порта (baud_rate, data_bits, parity, stop_bits) должны точно совпадать с тем, что выставлено на датчике. Если хоть один параметр не совпадает — данных не будет, и Telegraf запишет ошибку в лог. Это самая частая причина, почему «датчик молчит».
Даже при прямом RS485-подключении удобнее запустить mbusd и работать через Modbus TCP. Тогда можно параллельно отлаживать через modpoll, не останавливая Telegraf.
Шаг 3. Тестовый запуск до перезапуска службы
Запускать telegraf в тестовом режиме — хорошая привычка. Он выполнит опрос датчика один раз и выведет результат в stdout без записи в базу:
telegraf --config /etc/telegraf/telegraf.d/dl303.conf --test
При успешном опросе вывод будет примерно таким:
> DL-303,host=napi-rk3308b-s CO=0,CO2=815,Humidity=38.81,Temp=26.39,DewPoint=11.24 1718012345000000000
Это Line Protocol — то, что Telegraf запишет в InfluxDB. Реальные числа в выводе означают, что конфиг рабочий. Добились чистого вывода — перезапускаем службу:
systemctl restart telegraf
Теперь про типичные ошибки при тесте:
connection refused — шлюз mbusd не запущен или неверный адрес в поле controller.
i/o timeout — датчик не отвечает. Проверяем slave_id, параметры порта, полярность проводов A/B.
invalid character — синтаксическая ошибка в TOML. Смотрим на кавычки и лишние пробелы.
connection reset by peer — при RTU — скорость или параметры порта не совпадают с датчиком.
Шаг 4. Grafana — дашборд
После того, как данные пошли в InfluxDB, подключаем Grafana. Data Sources -> Add data source -> InfluxDB, Query Language: Flux. URL, токен и организация — те же, что в конфиге Telegraf.
Простейший Flux-запрос для графика температуры:
from(bucket: "sensors") |> range(start: -1h) |> filter(fn: (r) => r._measurement == "DL-303") |> filter(fn: (r) => r._field == "Temp")
Добавьте панель для каждого поля (CO2, Humidity, DewPoint) — дашборд готов. Для DL-303 разумно сразу поставить алерт на CO2 > 1000 ppm и CO > 50 ppm — это нормы по СанПиН для рабочих помещений. Grafana уведомит по email, Telegram или любым другим каналом.
Готовые JSON-шаблоны дашбордов для распространенных датчиков, включая DL-303 можно взять: github.com/lab240/telegraf-grafana-configs.
А если несколько датчиков на одной шине
RS-485 поддерживает до 32 устройств на сегмент без дополнительного оборудования. Каждому датчику нужен уникальный slave_id на шине и уникальное measurement в конфиге. Удобнее всего разложить по отдельным файлам в telegraf.d/ — Telegraf подберет все автоматически при рестарте:
/etc/telegraf/telegraf.d/ dl303-room1.conf# slave_id=1, measurement="DL-303-room1" dl303-room2.conf# slave_id=2, measurement="DL-303-room2" pressure.conf # slave_id=3, measurement="PressureSensor" ## Датчик 1[[inputs.modbus]] name = "DL-303-room1" slave_id = 1 controller = "file:///dev/ttyS3" ... ## Датчик 2[[inputs.modbus]] name = "DL-303-room2" slave_id = 2 controller = "file:///dev/ttyS3" ...
Telegraf опрашивает датчики последовательно — один запрос, один ответ. Если 10 датчиков x 500 мс timeout = 5 секунд на цикл, то интервал опроса в 1 секунду нереалистичен. При большом числе устройств увеличивайте timeout или interval.
Что делать с датчиком, если он без документации
Так бывает: датчик на руках, написано только «Modbus RTU, 9600 8N1, адрес 1», а документации нет. Алгоритм простой.
1. Опросить первые 30-40 holding-регистров подряд.
modpoll -m tcp -0 -a 1 -r 0 -c 40 127.0.0.1
2. Сравнить вывод с тем, что показывает датчик на дисплее или в родном ПО.
Значение 265 при температуре 26.5 C на экране — это регистр с scale=0.1. Значение 4587 при давлении 458.7 гПа — тоже scale=0.1. По таким совпадениям определяем, какой регистр что означает.
3. Учесть масштаб (scale) — часто датчик отдает значение умноженное на 10 или 100.
4. Для датчиков с float: некоторые устройства упаковывают 32-битный float в два соседних регистра.
Тогда в конфиге:
{ measurement="MySensor", name="Pressure", byte_order="ABCD", data_type="FLOAT32-IEEE", scale=1.0, address=[3,4] }
Byte_order для float бывает ABCD, DCBA, BADC — перебираем до осмысленного значения.
Графический интерфейс NapiConfig — то же самое без консоли
Весь путь выше пройден через SSH и текстовый редактор. На NapiLinux того же результата можно добиться из веб-интерфейса NapiConfig. Он открывается на порту 443, собран на Vue и FastAPI, ставить отдельно ничего не нужно — интерфейс уже в системе. Три частые операции при работе с датчиками собраны в одном месте. Это правка конфига Telegraf, проверка опроса и просмотр графиков, и все три не требуют консоли и памяти на пути к файлам.
Правка конфига Telegraf. Каждый датчик — это отдельный файл в telegraf.d. В NapiConfig он открывается в редакторе с подсветкой TOML. Правятся те же поля, что в шагах выше — slave_id, controller, адреса регистров, scale, — только без vim по SSH. Рядом кнопки теста и сохранения.
Отладка опроса. Кнопка «Тест» прогоняет telegraf —test на текущем конфиге и показывает результат в окне — строку Line Protocol с реальными значениями, лог Telegraf и код возврата. Это ровно проверка из Шага 3, но вывод идет в интерфейс, а не в stdout. Ошибка в scale, неверный slave_id, молчащий датчик — все увидите, службу перезапускать не надо.
Графики из базы. Раздел «Графики» читает ряды прямо из InfluxDB и строит их по выбранному регистру. Есть выбор поля, временной диапазон и множитель, так что форму сигнала по сырому значению регистра видно без запуска Grafana. Для быстрой проверки «данные идут и выглядят осмысленно» этого хватает. Grafana остается, скажем так, на своем месте — там, где нужны постоянные дашборды и алерты.
Заодно в NapiConfig есть страница Modbus-шлюза — тот самый мост RTU в TCP через mbusd из Шага 0, настраивается мышкой. Плюс управление сетевыми интерфейсами, службами systemd, просмотр логов и веб-терминал SSH на случай, если консоль все-таки понадобится.
Полный разбор стека с нуля есть на Хабре в статье Александра Фролова «Собираем метрики с датчиков через Modbus и Telegraf». Автор ставит Telegraf, InfluxDB и Grafana на разное железо — Raspberry Pi, Orange Pi, Repka Pi и модуль Front Control Compact, — подключает датчики XY-MD02 и PZEM-016 по RS485, разбирает настройку InfluxDB, срок хранения данных и работу через NapiConfig, все с командами mbpoll и скриншотами веб-интерфейса.
Статья А.Фролова будет полезной точкой входа, если стек поднимается вручную, а не на NapiLinux.
Выводы
Весь путь от подключенного датчика до рабочего дашборда:
1. Физически подключить RS485, убедиться через modpoll что датчик отвечает.
2. Написать конфиг Telegraf — 15-20 строк TOML.
3. Прогнать telegraf —test, убедиться что значения на выходе реальные.
4. Перезапустить службу, добавить панели в Grafana.
Telegraf берет на себя опрос, буферизацию и запись в базу. При потере связи с датчиком он записывает ошибку в лог и продолжает работать — следующий опрос будет через заданный интервал (по умолчанию 10 секунд). При восстановлении связи данные идут дальше без какого-либо вмешательства.
Стек (Telegraf + InfluxDB + Grafana) одинаково работает на ARM-сборщике в цеху и на x86-сервере в серверной. Данные локальны, лицензий нет, сообщества активны.
Хелп:
Веб-страница с диаграммами подключения
https://napiworld.ru/software/sensors/telegraf-modbus/
Шаблоны конфигов Telegraf и дашборды Grafana для разных датчиков: github.com/lab240/telegraf-grafana-configs
Документация плагина modbus: github.com/influxdata/telegraf/blob/master/plugins/inputs/modbus/README.md
Если будут вопросы по статье, реализациям или требуется дополнительная информация, просьба писать мне в ЛС.
ссылка на оригинал статьи https://habr.com/ru/articles/1055824/