Эта статья следует за частью 1 и содержит важные советы по модулям IoT Edge в azure-iot-edge-integration-test-шаблон.

Этот образец шаблона содержит шесть модулей IoT Edge и два потока данных интеграционного теста. Один из них — отправка агентом Azure Pipelines. прямой метод получение отчета о погоде и файлов отчетов о погоде, загруженных в хранилище BLOB-объектов Azure. Другой поток интеграционного теста — это прямой запрос метода, запрашивающий загрузку архивных файлов погоды.

Описание изображения

def module_termination_handler(signal, frame):
    print ("IoTHubClient sample stopped")
    stop_event.set()

stop_event = threading.Event()
signal.signal(signal.SIGTERM, module_termination_handler)
try:
    stop_event.wait()
except Exception as e:
    print("Unexpected error %s " % e)
    raise
finally:
    print("Shutting down client")
    module_client.shutdown()
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • Прямой обратный вызов метода из Центра Интернета вещей реализован с помощью method_request_handler(). При получении запроса прямого метода он отправляет сообщение запроса на WeatherReporter через Обмен данными по маршруту Azure Iot Edge.
async def method_request_handler(method_request):
    print('Direct Method: ', method_request.name, method_request.payload)
    if method_request.name in request_method_list:
        response_payload, response_status = await request_method_list[method_request.name](method_request.payload, module_client)
    else:
        response_payload = {"Response": "Direct method {} not defined".format(method_request.name)}
        response_status = 404

    method_response = MethodResponse.create_from_method_request(method_request, response_status, response_payload)
    await module_client.send_method_response(method_response)

module_client.on_method_request_received = method_request_handler
Войти в полноэкранный режим

Выйти из полноэкранного режима

async def request_weather_report(payload: dict, module_client: IoTHubModuleClient):
    try:
        json_string = json.dumps(payload)
        message = Message(json_string)
        await module_client.send_message_to_output(message, 'reportRequest')
        return {"Response": "Send weather report request for {}".format(payload['city'])}, 200
    except Exception as e:
        print(e)
        return {"Response": "Invalid parameter"}, 400
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • Обратный вызов для связи по маршруту Azure IoT Edge реализован с помощью receive_message_handler(). Он получает сообщения от WeatherReport модуль и отправляет запросы на FileGenerator модуль через тему связи ROS2.
async def receive_message_handler(message_received):
    if message_received.input_name == 'reportResponse':
        message_telemetry = Message(
            data=message_received.data.decode('utf-8'),
            content_encoding='utf-8',
            content_type="application/json",
        )
        await module_client.send_message_to_output(message_telemetry, 'telemetry')
        print("Weather report sent to IoT Hub")

        ros2_publisher_client.ros2_publisher(message_received.data.decode('utf-8'))
        print("ROS2 message sent to FileGenerator")

    elif  message_received.input_name == 'updateResponse':
        message_telemetry = Message(
            data=message_received.data.decode('utf-8'),
            content_encoding='utf-8',
            content_type="application/json",
        )
        await module_client.send_message_to_output(message_telemetry, 'telemetry')
        print("Download status sent to IoT Hub")
    else:
        print("Message received on unknown input: {}".format(message_received.input_name))

module_client.on_message_received = receive_message_handler
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • WeatherObserver написан с консольным приложением .NET6 на C#. Это просто и независимо от Azure IoT Edge или ROS2, и вы можете запускать его локально для целей отладки.

  • Обратный вызов, который обрабатывает запросы от IothubConnector реализуется с ioTHubModuleClient.SetInputMessageHandlerAsync().

await ioTHubModuleClient.SetInputMessageHandlerAsync(routeC2W, ParseRequests, ioTHubModuleClient).ConfigureAwait(false);
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • ФайлГенератор это модуль, написанный на Python, который получает запрос от IothubConnector и создает файлы отчетов о погоде на пограничном хост-компьютере.

  • Этот модуль использует rclpy.spin() чтобы само приложение работало и ждало запросов.

rclpy.init(args=args)
file_generator = FileGenerator()
rclpy.spin(file_generator)
file_generator.destroy_node()
rclpy.shutdown()
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • Обратный вызов для запросов ROS2 реализован с помощью create_subscription() подписки на тему ROS2.
def __init__(self):
    super().__init__('file_generator')
    self.subscription = self.create_subscription(
        String,
        os.getenv('ROS_TOPIC_NAME'),
        self.listener_callback,
        10)
    self.subscription

def listener_callback(self, msg):
Войти в полноэкранный режим

Выйти из полноэкранного режима

  • FileUploader это модуль, написанный на .NET6 C#, который извлекает файлы, сгенерированные FileGenerator и отправляет их в LocalBlobStorage.
  • FileUpdater модули написаны на .NET6 C# и загружают архивные файлы из хранилища BLOB-объектов Azure.

  • Он использует токен SAS, который позволяет модулю получать доступ только к определенному каталогу, поэтому эта система может работать в средах с несколькими арендаторами и несколькими пограничными устройствами. Этот токен SAS генерируется МанифестГенератор что объясняется в части 3.

  • В этом примере шаблона используется Локалблобстораже который создан Microsoft и используется из mcr.microsoft.com/azure-blob-storage:latest. Причина использования встроенного локального большого двоичного объекта заключается в том, что среда выполнения Azure IoT Edge и модули по умолчанию, включая EdgeHub а также EdgeAgent не поддерживают функции загрузки файлов.