Samouczek — tworzenie klienta urządzenia IoT przy użyciu protokołu MQTT bez korzystania z zestawu SDK urządzenia

W celu skompilowania klientów urządzeń IoT w ogóle należy użyć jednego z zestawów SDK urządzeń usługi Azure IoT. Jednak w scenariuszach, takich jak używanie urządzenia ograniczonego pamięci, może być konieczne użycie biblioteki MQTT do komunikowania się z centrum IoT.

Przykłady w tym samouczku korzystają z biblioteki Eclipse Mosquitto MQTT.

Z tego samouczka dowiesz się, jak wykonywać następujące czynności:

  • Skompiluj przykładowe aplikacje klienckie urządzenia języka C.
  • Uruchom przykład, który używa biblioteki MQTT do wysyłania danych telemetrycznych.
  • Uruchom przykład, który używa biblioteki MQTT do przetwarzania komunikatu z chmury do urządzenia wysyłanego z centrum IoT.
  • Uruchom przykład, który używa biblioteki MQTT do zarządzania bliźniaczą reprezentacją urządzenia na urządzeniu.

Aby wykonać kroki opisane w tym samouczku, możesz użyć maszyny deweloperów z systemem Windows lub Linux.

Jeśli nie masz subskrypcji platformy Azure, przed rozpoczęciem utwórz bezpłatne konto.

Wymagania wstępne

Przygotowywanie środowiska dla interfejsu wiersza polecenia platformy Azure

Wymagania wstępne dotyczące maszyn deweloperskich

Jeśli używasz systemu Windows:

  1. Zainstaluj program Visual Studio (Community, Professional lub Enterprise). Pamiętaj, aby włączyć programowanie aplikacji klasycznych z obciążeniem języka C++ .

  2. Zainstaluj narzędzie CMake. Włącz opcję Dodaj narzędzie CMake do ścieżki systemowej dla wszystkich użytkowników.

  3. Zainstaluj wersjęx64 mosquitto.

Jeśli używasz systemu Linux:

  1. Uruchom następujące polecenie, aby zainstalować narzędzia kompilacji:

    sudo apt install cmake g++
    
  2. Uruchom następujące polecenie, aby zainstalować bibliotekę klienta Mosquitto:

    sudo apt install libmosquitto-dev
    

Konfigurowanie środowiska

Jeśli nie masz jeszcze centrum IoT Hub, uruchom następujące polecenia, aby utworzyć centrum IoT w warstwie Bezpłatna w grupie zasobów o nazwie mqtt-sample-rg. Polecenie używa nazwy my-hub jako przykładu nazwy centrum IoT Do utworzenia. Wybierz unikatową nazwę centrum IoT, która ma być używana zamiast my-hub:

az group create --name mqtt-sample-rg --location eastus
az iot hub create --name my-hub --resource-group mqtt-sample-rg --sku F1 

Zanotuj nazwę centrum IoT Hub. Będzie ona potrzebna później.

Rejestrowanie urządzenia w centrum IoT Hub. Następujące polecenie rejestruje urządzenie o nazwie mqtt-dev-01 w centrum IoT o nazwie my-hub. Pamiętaj, aby użyć nazwy centrum IoT:

az iot hub device-identity create --hub-name my-hub --device-id mqtt-dev-01

Użyj następującego polecenia, aby utworzyć token SAS, który przyznaje urządzeniu dostęp do centrum IoT. Pamiętaj, aby użyć nazwy centrum IoT:

az iot hub generate-sas-token --device-id mqtt-dev-01 --hub-name my-hub --du 7200

Zanotuj token SAS, który zwraca dane wyjściowe polecenia, ponieważ będzie on potrzebny później. Token SAS wygląda następująco: SharedAccessSignature sr=my-hub.azure-devices.net%2Fdevices%2Fmqtt-dev-01&sig=%2FnM...sNwtnnY%3D&se=1677855761

Napiwek

Domyślnie token SAS jest ważny przez 60 minut. Opcja --du 7200 w poprzednim poleceniu wydłuża czas trwania tokenu do dwóch godzin. Jeśli wygaśnie, zanim wszystko będzie gotowe do użycia, wygeneruj nowy. Możesz również utworzyć token z dłuższym czasem trwania. Aby dowiedzieć się więcej, zobacz az iot hub generate-sas-token.

Klonowanie przykładowego repozytorium

Użyj następującego polecenia, aby sklonować przykładowe repozytorium do odpowiedniej lokalizacji na komputerze lokalnym:

git clone https://github.com/Azure-Samples/IoTMQTTSample.git

Repozytorium obejmuje również:

  • Przykład języka Python korzystający z biblioteki paho-mqtt .
  • Instrukcje dotyczące korzystania z interfejsu mosquitto_pub wiersza polecenia do interakcji z centrum IoT Hub.

Tworzenie przykładów języka C

Przed utworzeniem przykładu należy dodać szczegóły centrum IoT i urządzenia. W sklonowanym repozytorium IoTMQTTSample otwórz plik mosquitto/src/config.h . Dodaj nazwę centrum IoT Hub, identyfikator urządzenia i token SAS w następujący sposób. Pamiętaj, aby użyć nazwy centrum IoT:

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

#define IOTHUBNAME "my-hub"
#define DEVICEID   "mqtt-dev-01"
#define SAS_TOKEN  "SharedAccessSignature sr=my-hub.azure-devices.net%2Fdevices%2Fmqtt-dev-01&sig=%2FnM...sNwtnnY%3D&se=1677855761"

#define CERTIFICATEFILE CERT_PATH "IoTHubRootCA.crt.pem"

Uwaga

Plik IoTHubRootCA.crt.pem zawiera certyfikaty główne urzędu certyfikacji dla połączenia TLS.

Zapisz zmiany w pliku mosquitto/src/config.h .

Aby skompilować przykłady, uruchom następujące polecenia w powłoce:

cd mosquitto
cmake -Bbuild
cmake --build build

W systemie Linux pliki binarne znajdują się w folderze ./build pod folderem mosquitto .

W systemie Windows pliki binarne znajdują się w folderze .\build\Debug poniżej folderu mosquitto .

Wysyłanie danych telemetrycznych

W przykładzie mosquitto_telemetry pokazano, jak wysłać komunikat telemetrii z urządzenia do chmury do centrum IoT przy użyciu biblioteki MQTT.

Przed uruchomieniem przykładowej aplikacji uruchom następujące polecenie, aby uruchomić monitor zdarzeń centrum IoT. Pamiętaj, aby użyć nazwy centrum IoT:

az iot hub monitor-events --hub-name my-hub

Uruchom przykład mosquitto_telemetry. Na przykład w systemie Linux:

./build/mosquitto_telemetry

Polecenie az iot hub monitor-events generuje następujące dane wyjściowe, które pokazują ładunek wysyłany przez urządzenie:

Starting event monitor, use ctrl-c to stop...
{
    "event": {
        "origin": "mqtt-dev-01",
        "module": "",
        "interface": "",
        "component": "",
        "payload": "Bonjour MQTT from Mosquitto"
    }
}

Teraz możesz zatrzymać monitor zdarzeń.

Przeglądanie kodu

Następujące fragmenty kodu pochodzą z pliku mosquitto/src/mosquitto_telemetry.cpp .

Następujące instrukcje definiują informacje o połączeniu i nazwę tematu MQTT używanego do wysyłania komunikatu telemetrii:

#define HOST IOTHUBNAME ".azure-devices.net"
#define PORT 8883
#define USERNAME HOST "/" DEVICEID "/?api-version=2020-09-30"

#define TOPIC "devices/" DEVICEID "/messages/events/"

Funkcja main ustawia nazwę użytkownika i hasło do uwierzytelniania w centrum IoT. Hasło to token SAS utworzony dla urządzenia:

mosquitto_username_pw_set(mosq, USERNAME, SAS_TOKEN);

W przykładzie użyto tematu MQTT do wysyłania komunikatu telemetrii do centrum IoT:

int msgId  = 42;
char msg[] = "Bonjour MQTT from Mosquitto";

// once connected, we can publish a Telemetry message
printf("Publishing....\r\n");
rc = mosquitto_publish(mosq, &msgId, TOPIC, sizeof(msg) - 1, msg, 1, true);
if (rc != MOSQ_ERR_SUCCESS)
{
    return mosquitto_error(rc);
}
printf("Publish returned OK\r\n");

Aby dowiedzieć się więcej, zobacz Wysyłanie komunikatów z urządzenia do chmury.

Odbieranie komunikatu z chmury do urządzenia

W przykładzie mosquitto_subscribe przedstawiono sposób subskrybowania tematów MQTT i odbierania komunikatu z chmury do urządzenia z centrum IoT przy użyciu biblioteki MQTT.

Uruchom przykład mosquitto_subscribe. Na przykład w systemie Linux:

