Утилита «modbus_client»

From Wiren Board

Описание

modbus_client — утилита для опроса устройств по протоколам Modbus RTU и Modbus TCP из командной строки.

Подготовка к работе

Контроллер Wiren Board

С релиза wb-2310 на контроллеры предустановлена улучшенная утилита modbus_client_rpc — синтаксис идентичен modbus_client, но работает через драйвер wb-mqtt-serial, поэтому можно читать и писать регистры устройств не останавливая драйвер.

Утилита modbus_client из пакета modbus-utils предустановлена на все контроллеры Wiren Board. Для использования утилиты нужно подключиться к контроллеру по протоколу SSH.

Обычно порт RS-485 занят драйвером wb-mqtt-serial, поэтому перед запуском modbus_client этот драйвер надо остановить:

systemctl stop wb-mqtt-serial # для Wiren Board 5 и позднее
systemctl stop wb-homa-modbus # для Wiren Board 4

После завершения работы с modbus_client запустите драйвер обратно:

systemctl start wb-mqtt-serial # для Wiren Board 5 и позднее
systemctl start wb-homa-modbus # для Wiren Board 4

Настольный компьютер с Linux

Скачайте пакет для настольных компьютеров с Linux.

Перейдите в папку со скаченным пакетом и установите его командой:

sudo apt install ./modbus-utils_1.2.10_amd64.deb

Также автоматически должен установиться пакет libmodbus, если этого не произошло — установите его из репозитория apt.

Альтернативный способ собрать пакет из исходников, инструкция по сборке на портале поддержки.

Аргументы командной строки

Значения параметров (адрес устройства или регистра, таймаут, тип функции, значение для записи в регистр и т.д.) можно указывать как в шестнадцатеричном 0x**, так и в десятичном виде.

Вызов modbus_client без аргументов выдает краткое описание возможных аргументов команды:

modbus_client [--debug] [-m {rtu|tcp}] [-a<slave-addr=1>] [-c<read-no>=1]
        [-r<start-addr>=100] [-t<f-type>] [-o<timeout-ms>=1000] [{rtu-params|tcp-params}] serialport|host [<write-data>]
NOTE: if first reference address starts at 0, set -0
f-type:
        (0x01) Read Coils, (0x02) Read Discrete Inputs, (0x05) Write Single Coil
        (0x03) Read Holding Registers, (0x04) Read Input Registers, (0x06) WriteSingle Register
        (0x0F) WriteMultipleCoils, (0x10) Write Multiple register
rtu-params:
        b<baud-rate>=9600
        d{7|8}<data-bits>=8
        s{1|2}<stop-bits>=1
        p{none|even|odd}=even
tcp-params:
        p<port>=502
Examples (run with default mbServer at port 1502): 
        Write data:     modbus_client --debug -mtcp -t0x10 -r0 -p1502 127.0.0.1 0x01 0x02 0x03
        Read that data: modbus_client --debug -mtcp -t0x03 -r0 -p1502 127.0.0.1 -c3

Общие аргументы

Параметр Описание Обязателен Значение по умолчанию
--debug Может указываться в любой позиции и включает отладку, выводя на экран шестнадцатеричные коды отправляемых и принимаемых данных. нет
-m Определяет тип используемого протокола:
  • -mrtu — Modbus RTU,
  • -mtcp — Modbus TCP.

Он должен указываться первым в командной строке, или вторым, если первый аргумент — --debug или имя файла порта RS-485.

да
-a Задает Modbus-адрес устройства, к которому мы обращаемся. нет 1
Определяет, какое количество элементов мы запрашиваем. нет 1
-r Задает начальный адрес для чтения или записи. нет 100
-t Указывает код функции Modbus. Кратко они перечислены в выводе modbus_client, подробнее значения кодов описаны на странице Протокол Modbus. да
-o Задает таймаут в миллисекундах. нет 1000
-0 Ноль. Уменьшает на единицу адрес, задаваемый аргументом -r.
Это может быть полезным при работе с устройствами с нестандартной адресацией, например, с диапазоном адресов 1 — 65536 вместо привычного 0 — 65535.
нет

