Giter VIP home page Giter VIP logo

wb-mqtt-serial's Introduction

wb-mqtt-serial

Serial device <==> MQTT bridge which follows Wiren Board MQTT Conventions. It's designed to be used on Wiren Board family of programmable automation controllers (PACs), although there is nothing that prevents it from running on a arbitrary Linux machine.

Драйвер master-slave протоколов для устройств, работающих через последовательный порт. В драйвере wb-mqtt-serial реализована поддержка некоторых устройств, работающих по протоколам Modbus, Uniel, ИВТМ, Меркурий 230, Милур.

Запускается командой /etc/init.d/wb-mqtt-serial start По умолчанию запуск драйвера происходит при загрузке системы при наличии конфигурационного файла /etc/wb-mqtt-serial.conf. При установке пакета конфигурационный файл, в котором не описано ни одного подключенного устройства. При старте по умолчанию драйвер завершается с ошибкой. Добавьте устройства в /etc/wb-mqtt-serial.conf либо воспользуйтесь онлайн-редактором настроек для начала работы.

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

# service wb-mqtt-serial stop
# wb-mqtt-serial -c /etc/wb-mqtt-serial.conf -d

Конфигурационный файл построен по трёхуровневой схеме: порты (ports) -> устройства (devices) -> каналы (channels). Конфигурация устройства device может быть задана двумя способами: вручную прописать все параметры или задать только пять параметров:

{
    // По DeviceType драйвер будет искать параметры в папке
    // /usr/share/wb-mqtt-serial/templates.
    "device_type" : "DeviceType",

    // отображаемое имя устройства. Публикуется как
    // .../meta/name в MQTT
    // По умолчанию name берется из шаблона и добавляется slave_id, т.е.
    // "name" + " " + "slave_id"
    "name" : "somename",

    // уникальный идентификатор устройства в MQTT.
    // каждое элемент в devices должен иметь уникальный id
    // topic'и, относящиеся в MQTT к данному устройству,
    // имеют общий префикс /devices/<идентификатор топика>/...
    // также по умолчанию берется из шаблона с добавлением slave_id:
    // "deviceID" + "_" + slave_id
    "id" : "deviceID",

    // идентификатор slave
    "slave_id" : slaveID,

    // включить/выключить устройство. В случае задания
    // "enabled": false опрос устройства и запись значений
    // его каналов не происходит. По умолчанию - true.
    "enabled" : true,

    // если используется шаблон устройства, определения
    // каналов совмещаются. Если имя (name) в определении
    // канала устройства совпадает с именем канала в шаблоне,
    // свойства каналов из шаблона и определения устройства
    // совмещаются, при этом значения свойств из определения
    // устройства (в файле конфигурации) имеют преимущество.
    // Это можно использовать, например, для задания индивидуальных
    // интервалов опроса каналов. Если канал с таким же
    // именем, как канал в определении устройства, отсутствует
    // в шаблоне, создаётся новый канал.
    "channels": [
        {
            // имя канала. topic'и, соответствующие каналу,
            "name" : "Temp 1",
            "poll_interval": 10000
        }
    ]
}

Структура папки templates такова, что в каждом файле приведены параметры для одного типа устройств. Также можно совместить первый способ со вторым, к вышеприведенным 5 параметрам дописать конфигурацию для каналов, которые не прописаны в соответствующем файле в папке templates. См. также: пример конфигурационного файла с использованием шаблонов.

Ниже приведён пример конфигурационного файла /etc/wb-mqtt-serial.conf

