C 用 Azure IoT device SDKAzure IoT device SDK for C

Azure IoT device SDK は、Azure IoT Hub サービスとのメッセージの送受信プロセスを簡略化するために設計された一連のライブラリです。The Azure IoT device SDK is a set of libraries designed to simplify the process of sending messages to and receiving messages from the Azure IoT Hub service. SDK にはさまざまなバリエーションがあり、それぞれが特定のプラットフォームを対象としていますが、この記事では、 C 用 Azure IoT device SDKについて説明します。There are different variations of the SDK, each targeting a specific platform, but this article describes the Azure IoT device SDK for C.

注意

この記事で言及されている一部の機能 (cloud-to-device メッセージング、デバイス ツイン、デバイス管理など) は、IoT Hub の Standard レベルだけで使用することができます。Some of the features mentioned in this article, like cloud-to-device messaging, device twins, and device management, are only available in the standard tier of IoT Hub. IoT Hub の Basic レベルおよび Standard レベルの詳細については、適切な IoT Hub レベルの選び方に関するページを参照してください。For more information about the basic and standard IoT Hub tiers, see How to choose the right IoT Hub tier.

C 用 Azure IoT デバイス SDK は、移植性を最大限まで高めるために ANSI C (C99) で記述されています。The Azure IoT device SDK for C is written in ANSI C (C99) to maximize portability. この機能により、複数のプラットフォームとデバイス、特にディスクとメモリの量を最小限に抑えることが優先される環境でライブラリを操作しやすくなります。This feature makes the libraries well-suited to operate on multiple platforms and devices, especially where minimizing disk and memory footprint is a priority.

この SDK は幅広いプラットフォームでテストされています (詳細は、Azure Certified for IoT デバイス カタログに関するページを参照してください)。There are a broad range of platforms on which the SDK has been tested (see the Azure Certified for IoT device catalog for details). この記事には、Windows プラットフォームで実行されるサンプル コードのチュートリアルが含まれますが、この記事で説明するコードはサポートされるプラットフォーム全体で同じです。Although this article includes walkthroughs of sample code running on the Windows platform, the code described in this article is identical across the range of supported platforms.

次のビデオでは、C 用 Azure IoT SDK の概要が紹介されています。The following video presents an overview of the Azure IoT SDK for C:

この記事では、C 用 Azure IoT device SDK のアーキテクチャについて紹介します。また、デバイスのライブラリを初期化する方法、IoT Hub にデータを送信する方法、IoT Hub からメッセージを受信する方法を示します。This article introduces you to the architecture of the Azure IoT device SDK for C. It demonstrates how to initialize the device library, send data to IoT Hub, and receive messages from it. この記事の情報は、SDK を使用し始めるにあたり十分な内容ですが、ライブラリに関する追加情報を入手できる場所も紹介します。The information in this article should be enough to get started using the SDK, but also provides pointers to additional information about the libraries.

SDK のアーキテクチャSDK architecture

C 用 Azure IoT device SDK は GitHub リポジトリから入手でき、API の詳細は C API リファレンスに関するページで確認できます。You can find the Azure IoT device SDK for C GitHub repository and view details of the API in the C API reference.

最新バージョンのライブラリは、このリポジトリの master ブランチにあります。The latest version of the libraries can be found in the master branch of the repository:

リポジトリのマスター ブランチのスクリーンショット

  • SDK の中心となる実装は iothub_client フォルダー内にあり、このフォルダーには SDK 内の最下位の API 層の実装 (IoTHubClient) が格納されています。The core implementation of the SDK is in the iothub_client folder that contains the implementation of the lowest API layer in the SDK: the IoTHubClient library. IoTHubClient ライブラリには、IoT Hub とのメッセージの送受信のために、未加工メッセージングを実装する API が含まれています。The IoTHubClient library contains APIs implementing raw messaging for sending messages to IoT Hub and receiving messages from IoT Hub. このライブラリを使用する場合、メッセージのシリアル化はユーザー自身が実装する必要がありますが、IoT Hub と通信するためのその他の詳細は自動で処理されます。When using this library, you are responsible for implementing message serialization, but other details of communicating with IoT Hub are handled for you.

  • serializer フォルダーには、クライアント ライブラリを使用して Azure IoT Hub に送信する前にデータをシリアル化する方法を示す、ヘルパー関数とサンプルが含まれています。The serializer folder contains helper functions and samples that show you how to serialize data before sending to Azure IoT Hub using the client library. シリアライザーの使用は必須ではなく、利便性のために提供されています。The use of the serializer is not mandatory and is provided as a convenience. serializer ライブラリを使用するには、IoT Hub に送信するデータと IoT Hub から受信するメッセージを指定するモデルを定義します。To use the serializer library, you define a model that specifies the data to send to IoT Hub and the messages you expect to receive from it. いったんモデルを定義すれば、SDK が提供する API にアクセスして、シリアル化の詳細を気にすることなく、デバイスからクラウド、クラウドからデバイスへのメッセージを簡単に処理できます。Once the model is defined, the SDK provides you with an API surface that enables you to easily work with device-to-cloud and cloud-to-device messages without worrying about the serialization details. ライブラリは、MQTT や AMQP などのプロトコルを使用してトランスポートを実装するその他のオープン ソース ライブラリに依存しています。The library depends on other open source libraries that implement transport using protocols such as MQTT and AMQP.

  • IoTHubClient ライブラリは、次に示すその他のオープン ソース ライブラリに依存しています。The IoTHubClient library depends on other open source libraries:

    • Azure C 共有ユーティリティ ライブラリ。複数の Azure 関連 C SDK で必要となる基本タスク (文字列、リストの操作、IO など) に共通する機能を提供します。The Azure C shared utility library, which provides common functionality for basic tasks (such as strings, list manipulation, and IO) needed across several Azure-related C SDKs.

    • Azure uAMQP ライブラリ。リソースに制約のあるデバイス用に最適化された AMQP のクライアント側の実装です。The Azure uAMQP library, which is a client-side implementation of AMQP optimized for resource constrained devices.

    • Azure uMQTT ライブラリ。MQTT プロトコルを実装する汎用ライブラリで、リソースに制約のあるデバイス用に最適化されています。The Azure uMQTT library, which is a general-purpose library implementing the MQTT protocol and optimized for resource constrained devices.

