Azure IoT Device SDK voor C

De Apparaat-SDK van Azure IoT is een set bibliotheken die is ontworpen om het proces van het verzenden van berichten naar en het ontvangen van berichten van de Azure IoT Hub service te vereenvoudigen. Er zijn verschillende variaties van de SDK, die elk zijn gericht op een specifiek platform, maar in dit artikel wordt de Azure IoT Device SDK voor C beschreven.

Notitie

De Embedded C SDK is een alternatief voor beperkte apparaten die ondersteuning biedt voor de BYON-benadering (Bring Your Own Network). IoT-ontwikkelaars hebben de vrijheid om de MQTT-client, TLS en socket van hun keuze te gebruiken om een apparaatoplossing te maken. Meer informatie over de Embedded C SDK.

Notitie

Sommige van de functies die in dit artikel worden genoemd, zoals cloud-naar-apparaat-berichten, apparaatdubbels en apparaatbeheer, zijn alleen beschikbaar in de standaardlaag van IoT Hub. Raadpleeg How to choose the right IoT Hub tier (De juiste IoT Hub-prijscategorie kiezen) voor meer informatie over de Basic- en Standard-prijscategorieën van IoT Hub.

De Azure IoT Device SDK voor C is geschreven in ANSI C (C99) om de draagbaarheid te maximaliseren. Deze functie maakt de bibliotheken geschikt voor gebruik op meerdere platforms en apparaten, met name wanneer het minimaliseren van de schijf- en geheugenvoetafdruk een prioriteit is.

Er zijn een breed scala aan platformen waarop de SDK is getest (zie de apparaatcatalogus Azure Certified for IoT voor meer informatie). Hoewel dit artikel walkthroughs bevat voor voorbeeldcode die wordt uitgevoerd op het Windows-platform, is de code die in dit artikel wordt beschreven identiek voor alle ondersteunde platforms.

In de volgende video wordt een overzicht gegeven van de Azure IoT SDK voor C:

In dit artikel maakt u kennis met de architectuur van de Azure IoT Device SDK voor C. Het laat zien hoe u de apparaatbibliotheek initialiseert, gegevens naar IoT Hub verzendt en er berichten van ontvangt. De informatie in dit artikel moet voldoende zijn om aan de slag te gaan met de SDK, maar bevat ook aanwijzers naar aanvullende informatie over de bibliotheken.

SDK-architectuur

U vindt de Azure IoT Device SDK voor C GitHub opslagplaats en bekijk details van de API in de C API-verwijzing.

De nieuwste versie van de bibliotheken vindt u in de hoofdvertakking van de opslagplaats:

Schermopname van de main branch van de opslagplaats

  • De belangrijkste implementatie van de SDK staat in de iothub-clientmap _ die de implementatie bevat van de laagste API-laag in de SDK: de IoTHubClient-bibliotheek. De IoTHubClient-bibliotheek bevat API's die onbewerkte berichten implementeren voor het verzenden van berichten IoT Hub ontvangen van IoT Hub. Wanneer u deze bibliotheek gebruikt, bent u verantwoordelijk voor het implementeren van berichtenser serialisatie, maar andere details van de communicatie met IoT Hub worden voor u afgehandeld.

  • De serialisatiemap bevat helperfuncties en voorbeelden die laten zien hoe u gegevens serialiseert voordat u ze naar Azure IoT Hub met behulp van de clientbibliotheek. Het gebruik van de serializer is niet verplicht en wordt als een gemak aangeboden. Als u de serialisatiebibliotheek wilt gebruiken, definieert u een model dat de gegevens specificeert die naar de IoT Hub en de berichten die u ervan verwacht te ontvangen. Zodra het model is gedefinieerd, biedt de SDK u een API-gebied waarmee u eenvoudig apparaat-naar-cloud- en cloud-naar-apparaat-berichten kunt gebruiken zonder dat u zich zorgen hoeft te maken over de serialisatiedetails. De bibliotheek is afhankelijk van andere opensource-bibliotheken die transport implementeren met behulp van protocollen zoals MQTT en AMQP.

  • De IoTHubClient-bibliotheek is afhankelijk van andere opensource-bibliotheken:

    • De bibliotheek met gedeelde Hulpprogramma's van Azure C, die algemene functionaliteit biedt voor basistaken (zoals tekenreeksen, list manipulation en IO) die nodig zijn voor verschillende Azure-gerelateerde C SDK's.

    • De Azure uAMQP-bibliotheek, een implementatie aan de clientzijde van AMQP die is geoptimaliseerd voor apparaten met beperkte resources.

    • De Azure uMQTT-bibliotheek, een bibliotheek voor algemeen gebruik waarmee het MQTT-protocol wordt geïmplementeerd en geoptimaliseerd voor apparaten met beperkte resources.