{
    // опция debug включает или выключает отладочную печать.
    // Опция -d командной строки wb-mqtt-serial также
    // включает отладочную печать и имеет приоритет над
    // данной опцией.
    "debug": false,

    // список портов
    "ports": [
        {
            // тип порта - serial: RS-485, tcp: TCP/IP (по умолчанию - serial)
            "port_type": "serial",

            // устройство, соответствующее порту RS-485 (если выбран тип порта serial)
            "path" : "/dev/ttyNSC0",

            // IP адрес или имя хоста (если выбран тип порта TCP)
            "address": "127.0.0.1",

            // TCP порт (если выбран тип порта TCP)
            "port": 3000,

            // скорость порта
            "baud_rate": 9600,

            // паритет - N, O или E (по умолчанию - N)
            "parity": "N",

            // количество бит данных (по умолчанию - 8)
            "data_bits": 8,

            // количество стоп-бит
            "stop_bits": 2,

            // Минимальный интервал опроса каждого регистра
            // по-умолчанию для устройств, подключенных к порту,
            // в миллисекундах

            "poll_interval": 10,

            // Дополнительная задержка перед каждой отправкой данных в порт,
            // в микросекундах

            "guard_interval_us": 1000,

            // Таймаут соединения (только для TCP порта).
            // Если в течении указанного времени ни по одному устройству на порту не поступило данных (а также истек "connection_max_fail_cycles"),
            // TCP соединение будет разорвано и произойдет попытка переподключения
            "connection_timeout_ms": 5000,

            // Количество неудачных циклов опроса (только для TCP порта)
            // Если в течении указанного количества циклов опроса ни по одному устройству на порту не поступило данных (а также истек "connection_timeout_ms"),
            // TCP соединение будет разорвано и произойдет попытка переподключения
            "connection_max_fail_cycles": 2,

            // включить/выключить порт. В случае задания
            // "enabled": false опрос порта и запись значений
            // каналов в устройства на данном порту не происходит.
            // По умолчанию - true.
            "enabled": true,

            // список устройств на данном порту
            "devices" : [
                {
                    // отображаемое имя устройства. Публикуется как
                    // .../meta/name в MQTT
                    "name": "MSU34+TLP",

                    // уникальный идентификатор устройства в MQTT.
                    // каждое элемент в devices должен иметь уникальный id
                    // topic'и, относящиеся в MQTT к данному устройству,
                    // имеют общий префикс /devices/<идентификатор топика>/...
                    "id": "msu34tlp",

                    // идентификатор slave
                    "slave_id": 2,

                    // включить/выключить устройство. В случае задания
                    // "enabled": false опрос устройства и запись значений
                    // его каналов не происходит. По умолчанию - true.
                    "enabled": true,

                    // максимальное количество считываемых "пустых" регистров.
                    // Драйвер в целях оптимизации может считывать регистры
                    // "пачкой". При этом, если какие-либо регистры не
                    // были включены в конфигурацию, но в целях ускорения
                    // опроса (чтобы не разрывать "пачку") их всё-таки
                    // можно считывать, можно указать значение max_hole_size
                    // больше 0. В данный момент поддерживается только
                    // устройствами Modbus.
                    "max_reg_hole": 10,

                    // то же самое, что max_reg_hole, но для однобитовых
                    // регистров (coils и discrete inputs в Modbus). В данный
                    // момент поддерживается только устройствами Modbus.
                    "max_bit_hole": 80,

                    // максимальное количество регистров в одной пакетной операции
                    // чтения. В данный момент поддерживается только устройствами
                    // Modbus.
                    "max_read_registers": 10,

                    // Минимальный интервал опроса регистров данного устройства
                    // по умолчанию, в миллисекундах
                    "poll_interval": 10,

                    // Минимальный интервал между опросом индивидуальных регистров
                    // данного устройства в микросекундах
                    "guard_interval_us": 0,

                    // (При возникновении ошибки) Интервал после последнего успешного обмена данными с устройством,
                    // по истечении которого (а также "device_max_fail_cycles") устройство будет помечено отключенным и будет опрашиваться в ограниченном режиме
                    "device_timeout_ms": 3000,

                    // Количество неудачных циклов опроса устройства
                    // Если в течении указанного количества полных циклов опроса ни по одному регистру устройства не поступило данных (а также истек "device_timeout_ms"),
                    // устройство будет помечено отключенным и будет опрашиваться в ограниченном режиме
                    "device_max_fail_cycles": 2,

                    // список каналов устройства
                    "channels": [
                        {
                            // имя канала. topic'и, соответствующие каналу,
                            // публикуются как
                            // /devices/<идентификатор канала>/controls/<имя канала>
                            "name" : "Temp 1",

                            // тип регистра
                            // возможные значения для Modbus:
                            // "coil" - 1 бит, чтение/запись
                            // "discrete" - 1 бит, только чтение
                            // "holding" - 16 бит, чтение/запись, код функции на запись выбирается автоматически, в зависимости от размера
                            // "input" - 16 бит, только чтение
                            // "holding_single" - то же что и holding однако регистры записываются всегда по одному, кодом 06
                            // "holding_multi" - то же что и holding однако регистры записываются всегда кодом 16
                            "reg_type" : "input",

                            // адрес регистра
                            "address" : 0,

                            // тип элемента управления, например,
                            // "temperature", "text", "switch"
                            // Тип wo-switch задаёт вариант switch,
                            // для которого не производится опрос регистра -
                            // для таких каналов возможна только запись.
                            "type": "temperature",

                            // формат канала. Задаётся для регистров типа
                            // "holding" и "input". Возможные значения:
                            // "u16" - беззнаковое 16-битное целое
                            //         (используется по умолчанию)
                            // "s16" - знаковое 16-битное целое
                            // "u8" - беззнаковое 8-битное целое
                            // "s8" - знаковое 8-битное целое
                            // "u32" - беззнаковое 32-битное целое (big-endian).
                            //     (занимает 2 регистра, начиная с указанного)
                            // "s32" - знаковое 32-битное целое (big-endian).
                            //     (занимает 2 регистра, начиная с указанного)
                            // "s64" - знаковое 64-битное целое (big-endian).
                            //     (занимает 4 регистра, начиная с указанного)
                            // "u64" - беззнаковое 64-битное целое (big-endian).
                            //     (занимает 4 регистра, начиная с указанного)
                            //
                            // "float" - число с плаваяющей точкой IEEE 754. 32 bit. (big-endian).
                            //     (занимает 2 регистра, начиная с указанного)
                            // "double" - число с плаваяющей точкой двойной точности IEEE 754. 64 bit. (big-endian).
                            //     (занимает 4 регистра, начиная с указанного)
                            // "char8" - однобайтовый символ в кодировке ASCII

                            "format": "s8",

                            // Порядок 16-битных слов для каналов, имеющих размер больше 16 бит.
                            // Возможные значения:
                            //  "big_endian" (по-умолчанию): [0xAA 0xBB] [0xCC 0xDD] => 0xAABBCCDD
                            //  "little_endian":  [0xAA 0xBB] [0xCC 0xDD] => 0xCCDDAABB
                            "word_order" : "big_endian",

                            // для регистров типа coil и discrete
                            // с типом отображения switch/wo-swich
                            // также допускается задание on_value -
                            // числового значения, соответствующего
                            // состоянию "on" (см. ниже)

                            // минимальный интервал опроса данного регистра в миллисекундах
                            "poll_interval": 10
                        },
                        {
                            // Ещё один канал
                            "name" : "Illuminance",
                            "reg_type" : "input",
                            "address" : 1,
                            "type": "text"
                        },
                        {
                            "name" : "Pressure",
                            "reg_type" : "input",
                            "address" : 2,
                            "type": "text",
                            "scale": 0.075
                        },
                        {
                            "name" : "Temp 2",
                            "reg_type" : "input",
                            "address" : 3,
                            "type": "temperature",
                            "format": "s8"
                        }
                    ]
                },
                {
                    // ещё одно устройство на канале
                    "name": "DRB88",
                    "id": "drb88",
                    "enabled": true,
                    "slave_id": 22,

                    // секция инициализации
                    "setup": [
                        {
                            // название регистра (для отладки)
                            // Выводится в случае включённой отладочной печати.
                            "title": "Input 0 type",
                            // адрес holding-регистра
                            "address": 1,
                            // значение для записи
                            "value": 1
                        },
                        {
                            "title": "Input 0 module",
                            "address": 3,
                            "value": 3 // was: 11
                        }
                    ],
                    "channels": [
                        {
                            "name" : "Relay 1",
                            "reg_type" : "coil",
                            "address" : 0,
                            "type": "switch"
                        },
                        {
                            "name" : "Relay 2",
                            "reg_type" : "coil",
                            "address" : 1,
                            "type": "switch"
                        },
                        // ...
                        {
                            "name" : "Input 2",
                            "reg_type" : "input",
                            "address" : 1,
                            "type": "switch",
                            // значение, соответствующее состоянию "on"
                            "on_value": 101
                        },
                        {
                            "name" : "Input 3",
                            "reg_type" : "input",
                            "address" : 2,
                            "type": "switch",
                            "on_value": 101
                        },
                        // ...
                    ]
                }
            ]
        },
        {
            // ещё один порт со своим набором устройств
            "path" : "/dev/ttyNSC1",
            "baud_rate": 9600,
            "parity": "N",
            "data_bits": 8,
            "stop_bits": 1,
            "poll_interval": 100,
            "enabled": true,
            "devices" : [
                {
                    "name": "tM-P3R3",
                    "id": "tmp3r3",
                    "enabled": true,
                    "slave_id": 1,
                    "channels": [
                        {
                            "name" : "Relay 0",
                            "reg_type" : "coil",
                            "address" : 0,
                            "type": "switch"
                        },
                        // ...
                    ]
                },
                // ...
            ]
        }
    ]
}