これらのライブラリの使用については、サンプル コードを確認した方が簡単に理解できます。Use of these libraries is easier to understand by looking at example code. 次のセクションでは、SDK に含まれているいくつかのサンプル アプリケーションについて説明します。The following sections walk you through several of the sample applications that are included in the SDK. このチュートリアルは、SDK のアーキテクチャの層のさまざまな機能や、API の動作のしくみの概要を理解するうえで役立ちます。This walkthrough should give you a good feel for the various capabilities of the architectural layers of the SDK and an introduction to how the APIs work.

サンプルを実行する前にBefore you run the samples

C 用 Azure IoT device SDK のサンプルを実行する前に、Azure サブスクリプションで IoT Hub サービスのインスタンスを作成する必要があります。Before you can run the samples in the Azure IoT device SDK for C, you must create an instance of the IoT Hub service in your Azure subscription. そのうえで、次のタスクを実行してください。Then complete the following tasks:

  • 開発環境を準備するPrepare your development environment
  • デバイスの資格情報を取得するObtain device credentials.

開発環境を準備するPrepare your development environment

パッケージは一般的なプラットフォーム (Windows 用 NuGet、Debian と Ubuntu 用 apt_get など) に提供され、利用可能な場合にサンプルはこれらのパッケージを使用します。Packages are provided for common platforms (such as NuGet for Windows or apt_get for Debian and Ubuntu) and the samples use these packages when available. 場合によっては、デバイス向けに、またはデバイス上で SDK をコンパイルする必要があります。In some cases, you need to compile the SDK for or on your device. SDK をコンパイルする必要がある場合は、GitHub リポジトリで「Prepare your development environment (開発環境の準備)」を参照してください。If you need to compile the SDK, see Prepare your development environment in the GitHub repository.

サンプル アプリケーション コードを取得するには、GitHub から SDK のコピーをダウンロードします。To obtain the sample application code, download a copy of the SDK from GitHub. GitHub リポジトリmaster ブランチからソースのコピーを入手します。Get your copy of the source from the master branch of the GitHub repository.

デバイスの資格情報を取得するObtain the device credentials

これでサンプル ソース コートが手に入ったので、次にデバイスの資格情報のセットを取得します。Now that you have the sample source code, the next thing to do is to get a set of device credentials. デバイスを IoT ハブにアクセスできるようにするには、まず、そのデバイスを IoT Hub ID レジストリに追加する必要があります。For a device to be able to access an IoT hub, you must first add the device to the IoT Hub identity registry. デバイスを追加すると、そのデバイスから IoT ハブに接続するために必要な、デバイスの資格情報のセットが得られます。When you add your device, you get a set of device credentials that you need for the device to be able to connect to the IoT hub. 次のセクションで確認するサンプル アプリケーションでは、これらの資格情報はデバイスの接続文字列の形式であると想定しています。The sample applications discussed in the next section expect these credentials in the form of a device connection string.

IoT ハブの管理に役立つオープン ソース ツールがいくつかあります。There are several open source tools to help you manage your IoT hub.

このチュートリアルでは、グラフィカル デバイス エクスプローラー ツールを使います。This tutorial uses the graphical device explorer tool. VS Code で開発する場合は、VS Code 用の Azure IoT Tools を使用できます。You can use the Azure IoT Tools for VS Code if you develop in VS Code. CLI ツールを使いたい場合は、"Azure CLI 2.0 向けの IoT 拡張機能" ツールを使うこともできます。You can also use the the IoT extension for Azure CLI 2.0 tool if you prefer to use a CLI tool.

デバイス エクスプローラー ツールは、Azure IoT サービス ライブラリを使用して、デバイスの追加など、IoT Hub のさまざまな機能を実行します。The device explorer tool uses the Azure IoT service libraries to perform various functions on IoT Hub, including adding devices. デバイス エクスプローラー ツールを使用してデバイスを追加すると、デバイス用の接続文字列が表示されます。If you use the device explorer tool to add a device, you get a connection string for your device. この接続文字列は、サンプル アプリケーションを実行するために必要です。You need this connection string to run the sample applications.

