デバイスをリモート監視構成済みソリューションに接続する (Windows)
シナリオの概要
このシナリオでは、構成済みソリューション リモート監視に次のテレメトリを送信するデバイスを作成します。
- 外部温度
- 内部温度
- 湿度
わかりやすくするために、デバイス上のコードはサンプル値を生成しますが、実際のセンサーをデバイスに接続し、実際のテレメトリを送信することでサンプルを拡張することをお勧めします。
デバイスは、ソリューション ダッシュボードから呼び出されたメソッドと、ソリューション ダッシュボードで設定された必要なプロパティ値にも応答できます。
このチュートリアルを完了するには、アクティブな Azure アカウントが必要です。 アカウントがない場合は、無料試用アカウントを数分で作成することができます。 詳細については、「Azure の無料試用版サイト」を参照してください。
開始する前に
デバイスのコードを記述する前に、リモート監視の構成済みソリューションをプロビジョニングし、そのソリューションに新しいカスタム デバイスをプロビジョニングする必要があります。
リモート監視構成済みソリューションをプロビジョニングする
このチュートリアルで作成したデバイスは、構成済みソリューションの リモート監視 インスタンスにデータを送信します。 Azure アカウントでリモート監視構成済みソリューションをまだプロビジョニングしていない場合は、次の手順を使用します。
- [https://www.azureiotsolutions.com/] ページで、[+] をクリックしてソリューションを作成します。
- リモート監視 パネルで [ の選択] をクリックして、ソリューションを作成します。
- リモート監視ソリューション の作成] ページで、任意の ソリューション名を入力し、デプロイする リージョンを選択し、使用する Azure サブスクリプションを選択します。 [ソリューション 作成] をクリックします。
- プロビジョニング プロセスが完了するまで待ちます。
警告
構成済みのソリューションでは、課金対象の Azure サービスが使用されます。 不要な料金が発生しないように、サブスクリプションが完了したら、構成済みのソリューションをサブスクリプションから削除してください。 https://www.azureiotsolutions.com/ ページにアクセスして、構成済みのソリューションをサブスクリプションから完全に削除できます。
リモート監視ソリューションのプロビジョニング プロセスが完了したら、[Launch] をクリックして、ブラウザーでソリューション ダッシュボードを開きます。
リモート監視ソリューションでデバイスをプロビジョニングする
注
ソリューションで既にデバイスをプロビジョニングしている場合は、この手順をスキップできます。 クライアント アプリケーションを作成するときに、デバイスの資格情報を知る必要があります。
デバイスが構成済みソリューションに接続するには、有効な資格情報を使用して IoT Hub に自身を識別する必要があります。 ソリューション ダッシュボードからデバイスの資格情報を取得できます。 このチュートリアルの後半で、クライアント アプリケーションにデバイス資格情報を含めます。
リモート監視ソリューションにデバイスを追加するには、ソリューション ダッシュボードで次の手順を実行します。
ダッシュボードの左下隅にある [デバイス の追加]クリックします。
を追加する
[カスタム デバイス] パネルで、[新しいを追加] をクリックします。
を追加する
[自分でデバイス IDを定義する] を選択します。 mydeviceなどのデバイス ID を入力し、[ID の確認] をクリックして名前がまだ使用されていないことを確認し、[作成] をクリックしてデバイスをプロビジョニングします。
を追加する
デバイスの資格情報 (デバイス ID、IoT Hub ホスト名、デバイス キー) を書き留めます。 クライアント アプリケーションは、リモート監視ソリューションに接続するためにこれらの値を必要とします。 次に、 [Done] をクリックします。
を表示する
ソリューション ダッシュボードのデバイス一覧でデバイスを選択します。 次に、デバイスの詳細 パネルで、[デバイス を有効にするをクリックします。 デバイスの状態は現在 実行中のになりました。 リモート監視ソリューションは、デバイスからテレメトリを受信し、デバイスでメソッドを呼び出すようになりました。
Windows で C サンプル ソリューションを作成する
次の手順では、リモート監視構成済みソリューションと通信するクライアント アプリケーションを作成する方法を示します。 このアプリケーションは C で記述され、Windows 上でビルドおよび実行されます。
Visual Studio 2015 または Visual Studio 2017 でスターター プロジェクトを作成し、IoT Hub デバイス クライアント NuGet パッケージを追加します。
Visual Studio で、Visual C++ Win32 コンソール アプリケーション テンプレートを使用して C コンソール アプリケーションを作成します。 プロジェクトに RMDevice 名前を付けます。
Win32 アプリケーション ウィザードの [アプリケーション設定] ページで、コンソール アプリケーションの が選択されていることを確認し、プリコンパイル済みヘッダー と セキュリティ開発ライフサイクル (SDL) チェック オフにします。
ソリューション エクスプローラー で、stdafx.h、targetver.h、および stdafx.cpp ファイルを削除します。
ソリューション エクスプローラーので、ファイル RMDevice.cppの名前を RMDevice.c に変更します。
ソリューション エクスプローラーで、RMDevice プロジェクトを右クリックし、[NuGet パッケージの管理]をクリックします。 [ 閲覧] をクリックし、次に次の NuGet パッケージを検索してインストールします:。
- Microsoft.Azure.IoTHub.Serializer
- Microsoft.Azure.IoTHub.IoTHubClient
- Microsoft.Azure.IoTHub.MqttTransport
ソリューション エクスプローラー で、RMDevice プロジェクトを右クリックし、[プロパティ] クリックして、プロジェクトの [プロパティ ページ] ダイアログ ボックスを開きます。 詳細については、Visual C++ プロジェクトのプロパティの設定に関するページを参照してください。
リンカー フォルダーをクリックし、入力 プロパティ ページをクリックします。
crypt32.lib を 追加の依存関係 プロパティに追加します。 [OK] クリックし、もう一度 [OK] を してプロジェクトのプロパティ値を保存します。
Parson JSON ライブラリを RMDevice プロジェクトに追加し、必要な #include
ステートメントを追加します。
コンピューター上の適切なフォルダーで、次のコマンドを使用して Parson GitHub リポジトリを複製します。
git clone https://github.com/kgabis/parson.git
Parson リポジトリのローカル コピーから、parson.h ファイルと parson.c ファイルを、RMDevice プロジェクト フォルダーにコピーします。
Visual Studio で、RMDevice プロジェクトを右クリックし、[追加]] をクリックし、[既存の項目 ] をクリックします。
既存項目の追加 ダイアログで、RMDevice プロジェクト フォルダー内の parson.h ファイルと parson.c ファイルを選択します。 次 [ の追加] をクリックして、これら 2 つのファイルをプロジェクトに追加します。
Visual Studio で、RMDevice.c ファイルを開きます。 既存の
#include
ステートメントを次のコードに置き換えます。#include "iothubtransportmqtt.h" #include "schemalib.h" #include "iothub_client.h" #include "serializer_devicetwin.h" #include "schemaserializer.h" #include "azure_c_shared_utility/threadapi.h" #include "azure_c_shared_utility/platform.h" #include "parson.h"
注
これで、プロジェクトをビルドすることで、正しい依存関係が設定されていることを確認できます。
IoT デバイスの動作を指定する
IoT Hub シリアライザー クライアント ライブラリでは、モデルを使用して、デバイスが IoT Hub と交換するメッセージの形式を指定します。
#include
ステートメントの後に、次の変数宣言を追加します。 プレースホルダーの値 [デバイス ID] と [デバイス キー] を、リモート監視ソリューション ダッシュボードでデバイス用に指定した値に置き換えます。 [IoTHub 名] を置き換えるには、ソリューション ダッシュボードの IoT Hub ホスト名を使用します。 たとえば、IoT Hub ホスト名が contoso.azure-devices.netの場合は、[IoTHub 名] を contosoに置き換えます。static const char* deviceId = "[Device Id]"; static const char* connectionString = "HostName=[IoTHub Name].azure-devices.net;DeviceId=[Device Id];SharedAccessKey=[Device Key]";
次のコードを追加して、デバイスが IoT Hub と通信できるようにするモデルを定義します。 このモデルでは、デバイスが次のことが指定されます。
- 温度、外部温度、湿度、デバイス ID をテレメトリとして送信できます。
- デバイスに関するメタデータを IoT Hub に送信できます。 デバイスは、起動時に DeviceInfo オブジェクトに基本的なメタデータを送信します。
- 報告されたプロパティを IoT Hub のデバイス ツインに送信できます。 これらの報告されるプロパティは、構成、デバイス、およびシステムのプロパティにグループ化されます。
- IoT Hub のデバイス ツインで設定された必要なプロパティを受信して操作できます。
- 再起動 と InitiateFirmwareUpdate のダイレクトメソッドに応答可能で、ソリューションポータルを介して呼び出されます。 デバイスは、報告されたプロパティを使用して、サポートされているダイレクト メソッドに関する情報を送信します。
// Define the Model BEGIN_NAMESPACE(Contoso); /* Reported properties */ DECLARE_STRUCT(SystemProperties, ascii_char_ptr, Manufacturer, ascii_char_ptr, FirmwareVersion, ascii_char_ptr, InstalledRAM, ascii_char_ptr, ModelNumber, ascii_char_ptr, Platform, ascii_char_ptr, Processor, ascii_char_ptr, SerialNumber ); DECLARE_STRUCT(LocationProperties, double, Latitude, double, Longitude ); DECLARE_STRUCT(ReportedDeviceProperties, ascii_char_ptr, DeviceState, LocationProperties, Location ); DECLARE_MODEL(ConfigProperties, WITH_REPORTED_PROPERTY(double, TemperatureMeanValue), WITH_REPORTED_PROPERTY(uint8_t, TelemetryInterval) ); /* Part of DeviceInfo */ DECLARE_STRUCT(DeviceProperties, ascii_char_ptr, DeviceID, _Bool, HubEnabledState ); DECLARE_DEVICETWIN_MODEL(Thermostat, /* Telemetry (temperature, external temperature and humidity) */ WITH_DATA(double, Temperature), WITH_DATA(double, ExternalTemperature), WITH_DATA(double, Humidity), WITH_DATA(ascii_char_ptr, DeviceId), /* DeviceInfo */ WITH_DATA(ascii_char_ptr, ObjectType), WITH_DATA(_Bool, IsSimulatedDevice), WITH_DATA(ascii_char_ptr, Version), WITH_DATA(DeviceProperties, DeviceProperties), /* Device twin properties */ WITH_REPORTED_PROPERTY(ReportedDeviceProperties, Device), WITH_REPORTED_PROPERTY(ConfigProperties, Config), WITH_REPORTED_PROPERTY(SystemProperties, System), WITH_DESIRED_PROPERTY(double, TemperatureMeanValue, onDesiredTemperatureMeanValue), WITH_DESIRED_PROPERTY(uint8_t, TelemetryInterval, onDesiredTelemetryInterval), /* Direct methods implemented by the device */ WITH_METHOD(Reboot), WITH_METHOD(InitiateFirmwareUpdate, ascii_char_ptr, FwPackageURI), /* Register direct methods with solution portal */ WITH_REPORTED_PROPERTY(ascii_char_ptr_no_quotes, SupportedMethods) ); END_NAMESPACE(Contoso);
デバイスの動作を実装する
次に、モデルで定義されている動作を実装するコードを追加します。
ソリューション ダッシュボードで設定された必要なプロパティを処理する次の関数を追加します。 これらの必要なプロパティは、モデルで定義されます。
void onDesiredTemperatureMeanValue(void* argument) { /* By convention 'argument' is of the type of the MODEL */ Thermostat* thermostat = argument; printf("Received a new desired_TemperatureMeanValue = %f\r\n", thermostat->TemperatureMeanValue); } void onDesiredTelemetryInterval(void* argument) { /* By convention 'argument' is of the type of the MODEL */ Thermostat* thermostat = argument; printf("Received a new desired_TelemetryInterval = %d\r\n", thermostat->TelemetryInterval); }
IoT ハブを介して呼び出されるダイレクト メソッドを処理する次の関数を追加します。 これらのダイレクト メソッドは、モデルで定義されます。
/* Handlers for direct methods */ METHODRETURN_HANDLE Reboot(Thermostat* thermostat) { (void)(thermostat); METHODRETURN_HANDLE result = MethodReturn_Create(201, "\"Rebooting\""); printf("Received reboot request\r\n"); return result; } METHODRETURN_HANDLE InitiateFirmwareUpdate(Thermostat* thermostat, ascii_char_ptr FwPackageURI) { (void)(thermostat); METHODRETURN_HANDLE result = MethodReturn_Create(201, "\"Initiating Firmware Update\""); printf("Recieved firmware update request. Use package at: %s\r\n", FwPackageURI); return result; }
構成済みソリューションにメッセージを送信する次の関数を追加します。
/* Send data to IoT Hub */ static void sendMessage(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size) { IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size); if (messageHandle == NULL) { printf("unable to create a new IoTHubMessage\r\n"); } else { if (IoTHubClient_SendEventAsync(iotHubClientHandle, messageHandle, NULL, NULL) != IOTHUB_CLIENT_OK) { printf("failed to hand over the message to IoTHubClient"); } else { printf("IoTHubClient accepted the message for delivery\r\n"); } IoTHubMessage_Destroy(messageHandle); } free((void*)buffer); }
デバイスが構成済みソリューションに新しい報告されたプロパティ値を送信したときに実行される次のコールバック ハンドラーを追加します。
/* Callback after sending reported properties */ void deviceTwinCallback(int status_code, void* userContextCallback) { (void)(userContextCallback); printf("IoTHub: reported properties delivered with status_code = %u\n", status_code); }
次の関数を追加して、デバイスをクラウドの構成済みソリューションに接続し、データを交換します。 この関数は、次の手順を実行します。
- プラットフォームを初期化します。
- Contoso 名前空間をシリアル化ライブラリに登録します。
- デバイス接続文字列を使用してクライアントを初期化します。
- Thermostat モデルのインスタンスを作成します。
- 報告されたプロパティ値を作成して送信します。
- DeviceInfo オブジェクトを送信します。
- テレメトリを 1 秒ごとに送信するループを作成します。
- すべてのリソースを初期化解除します。
void remote_monitoring_run(void) { if (platform_init() != 0) { printf("Failed to initialize the platform.\n"); } else { if (SERIALIZER_REGISTER_NAMESPACE(Contoso) == NULL) { printf("Unable to SERIALIZER_REGISTER_NAMESPACE\n"); } else { IOTHUB_CLIENT_HANDLE iotHubClientHandle = IoTHubClient_CreateFromConnectionString(connectionString, MQTT_Protocol); if (iotHubClientHandle == NULL) { printf("Failure in IoTHubClient_CreateFromConnectionString\n"); } else { #ifdef MBED_BUILD_TIMESTAMP // For mbed add the certificate information if (IoTHubClient_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK) { printf("Failed to set option \"TrustedCerts\"\n"); } #endif // MBED_BUILD_TIMESTAMP Thermostat* thermostat = IoTHubDeviceTwin_CreateThermostat(iotHubClientHandle); if (thermostat == NULL) { printf("Failure in IoTHubDeviceTwin_CreateThermostat\n"); } else { /* Set values for reported properties */ thermostat->Config.TemperatureMeanValue = 55.5; thermostat->Config.TelemetryInterval = 3; thermostat->Device.DeviceState = "normal"; thermostat->Device.Location.Latitude = 47.642877; thermostat->Device.Location.Longitude = -122.125497; thermostat->System.Manufacturer = "Contoso Inc."; thermostat->System.FirmwareVersion = "2.22"; thermostat->System.InstalledRAM = "8 MB"; thermostat->System.ModelNumber = "DB-14"; thermostat->System.Platform = "Plat 9.75"; thermostat->System.Processor = "i3-7"; thermostat->System.SerialNumber = "SER21"; /* Specify the signatures of the supported direct methods */ thermostat->SupportedMethods = "{\"Reboot\": \"Reboot the device\", \"InitiateFirmwareUpdate--FwPackageURI-string\": \"Updates device Firmware. Use parameter FwPackageURI to specify the URI of the firmware file\"}"; /* Send reported properties to IoT Hub */ if (IoTHubDeviceTwin_SendReportedStateThermostat(thermostat, deviceTwinCallback, NULL) != IOTHUB_CLIENT_OK) { printf("Failed sending serialized reported state\n"); } else { printf("Send DeviceInfo object to IoT Hub at startup\n"); thermostat->ObjectType = "DeviceInfo"; thermostat->IsSimulatedDevice = 0; thermostat->Version = "1.0"; thermostat->DeviceProperties.HubEnabledState = 1; thermostat->DeviceProperties.DeviceID = (char*)deviceId; unsigned char* buffer; size_t bufferSize; if (SERIALIZE(&buffer, &bufferSize, thermostat->ObjectType, thermostat->Version, thermostat->IsSimulatedDevice, thermostat->DeviceProperties) != CODEFIRST_OK) { (void)printf("Failed serializing DeviceInfo\n"); } else { sendMessage(iotHubClientHandle, buffer, bufferSize); } /* Send telemetry */ thermostat->Temperature = 50; thermostat->ExternalTemperature = 55; thermostat->Humidity = 50; thermostat->DeviceId = (char*)deviceId; while (1) { unsigned char*buffer; size_t bufferSize; (void)printf("Sending sensor value Temperature = %f, Humidity = %f\n", thermostat->Temperature, thermostat->Humidity); if (SERIALIZE(&buffer, &bufferSize, thermostat->DeviceId, thermostat->Temperature, thermostat->Humidity, thermostat->ExternalTemperature) != CODEFIRST_OK) { (void)printf("Failed sending sensor value\r\n"); } else { sendMessage(iotHubClientHandle, buffer, bufferSize); } ThreadAPI_Sleep(1000); } IoTHubDeviceTwin_DestroyThermostat(thermostat); } } IoTHubClient_Destroy(iotHubClientHandle); } serializer_deinit(); } } platform_deinit(); }
参考までに、事前構成済みソリューションに送信されるテレメトリ メッセージ サンプルを次に示します。
{"DeviceId":"mydevice01", "Temperature":50, "Humidity":50, "ExternalTemperature":55}
サンプルの構築と実行
remote_monitoring_run 関数を呼び出すコードを追加し、デバイス アプリケーションをビルドして実行します。
main 関数を次のコードに置き換えて、remote_monitoring_run 関数を呼び出します。
int main() { remote_monitoring_run(); return 0; }
[ビルド] をクリックし、次に [ソリューションのビルド] をしてデバイス アプリケーションをビルドします。
ソリューション エクスプローラー で、RMDevice プロジェクトを右クリックし、[デバッグ ] をクリックし、[新しいインスタンス の開始] クリックしてサンプルを実行します。 コンソールには、アプリケーションが構成済みソリューションにサンプル テレメトリを送信し、ソリューション ダッシュボードで設定された必要なプロパティ値を受け取り、ソリューション ダッシュボードから呼び出されたメソッドに応答すると、メッセージが表示されます。
ダッシュボードでデバイス テレメトリを表示する
リモート監視ソリューションのダッシュボードを使用すると、デバイスが IoT Hub に送信するテレメトリを表示できます。
ブラウザーで、リモート監視ソリューション ダッシュボードに戻り、左側のパネルで [デバイス ] をクリックして、デバイスの一覧に移動します。
デバイスの一覧で、デバイスの状態が [実行中の ]表示されます。 有効でない場合は、[デバイスの詳細] パネルで [デバイス を有効にする] をクリックします。
を表示する
ダッシュボードに戻るには、ダッシュボード をクリックし、表示するデバイス のドロップダウンからデバイスを選択して、そのテレメトリを表示します。 サンプル アプリケーションからのテレメトリは、内部温度が 50 単位、外部温度が 55 単位、湿度が 50 単位です。
を表示する
デバイスでメソッドを呼び出す
リモート監視ソリューションのダッシュボードを使用すると、IoT Hub を介してデバイス上のメソッドを呼び出すことができます。 たとえば、リモート監視ソリューションでは、メソッドを呼び出してデバイスの再起動をシミュレートできます。
リモート監視ソリューション ダッシュボードで、左側のパネルの [デバイス] をクリックして、デバイスの一覧に移動します。
デバイスの一覧で、デバイスのデバイス ID クリックします。
[デバイスの詳細 パネル]で、[メソッドをクリックします。]
メソッド ドロップダウンで、InitiateFirmwareUpdate 選択し、FWPACKAGEURI ダミー URL を入力します。 [メソッドを呼び出し] をクリックして、デバイス上でメソッドを呼び出します。
デバイスがメソッドを処理するときに、デバイス コードを実行しているコンソールにメッセージが表示されます。 メソッドの結果は、ソリューション ポータルの履歴に追加されます。
次のステップ
構成済みソリューション カスタマイズ 記事では、このサンプルを拡張するいくつかの方法について説明します。 可能な拡張機能には、実際のセンサーの使用や追加のコマンドの実装が含まれます。
azureiotsuite.com サイト に対するのアクセス許可の詳細を確認できます。