Het gebruik van deze bibliotheken is gemakkelijker te begrijpen door naar voorbeeldcode te kijken. In de volgende secties vindt u een aantal voorbeeldtoepassingen die zijn opgenomen in de SDK. Deze walkthrough geeft u een goed idee van de verschillende mogelijkheden van de architectuurlagen van de SDK en een inleiding tot de manier waarop de API's werken.

Voordat u de voorbeelden gaat uitvoeren

Voordat u de voorbeelden in de Azure IoT Device SDK voor C kunt uitvoeren, moet u een exemplaar van de IoT Hub-service maken in uw Azure-abonnement. Voltooi vervolgens de volgende taken:

  • Uw ontwikkelomgeving voorbereiden
  • Apparaatreferenties verkrijgen.

Uw ontwikkelomgeving voorbereiden

Pakketten worden geleverd voor algemene platforms (zoals NuGet voor Windows of apt_get voor Debian en Ubuntu) en de voorbeelden gebruiken deze pakketten indien beschikbaar. In sommige gevallen moet u de SDK compileren voor of op uw apparaat. Als u de SDK moet compileren, zie Uw ontwikkelomgeving voorbereiden in de GitHub opslagplaats.

Als u de voorbeeldtoepassingscode wilt verkrijgen, downloadt u een kopie van de SDK van GitHub. Haal uw kopie van de bron op uit de hoofdvertakking van GitHub opslagplaats.

De apparaatreferenties verkrijgen

Nu u de voorbeeldbroncode hebt, is het volgende dat u moet doen om een set apparaatreferenties op te halen. Als u wilt dat een apparaat toegang heeft tot een IoT-hub, moet u het apparaat eerst toevoegen aan IoT Hub identiteitsregister. Wanneer u uw apparaat toevoegt, krijgt u een set apparaatreferenties die u nodig hebt om het apparaat verbinding te laten maken met de IoT-hub. In de voorbeeldtoepassingen die in de volgende sectie worden besproken, worden deze referenties verwacht in de vorm van een connection string.

Er zijn verschillende opensource-hulpprogramma's waarmee u uw IoT-hub kunt beheren.

In deze zelfstudie wordt gebruikgemaakt van het grafische hulpprogramma Device Explorer. U kunt de Azure IoT Tools voor VS Code gebruiken als u in VS Code ontwikkelt. U kunt ook de IoT-extensie voor het Hulpprogramma Azure CLI 2.0 gebruiken als u liever een CLI-hulpprogramma gebruikt.

Het hulpprogramma Device Explorer maakt gebruik van de Azure IoT-servicebibliotheken om verschillende functies uit te voeren op IoT Hub, waaronder het toevoegen van apparaten. Als u het hulpprogramma Device Explorer gebruikt om een apparaat toe te voegen, krijgt u een connection string voor uw apparaat. U hebt deze connection string nodig om de voorbeeldtoepassingen uit te voeren.

Als u niet bekend bent met het hulpprogramma Device Explorer, wordt in de volgende procedure beschreven hoe u het kunt gebruiken om een apparaat toe te voegen en een apparaat te verkrijgen connection string.

  1. Zie How to use the Device Explorer for IoT Hub devices (De Device Explorer gebruiken voor het IoT Hub apparaten) om het hulpprogramma Device Explorer te installeren.

  2. Wanneer u het programma uitvoeren, ziet u deze interface:

    Device Explorer Twin-schermopname

  3. Voer uw IoT Hub in het eerste veld in en klik op Bijwerken. Met deze stap configureert u het hulpprogramma zodat het kan communiceren met IoT Hub.

