В предыдущей статье подробно изложено подключение Modbus RTU устройства к конвертеру Modbus RTU <-> TCP. Подключим конвертер Modbus TCP и, соответственно, устройство Modbus RTU к облаку IoT Hub.
Для начала воспользуемся статьей на сайте Microsoft по подключению modbus устройств. Поскольку объяснение в статье очень подробное, нет смысла дублировать. Для моего оборудования настройки будут такими:
- IP: 192.168.26.110
- Address: 30001 + 1 (смещение) = 30002. Адресация Input Register начинается с 30001 адреса + смещение.
- Port: 8899 — в документации Microsoft и на сайте github с исходниками модуля modbus нет упоминания о том, как указать порт и не сказано какой порт является дефолтным. Посмотрим как отреагирует модуль, если опустить этот параметр.
- HwId — поправил название устройства, MAC адрес оставил из примера, не критично.
- DisplayName — поправил на «Temp».
Результирующий JSON для вставки в properties.
"properties.desired": { "PublishInterval": "2000", "SlaveConfigs": { "TermoSensor": { "SlaveConnection": "192.168.26.110", "HwId": "TermoSensor-0a:01:01:01:01:01", "Operations": { "Op01": { "PollingInterval": "1000", "UnitId": "1", "StartAddress": "30002", "Count": "1", "DisplayName": "Temp" } } } } } }
После развертывания модуля получаем следующиий набор ошибок:
PS C:\WINDOWS\system32> iotedge logs modbus -f IoT Hub module client initialized. Desired property change: {"PublishInterval":"2000","SlaveConfigs":{"TermoSensor":{"SlaveConnection":"192.168.26.110","HwId":"PowerMeter-0a:01:01:01:01:01","Operations":{"Op01":{"PollingInterval":"1000","UnitId":"1","StartAddress":"30002","Count":"1","DisplayName":"Temp"}}}},"$version":1} Attempt to load configuration: {"PublishInterval":"2000","SlaveConfigs":{"TermoSensor":{"SlaveConnection":"192.168.26.110","HwId":"PowerMeter-0a:01:01:01:01:01","Operations":{"Op01":{"PollingInterval":"1000","UnitId":"1","StartAddress":"30002","Count":"1","DisplayName":"Temp"}}}},"$version":1} Invalid TcpPort: , set to DefaultTcpPort: 502 Invalid RetryCount: , set to DefaultRetryCount: 10 Invalid RetryInterval: , set to DefaultRetryInterval: 50 Empty CorrelationId: , set to DefaultCorrelationId: DefaultCorrelationId Connect Slave failed Connection refused 192.168.26.110:502 Connection lost, reconnecting...
Итак:
- Порт по умолчанию — 502.
- Свойство для указания номера порта: TcpPort. О существовании этого параметра почему-то ничего не говорится в документации.
- Параметры RetryCount и RetryInterval можно не задавать, они есть по умолчанию.
Откорректируем Module Identity Twin. Возможность редактировать Module Identity Twin появляется только после того как модуль устройство развернуто на IoT Edge устройстве.
Добавляем в Module Identity Twin в desired строчку «TcpPort»: «8899», сохраняем. В логах видим:
Desired property change: {"PublishInterval":"2000","SlaveConfigs":{"TermoSensor":{"SlaveConnection":"192.168.26.110","TcpPort":"8899","HwId":"PowerMeter-0a:01:01:01:01:01","Operations":{"Op01":{"PollingInterval":"1000","UnitId":"1","StartAddress":"30002","Count":"1","DisplayName":"Temp"}}}},"$version":2} Attempt to load configuration: {"PublishInterval":"2000","SlaveConfigs":{"TermoSensor":{"SlaveConnection":"192.168.26.110","TcpPort":"8899","HwId":"PowerMeter-0a:01:01:01:01:01","Operations":{"Op01":{"PollingInterval":"1000","UnitId":"1","StartAddress":"30002","Count":"1","DisplayName":"Temp"}}}},"$version":2} Invalid RetryCount: , set to DefaultRetryCount: 10 Invalid RetryInterval: , set to DefaultRetryInterval: 50 Empty CorrelationId: , set to DefaultCorrelationId: DefaultCorrelationId Saving reported properties: {"PublishInterval":2000,"SlaveConfigs":{"TermoSensor":{"Operations":{"Op01":{"PollingInterval":1000,"UnitId":1,"StartAddress":"30002","Count":1,"DisplayName":"Temp","CorrelationId":"DefaultCorrelationId"}},"SlaveConnection":"192.168.26.110","RetryCount":10,"RetryInterval":50,"TcpPort":8899,"HwId":"PowerMeter-0a:01:01:01:01:01","BaudRate":null,"StopBits":null,"DataBits":null,"Parity":null}}} 30002: 261 30002: 261 30002: 261
Соответственно, видим, что модуль корректно отрабатывает смену настроек в desired. Появился введенный параметр «TcpPort»:»8899″ и он корректно отработал.
Добавим в desired операцию по считыванию поля влажности получаемого с адреса 300001 + 2.
"Op02": { "PollingInterval": "1000", "UnitId": "1", "StartAddress": "30003", "Count": "1", "DisplayName": "Humidity" }
Финально properties.desired должен выглядеть так:
"properties.desired": { "PublishInterval": "2000", "SlaveConfigs": { "TermoSensor": { "SlaveConnection": "192.168.26.110", "HwId": "TermoSensor-0a:01:01:01:01:01", "TcpPort": "8899", "Operations": { "Op01": { "PollingInterval": "5000", "UnitId": "1", "StartAddress": "30002", "Count": "1", "DisplayName": "Temp" }, "Op02": { "PollingInterval": "5000", "UnitId": "1", "StartAddress": "30003", "Count": "1", "DisplayName": "Humidity" } } } } }
Модуль получает информацию о смене desired property и выводит новые данные:
Desired property change: {"PublishInterval":"2000","SlaveConfigs":{"TermoSensor":{"SlaveConnection":"192.168.26.110","HwId":"PowerMeter-0a:01:01:01:01:01","Operations":{"Op01":{"PollingInterval":"1000","UnitId":"1","StartAddress":"30002","Count":"1","DisplayName":"Temp"},"Op02":{"PollingInterval":"1000","UnitId":"1","StartAddress":"30003","Count":"1","DisplayName":"Humidity"}},"TcpPort":"8899"}},"$version":3} Attempt to load configuration: {"PublishInterval":"2000","SlaveConfigs":{"TermoSensor":{"SlaveConnection":"192.168.26.110","HwId":"PowerMeter-0a:01:01:01:01:01","Operations":{"Op01":{"PollingInterval":"1000","UnitId":"1","StartAddress":"30002","Count":"1","DisplayName":"Temp"},"Op02":{"PollingInterval":"1000","UnitId":"1","StartAddress":"30003","Count":"1","DisplayName":"Humidity"}},"TcpPort":"8899"}},"$version":3} Invalid RetryCount: , set to DefaultRetryCount: 10 Invalid RetryInterval: , set to DefaultRetryInterval: 50 Empty CorrelationId: , set to DefaultCorrelationId: DefaultCorrelationId Empty CorrelationId: , set to DefaultCorrelationId: DefaultCorrelationId Saving reported properties: {"PublishInterval":2000,"SlaveConfigs":{"TermoSensor":{"Operations":{"Op01":{"PollingInterval":1000,"UnitId":1,"StartAddress":"30002","Count":1,"DisplayName":"Temp","CorrelationId":"DefaultCorrelationId"},"Op02":{"PollingInterval":1000,"UnitId":1,"StartAddress":"30003","Count":1,"DisplayName":"Humidity","CorrelationId":"DefaultCorrelationId"}},"SlaveConnection":"192.168.26.110","RetryCount":10,"RetryInterval":50,"TcpPort":8899,"HwId":"PowerMeter-0a:01:01:01:01:01","BaudRate":null,"StopBits":null,"DataBits":null,"Parity":null}}} 30002: 262 30003: 303 30002: 262 30003: 303
После проверки стоит сразу изменить интервал опроса сенсора хотя-бы до 5000 мс, в противном случае за час в облако уйдет 3600 х 2= 7200 сообщений и 8000 сообщений бесплатного аккаунта быстро закончатся.
Не забывайте останавливать работу модуля,
когда отправка данных в IoT Hub не нужна!
После того как IoT Hub получит 8000 сообщений, Microsoft заблокирует доступ к нему. Нельзя даже зайти на IoT Edge устройства, чтобы исправить настройки. Доступ появится на следующий день.
В исходниках модуля нашел описание параметров:
{ "PublishInterval": "push interval in millisecond", "SlaveConfigs": { "Slave01": { "SlaveConnection": "ipv4 address or the serial port name to Modbus device", "TcpPort": "tcp port of Modbus connection, default is 502", "RetryCount": "the max retry attempt when socket receive buffer is empty, default is 10", "RetryInterval": "the wait interval in millisecond between each retry, default is 50", "HwId": "unique HW Id defined by user", "BaudRate": "baud rate of serial communication (Modbus RTU only)", "DataBits": "data bits of serial communication (Modbus RTU only)", "StopBits": "stop bits of serial communication (Modbus RTU only)", "Parity": "parity of serial communication (Modbus RTU only)", "FlowControl": "flow control of serial communication (Modbus RTU only)", "Operations": { "Op01": { "PollingInterval": "polling interval in millisecond", "UnitId": "unit id of Modbus device", "StartAddress": "starting address of read request", "Count": "unit count of read request", "DisplayName": "alternative name defined by user", "CorrelationId": "id used to group output message" } } } } }
Ссылки
Для полноты информации можно почитать.