Для поддерживаемых устройств существуют шаблоны конфигурации. Для примера в приведенном ниже файле приведены разные варианты записи параметров, первое устройство задано через шаблон, второй device через шаблон, но параметры "name" и "id" заданы, и также можно добавить конфигурацию для канала, который добавится к тем, что есть в шаблоне(но он не должен описывать тот же канал что уже есть в шаблоне), и параметры третьего устройства записаны явно.

Подробнее о таймаутах и количестве неудачных циклов

  • циклом опроса устройства считается внутренний цикл опроса драйвера внутри которого был опрошен хотя бы один из регистров данного устройства.
  • connection_timeout_ms и connection_max_fail_cycles - указываются для порта типа TCP. Необходимы для автоматического восстановления соединения. Если в течение connection_timeout_ms и более чем connection_max_fail_cycles подряд циклов опроса все устройства были отключены, соединение сбрасывается и происходит попытка переподключения. Можно использовать только один тип таймаута, для этого нужно выставить значение 0 другому типу таймаута (например, чтобы осуществлять обраружение разрыва соединения только по времени, нужно выставить "connection_max_fail_cycles": 0). При большом количестве устройств на порту, длительность цикла опроса устройств может сильно варироваться в зависимости от числа отвечающих устройств, т.к. они вносят дополнительные задержки на ожидание ответа, поэтому если нужно обозначить минимальное количество циклов опроса до отключения вне зависимости от числа устройств можно использовать вариант connection_max_fail_cycles. При использовании только connection_timeout_ms, на количество попыток обращения к порту будут влиять другие временные настройки, такие как poll_interval, guard_interval, response_timeout и при их изменении возможно придется подстраивать значение connection_timeout_ms. Если же нужно исключить срабатывание таймаута на каких-то кратковременных случайных ошибках, которые не стоит считать обрывом связи, то нужно использовать connection_timeout_ms. При использовании параметров вместе, таймаут сработает только когда выполнятся оба условия, т.е. пройдет нужное время и количество циклов.
  • device_timeout_ms и device_max_fail_cycles - указывается для устройства. По семантике аналогичен connection_timeout_ms и connection_max_fail_cycles, но только для устройства. Нужен для выявления отключения устройства для повторной отправки setup - секции при переподключении. Если в течение device_timeout_ms и более чем device_max_fail_cycles подряд циклов ни один из опрошенных регистров не был успешно прочитан, то устройство будет помечено как отсоединенное и будет опрашиваться в ограниченном режиме, т.е. при наличии у устройства setup - секции, драйвер будет пытаться записать ее, а в противном случае, будет пытаться опросить устройство. Если первое обращение к устройству в ограниченном режиме закончилось ошибкой, драйвер считает что устройство все еще отключено и больше не опрашивает его в этом цикле. Это позволяет тратить меньше времени на отключенные устройства. Первый успешный запрос к устройству будет расценен как переподключение устройства.