Затем указываются специфические параметры протокола (Modbus RTU или Modbus TCP). Несмотря на информацию, выводимую в подсказке, эти параметры также начинаются со знака - (минус,дефис).

Для Modbus RTU

Параметр Описание Значение по умолчанию
-b Скорость передачи данных по последовательной линии 9600
-d Количество передаваемых бит данных, 7 или 8 8
-s Количество стоповых битов, 1 или 2 1
-p Контроль четности:
  • -pnone — нет проверки,
  • -peven — передается бит контроля на четность,
  • -podd— передается бит контроля на нечетность.
even

Для Modbus TCP

Параметр Описание
-p Номер TCP-порта устройства, с которым взаимодействует контроллер.

Далее следует имя файла порта RS-485 или адрес хоста, а в конце необязательный параметр — данные для функций записи.

Примеры использования с оборудованием Wiren Board

Проверка подключения к устройству и считывание адреса

Все устройства Wiren Board с протоколом Modbus RTU хранят адрес в регистре 128 — его удобно считывать для проверки подключения.

Читаем содержимое регистра 128 из устройства с адресом 2, подключенного к serial-порту /dev/ttyRS485-1, с помощью функции 0x03 (Read Holding Registers):

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a2 -t0x03 -r128
Аргумент Описание
--debug отладка включена, будут выведены шестнадцатеричные коды отправляемых и принимаемых данных
-mrtu выбран протокол Modbus RTU
-pnone без проверки контроля четности
-s2 стоповых битов 2
/dev/ttyRS485-1 адрес serial-порта, к которому подключено опрашиваемое устройство
-a2 адрес устройства, 2
-t0x03 адрес функции чтения из holding-регистра
-r128 адрес регистра, значение которого мы запрашиваем

Ответ:

Opening /dev/ttyRS485-1 at 9600 bauds (N, 8, 2)
[02][03][00][80][00][01][85][D1]
Waiting for a confirmation...
<02><03><02><00><02><7D><85>
SUCCESS: read 1 of elements:
        Data: 0x0002

Запись нового адреса

Записываем новый адреса устройства в регистр 128, используя функцию 0x06 (Write Single Register).

В примере используется широковещательный адрес 0. Использование примера в таком виде изменит адрес на всех устройствах Wiren Board, подключенных к порту /dev/ttyRS485-1. Чтобы этого не произошло — отсоедините другие устройства от шины.

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a0 -t0x06 -r128 2

Где 0 — широковещательный адрес, а 2 — адрес, который нужно задать.

Ответ:

Data to write: 0x2
Opening /dev/ttyRS485-1 at 9600 bauds (N, 8, 2)
[00][06][00][80][00][02][08][32]
Waiting for a confirmation...
ERROR Connection timed out: select
ERROR occured!

Сообщение об ошибке возникает всегда, когда запись производится на специальный (широковещательный) адрес 0 (-a0). Теперь к устройству нужно обращаться по адресу 2.

Пример неправильного использования команды:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a0 -t0x06 -r128

Здесь не указано значение, которое нужно записать в регистр адреса, поэтому устройство получит неизвестное значение.

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

Модель устройства занимает 6 регистров начиная с 200. В прошивках с быстрым Modbus добавлены дополнительные регистры с 206 по 219.

Чтение модели на старых прошивках

Прочтем регистры релейного модуля WB-MR6C с адресом 1, содержащие модель устройства: WBMR6C.

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x03 -r200 -c 6

Ответ:

Opening /dev/ttyRS485-1 at 9600 bauds (N, 8, 2)
[87][03][00][C8][00][06][5B][90]
Waiting for a confirmation...
<87><03><0C><00><57><00><42><00><4D><00><52><00><36><00><43><23><F3>
SUCCESS: read 6 of elements:
        Data: 0x0057 0x0042 0x004d 0x0052 0x0036 0x0043

