Wb-mqtt-mbgate
Сервис wb-mqtt-mbgate: Modbus-slave для внешних SCADA и ПЛК
Описание
Сервис wb-mqtt-mbgate делает контроллер Wiren Board Modbus-slave-устройством. Внешняя система (SCADA, ПЛК, операторская панель, диспетчерский сервер) читает данные с контроллера и отправляет команды по Modbus TCP или Modbus RTU.
Шлюз привязывает выбранные MQTT-каналы контроллера к Modbus-регистрам. Источник канала может быть любой: драйвер wb-mqtt-serial, опрашивающий устройства по RS-485 и другим интерфейсам; правило wb-rules; внешний скрипт.
Шлюз не работает в режиме Modbus-мастера и не опрашивает внешние устройства — для этого используется wb-mqtt-serial.
Когда это нужно
Типичные сценарии:
- SCADA с Modbus TCP. Контроллер выступает как slave, SCADA опрашивает регистры. Например, MasterSCADA, Inspector SCADA, IRidium Server.
- ПЛК верхнего уровня по Modbus TCP или RTU — ОВЕН, Schneider Electric, Siemens.
- Существующая сеть Modbus RTU, где диспетчерский пульт уже опрашивает приборы по RS-485.
- Операторская панель (HMI), работающая только с Modbus.
- Несколько slave-устройств в одном контроллере. Каналам назначаются разные
unit-id, и внешней системе контроллер представляется как несколько приборов на одной шине или одном TCP-подключении. Удобно при замене устаревших устройств с сохранением старой карты регистров.
Когда не нужно
Если внешняя система поддерживает несколько протоколов, выбирайте подходящий способ интеграции.
| Что поддерживает внешняя система | Что использовать |
|---|---|
| MQTT | Прямое подключение к MQTT |
| Modbus TCP или Modbus RTU | Шлюз wb-mqtt-mbgate, эта статья
|
| OPC UA | OPC UA |
| МЭК 60870-5-104 | Шлюз wb-mqtt-iec104
|
Если на контроллере работает SCADA-runtime, читающий MQTT напрямую (например, MasterSCADA 4D), промежуточное представление через Modbus не нужно.
Совместимость и требования
Шлюз wb-mqtt-mbgate входит в стандартную поставку прошивки Wiren Board и не требует отдельной установки. Контроллеры WB имеют два или более RS-485-порта — этого достаточно для одновременной работы шлюза в режиме RTU и драйвера wb-mqtt-serial на разных портах.
Внимание. Modbus TCP не аутентифицирует подключения: любой клиент с сетевым доступом к порту
502может читать регистры, а при наличии привязок Coil или Holding Register на запись — управлять реле и менять уставки. Ограничивайте доступ к порту средствами сети: firewall, отдельный VLAN, разрешение подключений только с адреса SCADA. Логин и пароль из раздела Подключение к MQTT-брокеру защищают соединение с MQTT-брокером, а не Modbus-сторону.
Принцип работы
Шлюз связывает MQTT-топики контроллера с Modbus-регистрами, видимыми внешней системе. Каждый MQTT-канал вида /devices/<DEVICE>/controls/<CHANNEL> можно привязать к Modbus-регистру; в конфигураторе он отображается как <DEVICE>/<CHANNEL> (например, wb-msw-v4_21/Temperature).
Конфигуратор берёт каналы из MQTT-брокера. Выбираются нужные, задаются unit-id и адрес регистра — значения становятся доступны по Modbus.
Поток данных
На запись Modbus-регистра шлюз публикует команду в /on-топик канала, а реагирует на неё обработчик канала: драйвер устройства передаёт команду по шине, обработчик правила wb-rules или внешний скрипт обрабатывает её программно.
Для физических Modbus-устройств, привязанных через wb-mqtt-serial, поток выглядит следующим образом. Чтение направлено от устройства к внешней системе: устройство → драйвер → MQTT → wb-mqtt-mbgate → Modbus-регистр → SCADA. Запись — в обратную сторону: SCADA → Modbus-регистр → wb-mqtt-mbgate → MQTT-топик /on канала → драйвер → устройство.
Запись асинхронная. Получив Modbus-команду записи, шлюз публикует значение в соответствующий MQTT-топик и сразу возвращает SCADA штатный Modbus-ответ — не дожидаясь, пока команда достигнет устройства. Драйвер передаёт значение по физической шине и при успешной записи публикует это же значение в MQTT как новое состояние канала. Шлюз обновляет кэш регистра, и SCADA получает его при следующем Modbus-чтении. Фактическое состояние устройства драйвер сверяет уже в следующем цикле опроса.
Типы Modbus-регистров
Шлюз использует все четыре стандартных типа регистров.
| Тип | Доступ | Ширина | Подходящий MQTT-канал |
|---|---|---|---|
| Discrete Input | чтение | 1 бит | дискретный, только чтение (например, состояние входа) |
| Coil | чтение и запись | 1 бит | дискретный, чтение и запись (реле) |
| Input Register | чтение | 16+ бит | числовой, только чтение (температура, напряжение) |
| Holding Register | чтение и запись | 16+ бит | числовой, чтение и запись (уставка, яркость) |
При добавлении канала конфигуратор предлагает подходящий тип по метаданным MQTT-канала; при необходимости тип меняется вручную. В read-only канал записи не пройдут даже через Coil/Holding Register: шлюз вернёт SCADA штатный Modbus-ответ, но обработчика записи на стороне MQTT-источника нет — состояние не изменится.
Шлюз поддерживает только функциональные коды чтения и записи стандартных регистров: 0x01, 0x02, 0x03, 0x04 (чтение), 0x05, 0x06, 0x0F, 0x10 (запись). Запрос с любым другим кодом функции (диагностика, работа с файлами, encapsulated transport) в текущей версии приводит к аварийному завершению сервиса — systemd перезапускает его примерно через 10 секунд. На стороне клиента используйте только перечисленные коды. Подробнее о функциональных кодах — Modbus.
Адресация и unit-id
Привязка канала к регистру задаётся двумя адресными параметрами: unit-id (1…255, в конфигураторе ID данных Modbus) — Modbus-адрес slave-устройства, и начальный адрес (0…65535) — позиция регистра внутри unit-id. Разным каналам можно назначать разные unit-id — внешней системе контроллер представляется как несколько slave-устройств на одном TCP-подключении или RTU-шине.
Автоприсваивание адресов
По умолчанию unit-id и адрес регистра считаются автоматически — конфигуратор хеширует имя канала. Алгоритм детерминирован: одинаковые имена каналов на разных контроллерах дают одинаковые адреса, и конфигурацию можно копировать без правки. Unit-id 0, 1, 2 и 247…255 автоприсваивание не использует — они оставлены для ручного назначения под каналы, которые SCADA или ПЛК ждёт на конкретном slave-адресе.
Совместимость с клиентами на unit-id = 1
Часть Modbus TCP-клиентов игнорирует unit-id и всегда подставляет 1 (реже — 255). Автоприсваивание выбирает unit-id из диапазона 3…246; эти unit-id недоступны такому клиенту — назначьте нужным каналам unit-id = 1 вручную.
Нумерация адресов регистров
Адреса регистров в wb-mqtt-mbgate нумеруются с нуля. Часть SCADA и Modbus-клиентов отображает их со сдвигом +1: регистр 100 в файле конфигурации показывается во внешней системе как 101. Если чтение не работает, проверьте, как нумерует регистры ваш клиент.
Формат данных
Для дискретных регистров формат не настраивается — это всегда один бит. Для числовых регистров задаются тип данных (format — Signed/Unsigned integer, BCD, IEEE 754 float, Varchar), размер (size — в байтах для чисел и в регистрах для текста), множитель (scale) и порядок байт и слов (byteswap, wordswap).
Размер числовых значений
Один Modbus-регистр содержит 2 байта.
| Тип значения | Размер | Регистров |
|---|---|---|
| 16-битное целое | 2 байта | 1 |
| 32-битное целое | 4 байта | 2 |
| 64-битное целое | 8 байт | 4 |
float (одинарная точность)
|
4 байта | 2 |
double (двойная точность)
|
8 байт | 4 |
varchar
|
задаётся в регистрах | по заданной длине |
Многорегистровые значения должны читаться целиком одним запросом. При размещении учитывайте, что они занимают несколько последовательных адресов регистров: float размером 4 байта с адреса 100 занимает регистры 100 и 101, следующее значение — не раньше 102.
Множитель
Параметр scale задаёт коэффициент пересчёта между MQTT и Modbus. Чтение: значение в Modbus = значение в MQTT × scale. Запись: значение в MQTT = значение в Modbus ÷ scale. Пример: температура 23.6 °C при scale = 10 передаётся как 236 (0x00EC); напряжение 220.3 В при scale = 10 — как 2203 (0x089B).
Внимание. При
scale = 0шлюз не выдаёт ошибку, но портит данные без какой-либо диагностики: на чтение в регистре всегда оказывается0независимо от значения в MQTT, на запись в MQTT-топик публикуется строка"inf". Если масштабирование не нужно, оставляйтеscale = 1.
Порядок байт и слов
По умолчанию используется big-endian — стандарт Modbus. Два флага меняют порядок: Обратный порядок байт в словах (byteswap) переставляет байты внутри 16-битного регистра, Обратный порядок слов (wordswap) — 16-битные слова в составном значении. Для полного little-endian нужны оба флага сразу; по одному они дают промежуточные раскладки, которые тоже встречаются в реальных системах.
Для 16-битных значений (один регистр) wordswap не имеет эффекта — у одного регистра нет второго слова для перестановки. byteswap нужен только если устройство нестандартно возвращает байты внутри регистра в обратном порядке; большинство устройств следуют стандарту Modbus, и флаг остаётся выключенным. На 32- и 64-битных типах (включая float и double) актуальны оба флага.
Кэш и латентность чтения
Шлюз держит локальный кэш всех привязанных регистров и обновляет его на каждое MQTT-сообщение. Modbus-запрос на чтение возвращает значение из кэша на момент запроса — без обращения к брокеру.
Задержка чтения определяется частотой публикаций в MQTT, а не быстродействием Modbus: для датчика, публикующего раз в минуту, значение в кэше может отставать от реального до минуты — независимо от того, как часто его опрашивает SCADA.
При записи (Coil или Holding Register) шлюз обновляет кэш сразу же. Modbus-клиент, читающий регистр сразу после собственной записи, прочитает свою команду — даже если устройство ещё не подтвердило исполнение.
Быстрый старт: Modbus TCP
Контроллер передаёт в SCADA по Modbus TCP две величины с датчика WB-MSW v.4: температуру и влажность. SCADA подключается по IP контроллера и читает Input Registers.
Итоговая карта регистров:
| MQTT-канал | Тип регистра | unit-id | Адрес | Формат | Множитель |
|---|---|---|---|---|---|
wb-msw-v4_21/Temperature
|
Input Register | 1 | 100 | signed, 2 байта | 10 |
wb-msw-v4_21/Humidity
|
Input Register | 1 | 101 | unsigned, 2 байта | 10 |
При температуре 23.6 °C SCADA прочитает в регистре 100 значение 236.
Настройка через веб-интерфейс.
- Откройте Настройки → Конфигурационные файлы → Шлюз MQTT - Modbus RTU/TCP slave.
- Выберите режим TCP. Оставьте значения по умолчанию: IP-адрес
*, Порт502. - В разделе Соответствия каналов и регистров добавьте канал
wb-msw-v4_21/Temperatureсо значениями: ID данных Modbus —1, Начальный адрес —100, Тип данных — Знаковое целое, Размер в байтах —2, Множитель —10. - Аналогично добавьте
wb-msw-v4_21/Humidity: Начальный адрес —101, Тип данных — Беззнаковое целое, остальные поля те же. - Нажмите Сохранить. Сервис перезапустится автоматически.
JSON-конфигурация (/etc/wb-mqtt-mbgate.conf):
{
"debug": false,
"modbus": { "host": "*", "port": 502 },
"mqtt": { "host": "/var/run/mosquitto/mosquitto.sock", "port": 0 },
"registers": {
"discretes": [],
"coils": [],
"inputs": [
{ "enabled": true, "topic": "wb-msw-v4_21/Temperature",
"unitId": 1, "address": 100,
"format": "signed", "size": 2, "scale": 10,
"byteswap": false, "wordswap": false },
{ "enabled": true, "topic": "wb-msw-v4_21/Humidity",
"unitId": 1, "address": 101,
"format": "unsigned", "size": 2, "scale": 10,
"byteswap": false, "wordswap": false }
],
"holdings": []
}
}
Проверка. С компьютера в той же сети или с самого контроллера:
modbus_client --debug -mtcp -a1 -t0x04 -r100 -c1 -p502 192.168.1.50
Флаги: -mtcp — TCP-режим, -a1 — unit-id, -t0x04 — чтение Input Registers, -r100 — адрес регистра, -c1 — число регистров, -p502 — TCP-порт, последний аргумент — IP контроллера. Ожидаемый вывод — Data: 0x00ec, после деления на множитель — температура 23.6 °C.
Быстрый старт: Modbus RTU
Контроллер подключён к ПЛК по RS-485 и работает как Modbus-slave в режиме RTU с unit-id 10. ПЛК читает температуру с датчика WB-MSW v.4 и управляет реле K1 на модуле WB-MR6C v.3.
Карта регистров:
| MQTT-канал | Тип регистра | unit-id | Адрес | Формат |
|---|---|---|---|---|
wb-msw-v4_21/Temperature
|
Input Register | 10 | 100 | signed, 2 байта, множитель 10 |
wb-mr6c_12/K1
|
Coil | 10 | 0 | — |
Подготовка порта. Шлюз будет отвечать через /dev/ttyRS485-2. Этот порт нельзя одновременно использовать с драйвером wb-mqtt-serial — отключите его в Настройки → Конфигурационные файлы → Настройка драйвера serial-устройств.
Настройка через веб-интерфейс.
- Откройте Настройки → Конфигурационные файлы → Шлюз MQTT - Modbus RTU/TCP slave.
- Выберите режим RTU. Укажите Путь к устройству
/dev/ttyRS485-2. Скорость, число бит, чётность, стоп-биты задайте в соответствии с настройками ПЛК (типичные значения: 9600, 8, N, 2). - Добавьте канал
wb-msw-v4_21/Temperature: ID данных Modbus —10, Начальный адрес —100. Остальные параметры — как в разделе Быстрый старт: Modbus TCP выше. - Добавьте канал
wb-mr6c_12/K1: ID данных Modbus —10, Начальный адрес —0. Канал автоматически попадает в раздел Coils. - Нажмите Сохранить.
JSON-конфигурация:
{
"debug": false,
"modbus": { "path": "/dev/ttyRS485-2",
"baud_rate": 9600, "parity": "N",
"data_bits": 8, "stop_bits": 2 },
"mqtt": { "host": "/var/run/mosquitto/mosquitto.sock", "port": 0 },
"registers": {
"discretes": [],
"coils": [
{ "enabled": true, "topic": "wb-mr6c_12/K1",
"unitId": 10, "address": 0 }
],
"inputs": [
{ "enabled": true, "topic": "wb-msw-v4_21/Temperature",
"unitId": 10, "address": 100,
"format": "signed", "size": 2, "scale": 10,
"byteswap": false, "wordswap": false }
],
"holdings": []
}
}
Проверка. Проверять RTU нужно с устройства, физически подключённого к той же RS-485-шине — внешнего ПЛК, компьютера с USB-RS-485-преобразователем или другого контроллера Wiren Board.
Чтение температуры:
modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyUSB0 -a10 -t0x04 -r100 -c1
Включение реле K1:
modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyUSB0 -a10 -t0x05 -r0 1
Параметры идентичны TCP-сценарию, кроме -mrtu (режим), -b9600 -pnone -s2 (параметры порта) и /dev/ttyUSB0 (USB-RS-485-преобразователь на стороне клиента; на контроллере Wiren Board это /dev/ttyRS485-1 или другой порт). -t0x05 — запись одиночного Coil, последний аргумент — значение (1 для включения). После записи реле физически срабатывает.
Справочник настроек
Шлюз настраивается через веб-интерфейс (раздел Настройки → Конфигурационные файлы → Шлюз MQTT - Modbus RTU/TCP slave) или прямым редактированием /etc/wb-mqtt-mbgate.conf. Оба способа работают с одним и тем же файлом.
Режим работы — Modbus TCP
| Поле формы | JSON-ключ | Описание |
|---|---|---|
| IP-адрес | host
|
IP-адрес или имя хоста для приёма подключений. * — любой адрес контроллера.
|
| Порт | port
|
TCP-порт. По умолчанию 502.
|
Режим работы — Modbus RTU
| Поле формы | JSON-ключ | Описание |
|---|---|---|
| Путь к устройству | path
|
Serial-порт, например /dev/ttyRS485-2.
|
| Скорость обмена | baud_rate
|
110, 300, 600, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200. |
| Контроль чётности | parity
|
N / E / O.
|
| Число бит данных | data_bits
|
5…8, обычно 8.
|
| Стоп биты | stop_bits
|
1 или 2.
|
Параметры RTU должны совпадать с настройками внешней системы. Порт не должен использоваться драйвером wb-mqtt-serial.
Подключение к MQTT-брокеру
| Поле формы | JSON-ключ | Описание |
|---|---|---|
| Адрес | host
|
Адрес брокера. По умолчанию — локальный UNIX-сокет /var/run/mosquitto/mosquitto.sock.
|
| Порт | port
|
Порт брокера. 0 для UNIX-сокета, 1883 для стандартного TCP.
|
| Интервал ожидания ответа | keepalive
|
Интервал MQTT keep-alive в секундах. По умолчанию 60.
|
| Включить аутентификацию по логину и паролю | auth
|
Использовать логин и пароль, если брокер их требует. |
| Логин | username
|
Имя пользователя при включённой аутентификации. |
| Пароль | password
|
Пароль. |
В большинстве случаев эти параметры менять не нужно — шлюз работает с локальным брокером контроллера.
Привязка канала к регистру
Общие поля для всех типов регистров:
| Поле формы | JSON-ключ | Описание |
|---|---|---|
| Включить | enabled
|
Включает привязку. Выключенные привязки игнорируются. |
| Канал MQTT | topic
|
Канал в формате <DEVICE>/<CHANNEL>.
|
| ID данных Modbus | unitId
|
unit-id slave-устройства, 1…255.
|
| Начальный адрес | address
|
Адрес регистра внутри unitId, 0…65535.
|
Дополнительно для Input Register и Holding Register:
| Поле формы | JSON-ключ | Описание |
|---|---|---|
| Тип данных | format
|
signed, unsigned, bcd, float, varchar.
|
| Размер в байтах (в регистрах для текста) | size
|
Размер значения. |
| Множитель | scale
|
Коэффициент пересчёта между MQTT и Modbus. |
| Обратный порядок байт в словах | byteswap
|
Меняет порядок байт внутри 16-битных регистров. |
| Обратный порядок слов | wordswap
|
Меняет порядок 16-битных слов в составном значении. |
Подробнее о форматах и порядке байт — раздел Формат данных выше.
Параметры командной строки
Сервис запускается через systemd и параметры берёт из файла конфигурации. При ручном запуске:
wb-mqtt-mbgate [-d <level>] [-c <config>]
| Флаг | Назначение |
|---|---|
-d 1
|
Отладочные сообщения шлюза. |
-d 2
|
Отладочные сообщения MQTT-библиотеки. |
-d 3
|
И то и другое. |
-d -1, -d -2, -d -3
|
Подавление информационных сообщений (шлюза, MQTT, обоих). |
-c <path>
|
Альтернативный путь к файлу конфигурации. По умолчанию /etc/wb-mqtt-mbgate.conf.
|
Сценарии интеграции
Произвольная карта регистров
Если внешняя система ожидает конкретную карту регистров — например, по требованию интегратора — unit-id и адрес регистра задаются вручную. Автоприсваивание не перезаписывает явно заданные значения.
Пример из ТЗ:
| Параметр | unit-id | Регистр | Тип |
|---|---|---|---|
| Температура помещения | 1 | 100 | Input Register |
| Влажность помещения | 1 | 101 | Input Register |
| Состояние реле освещения | 1 | 0 | Coil |
| Уставка температуры | 1 | 200 | Holding Register |
В конфигураторе для каждого канала открывается соответствующий тип, заполняются ID данных Modbus и Начальный адрес, остальные параметры — по форматам из ТЗ.
Несколько unit-id в одной карте
Удобно, когда SCADA ожидает несколько slave-устройств или контроллер заменяет несколько отдельных приборов с сохранением их unit-id и адресов регистров:
| Группа | unit-id | Адреса |
|---|---|---|
| Датчики климата | 10 | 100…199 |
| Релейные модули | 11 | 0…99 |
| Уставки | 12 | 200…299 |
См. раздел Адресация и unit-id выше.
Один unit-id и общая таблица
Если SCADA работает только с одним slave-устройством, всем каналам назначается один unit-id, а данные распределяются по диапазонам адресов регистров:
| Диапазон | Что хранится |
|---|---|
| 0…99 | Дискретные сигналы |
| 100…199 | Климат |
| 200…299 | Электросчётчики |
| 300…399 | Уставки |
Диапазон адресов регистров одного unit-id — 0…65535. При размещении многорегистровых значений (32-битное целое, float) учитывайте, что они занимают несколько последовательных адресов регистров — оставляйте место под все регистры значения.
Виртуальное устройство в wb-rules
Если внешней системе нужно отдать не показания одного физического устройства, а вычисленное или агрегированное значение, его собирают в правиле wb-rules как виртуальное устройство и привязывают к Modbus-регистру так же, как любой физический канал.
Задача: SCADA читает один регистр, содержащий сумму активных мощностей с четырёх электросчётчиков meter-1…meter-4, опрашиваемых драйвером wb-mqtt-serial по RS-485.
Правило в wb-rules (/etc/wb-rules/power-total.js):
defineVirtualDevice("power-total", {
title: "Суммарная активная мощность",
cells: {
Sum: { type: "power", value: 0, readonly: true, units: "W" }
}
});
defineRule("update-power-total", {
whenChanged: ["meter-1/Pa", "meter-2/Pa", "meter-3/Pa", "meter-4/Pa"],
then: function() {
dev["power-total/Sum"] =
(dev["meter-1/Pa"] || 0) +
(dev["meter-2/Pa"] || 0) +
(dev["meter-3/Pa"] || 0) +
(dev["meter-4/Pa"] || 0);
}
});
После сохранения правила в MQTT-брокере появляется новое устройство power-total с каналом Sum. Канал обновляется при каждом изменении любого из четырёх входных.
Привязка в wb-mqtt-mbgate:
| MQTT-канал | Тип регистра | unit-id | Адрес | Формат |
|---|---|---|---|---|
power-total/Sum
|
Input Register | 1 | 200 | signed, 4 байта |
SCADA читает регистр 200 на unit-id 1 и получает текущую сумму. Задержка совпадает с частотой публикаций в MQTT (см. раздел Кэш и латентность чтения) — регистр обновляется при каждом изменении любого из четырёх счётчиков.
Пример минимальный и не отслеживает достоверность входных каналов: если счётчик пропадёт со связи, в сумме продолжит учитываться его последнее значение, а сумма на стороне SCADA не получит признака ошибки. В ответственных задачах добавьте в правило контроль ошибки входных каналов.
Управление сервисом и диагностика
Команды управления
systemctl status wb-mqtt-mbgate # состояние сервиса
systemctl restart wb-mqtt-mbgate # перезапуск
journalctl -u wb-mqtt-mbgate -n 100 # последние 100 строк журнала
journalctl -u wb-mqtt-mbgate -f # журнал в реальном времени
Сервис автоматически перезапускается при сбоях (рестарт через 10 секунд) и не перезапускается при ошибках конфигурации — конфигурацию нужно сначала исправить.
Сохранение конфигурации перезапускает сервис: на время перезапуска опрос прерывается, активные Modbus TCP-подключения разрываются и устанавливаются заново. Правьте карту регистров, когда кратковременный обрыв опроса со стороны SCADA допустим.
Коды выхода
| Код | Значение | Поведение systemd |
|---|---|---|
| 0 | Штатное завершение | success |
| 1 | Внутренняя ошибка или таймаут остановки | автоматический перезапуск |
| 2 | Неверные аргументы командной строки | не перезапускается |
| 6 | Невалидная конфигурация | не перезапускается |
| 7 | Все каналы выключены (enabled: false)
|
success — сервис в inactive (dead), а не failed
|
Код 7 — нормальное состояние, если конфигурация ещё не заполнена. Сервис будет автоматически запущен после сохранения конфигурации с включёнными каналами.
Ограничения и особенности эксплуатации
- Нет режима master. Шлюз работает только как slave. Для опроса внешних Modbus-устройств —
wb-mqtt-serial. - Один режим на инстанс. Шлюз работает либо в TCP, либо в RTU — одновременно нельзя.
- RTU-порт занят эксклюзивно. Тот же порт нельзя одновременно использовать в
wb-mqtt-serial. - Латентность чтения определяется MQTT — см. раздел Кэш и латентность чтения.
- Modbus TCP без аутентификации. Доступ к порту
502нужно ограничивать средствами сети — см. Совместимость и требования. - Неподдерживаемый код функции завершает сервис (диагностика, файлы, encapsulated transport) — см. Типы Modbus-регистров.
scale = 0тихо портит данные — см. Множитель.
Проверка обмена через modbus_client
| Что проверить | Функция | Пример |
|---|---|---|
| Чтение Coil | 0x01
|
состояние реле |
| Чтение Discrete Input | 0x02
|
состояние входа |
| Чтение Holding Register | 0x03
|
уставка |
| Чтение Input Register | 0x04
|
измерение |
| Запись одиночного Coil | 0x05
|
включить реле |
| Запись одиночного Holding Register | 0x06
|
задать уставку |
| Запись нескольких Coils | 0x0F
|
групповое управление реле |
| Запись нескольких Holding Registers | 0x10
|
пакетная запись параметров |
Полный синтаксис команд — Modbus-client.
Типичные проблемы
Внешняя система не получает значения. Проверить по порядку: запущен ли сервис (systemctl status wb-mqtt-mbgate); есть ли значение в MQTT (mosquitto_sub -v -t '/devices/+/controls/+'); включена ли привязка в конфигурации (enabled: true); правильно ли указаны unit-id и тип регистра; нет ли сдвига адреса регистра на 1 во внешней системе.
Чтение работает, но значение не соответствует ожидаемому. Проверить размер значения (число регистров, читаемых внешней системой), тип данных, множитель, флаги порядка байт и слов. Например, четырёхбайтовый float, прочитанный как один регистр, даст некорректный результат.
Запись в регистр проходит, но устройство не реагирует. Канал в MQTT должен быть доступен на запись (не помечен как read-only) и привязан к Coil (для дискретных) или Holding Register (для числовых). Проверить, появляется ли новое значение в MQTT после записи: mosquitto_sub -v -t '/devices/<DEVICE>/controls/<CHANNEL>'.
В режиме RTU нет ответа. Проверить: освобождён ли порт от wb-mqtt-serial; совпадают ли скорость, чётность, биты данных, стоп-биты с настройками внешней системы; правильно ли подключены линии A/B и есть ли терминатор; нет ли другого устройства с таким же unit-id на шине.
Как отличить ошибку адресации от проблемы связи. Если клиент получает Modbus-исключение Illegal Data Address — связь и unit-id в порядке, но запрошенный адрес регистра не привязан в карте. Если же клиент получает таймаут (в Modbus TCP — соединение установлено, но ответа на запрос нет), то к запрошенному unit-id не привязан ни один регистр: проверьте unit-id в карте, прежде чем искать физическую проблему с подключением устройств.
Сервис не запускается после ручного редактирования файла конфигурации. Проверить JSON: запятые, кавычки, имена полей, вложенность секций modbus, mqtt, registers. Журнал: journalctl -u wb-mqtt-mbgate -n 100. Код выхода 6 в журнале означает, что конфигурация не прошла валидацию по JSON-схеме.
Значение отличается в 10/100/1000 раз. Проверить Множитель. Если в MQTT температура 23.6, а внешняя система получает целое 236 — это ожидаемое поведение при scale = 10. Чтобы передавать значения без масштабирования, задайте scale = 1.
Часто задаваемые вопросы
Можно ли построить произвольную карту регистров? Да — см. раздел Произвольная карта регистров.
Можно ли использовать разные unit-id в одной карте? Да, разным каналам — разные. См. раздел Несколько unit-id в одной карте.
Можно ли использовать один unit-id для всех данных? Да — см. раздел Один unit-id и общая таблица.
Можно ли использовать весь диапазон адресов регистров 0…65535? Да. При размещении учитывайте, что многорегистровые значения занимают несколько последовательных адресов регистров.
Можно ли отдавать дробные значения через целые регистры? Да, через Множитель. Например, температура 23.6 °C при scale = 10 передаётся как целое 236.
Можно ли записывать значения из SCADA обратно в устройство? Да, если MQTT-канал открыт на запись. Для дискретных значений используется Coil, для числовых — Holding Register. Если канал помечен как read-only, шлюз опубликует команду в MQTT, но фактическое состояние не изменится: у read-only канала нет обработчика записи.
Как контроллер узнает, что связь со SCADA пропала? Сам шлюз потерю связи не отслеживает. Стандартный паттерн: завести в wb-rules виртуальное устройство с записываемым каналом, привязать его как Holding Register или Coil и настроить SCADA на периодическую запись в него. Правило wb-rules следит за обновлением этого канала и переводит систему в безопасное состояние, если значение не обновлялось дольше заданного времени.
Что выбрать: Input Register или Holding Register? Автоматически по метаданным MQTT-канала: только чтение — Input, чтение и запись — Holding. Тип можно изменить вручную.
Нужно ли использовать wb-mqtt-mbgate, если внешняя система умеет MQTT? Обычно нет — предпочтительнее подключиться к MQTT-брокеру контроллера напрямую. Шлюз нужен только тогда, когда внешняя система умеет работать исключительно по Modbus.
Можно ли через wb-mqtt-mbgate опрашивать внешние Modbus-устройства? Нет — wb-mqtt-mbgate работает только в slave-режиме; для master-режима используется wb-mqtt-serial.
Полезные ссылки
- Modbus — протокол.
- Modbus-client — командная утилита для проверки обмена.
- MQTT — MQTT-брокер контроллера.
- wb-mqtt-serial — драйвер опроса внешних устройств (master-режим).
- OPC UA — альтернативный шлюз для трансляции MQTT в OPC UA.
- MasterSCADA on Wiren Board — установка SCADA-runtime прямо на контроллер, без шлюза.
- WB-MSW v.4, WB-MR6C v.3 — устройства, использованные в примерах статьи.