Значения по умолчанию:

Параметр Значение
device_timeout_ms 3000
device_max_fail_cycles 2
connection_timeout_ms 5000
connection_max_fail_cycles 2

Замечания для TCP порта:

При использовании TCP мостов, драйвер не видит разницы между двумя ситуациями:

  • физически отключены все устройства от моста
  • разорвано TCP соединение с мостом

так как в обоих случаях никаких данных драйвер не получает. Поэтому, в этом случае, connection_timeout для порта и device_timeout для устройств истекают одновременно.

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

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

Объединенное чтение регистров и его авто-отключение

Для ускорения опроса регистров устройств, драйвер объединяет чтение соседних регистров в один запрос (см. max_reg_hole, max_bit_hole), однако, считывание т.н. "пустых" регистров может привести к ошибкам на некоторых устройствах. Как только драйвер получает от устройства ошибку при считывании множества регистров, среди которых есть пустые, которая могла быть вызвана чтением пустых регистров (для Modbus: ILLEGAL_DATA_ADDRESS, ILLEGAL_DATA_VALUE), драйвер перестает объединенно считывать эти регистры.

Поддержка различных протоколов на одной шине

Возможно использование устройств, работающих по различным протоколам, на одном порту. При этом следует учитывать особенности конкретных протоколов. Например, фреймы устройств Uniel начинаются с байта 0xff, устройств ИВТМ - с байта 0x24 ('$'), в случае же протоколов Modbus, Меркурий 230 и Милур первым байтом фрейма является идентификатор slave, поэтому при совмещении подобных устройств следует внимательно подходить к выбору slave id - у устройств Милур, например, slave id по умолчанию равен 0xff, что приводит к конфликту с устройствами Uniel. Устройства Милур требуют дополнительных задержек при опросе (заданы в шаблоне) и при использовании на одной шине с другими устройствами могут снизить скорость опроса. Некоторые устройства, поддерживающие дополнительные протоколы, могут оказаться несовместимыми с теми или иными протоколами на той же шине, например, было замечено, что устройства с поддержкой протокола A-BUS производства "Разумный дом" не могут работать на одной шине с устройствами Uniel. Работа устройств ИВТМ на одной шине с устройствами, работающими по другим протоколам, не проверялась. Проверенная рабочая комбинация: Modbus + Milur (slave_id != 0xff) + Uniel на одной шине.