В ответе мы получили шесть 16-битных значений, в каждом из которых содержится код одного ASCII-символа. Преобразуем их:

echo -e $(modbus_client -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x03 -r200 -c 6 | grep Data | sed -e 's/.*Data://' -e 's/ 0x00/\\x/g')

Ответ:

WBMR6C

Чтение модели на прошивках с быстрым Modbus

В прошивках с быстрым Modbus нужно считать 20 регистров (200-219).

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x03 -r200 -c 20

Ответ:

Opening /dev/ttyRS485-1 at 9600 bauds (N, 8, 2)
[87][03][00][C8][00][14][DB][9D]
Waiting for a confirmation...
<87><03><28><00><57><00><42><00><4D><00><52><00><36><00><43><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><00><94><A3>
SUCCESS: read 20 of elements:
        Data: 0x0057 0x0042 0x004d 0x0052 0x0036 0x0043 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 0x0000

Или сразу преобразованный вид:

echo -e $(modbus_client -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x03 -r200 -c 20 | grep Data | sed -e 's/.*Data://' -e 's/ 0x00/\\x/g')

Ответ:

WBMR6C

Чтение версии прошивки

Прочтем версию прошивки из модуля с modbus-адресом 189. По адресу 250 хранится null-termitated строка максимальной длиной в 16 регистров. Прочтем 16 регистров, начиная с адреса 250, и преобразуем полученный шестнадцатеричный ответ в символьную строку:

echo -e $(modbus_client -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a189 -t0x03 -r250 -c 16 | grep Data | sed -e 's/.*Data://' -e 's/ 0x00/\\x/g')

В результате выполнения команды получаем строку, например 1.3.1.

Настройка параметров трансформаторов

Для настройки трансформаторов запишите нужные значения в регистры счётчика. Номера регистров смотрите в карте регистров счётчика.

В примере задаются параметры трёх трансформаторов, подключенных к первому каналу счётчика WB-MAP12E(H).

Трансформатор на фазе Коэффициент трансформации Фазовый сдвиг
L1 3001 501
L2 3002 502
L3 3003 503

Настройки записываются в память конкретного WB-MAP один раз:

$ modbus_client --debug -mrtu -pnone -b9600 -s2 /dev/ttyRS485-2 -a1 -t0x10 -r0x1460 3001 3002 3003 501 502 503

Включение реле релейного модуля

На модуле WB-MR14 включим реле с номером 6 (адреса регистров флагов начинаются с нуля, помним об этом!). Используем для этого команду 0x05 (Write Single Coil):

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x05 -r5 1

Ответ:

Data to write: 0x1
Opening /dev/ttyRS485-1 at 9600 bauds (N, 8, 2)
[01][05][00][05][FF][00][9C][3B]
Waiting for a confirmation...
<01><05><00><05><FF><00><9C><3B>
SUCCESS: written 1 elements!

Обратите внимание, утилита modbus_client при записи заменила 1 на 0x00FF, поскольку именно это значение служит для включения реле. Любое ненулевое значение будет заменено на 0x00FF, поэкспериментируйте.

Одновременное включение нескольких реле

Включим все нечетные реле и выключим все четные. Для этого используем функцию 0x0F (Write Multiple Coils). В модуле всего 14 реле, так что мы должны передать значения для 14 регистров с 0 по 13.

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x0F -r0 -c 14 255 0 255 0 255 0 255 0 255 0 255 0 255 0

Ответ:

Data to write: 0xff 0x00 0xff 0x00 0xff 0x00 0xff 0x00 0xff 0x00 0xff 0x00 0xff 0x00 
Opening /dev/ttyRS485-1 at 9600 bauds (N, 8, 2)
[01][0F][00][00][00][0E][02][55][15][1A][97]
Waiting for a confirmation...
<01><0F><00><00><00><0E><D4><0F>
SUCCESS: written 14 elements!