デバイス エクスプローラー ツールに慣れていない方のために、次の手順で、デバイス エクスプローラー ツールを使用してデバイスを追加し、デバイスの接続文字列を取得する方法について説明します。If you're not familiar with the device explorer tool, the following procedure describes how to use it to add a device and obtain a device connection string.

  1. デバイス エクスプローラー ツールをインストールするには、「How to use Device Explorer for IoT Hub devices (IoT Hub デバイス向けにデバイス エクスプローラーを使用する方法)」を参照してください。To install the device explorer tool, see How to use the Device Explorer for IoT Hub devices.

  2. プログラムを実行すると、次のインターフェイスが表示されます。When you run the program, you see this interface:

    Device Explorer ツインのスクリーンショット

  3. IoT Hub の接続文字列を最初のフィールドに入力し、 [更新] をクリックします。Enter your IoT Hub Connection String in the first field and click Update. この手順により、IoT Hub と通信できるようにツールが構成されます。This step configures the tool so that it can communicate with IoT Hub.

接続文字列は、 [IoT Hub サービス] > [設定] > [共有アクセス ポリシー] > [iothubowner] で確認できます。The Connection String can be found under IoT Hub Service > Settings > Shared Access Policy > iothubowner.

  1. IoT Hub の接続文字列を構成したら、 [管理] タブをクリックします。When the IoT Hub connection string is configured, click the Management tab:

    Device Explorer ツイン/管理のスクリーンショット

このタブで、IoT Hub に登録されたデバイスを管理します。This tab is where you manage the devices registered in your IoT hub.

  1. [作成] をクリックしてデバイスを作成します。You create a device by clicking the Create button. ダイアログが、一連のキー (プライマリおよびセカンダリ) が入力された状態で表示されます。A dialog displays with a set of pre-populated keys (primary and secondary). デバイス ID を入力し、 [作成] をクリックします。Enter a Device ID and then click Create.

    デバイス作成のスクリーンショット

  2. デバイスが作成されたら、デバイスの一覧が更新され、今作成したデバイスを含むすべての登録済みデバイスが表示されます。When the device is created, the Devices list updates with all the registered devices, including the one you just created. 新しいデバイスを右クリックすると、次のメニューが表示されます。If you right-click your new device, you see this menu:

    Device Explorer ツインの右クリックの結果

  3. [Copy connection string for selected device (選択したデバイスの接続文字列のコピー)] を選択すると、デバイスの接続文字列がクリップボードにコピーされます。If you choose Copy connection string for selected device, the device connection string is copied to the clipboard. デバイス接続文字列のコピーを保存しておきます。Keep a copy of the device connection string. 次のセクションで説明するサンプル アプリケーションを実行するときにこれが必要になります。You need it when running the sample applications described in the following sections.

前の手順が完了すると、コードを実行する準備が整います。When you've completed the steps above, you're ready to start running some code. 多くのサンプルでは、メインのソース ファイルの上部に、接続文字列を入力するための定数が使用されています。Most samples have a constant at the top of the main source file that enables you to enter a connection string. たとえば、iothub_client_samples_iothub_convenience_sample アプリケーションの対応する行は次のとおりです。For example, the corresponding line from the iothub_client_samples_iothub_convenience_sample application appears as follows.

static const char* connectionString = "[device connection string]";

IoTHubClient ライブラリを使用するUse the IoTHubClient library

azure-iot-sdk-c リポジトリ内の iothub_client フォルダーに samples フォルダーがあり、iothub_client_sample_mqtt というアプリケーションが格納されています。Within the iothub_client folder in the azure-iot-sdk-c repository, there is a samples folder that contains an application called iothub_client_sample_mqtt.

iothub_client_samples_iothub_convenience_sample アプリケーションの Windows バージョンには、次の Visual Studio のソリューションが含まれます。The Windows version of the iothub_client_samples_iothub_convenience_sample application includes the following Visual Studio solution:

Visual Studio のソリューション エクスプローラー

注意

Visual Studio で、プロジェクトのターゲットを最新バージョンに変更することを要求するプロンプトが表示された場合は、そのプロンプトを受け入れてください。If Visual Studio asks you to retarget the project to the latest version, accept the prompt.

このソリューションには単一のプロジェクトが含まれています。This solution contains a single project. このソリューションには 4 つの NuGet パッケージがインストールされています。There are four NuGet packages installed in this solution:

  • Microsoft.Azure.C.SharedUtilityMicrosoft.Azure.C.SharedUtility
  • Microsoft.Azure.IoTHub.MqttTransportMicrosoft.Azure.IoTHub.MqttTransport
  • Microsoft.Azure.IoTHub.IoTHubClientMicrosoft.Azure.IoTHub.IoTHubClient
  • Microsoft.Azure.umqttMicrosoft.Azure.umqtt

SDK を使った作業には必ず Microsoft.Azure.C.SharedUtility パッケージが必要となります。You always need the Microsoft.Azure.C.SharedUtility package when you are working with the SDK. このサンプルでは MQTT プロトコルを使用するため、Microsoft.Azure.umqtt パッケージと Microsoft.Azure.IoTHub.MqttTransport パッケージを含める必要があります (AMQP と HTTPS にも同等のパッケージが存在します)。This sample uses the MQTT protocol, therefore you must include the Microsoft.Azure.umqtt and Microsoft.Azure.IoTHub.MqttTransport packages (there are equivalent packages for AMQP and HTTPS). サンプルでは IoTHubClient ライブラリが使用されているため、ソリューション内に Microsoft.Azure.IoTHub.IoTHubClient パッケージも含める必要があります。Because the sample uses the IoTHubClient library, you must also include the Microsoft.Azure.IoTHub.IoTHubClient package in your solution.

