Azure RTOS のリアルタイムの室内環境センサー データを IoT Hub に送信する方法

完了

Azure Sphere のリアルタイム コアで、アップグレードされた微生物学の実験室の温度、気圧、湿度センサーが正常に動作しています。 顧客は満足しており、実験を行うことができます。 また、顧客は実験室の状態をリモートで監視したいと考えています。

このユニットでは、アップグレードされた実験室のセンサーからデータを読み取り、そのデータを IoT Hub に送信して監視できるようにする方法について学習します。

ソリューションのアーキテクチャ

Azure Sphere 高レベル アプリケーションで、Azure Sphere のリアルタイム コアのいずれかで実行されているアップグレードされた実験室のセンサーからデータをどのように読み取れるかについて以下に説明します。 その後、高レベルのアプリケーションからはこのデータが IoT Hub に安全に送信されるようになります。

Inter-core communications architecture.

Azure RTOS の実験室に導入されたソリューションのアーキテクチャを要約すると、次のようになります。

  1. Azure RTOS のリアルタイム環境センサー スレッドは 2 秒ごとに実行されます。 そのスレッドで最新の環境温度、湿度、および気圧のデータがメモリに格納されます。
  2. 高レベルのテレメトリ ストリーミング アプリからリアルタイム コアに対して、最新の環境データが要求されます。
  3. Azure RTOS のリアルタイム環境サービス スレッドが最新の環境データを使用して応答します。
  4. 高レベル アプリケーションでその環境データが JSON としてシリアル化され、テレメトリ メッセージが IoT Hub に送信されます。
  5. デバイスによって IoT Hub に送信されたテレメトリ メッセージが Azure IoT Explorer によってサブスクライブされ、テレメトリが表示されます。
  6. また、プロパティを設定することによって、室内の目標温度を設定することもできます。 そのプロパティは、IoT Hub デバイス ツイン メッセージを使用してデバイスに設定されます。
  7. その後、Azure Sphere によって、目標温度を満たすように HVAC 動作モードが設定されます。

コア間のメッセージ コントラクト

コア間で渡されるデータの形式を記述するコントラクトが必要です。 次の構造体は、このユニットで使用されているコア間コントラクトを宣言しています。 このコントラクトは IntercoreContract ディレクトリにあります。

typedef enum
{
    LP_IC_UNKNOWN,
    LP_IC_HEARTBEAT,
    LP_IC_ENVIRONMENT_SENSOR,
    LP_IC_SAMPLE_RATE
} LP_INTER_CORE_CMD;

typedef struct
{
    LP_INTER_CORE_CMD cmd;
    float temperature;
    float pressure;
    float humidity;
    int sample_rate;
} LP_INTER_CORE_BLOCK;

コア間のセキュリティ

通信するには、複数のコアで実行されるアプリケーションが、対応するコンポーネント ID を使用して構成されている必要があります。

リアルタイム アプリケーションのコンポーネント ID は、その app_manifest.json ファイルにあります。

{
  "SchemaVersion": 1,
  "Name": "AzureSphereIoTCentral",
  "ComponentId": "25025d2c-66da-4448-bae1-ac26fcdd3627",
  ...
}

高レベルのコア間の機能

高レベルの app_manifest.json ファイルの AllowedApplicationConnections プロパティは、Azure RTOS リアルタイム アプリケーションのコンポーネント ID に設定されます。

{
    ...
    "AllowedApplicationConnections": [ "6583cf17-d321-4d72-8283-0b7c5b56442b" ]
    ...
}

コア間通信の初期化

InitPeripheralAndHandlers では、lp_interCoreCommunicationsEnable に対して呼び出しが行われ、リアルタイムのコンポーネント ID とコア間コールバック関数が渡されます。

コア間コールバック関数は、リアルタイム コアからのメッセージが受信されたときに呼び出されます。

lp_interCoreCommunicationsEnable(REAL_TIME_COMPONENT_ID, InterCoreHandler);  // Initialize Inter Core Communications

リアルタイム コア アプリケーションへの要求の送信

リアルタイム コアに環境データを要求するには、次のようにします。

  1. コア間の制御ブロック コマンドを LP_IC_ENVIRONMENT_SENSOR に設定します。
  2. lp_interCoreSendMessage を呼び出し、コア間の制御ブロックを渡すことによって、要求メッセージを送信します。
/// <summary>
/// Read sensor and send to Azure IoT
/// </summary>
static void MeasureSensorHandler(EventLoopTimer* eventLoopTimer)
{
    if (ConsumeEventLoopTimerEvent(eventLoopTimer) != 0)
    {
        lp_terminate(ExitCode_ConsumeEventLoopTimeEvent);
    }
    else {
        // send request to Real-Time core app to read temperature, pressure, and humidity
        ic_control_block.cmd = LP_IC_ENVIRONMENT_SENSOR;
        lp_interCoreSendMessage(&ic_control_block, sizeof(ic_control_block));
    }
}

コア間のメッセージの受信

高レベル アプリケーションでメッセージが受信されると、コア間コールバック関数が呼び出され、環境データを含むコア間制御ブロックへの参照が渡されます。 アプリケーションによってデータが JSON としてシリアル化され、テレメトリ メッセージが IoT Hub に送信されます。HVAC 状態 LED は更新されます。

/// <summary>
/// Callback handler for Inter-Core Messaging - Does Device Twin Update, and Event Message
/// </summary>
static void InterCoreHandler(LP_INTER_CORE_BLOCK* ic_message_block)
{
    static int msgId = 0;

    switch (ic_message_block->cmd)
    {
    case LP_IC_ENVIRONMENT_SENSOR:
        if (snprintf(msgBuffer, JSON_MESSAGE_BYTES, msgTemplate, ic_message_block->temperature,
            ic_message_block->humidity, ic_message_block->pressure, msgId++) > 0) {

            Log_Debug("%s\n", msgBuffer);
            lp_azureMsgSendWithProperties(msgBuffer, telemetryMessageProperties, NELEMS(telemetryMessageProperties));

            SetHvacStatusColour((int)ic_message_block->temperature);

            // If the previous temperature not equal to the new temperature then update ReportedTemperature device twin
            if (previous_temperature != (int)ic_message_block->temperature) {
                lp_deviceTwinReportState(&dt_reportedTemperature, &ic_message_block->temperature);
                previous_temperature = (int)ic_message_block->temperature;
            }
        }
        break;
    default:
        break;
    }
}