./build/mosquitto_subscribe

Uruchom następujące polecenie, aby wysłać komunikat z chmury do urządzenia z centrum IoT Hub. Pamiętaj, aby użyć nazwy centrum IoT:

az iot device c2d-message send --hub-name my-hub --device-id mqtt-dev-01 --data "hello world"

Dane wyjściowe z mosquitto_subscribe wyglądają następująco:

Waiting for C2D messages...
C2D message 'hello world' for topic 'devices/mqtt-dev-01/messages/devicebound/%24.mid=d411e727-...f98f&%24.to=%2Fdevices%2Fmqtt-dev-01%2Fmessages%2Fdevicebound&%24.ce=utf-8&iothub-ack=none'
Got message for devices/mqtt-dev-01/messages/# topic

Przeglądanie kodu

Następujące fragmenty kodu pochodzą z pliku mosquitto/src/mosquitto_subscribe.cpp .

Poniższa instrukcja definiuje temat filtru używanego przez urządzenie do odbierania komunikatów w chmurze do urządzeń. Jest # wieloznacznymi symbolami wieloznacznymi:

#define DEVICEMESSAGE "devices/" DEVICEID "/messages/#"

Funkcja main używa mosquitto_message_callback_set funkcji do ustawiania wywołania zwrotnego w celu obsługi komunikatów wysyłanych z centrum IoT i używa mosquitto_subscribe funkcji do subskrybowania wszystkich komunikatów. Poniższy fragment kodu przedstawia funkcję wywołania zwrotnego:

void message_callback(struct mosquitto* mosq, void* obj, const struct mosquitto_message* message)
{
    printf("C2D message '%.*s' for topic '%s'\r\n", message->payloadlen, (char*)message->payload, message->topic);

    bool match = 0;
    mosquitto_topic_matches_sub(DEVICEMESSAGE, message->topic, &match);

    if (match)
    {
        printf("Got message for " DEVICEMESSAGE " topic\r\n");
    }
}

Aby dowiedzieć się więcej, zobacz Odbieranie komunikatów z chmury do urządzenia przy użyciu protokołu MQTT.

Aktualizowanie bliźniaczej reprezentacji urządzenia

W przykładzie mosquitto_device_twin pokazano , jak ustawić zgłoszoną właściwość w bliźniaczej reprezentacji urządzenia, a następnie odczytać właściwość z powrotem.

Uruchom przykład mosquitto_device_twin. Na przykład w systemie Linux:

./build/mosquitto_device_twin

Dane wyjściowe z mosquitto_device_twin wyglądają jak w poniższym przykładzie:

Setting device twin reported properties....
Device twin message '' for topic '$iothub/twin/res/204/?$rid=0&$version=2'
Setting device twin properties SUCCEEDED.

Getting device twin properties....
Device twin message '{"desired":{"$version":1},"reported":{"temperature":32,"$version":2}}' for topic '$iothub/twin/res/200/?$rid=1'
Getting device twin properties SUCCEEDED.

Przeglądanie kodu

Następujące fragmenty kodu pochodzą z pliku mosquitto/src/mosquitto_device_twin.cpp .

Poniższe instrukcje definiują tematy używane przez urządzenie do subskrybowania aktualizacji bliźniaczej reprezentacji urządzenia, odczytywania bliźniaczej reprezentacji urządzenia i aktualizowania bliźniaczej reprezentacji urządzenia:

#define DEVICETWIN_SUBSCRIPTION  "$iothub/twin/res/#"
#define DEVICETWIN_MESSAGE_GET   "$iothub/twin/GET/?$rid=%d"
#define DEVICETWIN_MESSAGE_PATCH "$iothub/twin/PATCH/properties/reported/?$rid=%d"

Funkcja main używa mosquitto_connect_callback_set funkcji do ustawiania wywołania zwrotnego w celu obsługi komunikatów wysyłanych z centrum IoT i używa mosquitto_subscribe funkcji do subskrybowania tematu $iothub/twin/res/# .

Poniższy fragment kodu przedstawia connect_callback funkcję używaną mosquitto_publish do ustawiania zgłaszanej właściwości w bliźniaczej reprezentacji urządzenia. Urządzenie publikuje komunikat w temacie $iothub/twin/PATCH/properties/reported/?$rid=%d . Wartość %d jest zwiększana za każdym razem, gdy urządzenie publikuje komunikat w temacie:

void connect_callback(struct mosquitto* mosq, void* obj, int result)
{
    // ... other code ...  

    printf("\r\nSetting device twin reported properties....\r\n");

    char msg[] = "{\"temperature\": 32}";
    char mqtt_publish_topic[64];
    snprintf(mqtt_publish_topic, sizeof(mqtt_publish_topic), DEVICETWIN_MESSAGE_PATCH, device_twin_request_id++);

    int rc = mosquitto_publish(mosq, NULL, mqtt_publish_topic, sizeof(msg) - 1, msg, 1, true);
    if (rc != MOSQ_ERR_SUCCESS)

    // ... other code ...  
}

Urządzenie subskrybuje $iothub/twin/res/# temat i gdy odbiera komunikat z centrum IoT Hub, message_callback funkcja go obsługuje. Po uruchomieniu przykładu message_callback funkcja zostanie wywołana dwukrotnie. Po raz pierwszy urządzenie odbiera odpowiedź z centrum IoT do zgłoszonej aktualizacji właściwości. Następnie urządzenie żąda bliźniaczej reprezentacji urządzenia. Po raz drugi urządzenie odbiera żądaną reprezentację urządzenia. Poniższy fragment kodu przedstawia message_callback funkcję:

void message_callback(struct mosquitto* mosq, void* obj, const struct mosquitto_message* message)
{
    printf("Device twin message '%.*s' for topic '%s'\r\n", message->payloadlen, (char*)message->payload, message->topic);

    const char patchTwinTopic[] = "$iothub/twin/res/204/?$rid=0";
    const char getTwinTopic[]   = "$iothub/twin/res/200/?$rid=1";

    if (strncmp(message->topic, patchTwinTopic, sizeof(patchTwinTopic) - 1) == 0)
    {
        // Process the reported property response and request the device twin
        printf("Setting device twin properties SUCCEEDED.\r\n\r\n");

        printf("Getting device twin properties....\r\n");

        char msg[] = "{}";
        char mqtt_publish_topic[64];
        snprintf(mqtt_publish_topic, sizeof(mqtt_publish_topic), DEVICETWIN_MESSAGE_GET, device_twin_request_id++);

        int rc = mosquitto_publish(mosq, NULL, mqtt_publish_topic, sizeof(msg) - 1, msg, 1, true);
        if (rc != MOSQ_ERR_SUCCESS)
        {
            printf("Error: %s\r\n", mosquitto_strerror(rc));
        }
    }
    else if (strncmp(message->topic, getTwinTopic, sizeof(getTwinTopic) - 1) == 0)
    {
        // Process the device twin response and stop the client
        printf("Getting device twin properties SUCCEEDED.\r\n\r\n");

        mosquitto_loop_stop(mosq, false);
        mosquitto_disconnect(mosq); // finished, exit program
    }
}

Aby dowiedzieć się więcej, zobacz Używanie MQTT do aktualizowania zgłaszanej właściwości bliźniaczej reprezentacji urządzenia i pobieranie właściwości bliźniaczej reprezentacji urządzenia za pomocą MQTT.

Czyszczenie zasobów

Jeśli planujesz kontynuować dalsze artykuły dla deweloperów urządzeń, możesz zachować i ponownie użyć zasobów używanych w tym artykule. W przeciwnym razie możesz usunąć zasoby utworzone w tym artykule, aby uniknąć dodatkowych opłat.

Możesz usunąć jednocześnie zarówno centrum, jak i zarejestrowane urządzenie, usuwając całą grupę zasobów za pomocą następującego polecenia interfejsu wiersza polecenia platformy Azure. Nie używaj tego polecenia, jeśli te zasoby współużytkują grupę zasobów z innymi zasobami, które chcesz zachować.

az group delete --name <YourResourceGroupName>

Aby usunąć tylko centrum IoT Hub, uruchom następujące polecenie przy użyciu interfejsu wiersza polecenia platformy Azure:

az iot hub delete --name <YourIoTHubName>

Aby usunąć tylko tożsamość urządzenia zarejestrowaną w centrum IoT Hub, uruchom następujące polecenie przy użyciu interfejsu wiersza polecenia platformy Azure:

az iot hub device-identity delete --hub-name <YourIoTHubName> --device-id <YourDeviceID>

Możesz również usunąć sklonowane przykładowe pliki z maszyny deweloperów.

Następne kroki

Teraz, gdy wiesz już, jak używać biblioteki Mosquitto MQTT do komunikowania się z usługą IoT Hub, sugerowanym następnym krokiem jest przejrzenie: