Connecting Third Party Devices to Wiren Board: различия между версиями

Материал из Wiren Board
 
(не показано 36 промежуточных версий 3 участников)
Строка 1: Строка 1:
{{DISPLAYTITLE: Как подключить Modbus RTU-устройство стороннего производителя к контроллеру Wiren Board?}}
{{DISPLAYTITLE: Как писать шаблоны для сторонних Modbus-устройств}}
== Введение ==
== Введение ==
Рекомендуем сперва поискать ваше устройств в [[Supported_devices | Таблице поддерживаемых устройств]] — вдруг оно уже там есть. Если устройства в списке нет, но оно поддерживает протокол [[Modbus|Modbus]], то его можно подключить к контроллеру Wiren Board.
Рекомендуем сперва поискать ваше устройств в [[Supported_devices | Таблице поддерживаемых устройств]] — вдруг оно уже там есть. Если устройства в списке нет, но оно поддерживает протокол [[Modbus|Modbus]], то его можно подключить к контроллеру Wiren Board.
Строка 9: Строка 9:
Независимо от вида протокола, алгоритм добавления поддержки устройства в наш контроллер будет такой:
Независимо от вида протокола, алгоритм добавления поддержки устройства в наш контроллер будет такой:
# Ищете документацию на ваше устройство с описанием его modbus-регистров.
# Ищете документацию на ваше устройство с описанием его modbus-регистров.
# Составляете шаблон для нашего драйвера wb-mqtt-serial.
# Составляете шаблон для нашего драйвера [[wb-mqtt-serial]].
# Копируете созданный шаблон на контроллер в папку  
# Копируете созданный шаблон на контроллер в папку  
# Выбираете в веб-интерфейсе контроллера свой шаблон и указываете адрес.
# Выбираете в веб-интерфейсе контроллера свой шаблон и указываете адрес.
Строка 15: Строка 15:
Некоторые производители Modbus-устройств не придерживаются стандартов протокола, что может сказаться на работе всей шины. Поэтому рекомендуем проверять работу новых устройств на отдельной шине и только после того, как добьётесь стабильной работы, подключать к ней другие Modbus-устройства.
Некоторые производители Modbus-устройств не придерживаются стандартов протокола, что может сказаться на работе всей шины. Поэтому рекомендуем проверять работу новых устройств на отдельной шине и только после того, как добьётесь стабильной работы, подключать к ней другие Modbus-устройства.


== Подключите устройство ==
== Подготовка ==
Для подключения стороннего устройства по протоколу Modbus RTU:
Устройство с Modbus RTU:
# Откройте документацию на устройство и убедитесь, что оно имеет интерфейс RS-485 и поддерживает протокол Modbus RTU.
# Откройте документацию на устройство и найдите описание modbus-регистров и параметров подключения (Baud rate, Data bits, Parity, Stop bits, Slave ID).
# Проверьте, нет ли вашего устройства в [[Supported_devices | Таблице поддерживаемых устройств]]. Если устройство там есть — используйте указанные в таблице рекомендации по подключению.
# Определите, какая информация вам нужна и в каких регистрах она находится.
# Подключите устройство к контроллеру по [[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:
После физического подключения устройства не всегда получается сразу установить с ним связь: параметры обмена могут быть неизвестны или забыты. Для этого можно воспользоваться утилитой [[Wb-mb-explorer | '''wb-mb-explorer''']]. Она позволяет просканировать шину на наличие устройств: проверить наличие подключенных устройств с указанными параметрами обмена, подобрать параметры обмена для устройства с указанным адресом, провести полный перебор все возможных комбинаций параметров обмена. Если будет обнаружено устройство Wiren Board, то для него будет выведена информация о модели устройства, его серийном номере, версии прошивки и параметрах обмена. Для стороннего modbus-устройства будут выведены только параметры обмена.
# Откройте документацию на устройство и найдите описание modbus-регистров и настроек подключения (адрес, порт).
# Утилита ''modbus_client'' в релизах до 2304 содержит ошибку, из-за которой она не может работать по протоколу Modbus TCP. Если успользуете устаревший релиз, то подключите устройство к компьютеру через Ethernet.
# Попробуйте [[Working_with_WB_devices_without_a_controller |считать из устройства]] значение одного известного вам регистра.  


== Настройте опрос по Modbus ==
Если вы смогли получить содержимое регистра — вы всё делаете верно и можете продолжать.
После установки соединения с устройством нужно настроить опрос его регистров. Настроить опрос стороннего Modbus-устройства на контроллере Wiren Board можно двумя способами:


*написать и добавить новый шаблон конфигурации устройства в папку пользовательских шаблонов <code>/etc/wb-mqtt-serial.conf.d/templates</code>, удобно если нужно сохранять настройки при обновлении ПО;
== Создание шаблона ==
*настроить опрос устройства в веб-интерфейсе контроллера без использования шаблона, при этом регистры устройства будут описаны сразу в файле <code>/etc/wb-mqtt-serial.conf</code>, удобно при тестировании.
Рассказать драйверу wb-mqtt-serial, который в контроллере работает с Modbus-устройствами можно двумя способами:
# [[RS-485:Configuration_via_Web_Interface#without-template|Добавить регистры]] устройства прямо в веб-интерфейсе контроллера. Этот способ удобен для быстрой проверки работы.
# Создать шаблон, который описывает регистры устройства, их тип и другие параметры. Этот способ удобен для масштабирования: просто копируете шаблон на другой контроллер и в нём появляется поддержка вашего устройства.


===Создание шаблона конфигурации===
Здесь мы рассмотрим создание простого шаблона. Упрощённо шаблон устройства выглядит так:
[[File:serial-configs.png |300px|thumb|right| Выбор шаблона конфигурации из выпадающего списка в веб-интерфейсе контроллера Wiren Board]]
<syntaxhighlight lang="json">
Рассмотрим настройку опроса Modbus-устройства с помощью шаблона конфигурации. Шаблон конфигурации удобен тем, что его можно без проблем переносить между разными контроллерами Wiren Board и использовать повторно.
{
    "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].'''


Шаблон конфигурации — это JSON-файл, который обрабатывается драйвером и определяет как регистры устройства будут отображаться в контроллере, форматы их значений и возможность взаимодействия с ними.
Допустим, у нас есть одноканальное Modbus-реле, у которого таблица регистров, показанная ниже.
{|  border="1" class="wikitable"
! Адрес || Тип || Название || Назначение
|-
| 0 || Discrete Input || Input 1 ||  Состояние входа устройства
|-
| 1 || Input Register || Input 1 Counter ||  Значение счётчика входов
|-
| 3 || Coil || Relay 1 ||  Состояние выхода и управление им
|-
| 10 || Holding || Input Mode ||  Выбор режима взаимодействия входов с выходами
|-
|}


Поддерживаемые устройства, для которых есть шаблоны, отображаются в выпадающем списке в веб-интерфейсе контроллера Wiren Board в разделе '''Настройки — Конфигурационные файлы — Настройка драйвера serial-устройств'''.
В таком случае шаблон будет выглядеть так:
 
<syntaxhighlight lang="json">
Рассмотрим последовательность создания шаблона нового Modbus-устройства.
{
    "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": 1,
                "type": "switch",
                "group": "channels"
            },
            {
                "name": "Input 1 Counter",
                "reg_type": "input",
                "address": 2,
                "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>


#Найдите документацию на устройство и таблицу modbus-регистров. По ней будут задаваться адреса нужных регистров.
== Загрузка шаблона на контроллер ==
#Создайте и откройте в редакторе файл шаблона.
Когда шаблон готов, его надо загрузить на контроллер:
#:Cоздать файл шаблона можно двумя способами: скопировать существующий шаблон из папки <code>/usr/share/wb-mqtt-serial/templates</code>, внести изменения и сохранить в папку <code>/etc/wb-mqtt-serial.conf.d/templates</code> или создать новый шаблон.  Далее описан второй случай.
# Сохраните шаблон в файл, например, <code>my-relay.json</code> и загрузите его на контроллер в папку <code>/etc/wb-mqtt-serial.conf.d/templates</code> по [[View_controller_files_from_your_computer|инструкции]].
#:<p>Удобнее всего создавать и редактировать JSON-файлы на компьютере в редакторе кода, поддерживающем синтаксис JSON, например, [https://code.visualstudio.com/ VS Code]. Если такого нет, можно использовать любой текстовый редактор.</p>
# Проверьте шаблон на синтаксические ошибки командой:
#:<p>После редактирования файлы шаблонов можно будет [[View_controller_files_from_your_computer | загрузить в контроллер]].</p>
#:<p>Вносить правки в существующий шаблон на контроллере можно с помощью консольного текстового редактора, например, [[nano | nano]].</p>
#:{{note|info|Если шаблон в папке пользовательских шаблонов идентичен по названию и идентификатору другому шаблону в папке стандартных шаблонов, будет использован тот, который лежит в папке пользовательских шаблонов.}}
#Опишите в созданном файле параметры вашего устройства.
#:[[File:json-example.png |300px|thumb|right| Пример шаблона конфигурации]]
#:JSON-файл состоит из JSON-объектов, которые содержат набор пар '''«Ключ : Значение»''', разделенные запятыми. JSON-объекты выделяются фигурными скобками. В качестве '''«Значения»''' может быть строка, число, булева переменная, массив, другой JSON-объект, массив JSON-объектов и т.д.
#:<p>Ключ — это и есть имя параметра, который вы хотите задать. Все параметры, которые понимает драйвер и их возможные значения можно найти в [https://github.com/wirenboard/wb-mqtt-serial#%D0%A4%D0%B0%D0%B9%D0%BB-%D0%BA%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%B8-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B инструкции на гитхабе].</p>
#:<p>Для работы шаблона обязательно нужно указать параметр '''device_type''', он определяет название устройства, по которому будет выполняться поиск шаблона. Также значение этого параметра будет отображаться в настройках в веб-интерфейсе.</p>
#:<p>Параметр '''group''' определяет группу устройств, в которую будет включено устройство в выпадающем списке в настройках устройства. Если его не указать, новый шаблон будет в самом низу списка. Список доступных групп смотрите в [https://github.com/wirenboard/wb-mqtt-serial#%D0%A4%D0%B0%D0%B9%D0%BB-%D0%BA%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%B8-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B инструкции на гитхабе].</p>
#:<p>Непосредственно сами регистры и их адреса задаются в параметре '''channels''', который содержит набор JSON-объектов, с параметрами регистра. Modbus-адрес из документации устройства нужно записать в параметр '''adress''', по этому адресу будет производиться запись и чтение значения параметра. Если дополнительно указать параметр '''write_address''', то по адресу из '''address''' будет производиться только чтение, а по адресу из '''write_address''' — только запись. В '''name''' указывается название параметра устройства. Здесь же задается формат данных, тип регистра и т.д. Полный набор также в [https://github.com/wirenboard/wb-mqtt-serial#%D0%A4%D0%B0%D0%B9%D0%BB-%D0%BA%D0%BE%D0%BD%D1%84%D0%B8%D0%B3%D1%83%D1%80%D0%B0%D1%86%D0%B8%D0%B8-%D0%B8-%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D1%8B инструкции на гитхабе].</p>
#:<p>Параметр '''groups''' необязательный и служит для группировки параметров в веб-интерфейсе контроллера Wiren Board.</p>
#Сохраните и шаблон и [[View_controller_files_from_your_computer | загрузите его на контроллер]] в папку <code>etc/wb-mqtt-serial.conf.d/templates</code>.
#Затем проверьте шаблон на корректность. Для этого выполните в консоли команду
#:<syntaxhighlight lang="bash">
#:<syntaxhighlight lang="bash">
wb-mqtt-serial -g
# 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>
</syntaxhighlight>
#:Эта команда проверит на корректность файлы шаблонов в папках <code>/usr/share/wb-mqtt-serial/templates</code> и <code>/etc/wb-mqtt-serial.conf.d/templates</code>. Если в шаблонах содержатся ошибки, то на экран будут выведены диагностические сообщения с указанием имени шаблона и описанием ошибки.
#: в примере в шаблоне ''my-best-template.json'' в строке 12, символ 5 ожидается <code>,</code> or <code>}</code>, а находится что-то другое.
#:<p>Перейдите в веб-интерфейс контроллера Wiren Board в раздел '''Настройки — Конфигурационные файлы — Настройка драйвера serial-устройств'''. Проверьте, что в выпадающем списке в настройках последовательного порта появилось название вашего устройства, заданное в параметре '''device_type'''.</p>
# Если с шаблоном всё в порядке, то перейдите в настройки драйвера и [[RS-485:Configuration_via_Web_Interface|выберите ваш шаблон]].
 
== Отклонения от стандарта и что с ними делать ==
=== Оптимизация запросов драйвером ===
Стандартом Modbus RTU предусмотрен обязательный интервал тишины в 3.5 символа между фреймами данных (под символом подразумевается посылка, состоящая из стартового бита, битов данных, бита четности и стоп-битов).
 
Для ускорения опроса устройств Wiren Board мы соблюдаем этот интервал только перед первым запросом к следующему в цикле опроса устройству (параметр ''frame_timeout_ms'' в шаблонах устройств).
 
Поэтому, чтобы соответствовать требованиям протокола Modbus-RTU, нужно для сторонних устройств задавать параметр ''guard_interval_us''. Этот параметр задает задержку перед записью каждого запроса в порт.


При создании шаблона  может потребоваться задать параметр <code>guard_interval_us</code> (задержка перед записью каждого запроса в порт) в случае если есть проблемы с работой устройства. Значение  этого параметра должно быть не менее 3.5 символа при выбранной скорости. Нужное значение рассчитывается по формуле:
Нужное значение рассчитывается по формуле:
<syntaxhighlight lang="bash">
<syntaxhighlight lang="bash">
guard_interval_us = (3.5*11*106)/(скорость в бит/с).
guard_interval_us = (3.5*11*10^6)/(скорость в бит/с).
</syntaxhighlight>
</syntaxhighlight>
Например, для скорости 9600 бит/с <code>guard_interval_us = (3.5*11*106)/9600 = 4000 мкс</code>. При проблемах с подключением стороннего устройства для теста это значение можно увеличить (например до 100000 мкс), так как сторонние устройства иногда работают не совсем корректно.
Например, для скорости 9600 бит/с <code>guard_interval_us = (3.5*11*10^6)/9600 = 4000 мкс</code>. При проблемах с подключением стороннего устройства для теста это значение можно увеличить (например до 100000 мкс), так как сторонние устройства иногда работают не совсем корректно.
 
=== Если каналы устройства периодически мигают красным ===
Со сторонними устройствами довольно частая ситуация, когда вы сделали шаблон, данные идут, но в логах сыпятся ошибки, а каналы устройства в веб-интерфейсе контроллера окрашивают красным.


===Конфигурирование в веб-интерфейсе===
Основная причина этому — устройство слишком медленно обрабатывает запросы нашего драйвера. Для начала мы рекомендуем подключить такие устройства на отдельную шину, чтобы они не тормозили работу нормальных устройств, а потом использовать рекомендации ниже.
[[File:custom-device-config.png |300px|thumb|right| Конфигурация Custom Modbus Device в веб-интерфейсе контроллера Wiren Board]]
Для конфигурирования нового Modbus-устройства можно указать его регистры прямо в веб-интерфейсе контроллера в разделе '''Настройки — Конфигурационные файлы — Настройка драйвера serial-устройств''', выбрав тип устройства '''Custom Modbus Device'''.
В этом случае появятся поля, в которых можно будет задать параметры регистра и его значение.


При таком способе настройки регистры будут прописаны в файле конфигурации serial-порта <code>/etc/wb-mqtt-serial.conf</code> без создания нового шаблона. Это полезно при тестировании нового устройства.
Чтобы починить, попробуйте увеличить параметр <code>guard_interval_us</code> вплоть до тысяч единиц, например, 5000. Если работа стабилизируется, потихоньку уменьшайте это значение до тех пор, пока ошибки не появятся вновь. Предыдущее значение, когда всё работало хорошо и будет вашим значением в шаблоне.


== Особенности реализации Modbus RTU в устройствах Wiren Board ==
Ещё есть параметр <code>response_timeout_ms</code> — это максимальное время ответа устройства в миллисекундах, по умолчанию 500 мс. С ним тоже можно аккуратно поэкспериментировать.
Стандартом Modbus RTU предусмотрен обязательный интервал тишины в 3.5 символа между фреймами данных (под символом подразумевается посылка, состоящая из стартового бита, битов данных, бита четности и стоп-битов).
 
Не выставляйте без нужды огромных значений в этих параметрах — это замедлит опрос устройств на порту, куда подключено проблемное устройство. Подробнее о том, как работают эти параметры, смотрите в [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>


Для ускорения опроса устройств Wiren Board мы соблюдаем этот интервал только перед первым запросом к следующему в цикле опроса устройству (параметр ''frame_timeout_ms'' в шаблонах устройств).
=== Произвольные значения в регистрах с бинарной логикой ===
Иногда бывает так, что по смыслу регистр должен представляться в веб-интерфейсе переключателем ВКЛ/ВЫКЛ, но допустимые значения у него не 1/0.


Поэтому, чтобы соответствовать требованиям протокола Modbus-RTU, нужно для сторонних устройств задавать параметр ''guard_interval_us''. Этот параметр задает задержку перед записью каждого запроса в порт.
В этом случае вы описываете обычный канал с типом '''switch''' и указываете значения <code>on_value</code> и <code>off_value</code>, например:


== Совместная работа модулей Wiren Board и устройств сторонних производителей на одной шине==
<syntaxhighlight lang="json">
При работе модулей Wiren Board и устройств сторонних производителей на одной шине RS-485 параметр <code>guard_interval_us</code> следует задавать целиком для порта, также следует изменить параметр '''RS-485 Response Delay (ms)''' (Задержка перед ответом по RS-485) у модулей Wiren Board (если такой параметр имеется), например, установив значение 8 мс. Это необходимо, так как несоблюдение интервалов тишины при обращении к модулям Wiren Board приводит к сбою в работе некоторых устройств сторонних производителей.
{
  "name": "Status",
  "reg_type": "holding",
  "address": "0",
  "type": "switch",
  "format": "u16",
  "on_value": "0x00a5", // ВКЛ
  "off_value": "0x005a" // ВЫКЛ
}
</syntaxhighlight>
Теперь драйвер будет автоматически при чтении конвертировать указанные значения в положение переключателя, а при изменении положения переключателя — записывать указанные значения.


== Полезные ссылки ==
== Полезные ссылки ==
Строка 99: Строка 272:
* [https://github.com/wirenboard/conventions/blob/main/README.md Описание соглашений MQTT]
* [https://github.com/wirenboard/conventions/blob/main/README.md Описание соглашений MQTT]
* [http://json.parser.online.fr Онлайн проверка JSON]
* [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]

Текущая версия на 17:38, 12 апреля 2024

Введение

Рекомендуем сперва поискать ваше устройств в Таблице поддерживаемых устройств — вдруг оно уже там есть. Если устройства в списке нет, но оно поддерживает протокол Modbus, то его можно подключить к контроллеру Wiren Board.

Существует два вида протокола Modbus:

  1. Modbus RTU — устройства соединяются по шине RS-485.
  2. Modbus TCP — устройства соединяются по локальной сети через Wi-Fi или Ethernet.

Независимо от вида протокола, алгоритм добавления поддержки устройства в наш контроллер будет такой:

  1. Ищете документацию на ваше устройство с описанием его modbus-регистров.
  2. Составляете шаблон для нашего драйвера wb-mqtt-serial.
  3. Копируете созданный шаблон на контроллер в папку
  4. Выбираете в веб-интерфейсе контроллера свой шаблон и указываете адрес.

Некоторые производители Modbus-устройств не придерживаются стандартов протокола, что может сказаться на работе всей шины. Поэтому рекомендуем проверять работу новых устройств на отдельной шине и только после того, как добьётесь стабильной работы, подключать к ней другие Modbus-устройства.

Подготовка

Устройство с Modbus RTU:

  1. Откройте документацию на устройство и найдите описание modbus-регистров и параметров подключения (Baud rate, Data bits, Parity, Stop bits, Slave ID).
  2. Подключите устройство к контроллеру по шине RS-485.
  3. Проверьте связь с устройством и правильность подключения:
    • Остановите драйвер wb-mqtt-serial или иное ПО, которое опрашивает устройство.
    • Подключитесь к устройству с помощью утилиты modbus_client и считайте данные из любого известного вам регистра.

Устройство Modbus TCP:

  1. Откройте документацию на устройство и найдите описание modbus-регистров и настроек подключения (адрес, порт).
  2. Утилита modbus_client в релизах до 2304 содержит ошибку, из-за которой она не может работать по протоколу Modbus TCP. Если успользуете устаревший релиз, то подключите устройство к компьютеру через Ethernet.
  3. Попробуйте считать из устройства значение одного известного вам регистра.

Если вы смогли получить содержимое регистра — вы всё делаете верно и можете продолжать.

Создание шаблона

Рассказать драйверу wb-mqtt-serial, который в контроллере работает с Modbus-устройствами можно двумя способами:

  1. Добавить регистры устройства прямо в веб-интерфейсе контроллера. Этот способ удобен для быстрой проверки работы.
  2. Создать шаблон, который описывает регистры устройства, их тип и другие параметры. Этот способ удобен для масштабирования: просто копируете шаблон на другой контроллер и в нём появляется поддержка вашего устройства.

Здесь мы рассмотрим создание простого шаблона. Упрощённо шаблон устройства выглядит так:

{
    "device_type": "my-relay",  // тип устройства  уникальный идентификатор
    "title": "My Relay",        // отображаемое название
    "group": "g-relay",         // группа, в которой будет отображаться шаблон. Список групп в документации
    "device": {                     
        "name": "MY-RELAY",     // имя устройства, используется в MQTT
        "id": "my-relay",
        "groups": [ ],          // группы параметров и каналов        
        "channels": [ ],        // каналы, доступно в скриптах и на вкладке Устройства
        "parameters": [ ],      // параметры, можно менять в настройках устройства
        "translations": { }     // переводы 
    }
}

Полное описание смотрите в документации драйвера wb-mqtt-serial на Github.

Допустим, у нас есть одноканальное Modbus-реле, у которого таблица регистров, показанная ниже.

Адрес Тип Название Назначение
0 Discrete Input Input 1 Состояние входа устройства
1 Input Register Input 1 Counter Значение счётчика входов
3 Coil Relay 1 Состояние выхода и управление им
10 Holding Input Mode Выбор режима взаимодействия входов с выходами

В таком случае шаблон будет выглядеть так:

{
    "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": 1,
                "type": "switch",
                "group": "channels"
            },
            {
                "name": "Input 1 Counter",
                "reg_type": "input",
                "address": 2,
                "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": "Режим входа"
            }
        }
    }
}

Загрузка шаблона на контроллер

Когда шаблон готов, его надо загрузить на контроллер:

  1. Сохраните шаблон в файл, например, my-relay.json и загрузите его на контроллер в папку /etc/wb-mqtt-serial.conf.d/templates по инструкции.
  2. Проверьте шаблон на синтаксические ошибки командой:
    # 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
    
    в примере в шаблоне my-best-template.json в строке 12, символ 5 ожидается , or }, а находится что-то другое.
  3. Если с шаблоном всё в порядке, то перейдите в настройки драйвера и выберите ваш шаблон.

Отклонения от стандарта и что с ними делать

Оптимизация запросов драйвером

Стандартом Modbus RTU предусмотрен обязательный интервал тишины в 3.5 символа между фреймами данных (под символом подразумевается посылка, состоящая из стартового бита, битов данных, бита четности и стоп-битов).

Для ускорения опроса устройств Wiren Board мы соблюдаем этот интервал только перед первым запросом к следующему в цикле опроса устройству (параметр frame_timeout_ms в шаблонах устройств).

Поэтому, чтобы соответствовать требованиям протокола Modbus-RTU, нужно для сторонних устройств задавать параметр guard_interval_us. Этот параметр задает задержку перед записью каждого запроса в порт.

Нужное значение рассчитывается по формуле:

guard_interval_us = (3.5*11*10^6)/(скорость в бит/с).

Например, для скорости 9600 бит/с guard_interval_us = (3.5*11*10^6)/9600 = 4000 мкс. При проблемах с подключением стороннего устройства для теста это значение можно увеличить (например до 100000 мкс), так как сторонние устройства иногда работают не совсем корректно.

Если каналы устройства периодически мигают красным

Со сторонними устройствами довольно частая ситуация, когда вы сделали шаблон, данные идут, но в логах сыпятся ошибки, а каналы устройства в веб-интерфейсе контроллера окрашивают красным.

Основная причина этому — устройство слишком медленно обрабатывает запросы нашего драйвера. Для начала мы рекомендуем подключить такие устройства на отдельную шину, чтобы они не тормозили работу нормальных устройств, а потом использовать рекомендации ниже.

Чтобы починить, попробуйте увеличить параметр guard_interval_us вплоть до тысяч единиц, например, 5000. Если работа стабилизируется, потихоньку уменьшайте это значение до тех пор, пока ошибки не появятся вновь. Предыдущее значение, когда всё работало хорошо и будет вашим значением в шаблоне.

Ещё есть параметр response_timeout_ms — это максимальное время ответа устройства в миллисекундах, по умолчанию 500 мс. С ним тоже можно аккуратно поэкспериментировать.

Не выставляйте без нужды огромных значений в этих параметрах — это замедлит опрос устройств на порту, куда подключено проблемное устройство. Подробнее о том, как работают эти параметры, смотрите в Диаграмме таймаутов цикла опроса.

Оба параметра пишутся в секцию device шаблона:

"device": {
    "name": "BAC-6000ELNW",
    "id": "bac-6000elnw",
    "response_timeout_ms": 100,
    "guard_interval_us": 5000,
...
}

Разные регистры для чтения состояния и управления

Иногда в сторонних устройствах встречаются особенности:

  1. В некоторые регистры можно только писать информацию, но нельзя считывать.
  2. Один и тот же параметр может читаться по одному адресу, а записываться по другому.

Для того, чтобы драйвер работал с такими устройствами без ошибок, мы добавили параметр write_address.

Писать можно, читать нельзя

Допустим, в нашем устройстве есть такой регистр только для записи.

Адрес Тип Название Назначение
20 Coil Relay 1 Switch Управление выходом. Только для записи.

В этом случае канал надо описывать так:

{
    "name": "Relay 1 Switch",
    "write_address": "20",
    "reg_type": "coil",
    "type": "pushbutton",
    "format": "u16",
    "group": "channels",
    "on_value": 1 // определяет, что записывать в регистр при нажатии
}

Писать в один регистр, читать из другого

Допустим, в нашем устройстве команда записывается в один регистр, а читается из другого. Этот метод можно использовать только, если у обоих регистров один тип. Если типы разные — создавайте два разных канала: на чтение и на запись.

Адрес Тип Название Назначение
20 Coil Relay 1 Switch Управление выходом. Только для записи.
21 Coil Relay 1 State Состояние выхода. Только для чтения.

В этом случае канал надо описывать так: у нас будет один параметр в контроллере, но при обмене данными запись будет производиться один регистр, а чтение — из другого:

{
    "name": "Relay 1",
    "write_address": "20",   // адрес, куда мы записываем команды
    "address": "21",         // адрес, по которому мы читаем состояние    
    "reg_type": "coil",
    "type": "switch",
    "format": "u16",
    "group": "channels"
}

Произвольные значения в регистрах с бинарной логикой

Иногда бывает так, что по смыслу регистр должен представляться в веб-интерфейсе переключателем ВКЛ/ВЫКЛ, но допустимые значения у него не 1/0.

В этом случае вы описываете обычный канал с типом switch и указываете значения on_value и off_value, например:

{
  "name": "Status",
  "reg_type": "holding",
  "address": "0",
  "type": "switch",
  "format": "u16",
  "on_value": "0x00a5", // ВКЛ
  "off_value": "0x005a" // ВЫКЛ
}

Теперь драйвер будет автоматически при чтении конвертировать указанные значения в положение переключателя, а при изменении положения переключателя — записывать указанные значения.

Полезные ссылки