サンプル アプリケーションの実装は、iothub_client_samples_iothub_convenience_sample ソース ファイル内にあります。You can find the implementation for the sample application in the iothub_client_samples_iothub_convenience_sample source file.

次の手順では、このサンプル アプリケーションを使用して、IoTHubClient ライブラリの使用に必要な内容を説明します。The following steps use this sample application to walk you through what's required to use the IoTHubClient library.

ライブラリを初期化するInitialize the library

注意

ライブラリの使用を開始する前に、プラットフォーム固有の初期化の実行が必要になる場合があります。Before you start working with the libraries, you may need to perform some platform-specific initialization. たとえば、Linux 上で AMQP を使用する計画がある場合は、OpenSSL ライブラリを初期化する必要があります。For example, if you plan to use AMQP on Linux you must initialize the OpenSSL library. GitHub リポジトリのサンプルはクライアントの起動時にユーティリティ関数 platform_init を呼び出し、終了する前に platform_deinit 関数を呼び出します。The samples in the GitHub repository call the utility function platform_init when the client starts and call the platform_deinit function before exiting. これらの関数は、platform.h ヘッダー ファイルで宣言されます。These functions are declared in the platform.h header file. ターゲットとするプラットフォームについてリポジトリでこれらの関数の定義を確認し、クライアントにいずれかのプラットフォーム固有の初期化コードを含める必要があるかどうかを判断する必要があります。Examine the definitions of these functions for your target platform in the repository to determine whether you need to include any platform-specific initialization code in your client.

ライブラリで作業を開始するには、最初に、IoT Hub クライアントのハンドルを割り当てる必要があります。To start working with the libraries, first allocate an IoT Hub client handle:

if ((iotHubClientHandle = 
  IoTHubClient_LL_CreateFromConnectionString(connectionString, MQTT_Protocol)) == NULL)
{
    (void)printf("ERROR: iotHubClientHandle is NULL!\r\n");
}
else
{
    ...

デバイス エクスプローラー ツールから取得したデバイスの接続文字列のコピーをこの関数に渡します。You pass a copy of the device connection string you obtained from the device explorer tool to this function. また、使用する通信プロトコルを指定します。You also designate the communications protocol to use. この例では MQTT を使用しますが、AMQP と HTTPS も使用できます。This example uses MQTT, but AMQP and HTTPS are also options.

有効な IOTHUB_CLIENT_HANDLE がある場合は、その API の呼び出しを開始して、IoT Hub との間でメッセージを送受信できます。When you have a valid IOTHUB_CLIENT_HANDLE, you can start calling the APIs to send and receive messages to and from IoT Hub.

メッセージを送信するSend messages

このサンプル アプリケーションによって、メッセージを IoT ハブに送信するループがセットアップされます。The sample application sets up a loop to send messages to your IoT hub. 次のスニペットが必要です。The following snippet:

  • メッセージを作成する。Creates a message.
  • プロパティをメッセージに追加する。Adds a property to the message.
  • メッセージを送信する。Sends a message.

まず、次のようにメッセージを作成します。First, create a message:

size_t iterator = 0;
do
{
    if (iterator < MESSAGE_COUNT)
    {
        sprintf_s(msgText, sizeof(msgText), "{\"deviceId\":\"myFirstDevice\",\"windSpeed\":%.2f}", avgWindSpeed + (rand() % 4 + 2));
        if ((messages[iterator].messageHandle = IoTHubMessage_CreateFromByteArray((const unsigned char*)msgText, strlen(msgText))) == NULL)
        {
            (void)printf("ERROR: iotHubMessageHandle is NULL!\r\n");
        }
        else
        {
            messages[iterator].messageTrackingId = iterator;
            MAP_HANDLE propMap = IoTHubMessage_Properties(messages[iterator].messageHandle);
            (void)sprintf_s(propText, sizeof(propText), "PropMsg_%zu", iterator);
            if (Map_AddOrUpdate(propMap, "PropName", propText) != MAP_OK)
            {
                (void)printf("ERROR: Map_AddOrUpdate Failed!\r\n");
            }

            if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messages[iterator].messageHandle, SendConfirmationCallback, &messages[iterator]) != IOTHUB_CLIENT_OK)
            {
                (void)printf("ERROR: IoTHubClient_LL_SendEventAsync..........FAILED!\r\n");
            }
            else
            {
                (void)printf("IoTHubClient_LL_SendEventAsync accepted message [%d] for transmission to IoT Hub.\r\n", (int)iterator);
            }
        }
    }
    IoTHubClient_LL_DoWork(iotHubClientHandle);
    ThreadAPI_Sleep(1);

    iterator++;
} while (g_continueRunning);

メッセージを送信するたびに、データが送信されるときに呼び出されるコールバック関数への参照を指定します。Every time you send a message, you specify a reference to a callback function that's invoked when the data is sent. この例では、コールバック関数は SendConfirmationCallback です。In this example, the callback function is called SendConfirmationCallback. 次のスニペットは、このコールバック関数を示しています。The following snippet shows this callback function:

static void SendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
{
    EVENT_INSTANCE* eventInstance = (EVENT_INSTANCE*)userContextCallback;
    (void)printf("Confirmation[%d] received for message tracking id = %zu with result = %s\r\n", callbackCounter, eventInstance->messageTrackingId, MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result));
    /* Some device specific action code goes here... */
    callbackCounter++;
    IoTHubMessage_Destroy(eventInstance->messageHandle);
}

メッセージの処理が終了したときに呼び出される IoTHubMessage_Destroy 関数に注意してください。Note the call to the IoTHubMessage_Destroy function when you're done with the message. この関数は、メッセージを作成したときに割り当てられたリソースを解放します。This function frees the resources allocated when you created the message.

メッセージを受信するReceive messages

メッセージの受信は非同期操作です。Receiving a message is an asynchronous operation. 最初に、デバイスがメッセージを受信したときに呼び出すコールバックを登録します。First, you register the callback to invoke when the device receives a message:

if (IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, ReceiveMessageCallback, &receiveContext) != IOTHUB_CLIENT_OK)
{
    (void)printf("ERROR: IoTHubClient_LL_SetMessageCallback..........FAILED!\r\n");
}
else
{
    (void)printf("IoTHubClient_LL_SetMessageCallback...successful.\r\n");
    ...

最後のパラメーターは任意のものを指す void ポインターです。The last parameter is a void pointer to whatever you want. このサンプルのポインターは整数を指していますが、より複雑なデータ構造を指すこともできます。In the sample, it's a pointer to an integer but it could be a pointer to a more complex data structure. このパラメーターにより、このコールバック関数を、この関数の呼び出し元と共有した状態で操作できます。This parameter enables the callback function to operate on shared state with the caller of this function.

デバイスがメッセージを受信すると、登録済みのコールバック関数が呼び出されます。When the device receives a message, the registered callback function is invoked. このコールバック関数は次のものを受信します。This callback function retrieves:

  • メッセージのメッセージ ID と関連付け ID。The message id and correlation id from the message.
  • メッセージのコンテンツ。The message content.
  • メッセージの任意のカスタム プロパティ。Any custom properties from the message.
static IOTHUBMESSAGE_DISPOSITION_RESULT ReceiveMessageCallback(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
    int* counter = (int*)userContextCallback;
    const char* buffer;
    size_t size;
    MAP_HANDLE mapProperties;
    const char* messageId;
    const char* correlationId;

    // Message properties
    if ((messageId = IoTHubMessage_GetMessageId(message)) == NULL)
    {
        messageId = "<null>";
    }

    if ((correlationId = IoTHubMessage_GetCorrelationId(message)) == NULL)
    {
        correlationId = "<null>";
    }

    // Message content
    if (IoTHubMessage_GetByteArray(message, (const unsigned char**)&buffer, &size) != IOTHUB_MESSAGE_OK)
    {
        (void)printf("unable to retrieve the message data\r\n");
    }
    else
    {
        (void)printf("Received Message [%d]\r\n Message ID: %s\r\n Correlation ID: %s\r\n Data: <<<%.*s>>> & Size=%d\r\n", *counter, messageId, correlationId, (int)size, buffer, (int)size);
        // If we receive the work 'quit' then we stop running
        if (size == (strlen("quit") * sizeof(char)) && memcmp(buffer, "quit", size) == 0)
        {
            g_continueRunning = false;
        }
    }

    // Retrieve properties from the message
    mapProperties = IoTHubMessage_Properties(message);
    if (mapProperties != NULL)
    {
        const char*const* keys;
        const char*const* values;
        size_t propertyCount = 0;
        if (Map_GetInternals(mapProperties, &keys, &values, &propertyCount) == MAP_OK)
        {
            if (propertyCount > 0)
            {
                size_t index;

                printf(" Message Properties:\r\n");
                for (index = 0; index < propertyCount; index++)
                {
                    (void)printf("\tKey: %s Value: %s\r\n", keys[index], values[index]);
                }
                (void)printf("\r\n");
            }
        }
    }

    /* Some device specific action code goes here... */
    (*counter)++;
    return IOTHUBMESSAGE_ACCEPTED;
}

IoTHubMessage_GetByteArray 関数を使用してメッセージを取得します。この例では文字列です。Use the IoTHubMessage_GetByteArray function to retrieve the message, which in this example is a string.

ライブラリの初期化を解除するUninitialize the library

イベントの送信とメッセージの受信が完了すると、IoT ライブラリの初期化を解除することができます。When you're done sending events and receiving messages, you can uninitialize the IoT library. これを行うには、次の関数呼び出しを発行します。To do so, issue the following function call:

IoTHubClient_LL_Destroy(iotHubClientHandle);

この呼び出しにより、以前に割り当てられていたリソースが、IoTHubClient_CreateFromConnectionString 関数によって解放されます。This call frees up the resources previously allocated by the IoTHubClient_CreateFromConnectionString function.

ご覧のように、IoTHubClient ライブラリを使用すると、簡単にメッセージを送受信できます。As you can see, it's easy to send and receive messages with the IoTHubClient library. 使用するプロトコルなど (開発者の観点からは単純な構成オプションです)、IoT Hub との通信に関する詳細情報は、ライブラリで処理されます。The library handles the details of communicating with IoT Hub, including which protocol to use (from the perspective of the developer, this is a simple configuration option).

IoTHubClient ライブラリでは、デバイスから IoT Hub に送信されるデータをシリアル化する方法を正確に制御することもできます。The IoTHubClient library also provides precise control over how to serialize the data your device sends to IoT Hub. この制御のレベルが利点になる場合もありますが、こうした実装の詳細が不要な場合もあります。In some cases this level of control is an advantage, but in others it is an implementation detail that you don't want to be concerned with. その場合は、次のセクションで説明する serializer ライブラリの使用を検討してください。If that's the case, you might consider using the serializer library, which is described in the next section.

serializer ライブラリを使用するUse the serializer library

概念的には、serializer ライブラリは、SDK の IoTHubClient ライブラリの上位に位置します。Conceptually the serializer library sits on top of the IoTHubClient library in the SDK. IoT Hub との基礎になる通信で IoTHubClient ライブラリを使用しますが、モデリング機能が追加されるため、開発者がメッセージのシリアル化を処理する負担が削減されます。It uses the IoTHubClient library for the underlying communication with IoT Hub, but it adds modeling capabilities that remove the burden of dealing with message serialization from the developer. このライブラリの動作のわかりやすい例を示します。How this library works is best demonstrated by an example.

azure-iot-sdk-c リポジトリ内の serializer フォルダー内には samples フォルダーがあり、simplesample_mqtt というアプリケーションが格納されています。Inside the serializer folder in the azure-iot-sdk-c repository, is a samples folder that contains an application called simplesample_mqtt. このサンプルの Windows バージョンには、次の Visual Studio のソリューションが含まれます。The Windows version of this sample includes the following Visual Studio solution:

mqtt サンプルの Visual Studio ソリューション

注意

Visual Studio で、プロジェクトのターゲットを最新バージョンに変更することを要求するプロンプトが表示された場合は、そのプロンプトを受け入れてください。If Visual Studio asks you to retarget the project to the latest version, accept the prompt.

前のサンプルと同様、このソリューションにも、いくつかの NuGet パッケージが含まれています。As with the previous sample, this one includes several NuGet packages:

  • Microsoft.Azure.C.SharedUtilityMicrosoft.Azure.C.SharedUtility
  • Microsoft.Azure.IoTHub.MqttTransportMicrosoft.Azure.IoTHub.MqttTransport
  • Microsoft.Azure.IoTHub.IoTHubClientMicrosoft.Azure.IoTHub.IoTHubClient
  • Microsoft.Azure.IoTHub.SerializerMicrosoft.Azure.IoTHub.Serializer
  • Microsoft.Azure.umqttMicrosoft.Azure.umqtt

ほとんどのパッケージは前のサンプルにも含まれていましたが、Microsoft.Azure.IoTHub.Serializer を使うのはこれが初めてです。You've seen most of these packages in the previous sample, but Microsoft.Azure.IoTHub.Serializer is new. このパッケージは、serializer ライブラリを使用するときに必要です。This package is required when you use the serializer library.

サンプル アプリケーションの実装は、iothub_client_samples_iothub_convenience_sample ファイル内にあります。You can find the implementation of the sample application in the iothub_client_samples_iothub_convenience_sample file.

次のセクションで、このサンプルの主要な部分について説明します。The following sections walk you through the key parts of this sample.

ライブラリを初期化するInitialize the library

serializer ライブラリの使用を開始するには、初期化 API を呼び出します。To start working with the serializer library, call the initialization APIs:

if (serializer_init(NULL) != SERIALIZER_OK)
{
    (void)printf("Failed on serializer_init\r\n");
}
else
{
    IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle = IoTHubClient_LL_CreateFromConnectionString(connectionString, MQTT_Protocol);
    srand((unsigned int)time(NULL));
    int avgWindSpeed = 10;

    if (iotHubClientHandle == NULL)
    {
        (void)printf("Failed on IoTHubClient_LL_Create\r\n");
    }
    else
    {
        ContosoAnemometer* myWeather = CREATE_MODEL_INSTANCE(WeatherStation, ContosoAnemometer);
        if (myWeather == NULL)
        {
            (void)printf("Failed on CREATE_MODEL_INSTANCE\r\n");
        }
        else
        {
...

serializer_init 関数の呼び出しは 1 回だけの呼び出しであり、基になるライブラリを初期化します。The call to the serializer_init function is a one-time call and initializes the underlying library. 次に、IoTHubClient_LL_CreateFromConnectionString 関数を呼び出します。これは、IoTHubClient サンプルに含まれる API と同じものです。Then, you call the IoTHubClient_LL_CreateFromConnectionString function, which is the same API as in the IoTHubClient sample. この呼び出しにより、デバイスの接続文字列が設定されます (この呼び出しは、使用するプロトコルを選択する場所でもあります)。This call sets your device connection string (this call is also where you choose the protocol you want to use). このサンプルでは、トランスポートとして MQTT を使用していますが、AMQP または HTTPS を使用することもできます。This sample uses MQTT as the transport, but could use AMQP or HTTPS.

最後に、CREATE_MODEL_INSTANCE 関数を呼び出します。Finally, call the CREATE_MODEL_INSTANCE function. WeatherStation はモデルの名前空間で、ContosoAnemometer はモデルの名前です。WeatherStation is the namespace of the model and ContosoAnemometer is the name of the model. モデルのインスタンスが作成されたら、そのモデルを使用して、メッセージの送受信を開始することができます。Once the model instance is created, you can use it to start sending and receiving messages. ただし、モデルがどのようなものかを理解する必要があります。However, it's important to understand what a model is.

モデルを定義するDefine the model

serializer ライブラリ内のモデルは、デバイスから IoT Hub に送信できるメッセージと、モデリング言語で "アクション" と呼ばれる、デバイスで受信できるメッセージを定義します。A model in the serializer library defines the messages that your device can send to IoT Hub and the messages, called actions in the modeling language, which it can receive. iothub_client_samples_iothub_convenience_sample サンプル アプリケーションと同様に、一連の C マクロを使用してモデルを定義します。You define a model using a set of C macros as in the iothub_client_samples_iothub_convenience_sample sample application:

BEGIN_NAMESPACE(WeatherStation);

DECLARE_MODEL(ContosoAnemometer,
WITH_DATA(ascii_char_ptr, DeviceId),
WITH_DATA(int, WindSpeed),
WITH_ACTION(TurnFanOn),
WITH_ACTION(TurnFanOff),
WITH_ACTION(SetAirResistance, int, Position)
);

END_NAMESPACE(WeatherStation);

BEGIN_NAMESPACEEND_NAMESPACE の両方のマクロは、モデルの名前空間を引数として取得します。The BEGIN_NAMESPACE and END_NAMESPACE macros both take the namespace of the model as an argument. これらのマクロの間には、モデルの定義とモデルが使用するデータ構造があることが想定されます。It's expected that anything between these macros is the definition of your model or models, and the data structures that the models use.

この例では、 ContosoAnemometerという単一のモデルがあります。In this example, there is a single model called ContosoAnemometer. このモデルは、デバイスが IoT Hub に送信できる、DeviceIdWindSpeed という 2 つのデータを定義します。This model defines two pieces of data that your device can send to IoT Hub: DeviceId and WindSpeed. また、デバイスが受信できる、TurnFanOnTurnFanOff、および SetAirResistance の 3 つのアクション (メッセージ) も定義されます。It also defines three actions (messages) that your device can receive: TurnFanOn, TurnFanOff, and SetAirResistance. 各データ要素には型があり、各アクションには名前 (また、必要に応じて一連のパラメーター) があります。Each data element has a type, and each action has a name (and optionally a set of parameters).

モデルで定義されたデータとアクションは、IoT Hub へのメッセージの送信とデバイスに送信されたメッセージへの応答に使用できる API へのアクセスを定義します。The data and actions defined in the model define an API surface that you can use to send messages to IoT Hub, and respond to messages sent to the device. このモデルの使用については、例を通じて理解するのが一番です。Use of this model is best understood through an example.

メッセージを送信するSend messages

このモデルは、IoT Hub に送信できるデータを定義します。The model defines the data you can send to IoT Hub. この例では、WITH_DATA マクロを使用して定義した 2 つのデータ項目のどちらかを意味します。In this example, that means one of the two data items defined using the WITH_DATA macro. DeviceId 値と WindSpeed 値を IoT ハブに送信するのに必要な手順はいくつかあります。There are several steps required to send DeviceId and WindSpeed values to an IoT hub. 最初に、送信するデータを設定します。The first is to set the data you want to send:

myWeather->DeviceId = "myFirstDevice";
myWeather->WindSpeed = avgWindSpeed + (rand() % 4 + 2);

前に定義したモデルでは、struct のメンバーを設定して値を設定できます。The model you defined earlier enables you to set the values by setting members of a struct. 次に、送信するメッセージをシリアル化します。Next, serialize the message you want to send:

unsigned char* destination;
size_t destinationSize;
if (SERIALIZE(&destination, &destinationSize, myWeather->DeviceId, myWeather->WindSpeed) != CODEFIRST_OK)
{
    (void)printf("Failed to serialize\r\n");
}
else
{
    sendMessage(iotHubClientHandle, destination, destinationSize);
    free(destination);
}

このコードは、デバイスからクラウドへのデータをシリアル化して、(送信先によって参照される) バッファーに格納します。This code serializes the device-to-cloud to a buffer (referenced by destination). 次に、sendMessage 関数を呼び出して、メッセージを IoT Hub に送信します。The code then invokes the sendMessage function to send the message to IoT Hub:

static void sendMessage(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size)
{
    static unsigned int messageTrackingId;
    IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size);
    if (messageHandle == NULL)
    {
        printf("unable to create a new IoTHubMessage\r\n");
    }
    else
    {
        if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, sendCallback, (void*)(uintptr_t)messageTrackingId) != 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);
    }
    messageTrackingId++;
}

IoTHubClient_LL_SendEventAsync の最後から 2 番目のパラメーターは、データが正常に送信されたときに呼び出されるコールバック関数の参照です。The second to last parameter of IoTHubClient_LL_SendEventAsync is a reference to a callback function that's called when the data is successfully sent. サンプル内のコールバック関数は次のとおりです。Here's the callback function in the sample:

void sendCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback)
{
    unsigned int messageTrackingId = (unsigned int)(uintptr_t)userContextCallback;

    (void)printf("Message Id: %u Received.\r\n", messageTrackingId);

    (void)printf("Result Call Back Called! Result is: %s \r\n", MU_ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result));
}