De verbindingsreeks vindt u onder IoT Hub Service > Instellingen Shared Access > Policy > iothubowner.

  1. Wanneer de IoT Hub connection string is geconfigureerd, klikt u op het tabblad Beheer:

    Device Explorer twin/beheer schermafbeelding

Op dit tabblad beheert u de apparaten die zijn geregistreerd in uw IoT-hub.

  1. U maakt een apparaat door op de knop Maken te klikken. Er wordt een dialoogvenster weergegeven met een set vooraf ingevulde sleutels (primaire en secundaire). Voer een apparaat-id in en klik vervolgens op Maken.

    Schermopname van Apparaat maken

  2. Wanneer het apparaat is gemaakt, wordt de lijst Apparaten bijgewerkt met alle geregistreerde apparaten, met inbegrip van het apparaat dat u zojuist hebt gemaakt. Als u met de rechtermuisknop op het nieuwe apparaat klikt, ziet u dit menu:

    Device Explorer dubbel met de rechtermuisknop op resultaat

  3. Als u Connection string voor het geselecteerde apparaat kiest, wordt connection string apparaat gekopieerd naar het klembord. Bewaar een kopie van het apparaat connection string. U hebt deze nodig bij het uitvoeren van de voorbeeldtoepassingen die in de volgende secties worden beschreven.

Wanneer u de bovenstaande stappen hebt voltooid, bent u klaar om code uit te voeren. De meeste voorbeelden hebben een constante bovenaan het hoofdbronbestand waarmee u een connection string. De bijbehorende regel uit de iothub_client _ voorbeelden _ iothub_convenience_sample toepassing wordt bijvoorbeeld als volgt weergegeven.

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

De IoTHubClient-bibliotheek gebruiken

In de map iothub-client _ in de opslagplaats azure-iot-sdk-c staat een map met voorbeelden met een toepassing met de naam iothub client _ sample _ _ mqtt.

De Windows-versie van de iothub_client _ voorbeelden _ iothub_convenience_sample toepassing bevat de volgende Visual Studio oplossing:

Visual Studio Solution Explorer

Notitie

Als Visual Studio vraagt om het project opnieuw in te stellen op de nieuwste versie, accepteert u de prompt.

Deze oplossing bevat één project. Er zijn vier NuGet-pakketten geïnstalleerd in deze oplossing:

  • Microsoft.Azure.C.SharedUtility
  • Microsoft.Azure.IoTHub.MqttTransport
  • Microsoft.Azure.IoTHub.IoTHubClient
  • Microsoft.Azure.umqtt

U hebt het pakket Microsoft.Azure.C.SharedUtility altijd nodig wanneer u met de SDK werkt. In dit voorbeeld wordt het MQTT-protocol gebruikt. Daarom moet u de pakketten Microsoft.Azure.umqtt en Microsoft.Azure.IoTHub.MqttTransport opnemen (er zijn gelijkwaardige pakketten voor AMQP en HTTPS). Omdat het voorbeeld gebruikmaakt van de IoTHubClient-bibliotheek, moet u ook het pakket Microsoft.Azure.IoTHub.IoTHubClient in uw oplossing opnemen.

U vindt de implementatie voor de voorbeeldtoepassing in de iothub_client _ voorbeelden _ iothub_convenience_sample bronbestand.

In de volgende stappen wordt deze voorbeeldtoepassing gebruikt om u te helpen bij wat er nodig is om de IoTHubClient-bibliotheek te gebruiken.

De bibliotheek initialiseren

Notitie

Voordat u met de bibliotheken gaat werken, moet u mogelijk een platformspecifieke initialisatie uitvoeren. Als u bijvoorbeeld van plan bent OM AMQP in Linux te gebruiken, moet u de OpenSSL-bibliotheek initialiseren. Met de voorbeelden in GitHub opslagplaats wordt het functieplatform van het hulpprogramma _ aanroepen wanneer de client wordt gestart en wordt de functie _ platformdeinit aanroepen voordat deze wordt afgesloten. Deze functies worden gedeclareerd in het headerbestand platform.h. Bekijk de definities van deze functies voor uw doelplatform in de opslagplaats om te bepalen of u platformspecifieke initialisatiecode in uw client moet opnemen.

