Connecting Third Party Devices to Wiren Board: различия между версиями
(адреса в примере и коде json-файла отличаются) |
|||
(не показано 17 промежуточных версий 3 участников) | |||
Строка 1: | Строка 1: | ||
{{DISPLAYTITLE: | {{DISPLAYTITLE: Подключение стороннего Modbus-устройства к контроллеру Wiren Board}} | ||
== Введение == | == Введение == | ||
Рекомендуем сперва поискать ваше устройств в [[Supported_devices | Таблице поддерживаемых устройств]] — вдруг оно уже там есть. Если устройства в списке нет, но оно поддерживает протокол [[Modbus|Modbus]], то его можно подключить к контроллеру Wiren Board. | Рекомендуем сперва поискать ваше устройств в [[Supported_devices | Таблице поддерживаемых устройств]] — вдруг оно уже там есть. Если устройства в списке нет, но оно поддерживает протокол [[Modbus|Modbus]], то его можно подключить к контроллеру Wiren Board. | ||
Строка 25: | Строка 25: | ||
Устройство Modbus TCP: | Устройство Modbus TCP: | ||
# Откройте документацию на устройство и найдите описание modbus-регистров и настроек подключения (адрес, порт). | # Откройте документацию на устройство и найдите описание modbus-регистров и настроек подключения (адрес, порт). | ||
# | # Так как утилита ''modbus_client'' содержит ошибку, из-за которой она не может работать по протоколу Modbus TCP, то подключите устройство к компьютеру через Ethernet. | ||
# Попробуйте | # Попробуйте считать из устройства значение одного известного вам регистра по [[Working_with_WB_devices_without_a_controller | инструкции]]. | ||
Если вы смогли получить содержимое регистра — вы всё делаете верно и можете продолжать. | Если вы смогли получить содержимое регистра — вы всё делаете верно и можете продолжать. | ||
Строка 32: | Строка 32: | ||
== Создание шаблона == | == Создание шаблона == | ||
Рассказать драйверу wb-mqtt-serial, который в контроллере работает с Modbus-устройствами можно двумя способами: | Рассказать драйверу wb-mqtt-serial, который в контроллере работает с Modbus-устройствами можно двумя способами: | ||
# [[RS-485:Configuration_via_Web_Interface#without-template| | # Добавить регистры устройства прямо в веб-интерфейсе контроллера по [[RS-485:Configuration_via_Web_Interface#without-template|инструкции]]. Этот способ удобен для быстрой проверки работы. | ||
# Создать шаблон, который описывает регистры устройства, их тип и другие параметры. Этот способ удобен для масштабирования: просто копируете шаблон на другой контроллер и в нём появляется поддержка вашего устройства. | # Создать шаблон, который описывает регистры устройства, их тип и другие параметры. Этот способ удобен для масштабирования: просто копируете шаблон на другой контроллер и в нём появляется поддержка вашего устройства. | ||
Строка 51: | Строка 51: | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Полное описание смотрите в [https://github.com/wirenboard/wb-mqtt-serial документации драйвера wb-mqtt-serial]. | |||
Допустим, у нас есть одноканальное Modbus-реле, у которого таблица регистров, показанная ниже. | Допустим, у нас есть одноканальное Modbus-реле, у которого таблица регистров, показанная ниже. | ||
Строка 92: | Строка 92: | ||
"name": "Input 1", | "name": "Input 1", | ||
"reg_type": "discrete", | "reg_type": "discrete", | ||
"address": | "address": 1, | ||
"type": "switch", | "type": "switch", | ||
"group": "channels" | "group": "channels" | ||
Строка 99: | Строка 99: | ||
"name": "Input 1 Counter", | "name": "Input 1 Counter", | ||
"reg_type": "input", | "reg_type": "input", | ||
"address": | "address": 2, | ||
"type": "value", | "type": "value", | ||
"group": "channels" | "group": "channels" | ||
Строка 154: | Строка 154: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
#: в примере в шаблоне ''my-best-template.json'' в строке 12, символ 5 ожидается <code>,</code> or <code>}</code>, а находится что-то другое. | #: в примере в шаблоне ''my-best-template.json'' в строке 12, символ 5 ожидается <code>,</code> or <code>}</code>, а находится что-то другое. | ||
# Если с шаблоном всё в порядке, то перейдите в настройки драйвера и [[RS-485:Configuration_via_Web_Interface| | # Если с шаблоном всё в порядке, то перейдите в настройки драйвера и выберите ваш шаблон — [[RS-485:Configuration_via_Web_Interface|инструкция]]. | ||
== Отклонения от стандарта и что с ними делать == | == Отклонения от стандарта и что с ними делать == | ||
=== Оптимизация запросов драйвером === | === Оптимизация запросов драйвером === | ||
В первую очередь, проверьте качество физического подключения устройств и только потом следуйте советам ниже. | |||
Стандартом Modbus RTU предусмотрен обязательный интервал тишины в 3.5 символа между фреймами данных (под символом подразумевается посылка, состоящая из стартового бита, битов данных, бита четности и стоп-битов). | Стандартом Modbus RTU предусмотрен обязательный интервал тишины в 3.5 символа между фреймами данных (под символом подразумевается посылка, состоящая из стартового бита, битов данных, бита четности и стоп-битов). | ||
Строка 166: | Строка 168: | ||
Нужное значение рассчитывается по формуле: | Нужное значение рассчитывается по формуле: | ||
<syntaxhighlight lang="bash"> | <syntaxhighlight lang="bash"> | ||
guard_interval_us = (3.5*11* | guard_interval_us = (3.5*11*106)/(скорость в бит/с). | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Например, для скорости 9600 бит/с <code>guard_interval_us = (3.5*11*106)/9600 = 4000 мкс</code>. При проблемах с подключением стороннего устройства для теста это значение можно увеличить (например до 100000 мкс), так как сторонние устройства иногда работают не совсем корректно. | |||
=== Разные регистры для чтения состояния и управления === | === Разные регистры для чтения состояния и управления === | ||
Строка 223: | Строка 203: | ||
==== Писать в один регистр, читать из другого==== | ==== Писать в один регистр, читать из другого==== | ||
Допустим, в нашем устройстве команда записывается в один регистр, а читается из другого. Этот метод можно использовать только, если у обоих регистров один тип. Если типы разные — создавайте два разных | Допустим, в нашем устройстве команда записывается в один регистр, а читается из другого. Этот метод можно использовать только, если у обоих регистров один тип. Если типы разные — создавайте два разных контрола: на чтение и на запись. | ||
{| border="1" class="wikitable" | {| border="1" class="wikitable" | ||
Строка 234: | Строка 214: | ||
|} | |} | ||
В этом случае канал надо описывать так | В этом случае канал надо описывать так — у нас будет один контрол, а при работе с устройством, записываться будет один регистр, а читаться другой: | ||
<syntaxhighlight lang="json"> | <syntaxhighlight lang="json"> | ||
{ | { | ||
Строка 259: | Строка 239: | ||
"type": "switch", | "type": "switch", | ||
"format": "u16", | "format": "u16", | ||
"on_value": "0x00a5", | "on_value": "0x00a5", | ||
"off_value": "0x005a" | "off_value": "0x005a" | ||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Полезные ссылки == | == Полезные ссылки == |
Версия 16:56, 17 февраля 2023
Введение
Рекомендуем сперва поискать ваше устройств в Таблице поддерживаемых устройств — вдруг оно уже там есть. Если устройства в списке нет, но оно поддерживает протокол Modbus, то его можно подключить к контроллеру Wiren Board.
Существует два вида протокола Modbus:
- Modbus RTU — устройства соединяются по шине RS-485.
- Modbus TCP — устройства соединяются по локальной сети через Wi-Fi или Ethernet.
Независимо от вида протокола, алгоритм добавления поддержки устройства в наш контроллер будет такой:
- Ищете документацию на ваше устройство с описанием его modbus-регистров.
- Составляете шаблон для нашего драйвера wb-mqtt-serial.
- Копируете созданный шаблон на контроллер в папку
- Выбираете в веб-интерфейсе контроллера свой шаблон и указываете адрес.
Некоторые производители Modbus-устройств не придерживаются стандартов протокола, что может сказаться на работе всей шины. Поэтому рекомендуем проверять работу новых устройств на отдельной шине и только после того, как добьётесь стабильной работы, подключать к ней другие Modbus-устройства.
Подготовка
Устройство с Modbus RTU:
- Откройте документацию на устройство и найдите описание modbus-регистров и параметров подключения (Baud rate, Data bits, Parity, Stop bits, Slave ID).
- Подключите устройство к контроллеру по шине RS-485.
- Проверьте связь с устройством и правильность подключения:
- Остановите драйвер wb-mqtt-serial или иное ПО, которое опрашивает устройство.
- Подключитесь к устройству с помощью утилиты modbus_client и считайте данные из любого известного вам регистра.
Устройство Modbus TCP:
- Откройте документацию на устройство и найдите описание modbus-регистров и настроек подключения (адрес, порт).
- Так как утилита modbus_client содержит ошибку, из-за которой она не может работать по протоколу Modbus TCP, то подключите устройство к компьютеру через Ethernet.
- Попробуйте считать из устройства значение одного известного вам регистра по инструкции.
Если вы смогли получить содержимое регистра — вы всё делаете верно и можете продолжать.
Создание шаблона
Рассказать драйверу wb-mqtt-serial, который в контроллере работает с Modbus-устройствами можно двумя способами:
- Добавить регистры устройства прямо в веб-интерфейсе контроллера по инструкции. Этот способ удобен для быстрой проверки работы.
- Создать шаблон, который описывает регистры устройства, их тип и другие параметры. Этот способ удобен для масштабирования: просто копируете шаблон на другой контроллер и в нём появляется поддержка вашего устройства.
Здесь мы рассмотрим создание простого шаблона. Упрощённо шаблон устройства выглядит так:
{
"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.
Допустим, у нас есть одноканальное 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": "Режим входа"
}
}
}
}
Загрузка шаблона на контроллер
Когда шаблон готов, его надо загрузить на контроллер:
- Сохраните шаблон в файл, например,
my-relay.json
и загрузите его на контроллер в папку/etc/wb-mqtt-serial.conf.d/templates
по инструкции. - Проверьте шаблон на синтаксические ошибки командой:
# 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}
, а находится что-то другое.
- Если с шаблоном всё в порядке, то перейдите в настройки драйвера и выберите ваш шаблон — инструкция.
Отклонения от стандарта и что с ними делать
Оптимизация запросов драйвером
В первую очередь, проверьте качество физического подключения устройств и только потом следуйте советам ниже.
Стандартом Modbus RTU предусмотрен обязательный интервал тишины в 3.5 символа между фреймами данных (под символом подразумевается посылка, состоящая из стартового бита, битов данных, бита четности и стоп-битов).
Для ускорения опроса устройств Wiren Board мы соблюдаем этот интервал только перед первым запросом к следующему в цикле опроса устройству (параметр frame_timeout_ms в шаблонах устройств).
Поэтому, чтобы соответствовать требованиям протокола Modbus-RTU, нужно для сторонних устройств задавать параметр guard_interval_us. Этот параметр задает задержку перед записью каждого запроса в порт.
Нужное значение рассчитывается по формуле:
guard_interval_us = (3.5*11*106)/(скорость в бит/с).
Например, для скорости 9600 бит/с guard_interval_us = (3.5*11*106)/9600 = 4000 мкс
. При проблемах с подключением стороннего устройства для теста это значение можно увеличить (например до 100000 мкс), так как сторонние устройства иногда работают не совсем корректно.
Разные регистры для чтения состояния и управления
Иногда в сторонних устройствах встречаются особенности:
- В некоторые регистры можно только писать информацию, но нельзя считывать.
- Один и тот же параметр может читаться по одному адресу, а записываться по другому.
Для того, чтобы драйвер работал с такими устройствами без ошибок, мы добавили параметр 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"
}