Compartir a través de


Tutorial: Uso de MQTT para desarrollar un cliente de dispositivo IoT sin usar un SDK de dispositivo

Si es posible, debería usar uno de los SDK de dispositivos Azure IoT para compilar los clientes de dispositivos IoT. Sin embargo, en escenarios como el uso de un dispositivo con restricción de memoria, es posible que tenga que usar una biblioteca MQTT para comunicarse con el centro de IoT.

Los ejemplos de este tutorial usan la biblioteca MQTT de Eclipse Mosquitto .

En este tutorial, aprenderá a:

  • Compile las aplicaciones de ejemplo de cliente del dispositivo de lenguaje C.
  • Ejecute un ejemplo que use la biblioteca MQTT para enviar telemetría.
  • Ejecute un ejemplo que use la biblioteca MQTT para procesar un mensaje de nube a dispositivo enviado desde ioT Hub.
  • Ejecute un ejemplo que use la biblioteca MQTT para administrar el dispositivo gemelo en el dispositivo.

Puede usar una máquina de desarrollo windows o Linux para completar los pasos descritos en este tutorial.

Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.

Prerrequisitos

Requisitos previos para la máquina de desarrollo

  1. Instale Visual Studio (Community, Professional o Enterprise). Asegúrese de habilitar la carga de trabajo Desarrollo de escritorio con C++ .

  2. Instale CMake. Habilite la opción Agregar CMake al sistema PATH para todos los usuarios .

  3. Instale la versión x64 de Mosquitto.

Preparación del entorno para la CLI de Azure

Configuración del entorno

Si aún no tiene un centro de IoT, ejecute los comandos siguientes para crear un centro de IoT de nivel gratuito en un grupo de recursos denominado mqtt-sample-rg. El comando usa el nombre my-hub como ejemplo para el nombre del centro de IoT que se va a crear. Elija un nombre único para su centro de IoT que se usará en lugar de 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 

Anote el nombre del centro de IoT, lo necesitará más adelante.

Registre un dispositivo en el centro de IoT. El comando siguiente registra un dispositivo llamado mqtt-dev-01 en un centro de IoT denominado my-hub. Asegúrese de usar el nombre del centro de IoT:

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

Use el comando siguiente para crear un token de SAS que conceda al dispositivo acceso al centro de IoT. Asegúrese de usar el nombre del centro de IoT:

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

Anote el token de SAS que el comando genera, ya que lo necesitará más adelante. El token de SAS tiene el aspecto SharedAccessSignature sr=my-hub.azure-devices.net%2Fdevices%2Fmqtt-dev-01&sig=%2FnM...sNwtnnY%3D&se=1677855761

Sugerencia

De forma predeterminada, el token de SAS es válido durante 60 minutos. La --du 7200 opción del comando anterior amplía la duración del token a dos horas. Si expira antes de que esté listo para usarlo, genere uno nuevo. También puede crear un token con una duración más larga. Para obtener más información, consulte az iot hub generate-sas-token.

Importante

En este artículo se incluyen los pasos para conectar un dispositivo mediante una firma de acceso compartido, también denominada autenticación de clave simétrica. Este método de autenticación es cómodo para probar y evaluar, pero autenticar un dispositivo mediante certificados X.509 es un enfoque más seguro. Para más información, consulte Procedimientos recomendados de seguridad para soluciones > de IoT Seguridad de la conexión.

Clonación del repositorio de ejemplo

Use el siguiente comando para clonar el repositorio de ejemplo en una ubicación adecuada en el equipo local:

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

El repositorio también incluye:

  • Ejemplo de Python que usa la paho-mqtt biblioteca.
  • Instrucciones para usar la mosquitto_pub CLI para interactuar con IoT Hub.

Compilación de los ejemplos de C

Antes de compilar el ejemplo, debe agregar los detalles del centro de IoT y del dispositivo. En el repositorio ioTMQTTSample clonado, abra el archivo mosquitto/src/config.h . Agregue el nombre del centro de IoT, el identificador de dispositivo y el token de SAS como se indica a continuación. Asegúrese de usar el nombre del centro de 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"

Nota:

El archivo IoTHubRootCA.crt.pem incluye los certificados raíz de CA para la conexión TLS.

Guarde los cambios en el archivo mosquitto/src/config.h .

Para compilar los ejemplos, ejecute los siguientes comandos en el shell:

cd mosquitto
cmake -Bbuild
cmake --build build

En Linux, los archivos binarios se encuentran en la carpeta ./build debajo de la carpeta mosquitto .

En Windows, los archivos binarios se encuentran en la carpeta .\build\Debug debajo de la carpeta mosquitto .

Envío de datos de telemetría

En el ejemplo de mosquitto_telemetry se muestra cómo enviar un mensaje de telemetría de dispositivo a nube al centro de IoT mediante la biblioteca MQTT.

Antes de ejecutar la aplicación de ejemplo, ejecute el siguiente comando para iniciar el monitor de eventos para ioT Hub. Asegúrese de usar el nombre del centro de IoT:

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

Ejecuta el ejemplo mosquitto_telemetry. Por ejemplo, en Linux:

./build/mosquitto_telemetry

az iot hub monitor-events Genera la salida siguiente que muestra la carga enviada por el dispositivo:

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

Ahora puede detener el monitor de eventos.

Revisión del código

Los fragmentos de código siguientes se toman del archivo mosquitto/src/mosquitto_telemetry.cpp .

Las instrucciones siguientes definen la información de conexión y el nombre del tema MQTT que se usa para enviar el mensaje de telemetría:

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

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

La main función establece el nombre de usuario y la contraseña para autenticarse con el centro de IoT. La contraseña es el token de SAS que creó para el dispositivo:

mosquitto_username_pw_set(mosq, USERNAME, SAS_TOKEN);

En el ejemplo se utiliza el tema de MQTT para enviar un mensaje de telemetría a tu IoT Hub.

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

Para más información, consulte Envío de mensajes de dispositivo a nube.

Recepción de un mensaje de nube a dispositivo

En el ejemplo de mosquitto_subscribe se muestra cómo suscribirse a temas MQTT y recibir mensajes de la nube al dispositivo desde el centro de IoT mediante la biblioteca MQTT.

Ejecute la muestra mosquitto_subscribe. Por ejemplo, en Linux:

./build/mosquitto_subscribe

Ejecute el comando siguiente para enviar un mensaje de nube a dispositivo desde ioT Hub. Asegúrese de usar el nombre del centro de IoT:

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

La salida de mosquitto_subscribe tiene un aspecto similar al del ejemplo siguiente:

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

Revisión del código

Los fragmentos de código siguientes se toman del archivo mosquitto/src/mosquitto_subscribe.cpp .

La siguiente instrucción define el filtro de tema que usa el dispositivo para recibir mensajes de nube a dispositivo. # es un carácter comodín de varios niveles:

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

La función main usa la función mosquitto_message_callback_set para establecer una devolución de llamada para controlar los mensajes enviados desde el centro de IoT y usa la función mosquitto_subscribe para suscribirse a todos los mensajes. El siguiente fragmento de código muestra la función de devolución de llamada:

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

Para más información, consulte Uso de MQTT para recibir mensajes de nube a dispositivo.

Actualización de un dispositivo gemelo

En el ejemplo mosquitto_device_twin se muestra cómo establecer una propiedad notificada en un dispositivo gemelo y, a continuación, volver a leer la propiedad.

Ejecute el ejemplo mosquitto_device_twin. Por ejemplo, en Linux:

./build/mosquitto_device_twin

La salida de mosquitto_device_twin tiene un aspecto similar al del ejemplo siguiente:

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.

Revisión del código

Los fragmentos de código siguientes se toman del archivo mosquitto/src/mosquitto_device_twin.cpp .

Las instrucciones siguientes definen los temas que usa el dispositivo para suscribirse a las actualizaciones de dispositivos gemelos, leer el dispositivo gemelo y actualizar el dispositivo gemelo:

#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"

La función main usa la función mosquitto_connect_callback_set para establecer una devolución de llamada para controlar los mensajes enviados desde el centro de IoT y usa la función mosquitto_subscribe para suscribirse al tema $iothub/twin/res/#.

El fragmento de código siguiente muestra la connect_callback función que usa mosquitto_publish para establecer una propiedad notificada en el dispositivo gemelo. El dispositivo publica el mensaje en el tema $iothub/twin/PATCH/properties/reported/?$rid=%d. El valor %d se incrementa cada vez que el dispositivo publica un mensaje en el tópico.

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

El dispositivo se suscribe al $iothub/twin/res/# tema y cuando recibe un mensaje del centro de IoT, la message_callback función la controla. Al ejecutar el ejemplo, se llama a la message_callback función dos veces. La primera vez el dispositivo recibirá una respuesta del centro de IoT a la actualización de la propiedad notificada. A continuación, el dispositivo solicitará el dispositivo gemelo. La segunda vez, el dispositivo recibe el dispositivo gemelo solicitado. En el fragmento de código siguiente se muestra la message_callback función :

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

Para más información, consulte Uso de MQTT para actualizar una propiedad notificada de dispositivo gemelo y Usar MQTT para recuperar una propiedad de dispositivo gemelo.

Limpieza de recursos

Si tiene previsto continuar con más artículos para desarrolladores de dispositivos, puede conservar y reutilizar los recursos que usó en este artículo. De lo contrario, puede eliminar los recursos que creó en este artículo para evitar más cargos.

Puede eliminar el dispositivo concentrador y registrado a la vez mediante la eliminación del grupo de recursos completo con el siguiente comando de la CLI de Azure. No use este comando si estos recursos comparten un grupo de recursos con otros recursos que desea conservar.

az group delete --name <YourResourceGroupName>

Para eliminar solo el centro de IoT, ejecute el siguiente comando mediante la CLI de Azure:

az iot hub delete --name <YourIoTHubName>

Para eliminar solo la identidad del dispositivo que registró con ioT Hub, ejecute el siguiente comando mediante la CLI de Azure:

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

También puede quitar los archivos de ejemplo clonados de la máquina de desarrollo.

Pasos siguientes

Ahora que ha aprendido a usar la biblioteca MQTT de Mosquitto para comunicarse con IoT Hub, un siguiente paso sugerido es revisar los ejemplos de aplicaciones MQTT en GitHub.