2 番目のパラメーターは、ユーザー コンテキストを指すポインターであり、IoTHubClient_LL_SendEventAsync に渡したポインターと同じものです。The second parameter is a pointer to user context; the same pointer passed to IoTHubClient_LL_SendEventAsync. ここでは、このコンテキストは単純なカウンターですが、任意の内容にすることができます。In this case, the context is a simple counter, but it can be anything you want.

デバイスからクラウドへのメッセージの送信に必要なものは以上です。That's all there is to sending device-to-cloud messages. 残りは、メッセージを受信する方法の説明のみです。The only thing left to cover is how to receive messages.

メッセージを受信するReceive messages

メッセージの受信は、 IoTHubClient ライブラリでメッセージが動作するしくみと同様です。Receiving a message works similarly to the way messages work in the IoTHubClient library. まず、メッセージのコールバック関数を登録します。First, you register a message callback function:

if (IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, 
  IoTHubMessage, myWeather) != IOTHUB_CLIENT_OK)
{
    printf("unable to IoTHubClient_SetMessageCallback\r\n");
}
else
{
...

そのうえで、メッセージを受信したときに呼び出されるコールバック関数を記述します。Then, you write the callback function that's invoked when a message is received:

static IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubMessage(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
    IOTHUBMESSAGE_DISPOSITION_RESULT result;
    const unsigned char* buffer;
    size_t size;
    if (IoTHubMessage_GetByteArray(message, &buffer, &size) != IOTHUB_MESSAGE_OK)
    {
        printf("unable to IoTHubMessage_GetByteArray\r\n");
        result = IOTHUBMESSAGE_ABANDONED;
    }
    else
    {
        /*buffer is not zero terminated*/
        char* temp = malloc(size + 1);
        if (temp == NULL)
        {
            printf("failed to malloc\r\n");
            result = IOTHUBMESSAGE_ABANDONED;
        }
        else
        {
            (void)memcpy(temp, buffer, size);
            temp[size] = '\0';
            EXECUTE_COMMAND_RESULT executeCommandResult = EXECUTE_COMMAND(userContextCallback, temp);
            result =
                (executeCommandResult == EXECUTE_COMMAND_ERROR) ? IOTHUBMESSAGE_ABANDONED :
                (executeCommandResult == EXECUTE_COMMAND_SUCCESS) ? IOTHUBMESSAGE_ACCEPTED :
                IOTHUBMESSAGE_REJECTED;
            free(temp);
        }
    }
    return result;
}

このコードは定型句であるため、すべてのソリューションで同じになります。This code is boilerplate -- it's the same for any solution. この関数は、メッセージを受信し、EXECUTE_COMMAND を呼び出して、適切な関数へのルーティングを処理します。This function receives the message and takes care of routing it to the appropriate function through the call to EXECUTE_COMMAND. この時点で呼び出す関数は、モデルのアクションの定義によって異なります。The function called at this point depends on the definition of the actions in your model.

モデルのアクションを定義するとき、対応するメッセージをデバイスが受信するときに呼び出される関数を実装する必要があります。When you define an action in your model, you're required to implement a function that's called when your device receives the corresponding message. たとえば、モデルで次のアクションが定義されているとします。For example, if your model defines this action:

WITH_ACTION(SetAirResistance, int, Position)

この場合、次のシグネチャを持つ関数を定義します。Define a function with this signature:

EXECUTE_COMMAND_RESULT SetAirResistance(ContosoAnemometer* device, int Position)
{
    (void)device;
    (void)printf("Setting Air Resistance Position to %d.\r\n", Position);
    return EXECUTE_COMMAND_SUCCESS;
}

関数の名前はモデル内のアクションの名前に一致し、関数のパラメーターはアクションに対して指定されたパラメーターに一致することに注意してください。Note how the name of the function matches the name of the action in the model and that the parameters of the function match the parameters specified for the action. 最初のパラメーターは常に必要であり、モデルのインスタンスへのポインターが含まれます。The first parameter is always required and contains a pointer to the instance of your model.

デバイスがこのシグネチャと一致するメッセージを受信すると、対応する関数が呼び出されます。When the device receives a message that matches this signature, the corresponding function is called. したがって、 IoTHubMessageの定型コードを含める必要があることを除けば、メッセージの受信は、モデルで定義されている各アクションに単純な関数を定義する処理のみで実行できます。Therefore, aside from having to include the boilerplate code from IoTHubMessage, receiving messages is just a matter of defining a simple function for each action defined in your model.

ライブラリの初期化を解除するUninitialize the library

データの送信とメッセージの受信が完了すると、次の方法で IoT ライブラリの初期化を解除することができます。When you're done sending data and receiving messages, you can uninitialize the IoT library:

...
        DESTROY_MODEL_INSTANCE(myWeather);
    }
    IoTHubClient_LL_Destroy(iotHubClientHandle);
}
serializer_deinit();

この 3 つの各関数は、前に説明した 3 つの初期化関数に対応しています。Each of these three functions aligns with the three initialization functions described previously. これらの API を呼び出すと、以前に割り当てたリソースが確実に解放されます。Calling these APIs ensures that you free previously allocated resources.

次の手順Next Steps

この記事では、C 用 Azure IoT device SDK のライブラリの使用方法の基本を説明しました。SDK の内容、そのアーキテクチャ、Windows サンプルの実行を開始する方法を理解するうえで十分な情報を提供しました。This article covered the basics of using the libraries in the Azure IoT device SDK for C. It provided you with enough information to understand what's included in the SDK, its architecture, and how to get started working with the Windows samples. 次の記事では、 IoTHubClient ライブラリに関する詳細を説明することで、引き続き SDK について記述します。The next article continues the description of the SDK by explaining more about the IoTHubClient library.

IoT Hub 用の開発の詳細については、「Azure IoT SDK」を参照してください。To learn more about developing for IoT Hub, see the Azure IoT SDKs.

IoT Hub の機能を詳しく調べるには、次のリンクを使用してください。To further explore the capabilities of IoT Hub, see: