Управление устройствами по Modbus с IoT Hub. Direct Method. Урок 11.

В предыдущем уроке был рассмотрен вариант управления устройствами из облака Microsoft IoT Hub через Module Identity Twin. На мой взгляд реализация C2D управления далека от совершенства, но особо выбора нет. Рассмотрим реализацию другого способа передачи данных на IoT Edge устройство для управления оборудованием по протоколу Modbus TCP.

Direct method

Второй способ отправить сообщение из IoT Hub в модуль — direct method. Добавим код:

       private static Task<MethodResponse> ModbusWrite(MethodRequest methodRequest, object userContext)
        {
            try
            {
                var moduleClient = userContext as ModuleClient;
                if (moduleClient == null)
                {
                    throw new InvalidOperationException("UserContext doesn't contain " + "expected values");
                }

                var data = Encoding.UTF8.GetString(methodRequest.Data);
                string result = string.Empty;
                int resultCode = 200;
                if (!string.IsNullOrEmpty(data))
                {
                    Console.WriteLine("Received JSON: " + data);
                    BuildWriteCommand(data, moduleClient);
                    result = "{\"result\":\"Executed direct method: " + methodRequest.Name + "\"}";
                    resultCode = 200;
                }
                else
                {
                    result = "{\"result\":\"Invalid parameter\"}";
                    resultCode = 400;
                }
                // Acknowlege the direct method call with a 200 success message
                return Task.FromResult(new MethodResponse(Encoding.UTF8.GetBytes(result), resultCode));

            }
            catch (Exception err)
            {
                Console.WriteLine("Error in ModbusWrite: " + err.Message);
                // Acknowlege the direct method call with a 400 error message
                string result = "{\"result\":\"Invalid parameter\"}";
                return Task.FromResult(new MethodResponse(Encoding.UTF8.GetBytes(result), 400));
            }
        }

И в метод Init() добавим регистрацию CallBack функции для перехвата вызова direct method:

            // Create a handler for the direct method call
            await ioTHubModuleClient.SetMethodHandlerAsync("Write", ModbusWrite, ioTHubModuleClient);

Снова запускаем «Build and Push IoT Edge Solution». В конце процесса отобразится хэш собранного образа:

0.0.1-amd64: digest: sha256:2387d5acd226b8e94d20eac9ab99c86c6a40e2b8bb8c21b7cff6103c57303813 size: 1789

На IoT Edge устройстве останавливаем сервис «Stop-Service iotedge» и выполняем команду

PS C:\WINDOWS\system32> docker pull azureiotlabcontainerregistry683.azurecr.io/modbuswriter:0.0.1-amd64
0.0.1-amd64: Pulling from modbuswriter
Digest: sha256:2387d5acd226b8e94d20eac9ab99c86c6a40e2b8bb8c21b7cff6103c57303813
Status: Image is up to date for azureiotlabcontainerregistry683.azurecr.io/modbuswriter:0.0.1-amd64

Сравниваем хэш, чтобы быть уверным, что принят верный образ. Затем запускаем «Start-Service iotedge».

Заходим в раздел Direct method модуля modbuswriter и запускаем тот-же JSON, что использовался в properties.desired. И получаем успешный Result:

{"status":200,"payload":{"result":"Executed direct method: Write"}}

и сообщение в логах modbus:

Modbus Writer - Received command
Received message: 10, Body: [{"hwId":"TermoSensor-0a:01:01:01:01:01","uId":"1","address":"00017","value":"1"}]
Write device TermoSensor-0a:01:01:01:01:01, address: 00017, value: 1

говорящее о успешной передаче данных модулем modbus.

Отмечу, что передача данных C2D через «Direct method», по моим наблюдениям, менее надежна, чем отправка через properties.desired. По крайней мере, ошибки с timeout возникают чаще. При этом работа тестировалось на достаточно быстром Wi-Fi канале. При тестировании на GPRS конвертере Modbus RTU <-> TCP, скорее всего, результат будет значительно хуже.

Вероятно, это связано с спецификой отработки properties.desired. Отправка данных через этот канал может проходить с очень большой задержкой, но рано или поздно оно проходит, не приводя к возникновению ошибок. «Direct method», похоже, пытается передать данные и получить подтверждение за время заданное в настройках timeout.

Управление релейным модулем по Modbus

Чтобы протестировать управление устройством по Modbus на релейном модуле было сделано следующее:

  • Соединены параллельно входы A и B релейного модуля с соответствующими контактами датчика температуры и клеммами A и B конвертера Modbus RTU <-> TCP. Получил мини RS485 сеть.
  • Сменил SlaveID адрес датчика температуры и влажности на 0х02, а на релейном модуле остался адрес 0х01, чтобы исключить кофнфлик устрйоств в RS485 сети.

Ранее в статье использовалась функция 0x05, отраженная в документации, для записи в Discrete Output Register. Адресация этих регистров начинается с 1.

Memory Address Type Memory Type
1-9999 Read-Write Discrete Output Coils
10001-19999 Read-Only Discrete Input Contacts
30001-39999 Read-Only Analog Input Registers
40001-49999 Read-Write Analog Output Holding Registers

Соответственно, чтобы получить состояние Discrete Output Register нужно вычитать 4 регистра соответствующих реле, начиная с 00001 адреса. Состояние реле:

  • «0» — реле выключено.
  • «1» — реле включено.

Для релейного модуля вычитываем значения состояния регистров. JSON скрипт для штатного модуля Microsoft modbus будет такими:

"properties.desired": {
    "PublishInterval": "20000",
      "SlaveConfigs": {
        "TermoSensor": {
          "SlaveConnection": "192.168.26.110",
          "HwId": "RelaysModule",
          "TcpPort": "8899",         
          "Operations": {
            "Op01": {
              "PollingInterval": "20000",
              "UnitId": "1",
              "StartAddress": "00001",
              "Count": "4",
              "DisplayName": "RelaysStatus"
            }
        }
     }
   }
}

В данном случае единовременно вычитываются все четыре регистра, управляющие реле.

Этот JSON скрипт добавлен в properties.desired к настройкам Modbus для термодатчика. Это позволяет одновременно ситывать данные по Modbus с термодатчика и читать состояние реле.

Для разработанного модуля modbuswriter JSON скрипт для модуля реле приведен ниже. Для включения первого реле нужно отправить команду:

"properties": {
  "desired": {
    "hwId": "RelaysModule",
    "uId": "1",
    "address": "00001",
    "value": "1"
  }
}

Устройство будет управляться командами, отправляемыми из облака Microsoft IoT Hub на устрйоство через «Direct Method».

В следующем уроке разберем создание Azure Functions Module для передачи данных в Modbus модуль.

Spread the love
Запись опубликована в рубрике IT рецепты, IT решения для бизнеса с метками , . Добавьте в закладки постоянную ссылку.