Таблица шаблонов device_type

Сгруппирована по протоколам.

Modbus-RTU

Device device_type id_prefix name_prefix
"Разумный дом" четырёхканальный диммер светодиодов DDL4 DDL24 ddl24 DDL24
"Разумный дом" релейный модуль DRB88 DRB88 drb88 DRB88
"ICP DAS" модуль управления освещением LC-103 LC-103 lc-103 LC-103
"Разумный дом" MSU24 MSU24 msu24 MSU24
"Разумный дом" MSU21 MSU21 msu21 MSU21
"Разумный дом" MSU34+TLP MSU34 msu34tlp MSU34+TLP
"Разумный дом" MSU34+TLHP MSU34TLHP msu34tlhp MSU34+TLHP
"ICP DAS" модуль ввода-вывода TM-P3R3 TM-P3R3 TM-P3R3 tmp3r3
"Kvadro" модуль подключения термометров 1-wire kvadro-1wire kvadro-1wire Kvadro 1-Wire
PD561Z-9SY счётчик электроэнергии PD561Z pd561z pd561z
SDM220 счётчик электроэнергии SDM220 sdm220 sdm220
SDM120 счётчик электроэнергии SDM120 sdm120 sdm120
WELLPRO WP8028ADAM (8DI/8DO) WP8028ADAM wp8028adam WP8028ADAM
Wiren Board RGB-диммер WB-MRGB WB-MRGB WB-MRGB wb-mrgb
Wiren Board Релейный модуль WB-MRM2 WB-MRM2 WB-MRM2 wb-mrm2
Wiren Board Релейный модуль WB-MR11 WB-MR11 WB-MR11 wb-mr11
Wiren Board Релейный модуль WB-MR14 WB-MR14 WB-MR14 wb-mr14
Wiren Board модуль дискретных/счётных входов WB-MCM16 WB-MCM16 WB-MCM16 wb-mcm16
Wiren Board Датчик WB-MS-THLS / WB-MSW-THLS WB-MS-THLS wb-ms-thls WB-MS-THLS
Wiren Board Датчик WB-MS-THLS / WB-MSW-THLS (fw. v.2) WB-MS-THLS v.2 wb-ms-thls WB-MS-THLS

Милур

Device device_type id_prefix name_prefix
Счётчик электроэнергии Милур-305 milur305 milur305 Milur 305
Счётчик электроэнергии Милур-105 (Милур-104) Milur 104/105 milur105 Milur 105

Mercury 230

Device device_type id_prefix name_prefix
Счётчик электроэнергии Меркурий-230 mercury230 mercury230ar02 Mercury 230AR-02

Uniel

Device device_type id_prefix name_prefix
Модуль управления освещением UCH-M111RX UCH-M111RX uchm111rx UCH-M111RX 0808
Модуль управления автоматикой UCH-M121RX UCH-M121RX uchm121rx UCH-M121RX 0808
Диммер светодиодных ламп UCH-M141RC UCH-M141RC uchm141rc UCH-M141RC 0808

ИВТМ

Device device_type id_prefix name_prefix
Термогигрометр ИВТМ-7 М 3 IVTM-7M-3 ivtm7m3 IVTM-7M-3

Пульсар

Device device_type id_prefix name_prefix
Счётчик воды "Пульсар" pulsar-water pulsar-water Pulsar Water Meter
Счётчик воды многоструйный "Пульсар-М" pulsar-m-water pulsar-m-water Pulsar-M Water Meter
Счётчик тепла "Пульсар" pulsar-heat pulsar-heat Pulsar Heat Meter

wb-mqtt-serial's People

Contributors

evgeny-boger avatar ivan4th avatar django-kz avatar xrengine512 avatar attiladoor avatar kilpio avatar lexszero avatar poglazov avatar webconn avatar serezhachernik avatar nikitoz236 avatar v12aml avatar jolfzverb avatar ucayalifish avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.