Azure IoT Hub ダイレクト メソッドを使用して Azure Sphere デバイスをリモートで再起動する方法

完了

このユニットでは、Azure IoT Explorer から Azure Sphere をリモートで再起動する方法について学習します。

IoT Hub ダイレクト メソッド コマンドの概要

Azure IoT Hub では、デバイスに対してアクションを呼び出すためにダイレクト メソッド コマンドが使用されます。 コマンドは、デバイスの対話式制御によく使用されます。たとえば、ファンや照明をオンにしたり、このユニットの場合は Azure Sphere を再起動したりする場合です。

IoT Hub ダイレクト メソッドは、(ユーザーが指定したタイムアウトの後) 直ちに成功または失敗するという点で HTTP 呼び出しに似たデバイスとの要求/応答の対話を表します。 この方法は、デバイスが応答できるかどうかに応じて即座に実行するアクションが異なるシナリオで便利です。

Note

Azure Sphere のリモート再起動が必要になる場合がある理由はいくつかあります。 デバイス証明書、OS の更新、およびアプリケーションの更新は、24 時間サイクルで、またはデバイスが再起動された後に実行されます。 更新を強制するためにデバイスを再起動する必要がある場合、操作上の理由が考えられます。

Azure Sphere のリモート再起動

IoT Explorer からダイレクト メソッド コマンドを呼び出してデバイスを再起動できます。 デバイスが再起動するまで待機する秒数を設定する必要があります。 Azure IoT Hub から、省略可能なペイロードを含むダイレクト メソッド メッセージがデバイスに送信されます。 デバイスからは、ステータス コードと、必要に応じて、コマンドが成功したか失敗したかを示すメッセージが返されます。

The illustration shows a device twin configuration pattern.

Azure Sphere IoT Explorer を再起動する手順

以下の手順では、Azure IoT Explorer と Azure IoT Hub ダイレクト メソッドを cloud-to-device の制御に使用する方法の概要を説明します。

  1. Azure IoT Explorer から、[Restart Device]\(デバイスの再起動\) IoT Hub ダイレクト メソッド コマンドを呼び出すことができます。
  2. そうすると、Azure IoT Hub からダイレクト メソッド コマンド メッセージがデバイスに送信されます。
  3. Azure Sphere 上で RestartDeviceHandler 関数が呼び出されます。
  4. 次に、デバイスからデバイス ツインの ReportedRestartUTC メッセージが Azure IoT に送信され、デバイスが再起動された時刻が記録されます。
  5. ダイレクト メソッドからは、HTTP 状態コードと応答メッセージで応答が返されます。
  6. その後、Azure Sphere が再起動されます。
  7. Azure IoT Explorer で、デバイスの ReportedRestartUTC プロパティがクエリされて表示されます。

ダイレクト メソッドのバインドの概要

ダイレクト メソッドのバインドにより、IoT Hub ダイレクト メソッド コマンド名が、アクションを実装するために呼び出されるハンドラー関数にマップされます。

次の例では、Azure Sphere を再起動するためのダイレクト メソッドのバインドを宣言しています。 この宣言により、Azure IoT Hub ダイレクト メソッドの RestartDevice コマンドと、RestartDeviceHandler というハンドラー関数がマップされます。

static LP_DIRECT_METHOD_BINDING dm_restartDevice = {
    .methodName = "RestartDevice",
    .handler = RestartDeviceHandler };

Azure Sphere のリモート再起動

ハンドラー関数 RestartDeviceHandler の実装を次に示します。 ハンドラー関数は、デバイスで Azure IoT Hub からの RestartDevice という名前のダイレクト メソッド メッセージが受信されたときに呼び出されます。

/// <summary>
/// Start Device Power Restart Direct Method 'ResetMethod' integer seconds eg 5
/// </summary>
static LP_DIRECT_METHOD_RESPONSE_CODE RestartDeviceHandler(JSON_Value* json, LP_DIRECT_METHOD_BINDING* directMethodBinding, char** responseMsg)
{
    const size_t responseLen = 60; // Allocate and initialize a response message buffer. The calling function is responsible for the freeing memory
    static struct timespec period;

    *responseMsg = (char*)malloc(responseLen);
    memset(*responseMsg, 0, responseLen);

    if (json_value_get_type(json) != JSONNumber) { return LP_METHOD_FAILED; }

    int seconds = (int)json_value_get_number(json);

    // leave enough time for the device twin dt_reportedRestartUtc to update before restarting the device
    if (seconds > 2 && seconds < 10)
    {
        // Report Device Restart UTC
        lp_deviceTwinReportState(&dt_reportedRestartUtc, lp_getCurrentUtc(msgBuffer, sizeof(msgBuffer))); // LP_TYPE_STRING

        // Create Direct Method Response
        snprintf(*responseMsg, responseLen, "%s called. Restart in %d seconds", directMethodBinding->methodName, seconds);

        // Set One Shot LP_TIMER
        period = (struct timespec){ .tv_sec = seconds, .tv_nsec = 0 };
        lp_timerOneShotSet(&restartDeviceOneShotTimer, &period);

        return LP_METHOD_SUCCEEDED;
    }
    else
    {
        snprintf(*responseMsg, responseLen, "%s called. Restart Failed. Seconds out of range: %d", directMethodBinding->methodName, seconds);
        return LP_METHOD_FAILED;
    }
}

Azure Sphere の PowerControls 機能

RestartDeviceHandler 関数を使用して、秒単位で測定された指定の再起動期間の後に DelayRestartDeviceTimerHandler 関数を呼び出すワンショット タイマーを設定します。 DelayRestartDeviceTimerHandler 関数では、PowerManagement_ForceSystemReboot API に対して呼び出しが行われます。 PowerManagement_ForceSystemReboot API では、PowerControls 機能を app_manifest.json ファイルで宣言する必要があります。

"PowerControls": [
    "ForceReboot"
]

ダイレクト メソッドをハンドラーにマップする方法

宣言されたすべてのダイレクト メソッド バインドを、directMethodBindingSet 配列への参照渡しによって追加する必要があります。 デバイスによって Azure IoT Hub からのダイレクト メソッド メッセージが受信されると、directMethodBindingSet 配列内に一致する methodName 名がないか確認されます。 一致が見つかった場合は、対応するハンドラー関数が呼び出されます。

LP_DIRECT_METHOD_BINDING* directMethodBindingSet[] = { &dm_restartDevice };

ダイレクト メソッドのバインド セットを開く

ダイレクト メソッドのバインド セットは、main.c にある InitPeripheralsAndHandlers 関数で初期化されます。

lp_directMethodSetOpen(directMethodBindingSet, NELEMS(directMethodBindingSet));

ダイレクト メソッドのバインド セットを閉じる

ダイレクト メソッドのバインド セットは、main.c にある ClosePeripheralsAndHandlers 関数で閉じられます。

lp_directMethodSetClose();