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

Материал из Wiren Board
 
(не показаны 54 промежуточные версии 4 участников)
Строка 1: Строка 1:
{{DISPLAYTITLE: Как подключить Modbus RTU-устройство стороннего производителя к контроллеру Wirenboard?}}
{{DISPLAYTITLE: Как писать шаблоны для сторонних Modbus-устройств}}
== Введение ==
== Введение ==
Modbus RTU один из распространенных протоколов для связи устройств. Если устройство стороннего производителя поддерживает протокол Modbus RTU, то его можно подключить к контроллеру Wirenboard.
Рекомендуем сперва поискать ваше устройств в [[Supported_devices | Таблице поддерживаемых устройств]] вдруг оно уже там есть. Если устройства в списке нет, но оно поддерживает протокол [[Modbus|Modbus]], то его можно подключить к контроллеру Wiren Board.


Список всех поддерживаемых контроллером протоколов можно найти в [[Supported_devices | Таблице поддерживаемых устройств]].  
Существует два вида протокола Modbus:
# Modbus RTU — устройства соединяются по шине RS-485.
# Modbus TCP — устройства соединяются по локальной сети через Wi-Fi или Ethernet.
 
Независимо от вида протокола, алгоритм добавления поддержки устройства в наш контроллер будет такой:
# Ищете документацию на ваше устройство с описанием его modbus-регистров.
# Составляете шаблон для нашего драйвера [[wb-mqtt-serial]].
# Копируете созданный шаблон на контроллер в папку
# Выбираете в веб-интерфейсе контроллера свой шаблон и указываете адрес.


Некоторые производители 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-mqtt-serial_templates | создайте шаблон для драйвера wb-mqtt-serial]] в шаблоне укажите:
# Откройте документацию на устройство и найдите описание modbus-регистров и настроек подключения (адрес, порт).
* регистры, в которых хранятся нужные вам данные;
# Утилита ''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>.
Если вы смогли получить содержимое регистра — вы всё делаете верно и можете продолжать.
<p>Например, для скорости 9600 бит/с <code>guard_interval_us = (3.5*11*10<sup>6</sup>)/9600 = 4000 мкс</code>. При проблемах с подключением стороннего устройства для теста это значение можно увеличить (например до 100000 мкс), так как сторонние устройства иногда работают не совсем корректно.</p>
 
* для проверки корректности шаблона выполните на контроллере команду <code>wb-mqtt-serial -g</code>.
== Создание шаблона ==
Эта команда проверит на корректность файлы шаблонов в директориях <code>/usr/share/wb-mqtt-serial/templates</code> (директория предустановленных шаблонов) и <code>/etc/wb-mqtt-serial.conf.d/templates</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": 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>
 
== Загрузка шаблона на контроллер ==
Когда шаблон готов, его надо загрузить на контроллер:
# Сохраните шаблон в файл, например, <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 ==
=== Произвольные значения в регистрах с бинарной логикой ===
Стандартом Modbus RTU предусмотрен обязательный интервал тишины между фреймами данных в 3.5 символа — ''frame_timeout_ms''.
Иногда бывает так, что по смыслу регистр должен представляться в веб-интерфейсе переключателем ВКЛ/ВЫКЛ, но допустимые значения у него не 1/0.


Для ускорения опроса устройств Wiren Board мы соблюдаем этот интервал только перед первым запросом к следующему в цикле опроса устройству.
В этом случае вы описываете обычный канал с типом '''switch''' и указываете значения <code>on_value</code> и <code>off_value</code>, например:


Поэтому, чтобы соответствовать требованиям протокола Modbus-RTU, нужно для сторонних устройств задавать параметр ''guard_interval_us''.
<syntaxhighlight lang="json">
{
  "name": "Status",
  "reg_type": "holding",
  "address": "0",
  "type": "switch",
  "format": "u16",
  "on_value": "0x00a5", // ВКЛ
  "off_value": "0x005a" // ВЫКЛ
}
</syntaxhighlight>
Теперь драйвер будет автоматически при чтении конвертировать указанные значения в положение переключателя, а при изменении положения переключателя — записывать указанные значения.


== Полезные ссылки ==
== Полезные ссылки ==
Строка 40: Строка 269:
* [[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]

Текущая версия на 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" // ВЫКЛ
}

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

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