Обратите внимание на структуру данных запроса:

  • [01] — адрес
  • [0F] — код функции Write Multiple Coils
  • [00][00] — адрес первого регистра флагов для записи
  • [00][0E] — количество элементов для записи (14)
  • [02] — количество байт данных (14 бит помещаются в 2 байтах)
  • [55][15] — 01010101 00010101 (первое реле — младший бит первого байта, 8 реле — старший бит первого байта, 9 реле — младший бит второго байта)
  • [1A][97] — CRC16

А так же на структуру ответа:

  • <01> — адрес
  • <0F> — код функции Write Multiple Coils
  • <00><00> — адрес первого регистра флагов для записи
  • <00><0E> — количество записанных регистров флагов
  • <D4><0F> — CRC16

Подробнее описание структуры данных запросов и ответов можно найти на странице Протокол Modbus.

Настройка взаимодействия входов и выходов реле

Выключатели с фиксацией

Чтобы перевести входы в режим «Выключатель с фиксацией», запишите в регистры настройки входов значение 1.

В примере мы изменим режим входов с 1 по 6 и аварийного входа 0 в устройстве с адресом 1:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r9 1 1 1 1 1 1 1

Теперь входы функционируют в режиме «Выключатель с фиксацией», а активация выключателя, подключенного ко входу 0, выключит все реле.

Выключатели без фиксации

Чтобы перевести все входы в режим «Выключатель без фиксации», запишите в регистры настройки входов значение 0.

В примере мы изменим режим входов с 1 по 6 и аварийного входа 0 в устройстве с адресом 1:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r9 0 0 0 0 0 0 0

Теперь входы функционируют в режиме «Выключатель без фиксации», а кратковременное нажатие на кнопку, подключенную ко входу 0, выключит все реле.

Отключить взаимодействие входов и реле

Для отключения взаимодействия входов и реле (например, если мы хотим управлять реле только через движок правил контроллера) запишем в регистры 9, 10, 11, 12, 13, 14 значение 3:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r9 3 3 3 3 3 3

Теперь нажатия на кнопки или переключение выключателей не будет изменять состояние реле: ими можно управлять только программно, по Modbus. При этом функция аварийного входа 0 сохраняется: кратковременное нажатие на кнопку, подключенную ко входу 0, выключит все реле.

Если мы хотим отключить и вход 0, то запишем значение 3 в регистр 16 устройства с адресом 1:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x06 -r16 3

Использование Mapping-матрицы

Более сложные сценарии взаимодействия входов с реле можно реализовать с помощью Mapping-матрицы. Для этого запишем в регистры настройки взаимодействия входов/выходов — значение 4:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r9 4 4 4 4 4 4
modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x06 -r16 4

Для настройки Mapping-матрицы нужно знать номер регистра, который отвечает за взаимодействие входа и выхода, и код, который нужно записать в этот регистр. Эту информацию можно найти на странице описания Mapping-матриц.

В заводской поставке Mapping-матрица заполнена нулями. Если вы не уверены в этом и хотите стереть всю матрицу, запишите 0 в каждый из 64 holding-регистров, начиная с 384:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r384 $(printf ' 0%.0s' {1..64})

Вход 0 включает и выключает все реле

Запрограммируем матрицу таким образом, чтобы вход 0, работая в режиме выключателя без фиксации включал и отключал все реле модуля при замыкании.

Для этого обратимся к карте регистров mapping-матрицы и увидим, что входу 0 соответствуют регистры 440 — 447. Причем за взаимодействие со входами 1 — 6 отвечают регистры 440 — 445.

Мы хотим, чтобы вход работал, как выключатель без фиксации и срабатывал при нажатии, а при размыкании ничего бы не происходило. При каждом нажатии состояние всех реле должно инвертироваться. Это соответствует комбинации 11 00: (12, 0x0C) — Изменить состояние выхода при замыкании: Mm 1100.png
Запишем в регистры 440 — 445 значение 12:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r440 12 12 12 12 12 12

Проверим работу: при первом замыкании входа 0 все реле включаются, при втором — все реле выключаются.

Инвертированный выключатель с фиксацией

Настроим входы таким образом, чтобы при замкнутых входах реле были бы выключены, а при разомкнутых -- включены. Для этого при замыкании входа (передний фронт) соответствующий выход должен выключаться (01), а при размыкании входа (задний фронт) — включаться (10). Это соответствует значению 6: Mm 0110.png
В матрице нужные регистры взаимодействия вход 1 — выход 1, вход 2 — выход 2 и т.д. расположены по диагонали. Это регистры 384, 393, 402, 411, 420, 429. В них надо записать значение 6:

for i in 384 393 402 411 420 429; do modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x06 -r$i 6; done

Обратите внимание: изменение состояния реле происходят только при изменении состояния ввода.

Обработка типов нажатий

Матрицы типов нажатий можно посмотреть на странице Mapping-матрица.

Чтобы понять принцип, рассмотрим пример. К входу 2 реле подключена кнопка и нам нужно настроить так, чтобы при двойном нажатии на эту кнопку включалось реле 5, а при коротком переключалось реле 3.

Запишем в регистр настройки взаимодействия входов/выходов входа 2 значение 6:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x06 -r10 6

Теперь запишем в соответствующий входу 2 и выходу 5 регистр из матрицы двойных нажатий действие «10 — включить» (dec = 2), а в соответствующий входу 2 и выходу 3 регистр из матрицы коротких нажатий действие «11 — инвертировать значение» (dec = 3):

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x06 -r684 2
modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x06 -r554 3

Аналогично настраиваются другие типы нажатий.

Датчик протечки

ВНИМАНИЕ: используемый в примере режим 5 — восстановление состояния выхода через 20 минут, доступен только для WB-MWAC.

Пусть датчик протечки подключен ко входу 1, а реле 1 и 2 управляют приводами шаровых кранов. Реле 3 управляет сигнальной лампой или зуммером. При смачивании датчика протечки реле 1 и реле 2 замыкаются и приводы закрывают шаровые краны. Реле 3 замыкается и включает зуммер. Вход 2 запрограммируем для сброса тревоги и открытия шаровых кранов.

Очистим mapping-матрицу:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r384 $(printf ' 0%.0s' {1..64})

Применим в нашем случае режим, когда состояние входа повторяется каждые 20 минут, для этого запишем в регистр 9 значение 5 (управлять в соответствии с mapping-матрицей, через 20 минут повторно имитировать состояние ввода), а в остальные — значение 4 (управлять в соответствии с mapping-матрицей).

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r9 5 4 4 4 4 4

Для входа датчика протечки (вход 1) используем режим 1000 (8) — включать при замыкании. Mm 1000.png
Для входа кнопки сброса (вход 2) используем режим 0100 (4) — выключить при замыкании. Mm 0100.png

По карте mapping-регистров определяем, что для входа 1 надо записать значение 8 в регистры 384, 385, 386, а для входа 2 — записать значение 4 в регистры 392, 393, 394:

modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r384 8 8 8
modbus_client --debug -mrtu -b9600 -pnone -s2 /dev/ttyRS485-1 -a1 -t0x10 -r392 4 4 4

Проверка: замкнем вход 1 и iGND и оставим его замкнутым. Должны включиться реле 1, 2 и 3. Затем замкнем и разомкнем вход 2 — все три реле выключились. Ждем 20 минут. Поскольку вход 1 остается замкнутым (протечка не устранена), через 20 минут реле 1, 2 и 3 снова включатся.

Оставляя вход 1 замкнутым, выключим и включим питание реле: через 20 минут реле 1, 2 и 3 снова включатся.