Als u met de bibliotheken wilt gaan werken, moet u eerst een IoT Hub-clienting handle:

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

U kunt een kopie van de apparaat-connection string die u hebt verkregen van het hulpprogramma Device Explorer doorgeven aan deze functie. U wijst ook het communicatieprotocol aan dat moet worden gebruikt. In dit voorbeeld wordt MQTT gebruikt, maar AMQP en HTTPS zijn ook opties.

Wanneer u een geldige IOTHUB _ CLIENT _ HANDLE hebt, kunt u beginnen met het aanroepen van de API's voor het verzenden en ontvangen van berichten van en naar IoT Hub.

Berichten verzenden

De voorbeeldtoepassing stelt een lus in voor het verzenden van berichten naar uw IoT-hub. Het volgende codefragment:

  • Hiermee maakt u een bericht.
  • Voegt een eigenschap toe aan het bericht.
  • Verzendt een bericht.

Maak eerst een bericht:

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);

Telkens wanneer u een bericht verzendt, geeft u een verwijzing op naar een callback-functie die wordt aangeroepen wanneer de gegevens worden verzonden. In dit voorbeeld heet de callback-functie SendConfirmationCallback. In het volgende codefragment ziet u deze callback-functie:

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);
}

Noteer de aanroep van de functie IoTHubMessage _ Destroy wanneer u klaar bent met het bericht. Met deze functie worden de resources vrijgemaakt die zijn toegewezen bij het maken van het bericht.

Berichten ontvangen

Het ontvangen van een bericht is een asynchrone bewerking. Eerst registreert u de callback die moet worden aanroepen wanneer het apparaat een bericht ontvangt:

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");
    ...

De laatste parameter is een void-aanwijzer naar wat u wilt. In het voorbeeld is het een aanwijzer naar een geheel getal, maar het kan een aanwijzer zijn naar een complexere gegevensstructuur. Met deze parameter kan de callback-functie worden gebruikt voor de gedeelde status met de aanroeper van deze functie.

Wanneer het apparaat een bericht ontvangt, wordt de geregistreerde callback-functie aangeroepen. Deze callback-functie haalt het volgende op:

  • De bericht-id en correlatie-id van het bericht.
  • De inhoud van het bericht.
  • Aangepaste eigenschappen van het bericht.
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;
}

Gebruik de functie IoTHubMessage _ GetByteArray om het bericht op te halen, wat in dit voorbeeld een tekenreeks is.

De bibliotheek uninitialiseren

Wanneer u klaar bent met het verzenden van gebeurtenissen en het ontvangen van berichten, kunt u de IoT-bibliotheek uninitialiseren. Als u dit wilt doen, roept u de volgende functie aan:

IoTHubClient_LL_Destroy(iotHubClientHandle);

Met deze aanroep worden de resources vrij die eerder zijn toegewezen door de functie IoTHubClient _ CreateFromConnectionString.

Zoals u ziet, is het eenvoudig om berichten te verzenden en te ontvangen met de IoTHubClient-bibliotheek. De bibliotheek verwerkt de details van de communicatie met IoT Hub, waaronder welk protocol moet worden gebruikt (vanuit het perspectief van de ontwikkelaar is dit een eenvoudige configuratieoptie).

De IoTHubClient-bibliotheek biedt ook nauwkeurige controle over het serialiseren van de gegevens die uw apparaat naar uw IoT Hub. In sommige gevallen is dit beheerniveau een voordeel, maar in andere gevallen is het een implementatiedetail waar u zich niet mee bezig wilt houden. Als dat het geval is, kunt u overwegen de serializer-bibliotheek te gebruiken, die in de volgende sectie wordt beschreven.

De serialisatiebibliotheek gebruiken

Conceptueel gezien bevindt de serialisatiebibliotheek zich boven op de IoTHubClient-bibliotheek in de SDK. Het maakt gebruik van de IoTHubClient-bibliotheek voor de onderliggende communicatie met IoT Hub, maar voegt modelleringsmogelijkheden toe die de last van het omgaan met berichtseralisatie van de ontwikkelaar wegnemen. Hoe deze bibliotheek werkt, wordt het beste gedemonstreerd in een voorbeeld.

In de serialisatiemap in de opslagplaats azure-iot-sdk-cstaat een map met voorbeelden met een toepassing met de naam simplesample _ mqtt. De Windows versie van dit voorbeeld bevat de volgende Visual Studio oplossing:

Visual Studio Oplossing voor mqtt-voorbeeld

Notitie

Als Visual Studio vraagt om het project opnieuw in te stellen op de nieuwste versie, accepteert u de prompt.

Net als bij het vorige voorbeeld bevat dit voorbeeld verschillende NuGet-pakketten:

  • Microsoft.Azure.C.SharedUtility
  • Microsoft.Azure.IoTHub.MqttTransport
  • Microsoft.Azure.IoTHub.IoTHubClient
  • Microsoft.Azure.IoTHub.Serializer
  • Microsoft.Azure.umqtt

U hebt de meeste van deze pakketten in het vorige voorbeeld gezien, maar Microsoft.Azure.IoTHub.Serializer is nieuw. Dit pakket is vereist wanneer u de serializer-bibliotheek gebruikt.

U vindt de implementatie van de voorbeeldtoepassing in de iothub_client _ voorbeelden _ iothub_convenience_sample bestand.

De volgende secties helpen u bij de belangrijkste onderdelen van dit voorbeeld.

De bibliotheek initialiseren

Als u wilt gaan werken met de serialisatiebibliotheek, roept u de initialisatie-API's aan:

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
        {
...

De aanroep van de _ serializer-init-functie is een een-time-aanroep en initialiseert de onderliggende bibliotheek. Vervolgens roept u de functie IoTHubClient _ LL _ CreateFromConnectionString aan. Dit is dezelfde API als in het IoTHubClient-voorbeeld. Met deze aanroep wordt uw connection string (deze aanroep is ook de plek waar u het protocol kiest dat u wilt gebruiken). In dit voorbeeld wordt MQTT als transport gebruikt, maar kan AMQP of HTTPS worden gebruikt.

Roep ten slotte de functie CREATE _ MODEL _ INSTANCE aan. WeatherStation is de naamruimte van het model en ContosoAnemometer is de naam van het model. Zodra het model-exemplaar is gemaakt, kunt u deze gebruiken om berichten te verzenden en te ontvangen. Het is echter belangrijk om te begrijpen wat een model is.

Het model definiëren

Een model in de serialisatiebibliotheek definieert de berichten die uw apparaat naar IoT Hub kan verzenden, en de berichten, acties genoemd in de modelleringstaal, die het kan ontvangen. U definieert een model met behulp van een set C-macro's zoals in de iothub_client _ voorbeelden _ iothub_convenience_sample voorbeeldtoepassing:

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);

De macro's BEGIN _ NAMESPACE en END _ NAMESPACE nemen beide de naamruimte van het model als argument. Er wordt verwacht dat alles tussen deze macro's de definitie van uw model of modellen is, en de gegevensstructuren die door de modellen worden gebruikt.

In dit voorbeeld is er één model met de naam ContosoAnemometer. Dit model definieert twee soorten gegevens die uw apparaat naar de IoT Hub: DeviceId en WindSpeed. Het definieert ook drie acties (berichten) die uw apparaat kan ontvangen: TurnFanOn, TurnFanOff en SetAirResistance. Elk gegevenselement heeft een type en elke actie heeft een naam (en optioneel een set parameters).

De gegevens en acties die in het model zijn gedefinieerd, definiëren een API-gebied dat u kunt gebruiken om berichten te verzenden naar IoT Hub en te reageren op berichten die naar het apparaat worden verzonden. Het gebruik van dit model is het best te begrijpen in een voorbeeld.

Berichten verzenden

