Este tema describe cómo invocar las operaciones de API del Link SDK para C con el fin de conectar dispositivos basados en Message Queuing Telemetry Transport (MQTT) 5.0 a IoT Platform y habilitar la mensajería. En este ejemplo se utiliza el archivo de código de muestra ./demos/mqtt_v5_basic_demo.c.
Contexto
Para obtener más información sobre las conexiones de dispositivos mediante MQTT 5.0, consulte Overview.
Paso 1: Inicializar el SDK
-
Agregue los archivos de encabezado.
#include "aiot_state_api.h" #include "aiot_sysdep_api.h" #include "aiot_mqtt_api.h" -
Agregue la dependencia subyacente y configure la función de salida de registros.
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb); -
Invoque la operación aiot_mqtt_init para crear una instancia de cliente MQTT e inicializar los parámetros predeterminados.
mqtt_handle = aiot_mqtt_init(); if (mqtt_handle == NULL) { printf("aiot_mqtt_init failed\n"); return -1; }
Paso 2: Configurar las funciones obligatorias
Invoque la operación aiot_mqtt_setopt para configurar los siguientes elementos. Para obtener más información sobre los parámetros de la operación, consulte aiot_mqtt_option_t.
-
Configure los parámetros de conexión.
-
Código de muestra:
char *product_key = "a18wP******"; char *device_name = "LightSwitch"; char *device_secret = "uwMTmVAMnGGHaAkqmeDY6cHxxB******"; char *mqtt_host = "iot-06z00ax1o******.mqtt.iothub.aliyuncs.com"; ... ... /* Specify the version of MQTT. */ protocol_version = AIOT_MQTT_VERSION_5_0; aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_VERSION, (void *)&protocol_version); /* Specify the endpoint of the MQTT broker. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_HOST, (void *)url); /* Specify the port of the MQTT broker. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PORT, (void *)&port); /* Specify the ProductKey of the product to which the device belongs. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PRODUCT_KEY, (void *)product_key); /* Specify the DeviceName of the device. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_NAME, (void *)device_name); /* Specify the DeviceSecret of the device. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_SECRET, (void *)device_secret); /* Specify the security credential of the connection. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED, (void *)&cred); /* If you want to use the Assigned Client Identifier feature of MQTT 5.0, set the use_assigned_clientid parameter to 1.*/ uint8_t use_assigned_clientid = 0; aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_ASSIGNED_CLIENTID, (void *)(&use_assigned_clientid)); -
Parámetros:
Parámetro
Ejemplo
Descripción
mqtt_host
iot-06z00ax1o******.mqtt.iothub.aliyuncs.com
El endpoint al que desea conectar el dispositivo.
Para consultar el endpoint de una instancia Enterprise Edition o de una instancia pública de la nueva versión, vaya al panel Development Configurations de la página Instance Details en la consola de IoT Platform.
Si utiliza una instancia pública de la versión anterior, el endpoint de la instancia pública tiene el formato
${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com.
Para obtener más información sobre las instancias públicas de la nueva y la antigua versión, las instancias Enterprise Edition y los endpoints, consulte View the endpoint of an instance.
product_key
a18wP******
La información de verificación del dispositivo. Para obtener más información, consulte Obtain device verification information.
En este ejemplo se utiliza el método de verificación de certificado único por dispositivo.
device_name
LightSwitch
device_secret
uwMTmVAMnGGHaAkqmeDY6cHxxB******
protocol_version
AIOT_MQTT_VERSION_5_0
Especifique 5.0 como número de versión de MQTT.
use_assigned_clientid
1
Si desea utilizar la función
Assigned Client Identifierde MQTT 5.0, establezca el parámetrouse_assigned_clientiden 1. -
Descripción del mecanismo keep-alive de MQTT:
ImportanteDurante un periodo de keep-alive, el dispositivo debe enviar como mínimo un mensaje, incluidas las solicitudes de ping.
Un temporizador se inicia cuando IoT Platform envía un mensaje CONNACK como respuesta a un mensaje CONNECT. Si IoT Platform recibe un mensaje PUBLISH, SUBSCRIBE, PING o PUBACK, el temporizador se restablece. IoT Platform comprueba el latido de la conexión MQTT cada 30 segundos. El tiempo de espera para la comprobación del latido es el periodo transcurrido entre el momento en que un dispositivo se conecta a IoT Platform y el momento en que se realiza la siguiente comprobación de latido. El tiempo máximo de espera se calcula mediante la siguiente fórmula: Intervalo de latido × 1.5 + Tiempo de espera para la comprobación de latido. Si el servidor no recibe mensajes del dispositivo dentro del tiempo máximo de espera, finaliza la conexión con el dispositivo.
Link SDK para C proporciona el mecanismo keep-alive. La siguiente tabla describe el parámetro que puede configurar para especificar valores personalizados relacionados con el latido para las conexiones de dispositivos. De lo contrario, se utilizan los valores predeterminados.
Elemento
Valor predeterminado
Descripción
AIOT_MQTTOPT_HEARTBEAT_MAX_LOST
2
El número máximo de latidos que pueden perderse. Si se supera el límite, el sistema establece una nueva conexión.
AIOT_MQTTOPT_HEARTBEAT_INTERVAL_MS
25,000
El intervalo entre una desconexión y una nueva conexión establecida por el sistema. Valores válidos: de 1000 a 1200000. Unidad: milisegundos.
AIOT_MQTTOPT_KEEPALIVE_SEC
1,200
El periodo de keep-alive. Después de perderse el latido, el sistema puede establecer una nueva conexión dentro de un periodo especificado. Valor válido: de 30 a 1200. Unidad: segundos. Se recomienda especificar un valor mayor que 300.
-
-
Configure las devoluciones de llamada para supervisar el estado y recibir mensajes.
-
Configure una devolución de llamada para supervisar el estado.
-
Código de muestra:
int main(int argc, char *argv[]) { ... ... /* Specify the default callback to receive MQTT messages. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_RECV_HANDLER, (void *)demo_mqtt_default_recv_handler); /* Specify the callback to handle MQTT events. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_EVENT_HANDLER, (void *)demo_mqtt_event_handler); ... ... } -
Parámetros:
Elemento
Ejemplo
Descripción
AIOT_MQTTOPT_RECV_HANDLER
demo_mqtt_default_recv_handler
Cuando se recibe un mensaje, se invoca la devolución de llamada para realizar las operaciones necesarias.
AIOT_MQTTOPT_EVENT_HANDLER
demo_mqtt_event_handler
Cuando cambia el estado de la conexión del dispositivo, se invoca la devolución de llamada para realizar las operaciones necesarias.
-
-
Defina la devolución de llamada para supervisar el estado.
ImportanteNo especifique lógica que consuma mucho tiempo para gestionar eventos. De lo contrario, los hilos utilizados para recibir paquetes podrían bloquearse.
El estado de la conexión cambia debido a varias causas, como excepciones de red, reconexiones automáticas y desconexiones.
Para gestionar los cambios en el estado de la conexión, puede modificar el código en la sección TODO según sus requisitos empresariales.
/* The callback to handle MQTT events. When the connection is created, recovered, or closed, the callback is called. For information about the event definition, see core/aiot_mqtt_api.h. */ void demo_mqtt_event_handler(void *handle, const aiot_mqtt_event_t *event, void *userdata) { switch (event->type) { /* Call the aiot_mqtt_connect operation to establish a connection to the MQTT broker. */ case AIOT_MQTTEVT_CONNECT: { printf("AIOT_MQTTEVT_CONNECT\n"); /* TODO: Specify the logic to establish a connection. Do not call time-consuming functions that may block threads. */ */ } break; /* If a disconnection error occurs due to a network exception, the SDK automatically initiates a request to reconnect to the MQTT broker. */ case AIOT_MQTTEVT_RECONNECT: { printf("AIOT_MQTTEVT_RECONNECT\n"); /* TODO: Specify the logic to re-establish a connection. Do not call time-consuming functions that may block threads. */ */ } break; /* A disconnection error occurs due to a network exception. The underlying read or write operation fails. A heartbeat response is not obtained from the MQTT broker. */ case AIOT_MQTTEVT_DISCONNECT: { char *cause = (event->data.disconnect == AIOT_MQTTDISCONNEVT_NETWORK_DISCONNECT) ? ("network disconnect") : ("heartbeat disconnect"); printf("AIOT_MQTTEVT_DISCONNECT: %s\n", cause); /* TODO: Specify the logic to process disconnection issues. Do not call time-consuming functions that may block threads. */ */ } break; default: { } } } -
Defina la devolución de llamada para recibir mensajes.
ImportanteNo especifique lógica que consuma mucho tiempo para procesar mensajes. De lo contrario, los hilos utilizados para recibir paquetes podrían bloquearse.
Para procesar los mensajes recibidos, puede modificar el código en la sección TODO según sus requisitos empresariales.
/* The default callback function that can be called to receive MQTT messages. This function is called when the SDK receives an MQTT message from the MQTT broker and no custom callback is available. */ void demo_mqtt_default_recv_handler(void *handle, const aiot_mqtt_recv_t *packet, void *userdata) { switch (packet->type) { case AIOT_MQTTRECV_HEARTBEAT_RESPONSE: { printf("heartbeat response\n"); /* TODO: Define the logic for sending a heartbeat response to the server. In most cases, a response is not sent. */ } break; case AIOT_MQTTRECV_SUB_ACK: { printf("suback, res: -0x%04X, packet id: %d, max qos: %d\n", -packet->data.sub_ack.res, packet->data.sub_ack.packet_id, packet->data.sub_ack.max_qos); /* TODO: Define the logic for sending a response from the MQTT broker to a subscription request. In most cases, a response is not sent. */ } break; case AIOT_MQTTRECV_UNSUB_ACK: { printf("unsuback, , packet id: %d\n", packet->data.unsub_ack.packet_id); /* TODO: Define the logic for sending a response from the MQTT broker to a subscription request. In most cases, a response is not sent. */ } break; case AIOT_MQTTRECV_PUB: { printf("pub, qos: %d, topic: %.*s\n", packet->data.pub.qos, packet->data.pub.topic_len, packet->data.pub.topic); printf("pub, payload: %.*s\n", packet->data.pub.payload_len, packet->data.pub.payload); printf("pub, payload len: %x\n", packet->data.pub.payload_len); aiot_mqtt_props_print(packet->data.pub.props); } break; case AIOT_MQTTRECV_PUB_ACK: { printf("puback, packet id: %d\n", packet->data.pub_ack.packet_id); /* TODO: Define the logic for sending a response from the MQTT broker to a reported QoS 1 message. Typically, a response is not sent. */ } break; case AIOT_MQTTRECV_CON_ACK: { aiot_mqtt_props_print(packet->data.con_ack.props); } break; case AIOT_MQTTRECV_DISCONNECT: { printf("server disconnect, reason code: 0x%x\n", packet->data.server_disconnect.reason_code); } break; default: { } } } -
Habilite los hilos de keep-alive.
res = pthread_create(&g_mqtt_process_thread, NULL, demo_mqtt_process_thread, mqtt_handle); if (res < 0) { printf("pthread_create demo_mqtt_process_thread failed: %d\n", res); return -1; } -
Para gestionar los hilos de keep-alive, defina la siguiente función:
void *demo_mqtt_process_thread(void *args) { int32_t res = STATE_SUCCESS; while (g_mqtt_process_thread_running) { res = aiot_mqtt_process(args); if (res == STATE_USER_INPUT_EXEC_DISABLED) { break; } sleep(1); } return NULL; } -
Habilite los hilos para recibir mensajes.
res = pthread_create(&g_mqtt_recv_thread, NULL, demo_mqtt_recv_thread, mqtt_handle); if (res < 0) { printf("pthread_create demo_mqtt_recv_thread failed: %d\n", res); return -1; } -
Para gestionar los hilos, defina la siguiente función:
void *demo_mqtt_recv_thread(void *args) { int32_t res = STATE_SUCCESS; while (g_mqtt_recv_thread_running) { res = aiot_mqtt_recv(args); if (res < STATE_SUCCESS) { if (res == STATE_USER_INPUT_EXEC_DISABLED) { break; } sleep(1); } } return NULL; } -
Código de muestra:
/* Use the sample code that shows how to subscribe to a topic over MQTT based on your business requirements. */ { char *sub_topic = "/sys/${YourProductKey}/${YourDeviceName}/thing/event/property/post_reply"; mqtt_properties_t *sub_props = aiot_mqtt_props_init(); aiot_mqtt_props_add(sub_props, &user_prop); /* The subscription options. */ sub_options_t opts = { .no_local = 1, .qos = 1, .retain_as_publish = 1, .retain_handling = 1, }; res = aiot_mqtt_sub_v5(mqtt_handle, sub_topic, &opts, NULL, NULL, sub_props); aiot_mqtt_props_deinit(&sub_props); if (res < 0) { printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res); aiot_mqtt_deinit(&mqtt_handle); return -1; } }NotaPara obtener más información sobre la propiedad de usuario
MQTT_PROP_ID_USER_PROPERTYque se especifica en el siguiente código, consulte mqtt_property_identify_t.Para obtener más información sobre cómo especificar opciones de suscripción, consulte sub_options_t.
-
Parámetros:
Parámetro
Ejemplo
Descripción
sub_topic
/a18wP******/LightSwitch/user/get
El tema sobre el cual el dispositivo tiene permiso de suscripción. Descripción:
a1oGs******es la ProductKey del dispositivo.LightSwitches el DeviceName del dispositivo.
En este ejemplo se utiliza el tema personalizado predeterminado.
El dispositivo puede recibir mensajes de IoT Platform mediante este tema.
Para obtener más información, consulte What is a topic.
sub_props
aiot_mqtt_props_init()
Las propiedades adicionales que desea especificar para la suscripción.
opts
.no_local = 1,
.qos = 1,
.retain_as_publish = 1,
.retain_handling = 1,
Las opciones de suscripción.
-
Código de muestra:
mqtt_properties_t *pub_props = aiot_mqtt_props_init(); /* Use the sample code that shows how to send a message over MQTT based on your business requirements.*/ char *pub_topic = "/sys/${YourProductKey}/${YourDeviceName}/thing/event/property/post"; char *pub_payload = "{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}"; mqtt_property_t response_prop = { .id = MQTT_PROP_ID_RESPONSE_TOPIC, .value.str.len = strlen(pub_topic), .value.str.value = (uint8_t *)pub_topic, }; char *demo_data_str = "12345"; mqtt_property_t correlation_prop = { .id = MQTT_PROP_ID_CORRELATION_DATA, .value.str.len = strlen(demo_data_str), .value.str.value = (uint8_t *)demo_data_str, }; aiot_mqtt_props_add(pub_props, &response_prop); aiot_mqtt_props_add(pub_props, &correlation_prop); res = aiot_mqtt_pub_v5(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)(strlen(pub_payload)), 1,0, pub_props); if (res < 0) { printf("aiot_mqtt pub failed, res: -0x%04X\n", -res); aiot_mqtt_deinit(&mqtt_handle); return -1; }NotaPara obtener más información sobre la propiedad de usuario
MQTT_PROP_ID_USER_PROPERTYque se especifica en el siguiente código, consulte mqtt_property_identify_t. -
Parámetros:
Parámetro
Ejemplo
Descripción
pub_topic
/a18wP******/LightSwitch/user/update
El tema sobre el cual tiene permiso de publicación. Descripción:
a1oGs******indica la ProductKey del dispositivo.LightSwitchindica el DeviceName del dispositivo.
El dispositivo envía mensajes a IoT Platform mediante este tema.
Para obtener más información, consulte What is a topic.
pub_payload
{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}
El contenido del mensaje que desea enviar a IoT Platform.
En este ejemplo se utiliza un tema personalizado. Por lo tanto, puede especificar un formato de mensaje personalizado.
Para obtener más información, consulte Data formats.
pub_props
Para obtener más información, consulte el código de muestra.
Las propiedades que se incluyen en el mensaje.
Para obtener más información sobre los límites de comunicación, consulte Limits.
Si el número de mensajes supera el umbral, inicie sesión en la consola de IoT Platform para consultar los mensajes acumulados. Para obtener más información, consulte View and monitor consumer groups.
-
Después de configurar el archivo de código de muestra, compílelo para generar un archivo ejecutable. En este ejemplo se genera el archivo ejecutable ./output/mqtt-v5-basic-demo.
Para obtener más información, consulte Prepare an environment.
Para obtener más información sobre el resultado de la ejecución, consulte Operational logs.
Paso 3: Establecer una conexión
Invoque la operación aiot_mqtt_connect_v5 para enviar una solicitud de conexión y autenticación a IoT Platform. Para obtener información sobre cómo configurar los parámetros, consulte Configurar parámetros de conexión.
NotaPara obtener más información sobre la propiedad de usuario
MQTT_PROP_ID_USER_PROPERTYque se especifica en el siguiente código de muestra, consulte mqtt_property_identify_t.mqtt_properties_t *conn_props = aiot_mqtt_props_init(); mqtt_property_t user_prop = { .id = MQTT_PROP_ID_USER_PROPERTY, .value.str_pair.key.len = strlen("demo_key"), .value.str_pair.key.value = (uint8_t *)"demo_key", .value.str_pair.value.len = strlen("demo_value"), .value.str_pair.value.value = (uint8_t *)"demo_value", }; aiot_mqtt_props_add(conn_props, &user_prop); /* Establish a connection to the server over MQTT 5.0. */ res = aiot_mqtt_connect_v5(mqtt_handle, NULL, conn_props); aiot_mqtt_props_deinit(&conn_props); if (res < STATE_SUCCESS) { /* If the MQTT connection fails to be established, release the resources of the MQTT instance. */ aiot_mqtt_deinit(&mqtt_handle); printf("aiot_mqtt_connect failed: -0x%04X\n\r\n", -res); printf("please check variables like mqtt_host, produt_key, device_name, device_secret in demo\r\n"); return -1; }Paso 4: Habilitar hilos de keep-alive
Invoque la operación aiot_mqtt_process para enviar un mensaje de latido al agente MQTT y reenviar los mensajes QoS 1 para los que no se generaron respuestas. De esta manera se habilita una conexión persistente.
Paso 5: Habilitar hilos para recibir mensajes
Invoque la operación aiot_mqtt_recv para recibir mensajes MQTT del agente. Las operaciones necesarias se realizan mediante la devolución de llamada para recibir mensajes. Si ocurre una desconexión y posteriormente una reconexión automática, las operaciones necesarias se realizan mediante la devolución de llamada para gestionar eventos.
Paso 6: Suscribirse a un tema
Invoque la operación aiot_mqtt_sub_v5 para suscribirse a un tema específico.
Paso 7: Enviar un mensaje
Invoque la operación aiot_mqtt_pub_v5 para enviar un mensaje a un tema específico.
Una vez establecida la conexión MQTT entre el dispositivo e IoT Platform, asegúrese de que el número de mensajes no supere el umbral.
Paso 8: Desconectar el dispositivo de IoT Platform
Invoque la operación aiot_mqtt_disconnect_v5 para desconectar el dispositivo de IoT Platform.
Para obtener más información sobre la propiedad de usuario
MQTT_PROP_ID_USER_PROPERTYque se especifica en el siguiente código de muestra, consulte mqtt_property_identify_t.NotaLas conexiones MQTT están diseñadas para dispositivos que permanecen conectados de forma persistente. Puede desconectar dispositivos de IoT Platform. En este ejemplo, el hilo principal se utiliza para configurar parámetros y establecer una conexión. Una vez establecida la conexión, puede poner el hilo principal en reposo.
{ mqtt_properties_t *disconn_props = aiot_mqtt_props_init(); /* The reason code 0x0 indicates a normal disconnection. */ int demo_reason_code = 0x0; char *demo_reason_string = "normal_exit"; mqtt_property_t reason_prop = {.id = MQTT_PROP_ID_REASON_STRING, .value.str.len = strlen(demo_reason_string), .value.str.value = (uint8_t *)demo_reason_string}; aiot_mqtt_props_add(disconn_props, &reason_prop); res = aiot_mqtt_disconnect_v5(mqtt_handle, demo_reason_code, disconn_props); aiot_mqtt_props_deinit(&disconn_props); }Paso 9: Salir del programa
Invoque la operación aiot_mqtt_deinit para eliminar la instancia de cliente MQTT y liberar los recursos correspondientes.
res = aiot_mqtt_deinit(&mqtt_handle); if (res < STATE_SUCCESS) { printf("aiot_mqtt_deinit failed: -0x%04X\n", -res); return -1; }Siguientes pasos
-