|
|
(не показано 60 промежуточных версий 4 участников) |
Строка 1: |
Строка 1: |
| {{DISPLAYTITLE: Как писать шаблоны для сторонних Modbus-устройств}} | | {{DISPLAYTITLE: Как подключить Modbus RTU-устройство стороннего производителя к контроллеру Wirenboard?}} |
| == Введение == | | == Введение == |
| Рекомендуем сперва поискать ваше устройств в [[Supported_devices | Таблице поддерживаемых устройств]] — вдруг оно уже там есть. Если устройства в списке нет, но оно поддерживает протокол [[Modbus|Modbus]], то его можно подключить к контроллеру Wiren Board.
| | Modbus RTU — один из распространенных протоколов для связи устройств. Если устройство стороннего производителя поддерживает протокол Modbus RTU, то его можно подключить к контроллеру Wirenboard. |
|
| |
|
| Существует два вида протокола Modbus:
| | Список всех поддерживаемых контроллером протоколов можно найти в [[Supported_devices | Таблице поддерживаемых устройств]]. |
| # Modbus RTU — устройства соединяются по шине RS-485.
| |
| # Modbus TCP — устройства соединяются по локальной сети через Wi-Fi или Ethernet.
| |
|
| |
|
| Независимо от вида протокола, алгоритм добавления поддержки устройства в наш контроллер будет такой:
| | == Подключите устройство == |
| # Ищете документацию на ваше устройство с описанием его modbus-регистров. | | Для подключения стороннего устройства по протоколу Modbus RTU: |
| # Составляете шаблон для нашего драйвера [[wb-mqtt-serial]]. | | # Откройте документацию на устройство и убедитесь, что оно имеет интерфейс RS-485 и поддерживает протокол Modbus RTU. |
| # Копируете созданный шаблон на контроллер в папку
| | # Проверьте, нет ли вашего устройства в [[Supported_devices | Таблице поддерживаемых устройств]]. Если устройство там есть — используйте указанные в таблице рекомендации по подключению. |
| # Выбираете в веб-интерфейсе контроллера свой шаблон и указываете адрес. | | # Определите, какая информация вам нужна и в каких регистрах она находится. |
| | |
| Некоторые производители Modbus-устройств не придерживаются стандартов протокола, что может сказаться на работе всей шины. Поэтому рекомендуем проверять работу новых устройств на отдельной шине и только после того, как добьётесь стабильной работы, подключать к ней другие Modbus-устройства.
| |
| | |
| == Подготовка ==
| |
| Устройство с Modbus RTU:
| |
| # Откройте документацию на устройство и найдите описание modbus-регистров и параметров подключения (Baud rate, Data bits, Parity, Stop bits, Slave ID).
| |
| # Подключите устройство к контроллеру по [[RS-485 | шине RS-485]]. | | # Подключите устройство к контроллеру по [[RS-485 | шине RS-485]]. |
| | # Узнайте в документации на устройство параметры подключения: скорость (Baud rate), Количество битов данных (Data bits), Бит чётности (Parity), Количество стоповых битов (Stop bits), Modbus-адрес устройства. |
| # Проверьте связь с устройством и правильность подключения: | | # Проверьте связь с устройством и правильность подключения: |
| #* {{Wbincludes:Stop wb-mqtt-serial}} | | #* {{Wbincludes:Stop wb-mqtt-serial}} |
| #* Подключитесь к устройству с помощью утилиты [[modbus_client]] и считайте данные из любого известного вам регистра. | | #* Подключитесь к устройству с помощью утилиты [[modbus_client]] и считайте данные из любого известного вам регистра. |
| | Если чтение данных пройдёт успешно — вы верно подключили устройство и настроили параметры соединения. |
|
| |
|
| Устройство Modbus TCP:
| | == Создайте шаблон == |
| # Откройте документацию на устройство и найдите описание modbus-регистров и настроек подключения (адрес, порт).
| | Для удобства использования устройства [[Wb-mqtt-serial_templates | создайте шаблон для драйвера wb-mqtt-serial]] в шаблоне укажите: |
| # Утилита ''modbus_client'' в релизах до 2304 содержит ошибку, из-за которой она не может работать по протоколу Modbus TCP. Если успользуете устаревший релиз, то подключите устройство к компьютеру через Ethernet.
| | * регистры, в которых хранятся нужные вам данные; |
| # Попробуйте [[Working_with_WB_devices_without_a_controller |считать из устройства]] значение одного известного вам регистра.
| | * параметры инициализации, если они необходимы; |
| | | * обязательно задайте параметр <code>guard_interval_us</code>, значение которого должно быть не менее 3.5 символа при выбранной скорости. Нужное значение рассчитывается по формуле: <code>guard_interval_us = (3.5*11*10<sup>6</sup>)/(скорость в бит/с)</code>. Например, для скорости 9600 бит/с <code>guard_interval_us = (3.5*11*10<sup>6</sup>)/9600 = 4000 мкс</code>. |
| Если вы смогли получить содержимое регистра — вы всё делаете верно и можете продолжать.
| |
| | |
| == Создание шаблона == | |
| Рассказать драйверу wb-mqtt-serial, который в контроллере работает с Modbus-устройствами можно двумя способами:
| |
| # [[RS-485:Configuration_via_Web_Interface#without-template|Добавить регистры]] устройства прямо в веб-интерфейсе контроллера. Этот способ удобен для быстрой проверки работы.
| |
| # Создать шаблон, который описывает регистры устройства, их тип и другие параметры. Этот способ удобен для масштабирования: просто копируете шаблон на другой контроллер и в нём появляется поддержка вашего устройства.
| |
| | |
| Здесь мы рассмотрим создание простого шаблона. Упрощённо шаблон устройства выглядит так:
| |
| <syntaxhighlight lang="json">
| |
| {
| |
| "device_type": "my-relay", // тип устройства — уникальный идентификатор
| |
| "title": "My Relay", // отображаемое название
| |
| "group": "g-relay", // группа, в которой будет отображаться шаблон. Список групп в документации
| |
| "device": {
| |
| "name": "MY-RELAY", // имя устройства, используется в MQTT
| |
| "id": "my-relay",
| |
| "groups": [ ], // группы параметров и каналов
| |
| "channels": [ ], // каналы, доступно в скриптах и на вкладке Устройства
| |
| "parameters": [ ], // параметры, можно менять в настройках устройства
| |
| "translations": { } // переводы
| |
| }
| |
| }
| |
| </syntaxhighlight>
| |
| '''Полное описание смотрите в [https://github.com/wirenboard/wb-mqtt-serial документации драйвера wb-mqtt-serial на Github].'''
| |
| | |
| Допустим, у нас есть одноканальное Modbus-реле, у которого таблица регистров, показанная ниже.
| |
| {| border="1" class="wikitable"
| |
| ! Адрес || Тип || Название || Назначение
| |
| |-
| |
| | 0 || Discrete Input || Input 1 || Состояние входа устройства
| |
| |-
| |
| | 1 || Input Register || Input 1 Counter || Значение счётчика входов
| |
| |-
| |
| | 3 || Coil || Relay 1 || Состояние выхода и управление им
| |
| |-
| |
| | 10 || Holding || Input Mode || Выбор режима взаимодействия входов с выходами
| |
| |-
| |
| |}
| |
| | |
| В таком случае шаблон будет выглядеть так:
| |
| <syntaxhighlight lang="json">
| |
| {
| |
| "device_type": "my-relay",
| |
| "title": "My Relay",
| |
| "group": "g-relay",
| |
| "device": {
| |
| "name": "MY-RELAY",
| |
| "id": "my-relay",
| |
| "groups": [
| |
| {
| |
| "title": "Channels",
| |
| "id": "channels",
| |
| "order": 0
| |
| },
| |
| {
| |
| "title": "Settings",
| |
| "id": "settings",
| |
| "order": 1
| |
| }
| |
| ],
| |
| "channels": [
| |
| {
| |
| "name": "Input 1",
| |
| "reg_type": "discrete",
| |
| "address": 0,
| |
| "type": "switch",
| |
| "group": "channels"
| |
| },
| |
| {
| |
| "name": "Input 1 Counter",
| |
| "reg_type": "input",
| |
| "address": 1,
| |
| "type": "value",
| |
| "group": "channels"
| |
| },
| |
| {
| |
| "name": "Relay 1",
| |
| "reg_type": "coil",
| |
| "address": 3,
| |
| "type": "switch",
| |
| "group": "channels"
| |
| }
| |
| ],
| |
| "parameters": [
| |
| {
| |
| "id": "input1",
| |
| "title": "Input Mode",
| |
| "reg_type": "input",
| |
| "address": 10,
| |
| "format": "s8",
| |
| "enum": [
| |
| 1,
| |
| 2
| |
| ],
| |
| "enum_titles": [
| |
| "Switch Relay",
| |
| "Not used"
| |
| ],
| |
| "default": 1
| |
| }
| |
| ],
| |
| "translations": {
| |
| "ru": {
| |
| "Channels": "Каналы",
| |
| "Settings": "Настройки",
| |
| "Input 1": "Вход 1",
| |
| "Input 1 Counter": "Вход 1 счетчик",
| |
| "Relay 1": "Реле 1",
| |
| "Input Mode": "Режим входа"
| |
| }
| |
| }
| |
| }
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| == Загрузка шаблона на контроллер ==
| |
| Когда шаблон готов, его надо загрузить на контроллер:
| |
| # Сохраните шаблон в файл, например, <code>my-relay.json</code> и загрузите его на контроллер в папку <code>/etc/wb-mqtt-serial.conf.d/templates</code> по [[View_controller_files_from_your_computer|инструкции]].
| |
| # Проверьте шаблон на синтаксические ошибки командой:
| |
| #:<syntaxhighlight lang="bash">
| |
| # wb-mqtt-serial -g
| |
| <3>ERROR: [serial config] Failed to parse /etc/wb-mqtt-serial.conf.d/templates/my-best-template.json
| |
| Failed to parse JSON /etc/wb-mqtt-serial.conf.d/templates/my-best-template.json:* Line 12, Column 5
| |
| Missing ',' or '}' in object declaration
| |
| </syntaxhighlight>
| |
| #: в примере в шаблоне ''my-best-template.json'' в строке 12, символ 5 ожидается <code>,</code> or <code>}</code>, а находится что-то другое.
| |
| # Если с шаблоном всё в порядке, то перейдите в настройки драйвера и [[RS-485:Configuration_via_Web_Interface|выберите ваш шаблон]].
| |
| | |
| == Отклонения от стандарта и что с ними делать ==
| |
| === Оптимизация запросов драйвером ===
| |
| Стандартом Modbus RTU предусмотрен обязательный интервал тишины в 3.5 символа между фреймами данных (под символом подразумевается посылка, состоящая из стартового бита, битов данных, бита четности и стоп-битов).
| |
| | |
| Для ускорения опроса устройств Wiren Board мы соблюдаем этот интервал только перед первым запросом к следующему в цикле опроса устройству (параметр ''frame_timeout_ms'' в шаблонах устройств).
| |
| | |
| Поэтому, чтобы соответствовать требованиям протокола Modbus-RTU, нужно для сторонних устройств задавать параметр ''guard_interval_us''. Этот параметр задает задержку перед записью каждого запроса в порт.
| |
| | |
| Нужное значение рассчитывается по формуле: | |
| <syntaxhighlight lang="bash"> | |
| guard_interval_us = (3.5*11*10^6)/(скорость в бит/с). | |
| </syntaxhighlight> | |
| Например, для скорости 9600 бит/с <code>guard_interval_us = (3.5*11*10^6)/9600 = 4000 мкс</code>. При проблемах с подключением стороннего устройства для теста это значение можно увеличить (например до 100000 мкс), так как сторонние устройства иногда работают не совсем корректно. | |
| | |
| === Если каналы устройства периодически мигают красным ===
| |
| Со сторонними устройствами довольно частая ситуация, когда вы сделали шаблон, данные идут, но в логах сыпятся ошибки, а каналы устройства в веб-интерфейсе контроллера окрашивают красным.
| |
| | |
| Основная причина этому — устройство слишком медленно обрабатывает запросы нашего драйвера. Для начала мы рекомендуем подключить такие устройства на отдельную шину, чтобы они не тормозили работу нормальных устройств, а потом использовать рекомендации ниже.
| |
| | |
| Чтобы починить, попробуйте увеличить параметр <code>guard_interval_us</code> вплоть до тысяч единиц, например, 5000. Если работа стабилизируется, потихоньку уменьшайте это значение до тех пор, пока ошибки не появятся вновь. Предыдущее значение, когда всё работало хорошо и будет вашим значением в шаблоне.
| |
| | |
| Ещё есть параметр <code>response_timeout_ms</code> — это максимальное время ответа устройства в миллисекундах, по умолчанию 500 мс. С ним тоже можно аккуратно поэкспериментировать.
| |
| | |
| Не выставляйте без нужды огромных значений в этих параметрах — это замедлит опрос устройств на порту, куда подключено проблемное устройство. Подробнее о том, как работают эти параметры, смотрите в [https://github.com/wirenboard/wb-mqtt-serial#%D0%94%D0%B8%D0%B0%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0-%D1%82%D0%B0%D0%B9%D0%BC%D0%B0%D1%83%D1%82%D0%BE%D0%B2-%D1%86%D0%B8%D0%BA%D0%BB%D0%B0-%D0%BE%D0%BF%D1%80%D0%BE%D1%81%D0%B0 Диаграмме таймаутов цикла опроса].
| |
| | |
| Оба параметра пишутся в секцию device шаблона:
| |
| <syntaxhighlight lang="json">
| |
| "device": {
| |
| "name": "BAC-6000ELNW",
| |
| "id": "bac-6000elnw",
| |
| "response_timeout_ms": 100,
| |
| "guard_interval_us": 5000,
| |
| ...
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| === Разные регистры для чтения состояния и управления ===
| |
| Иногда в сторонних устройствах встречаются особенности:
| |
| # В некоторые регистры можно только писать информацию, но нельзя считывать.
| |
| # Один и тот же параметр может читаться по одному адресу, а записываться по другому.
| |
| | |
| Для того, чтобы драйвер работал с такими устройствами без ошибок, мы добавили параметр '''write_address'''.
| |
| | |
| ==== Писать можно, читать нельзя ====
| |
| Допустим, в нашем устройстве есть такой регистр только для записи.
| |
| | |
| {| border="1" class="wikitable"
| |
| ! Адрес || Тип || Название || Назначение
| |
| |-
| |
| | 20 || Coil || Relay 1 Switch || Управление выходом. Только для записи.
| |
| |-
| |
| |}
| |
| | |
| В этом случае канал надо описывать так:
| |
| <syntaxhighlight lang="json">
| |
| {
| |
| "name": "Relay 1 Switch",
| |
| "write_address": "20",
| |
| "reg_type": "coil",
| |
| "type": "pushbutton",
| |
| "format": "u16",
| |
| "group": "channels",
| |
| "on_value": 1 // определяет, что записывать в регистр при нажатии
| |
| }
| |
| </syntaxhighlight>
| |
| | |
| ==== Писать в один регистр, читать из другого====
| |
| Допустим, в нашем устройстве команда записывается в один регистр, а читается из другого. Этот метод можно использовать только, если у обоих регистров один тип. Если типы разные — создавайте два разных канала: на чтение и на запись.
| |
| | |
| {| border="1" class="wikitable"
| |
| ! Адрес || Тип || Название || Назначение
| |
| |-
| |
| | 20 || Coil || Relay 1 Switch|| Управление выходом. Только для записи.
| |
| |-
| |
| | 21 || Coil || Relay 1 State|| Состояние выхода. Только для чтения.
| |
| |-
| |
| |}
| |
| | |
| В этом случае канал надо описывать так: у нас будет один параметр в контроллере, но при обмене данными запись будет производиться один регистр, а чтение — из другого:
| |
| <syntaxhighlight lang="json">
| |
| {
| |
| "name": "Relay 1",
| |
| "write_address": "20", // адрес, куда мы записываем команды
| |
| "address": "21", // адрес, по которому мы читаем состояние
| |
| "reg_type": "coil",
| |
| "type": "switch",
| |
| "format": "u16",
| |
| "group": "channels"
| |
| }
| |
| </syntaxhighlight>
| |
|
| |
|
| === Произвольные значения в регистрах с бинарной логикой === | | == Особенности реализации Modbus RTU в устройствах Wiren Board == |
| Иногда бывает так, что по смыслу регистр должен представляться в веб-интерфейсе переключателем ВКЛ/ВЫКЛ, но допустимые значения у него не 1/0.
| | Стандартом Modbus RTU предусмотрен обязательный интервал тишины между фреймами данных в 3.5 символа — ''frame_timeout_ms''. |
|
| |
|
| В этом случае вы описываете обычный канал с типом '''switch''' и указываете значения <code>on_value</code> и <code>off_value</code>, например:
| | Для ускорения опроса устройств Wiren Board мы соблюдаем этот интервал только перед первым запросом к следующему в цикле опроса устройству. |
|
| |
|
| <syntaxhighlight lang="json">
| | Поэтому, чтобы соответствовать требованиям протокола Modbus-RTU, нужно для сторонних устройств задавать параметр ''guard_interval_us''. |
| {
| |
| "name": "Status",
| |
| "reg_type": "holding",
| |
| "address": "0",
| |
| "type": "switch",
| |
| "format": "u16",
| |
| "on_value": "0x00a5", // ВКЛ
| |
| "off_value": "0x005a" // ВЫКЛ
| |
| }
| |
| </syntaxhighlight>
| |
| Теперь драйвер будет автоматически при чтении конвертировать указанные значения в положение переключателя, а при изменении положения переключателя — записывать указанные значения.
| |
|
| |
|
| == Полезные ссылки == | | == Полезные ссылки == |
Строка 269: |
Строка 34: |
| * [[Modbus|Описание протокола Modbus]] | | * [[Modbus|Описание протокола Modbus]] |
| * [[RS-485|Описание шины RS-485]] | | * [[RS-485|Описание шины RS-485]] |
| * [https://github.com/wirenboard/wb-mqtt-serial Документация wb-mqtt-serial]
| | * Темы на форуме: |
| * [https://github.com/wirenboard/conventions/blob/main/README.md Описание соглашений MQTT]
| |
| * [http://json.parser.online.fr Онлайн проверка JSON]
| |
| * Темы на портале: | |
| ** [https://support.wirenboard.com/t/oshibki-pri-chtenii-bolid-s2000-pp/8080 Ошибки при чтении Bolid С2000-ПП] | | ** [https://support.wirenboard.com/t/oshibki-pri-chtenii-bolid-s2000-pp/8080 Ошибки при чтении Bolid С2000-ПП] |
| ** [https://support.wirenboard.com/t/request-timed-out/8344/17 Request timed out] | | ** [https://support.wirenboard.com/t/request-timed-out/8344/17 Request timed out] |
| ** [https://support.wirenboard.com/t/oshibki-pri-chtenii-modbus-ustrojstv/8253 Ошибки при чтении Modbus устройств] | | ** [https://support.wirenboard.com/t/oshibki-pri-chtenii-modbus-ustrojstv/8253 Ошибки при чтении ModBus устройств] |
| ** [https://support.wirenboard.com/t/wb-mr6hv-i-perestalo-otvechat-po-modbus/8286/18 WB-MR6HV/I перестало отвечать по Modbus] | | ** [https://support.wirenboard.com/t/wb-mr6hv-i-perestalo-otvechat-po-modbus/8286/18 WB-MR6HV/I перестало отвечать по Modbus] |
| ** [https://support.wirenboard.com/t/konvertor-modbas-dlya-vnutrennego-bloka-kondiczionera-uty-vmsx/9252 Подключение конвертера Modbus]
| |