Het model definieert de gegevens die u naar uw IoT Hub. In dit voorbeeld betekent dit dat een van de twee gegevensitems die zijn gedefinieerd met behulp van de WITH_DATA macro. Er zijn verschillende stappen vereist om de waarden DeviceId en WindSpeed te verzenden naar een IoT-hub. De eerste is het instellen van de gegevens die u wilt verzenden:

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

Met het model dat u eerder hebt gedefinieerd, kunt u de waarden instellen door leden van een struct in te stellen. Serialiseer vervolgens het bericht dat u wilt verzenden:

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);
}

Met deze code wordt het apparaat naar de cloud geser serialiseert naar een buffer (waarnaar wordt verwezen door de bestemming). De code roept vervolgens de functie sendMessage aan om het bericht naar de 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++;
}

De op een na laatste parameter van IoTHubClient _ LL _ SendEventAsync is een verwijzing naar een callback-functie die wordt aangeroepen wanneer de gegevens zijn verzonden. Dit is de callback-functie in het voorbeeld:

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));
}

De tweede parameter is een aanwijzer naar de gebruikerscontext; dezelfde aanwijzer doorgegeven aan IoTHubClient _ LL _ SendEventAsync. In dit geval is de context een eenvoudig teller, maar het kan alles zijn wat u wilt.

Meer is er niet nodig om apparaat-naar-cloud-berichten te verzenden. Het enige dat u nog moet behandelen, is het ontvangen van berichten.

Berichten ontvangen

Het ontvangen van een bericht werkt op dezelfde manier als berichten in de IoTHubClient-bibliotheek. Eerst registreert u een functie voor het terugroepen van berichten:

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

Vervolgens schrijft u de callback-functie die wordt aangeroepen wanneer een bericht wordt ontvangen:

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;
}

Deze code is standaard. Deze is hetzelfde voor elke oplossing. Deze functie ontvangt het bericht en zorgt voor routering naar de juiste functie via de aanroep van EXECUTE _ COMMAND. De functie die op dit moment wordt aangeroepen, is afhankelijk van de definitie van de acties in uw model.

Wanneer u een actie in uw model definieert, moet u een functie implementeren die wordt aangeroepen wanneer uw apparaat het bijbehorende bericht ontvangt. Als uw model bijvoorbeeld deze actie definieert:

WITH_ACTION(SetAirResistance, int, Position)

Definieer een functie met deze handtekening:

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;
}

U kunt zien dat de naam van de functie overeenkomt met de naam van de actie in het model en dat de parameters van de functie overeenkomen met de parameters die zijn opgegeven voor de actie. De eerste parameter is altijd vereist en bevat een aanwijzer naar het exemplaar van uw model.

Wanneer het apparaat een bericht ontvangt dat overeenkomt met deze handtekening, wordt de bijbehorende functie aangeroepen. Daarom is het niet nodig om de standaardcode van IoTHubMessage op te nemen, maar is het ontvangen van berichten slechts een kwestie van het definiëren van een eenvoudige functie voor elke actie die in uw model is gedefinieerd.

De bibliotheek uninitialiseren

Wanneer u klaar bent met het verzenden van gegevens en het ontvangen van berichten, kunt u de IoT-bibliotheek uninitialiseren:

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

Elk van deze drie functies komt overeen met de drie initialisatiefuncties die eerder zijn beschreven. Als u deze API's aanroept, zorgt u ervoor dat u eerder toegewezen resources vrij hebt.

Volgende stappen

In dit artikel zijn de basisbeginselen van het gebruik van de bibliotheken in de Azure IoT Device SDK voor C behandeld. Het bood u voldoende informatie om te begrijpen wat er in de SDK is opgenomen, de architectuur en hoe u aan de slag kunt gaan met de Windows voorbeelden. Het volgende artikel gaat verder met de beschrijving van de SDK door meer informatie te geven over de IoTHubClient-bibliotheek.

Zie de Azure IoT SDK'IoT Hubmeer informatie over het ontwikkelen voor IoT Hub.

Zie voor meer informatie over de mogelijkheden van IoT Hub: