Цепочка модулей IoT Edge. Урок 7.

Данные считываемые из регистров Modbus перед передачей в облако для анализа и визуализации нередко требуют предварительной обработки. Например, в случае с термодатчиком предыдущих статьях необходимо разделить полученные значения с датчика на 10.

Архтитектура модулей в IoT Edge Runtime построена на микросервисной архитектуре. Каждый модуль, формально, ничего не знает о том, что данные на его вход поступают с предыдущего модуля. Он делает обработку входящего потока данных по некоторому алгоритму («черный ящик») и передает его на выход.

При этом сам модуль не подозревает, принимает ли модифицированный им поток данных следующий модуль или они уходят сразу в облако IoT Hub. Т.е. внутренние алгоритмы работы каждого такого «черного ящика», формально, не должны зависеть от предыдущего модуля.

Настройки маршрутизации заданные в конфигурации определяют последовательность обработки данных модулями. В идеале, если обеспечена работа модулей, как «черных ящиков», они должны с легкостью допускать изменение порядка. Но, понятно, что это в идеале. По факту-же каждый модуль должен представлять, что за данные к нему приходят и в каком формате, чтобы производить обработку.

Сборка модулей ABB Modbus

Для проверки как отрабатывает цепочка, воспользуемся модулем разработанным Maxim Khlupnov: https://github.com/MaxKhlupnov/SmartHive.AbbEdge. Соберем проект из исходников:

  1. Создаем клон исходников с GitHub.
    git clone https://github.com/MaxKhlupnov/SmartHive.AbbEdge.git
  2. В папку ABBEdge копируем файл .env и .gitignore из проекта созданного с «чистого листа»  (см. статью «Часть 6»).
  3. Вписываем в файл deployment.template.json информацию для авторизации в Azure Containers Registry. Можно затереть секции «docker» и «smarthive», поскольку мы будем создавать образ модуля в нашем собственном Azure Containers Registry. В registryCredentials останется только строчки с именем вашего registry. В моем случае  warlibregistry с адресом warlibregistry.azurecr.io:
                "registryCredentials": {
                 "warlibregistry": {
                    "username": "$CONTAINER_REGISTRY_USERNAME_warlibregistry",
                    "password": "$CONTAINER_REGISTRY_PASSWORD_warlibregistry",
                    "address": "warlibregistry.azurecr.io"
                  }
                }
  4. Заменяем в секции modules -> modbus адрес образа с
    "image": "microsoft/azureiotedge-modbus-tcp:GA-preview-amd64"

    на адрес из статьи «Часть 6» или адрес репозитория Microsoft (mcr.microsoft.com/azureiotedge/modbus:1.0):

    "image": "warlibregistry.azurecr.io/iotedgemodbus:0.0.1-amd64"
  5. Заходим в подпапку: SmartHive.AbbEdge\ABBEdge\modules\abbDriveProfile\
  6. Находим файл modules.json и заменяем там
    "repository": "smarthive.azurecr.io/abb-drive-profile"

    адрес на

    "repository": "warlibregistry.azurecr.io/abb-drive-profile"
  7. Можно обновить файлы проекта до текущего TargetFramework. Для этого в файлах проекта *.csproj в соответствующих папках меняем framework с netcoreapp2.0 на последний на сегодня: netcoreapp2.1. Аналогичную операцию надо сделать и в Dockerfile.* Для Dockerfile.* недостаточно заменить цифру 2.0 на 2.1, поскольку названия framework после цифры отличаются. Проще скопировать все файлы из проекта «с чистого листа», заменив ENTRYPOINT на верный.
  8. Аналогичную замену делаем и в файле  SmartHive.AbbEdge\AbbEdge\modules\abbRemoteMonitoringGateway\module.json.
  9. В Visual Studio Code открываем Workspace: File -> Open workspace… -> AbbEdge.code-workspace (в корне папки).
  10. Кликаем правой клавишей мыши на deployment.template.json и запускаем «Build and Push IoT Edge Solution».
  11. Если build & push прошел без ошибок, то в Azure Containers Registry появятся образы abbremotemonitoringgateway и abb-drive-profile.

Настройки Modbus термодатчика

  1. Создаем новое тестовое IoT Edge устройство. Например, с именем TermoSensorWithConverter.
  2. Добавляем modbus модуль как описано в статье: «Часть 5«. Даем имя модулю modbus.
  3. Добавляем модуль ABBDriveProfile как описано в статье Максима.  Путь правим на свой (в моем случае «warlibregistry.azurecr.io»):
    Name - abbDriveProfile
    Image URI - warlibregistry.azurecr.io/abb-drive-profile:0.0.1-amd64
  4. В properties.desired секция SignalConfig для термодатчика будет выглядеть так:
    {
      "properties.desired": {
        "SignalConfigs": {
    	"Temp": {
    		"ValueFormula": "Temp / 10.0",
    		"ValueType": "Double",
    		"ValueUnit": "oC"
    	},
    	"Humidity": {
    		"ValueFormula": "Humidity / 10.0",
    		"ValueType": "Double",
    		"ValueUnit": "%"
    	}
        }
      }
    }
  5. Для визуализации сконвертированных в правильный вид данных достаточно модуля  modbus и abbDriveProfile. Маршрут для передачи данных в IoT Hub будет выглядеть следующим образом:
    {
      "routes": {
        "modbusToAbbAcsEdgeProfile": "FROM /messages/modules/modbus/outputs/modbusOutput INTO BrokeredEndpoint(\"/modules/abbDriveProfile/inputs/driveProfileInput\")",
        "abbDriveProfileToIoTHub": "FROM /messages/modules/abbDriveProfile/outputs/driveProfileOutput INTO $upstream"
      }
    }
  6. Завершим добавление модулей для IoT Edge устройства TermoSensorWithConverter.
  7. На локальном ПК развернем IoT Edge Runtime передав в качестве параметра connection string от TermoSensorWithConverter.
  8. Посмотрим логи abbDriveProfile командой «iotedge logs abbDriveProfile -f»:
    Drive profile module - Received message
    Received message: 64, Body: [{"PublishTimestamp":"2018-11-19 09:01:40","Content":[{"HwId":"TermoSensor-0a:01:01:01:01:01","Data":[{"CorrelationId":"DefaultCorrelationId","SourceTimestamp":"2018-11-19 09:01:32","Values":[{"DisplayName":"Humidity","Address":"30003","Value":"393"},{"DisplayName":"Temp","Address":"30002","Value":"262"}]}]}]}]
    Temp : 262
    Result: 26.2
    Humidity : 393
    Result: 39.3
     signals processed: 2
    Telemetry message succesfully sent: [{"HwId":"TermoSensor-0a:01:01:01:01:01","SourceTimestamp":"2018-11-19 09:01:32","Name":"Temp","Value":"26.2","ValueType":"Double","ValueUnit":"oC"},{"HwId":"TermoSensor-0a:01:01:01:01:01","SourceTimestamp":"2018-11-19 09:01:32","Name":"Humidity","Value":"39.3","ValueType":"Double","ValueUnit":"%"}]
  9. Видно, что модуль abbDriveProfile корректно принимает информацию с Modbus, производит необходимые вычисления и отправляет в IoT Hub преобразованные данные в JSON.
  10. Отметим, что если посмотреть командой «iotedge logs modbus -f» логи с модуля modbus, то там идет построчный вывод информации о номере регистра modbus и температуре:
    30002: 260
    30003: 348
    30002: 260
    30003: 348

    Модуль-же abbDriveProfile приниает на вход JSON с детальной информацией о том, какой датчик отправил информацию, символическое имя регистра, значение. Видно, что информация в логах отличается от информации, которая фактически транслируется на вход:

    {"PublishTimestamp":"2018-11-19 09:01:40","Content":[{"HwId":"TermoSensor-0a:01:01:01:01:01","Data":[{"CorrelationId":"DefaultCorrelationId","SourceTimestamp":"2018-11-19 09:01:32","Values":[{"DisplayName":"Humidity","Address":"30003","Value":"393"},{"DisplayName":"Temp","Address":"30002","Value":"262"}]}]}]}

Тестирование

Чтобы посмотреть, что реально принимает IoT Hub от устройства воспользуемся консольным приложением из статьи. Пример работы приложения в документации на сайте Microsoft.

Отмечу, что если идет отправка в IoT Hub информаци с нескольких IoT Edge устройств, то все эти потоки данных смешиваются и отображаются в приложении по мере поступления.

Для анализа логов по каждому устройству есть приложение из инструментария работы с IoT Hub: DeviceExplorer. Но в логах этого приложения отображается только JSON, который был передан устройством без служебной информации. Поэтому его не удобно использовать, например, при написании QUERY для Stream Analytics Job.

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