This topic describes how to call the API operations of Link SDK for C to connect Message Queuing Telemetry Transport (MQTT) 5.0-based devices to IoT Platform and enable messaging. In this example, the ./demos/mqtt_v5_basic_demo.c
sample code file is used.
Background information
For more information about device connections over MQTT 5.0, see Overview.
Step 1: Initialize the SDK
Add header files.
#include "aiot_state_api.h" #include "aiot_sysdep_api.h" #include "aiot_mqtt_api.h"
Add the underlying dependency and configure the log output feature.
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);
Call the aiot_mqtt_init operation to create an MQTT client instance and initialize the default parameters.
mqtt_handle = aiot_mqtt_init(); if (mqtt_handle == NULL) { printf("aiot_mqtt_init failed\n"); return -1; }
Step 2: Configure required features
Call the aiot_mqtt_setopt operation to configure the following items: For more information about the parameters of the operation, see aiot_mqtt_option_t.
Configure connection parameters.
Sample code:
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));
Parameters:
Parameter
Example
Description
mqtt_host
iot-06z00ax1o******.mqtt.iothub.aliyuncs.com
The endpoint to which you want to connect the device.
To view the endpoint of an Enterprise Edition instance or a public instance of the new version, go to the Development Configurations panel of the Instance Details page in the IoT Platform console.
If you use a public instance of the previous version, the endpoint of the public instance is in the
${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com
format.
For more information about public instances of the new version and the old version, Enterprise Edition instance, and endpoints, see View the endpoint of an instance.
product_key
a18wP******
The device verification information. For more information, see Obtain device verification information.
In this example, the unique-certificate-per-device verification method is used.
device_name
LightSwitch
device_secret
uwMTmVAMnGGHaAkqmeDY6cHxxB******
protocol_version
AIOT_MQTT_VERSION_5_0
Specify 5.0 as the version number of MQTT.
use_assigned_clientid
1
If you want to use the
Assigned Client Identifier
feature of MQTT 5.0, set theuse_assigned_clientid
parameter to 1.Description of the MQTT keep-alive mechanism:
ImportantDuring a keep-alive period, the device must send at least one message, including ping requests.
A timer starts when IoT Platform sends a CONNACK message as a response to a CONNECT message. If IoT Platform receives a PUBLISH, SUBSCRIBE, PING, or PUBACK message, the timer is reset. IoT Platform checks the heartbeat of the MQTT connection every 30 seconds. The wait time for the heartbeat check is the period between the point in time at which a device connects to IoT Platform and the point in time at which the next heartbeat check is performed. The maximum timeout period is calculated by using the following formula:
Heartbeat interval × 1.5 + Wait time for the heartbeat check
. If the server receives no messages from the device within the maximum timeout period, the server ends the connection with the device.
Link SDK for C provides the keep-alive mechanism. The following table describes the parameter that you can configure to specify custom heartbeat-related values for device connections. Otherwise, the default values are used.
Item
Default value
Description
AIOT_MQTTOPT_HEARTBEAT_MAX_LOST
2
The maximum number of heartbeats that can be lost. If the limit is exceeded, the system establishes a new connection.
AIOT_MQTTOPT_HEARTBEAT_INTERVAL_MS
25,000
The interval between a disconnection and a new connection that is established by the system. Valid values: 1000 to 1200000. Unit: milliseconds.
AIOT_MQTTOPT_KEEPALIVE_SEC
1,200
The keep-alive period. After the heartbeat is lost, the system can establish a new connection within a specified period. Valid value: 30 to 1200. Unit: seconds. We recommend that you specify a value that is greater than 300.
Configure callbacks to monitor status and receive messages.
Step 3: Establish a connection
Call the aiot_mqtt_connect_v5 operation to send a connection and authentication request to IoT Platform. For information about how to configure the parameters, see Configure connection parameters.
For more information about the MQTT_PROP_ID_USER_PROPERTY
user property that is specified in the following sample code, see 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;
}
Step 4: Enable keep-alive threads
Call the aiot_mqtt_process operation to send a heartbeat message to the MQTT broker and re-send the QoS 1
messages for which no responses are generated. This way, a persistent connection is enabled.
Enable keep-alive threads.
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; }
To manage the keep-alive threads, define the following function:
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; }
Step 5: Enable threads to receive messages
Call the aiot_mqtt_recv operation to receive MQTT messages from the broker. The required operations are performed by using the callback to receive messages. If a disconnection and then an automatic reconnection occur, the required operations are performed by using the callback to handle events.
Enable threads to receive messages.
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; }
To manage the threads, define the following function:
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; }
Step 6: Subscribe to a topic
Call the aiot_mqtt_sub_v5 operation to subscribe to a specified topic.
Sample code:
/* 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; } }
NoteFor more information about the
MQTT_PROP_ID_USER_PROPERTY
user property that is specified in the following code, see mqtt_property_identify_t.For more information about how to specify subscription options, see sub_options_t.
Parameters:
Parameter
Example
Description
sub_topic
/a18wP******/LightSwitch/user/get
The topic on which the device has the Subscribe permission. Description:
a1oGs******
is the ProductKey of the device.LightSwitch
is the DeviceName of the device.
In this example, the default custom topic is used.
The device can receive messages from IoT Platform by using this topic.
For more information, see Topics.
sub_props
aiot_mqtt_props_init()
The additional properties that you want to specify for the subscription.
opts
.no_local = 1,
.qos = 1,
.retain_as_publish = 1,
.retain_handling = 1,
The subscription options.
Step 7: Send a message
Call the aiot_mqtt_pub_v5 operation to send a message to a specified topic.
Sample code:
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; }
NoteFor more information about the
MQTT_PROP_ID_USER_PROPERTY
user property that is specified in the following code, see mqtt_property_identify_t.Parameters:
Parameter
Example
Description
pub_topic
/a18wP******/LightSwitch/user/update
The topic on which you have the Publish permission. Description:
a1oGs******
indicates the ProductKey of the device.LightSwitch
indicates the DeviceName of the device.
The device sends messages to IoT Platform by using this topic.
For more information, see Topics.
pub_payload
{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}
The content of the message that you want to send to IoT Platform.
In this example, a custom topic is used. Therefore, you can specify a custom message format.
For more information, see Data formats.
pub_props
For more information, see the sample code.
The properties that are included in the message.
After an MQTT connection between the device and IoT Platform is established, make sure that the number of messages does not exceed the threshold.
For more information about communication limits, see Limits.
If the number of messages exceeds the threshold, log on to the IoT Platform console to view accumulated messages. For more information, see View and monitor consumer groups.
Step 8: Disconnect the device from IoT Platform
Call the aiot_mqtt_disconnect_v5 operation to disconnect the device from IoT Platform.
For more information about the MQTT_PROP_ID_USER_PROPERTY
user property that is specified in the following sample code, see mqtt_property_identify_t.
MQTT connections are applied to devices that remain persistently connected. You can disconnect devices from IoT Platform. In this example, the main thread is used to configure parameters and establish a connection. After the connection is established, you can put the main thread to sleep.
{
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);
}
Step 9: Exit the program
Call aiot_mqtt_deinit operation to delete the MQTT client instance and release the corresponding resources.
res = aiot_mqtt_deinit(&mqtt_handle);
if (res < STATE_SUCCESS) {
printf("aiot_mqtt_deinit failed: -0x%04X\n", -res);
return -1;
}
What to do next
After you configure the sample code file, compile the file to generate an executable file. In this example, the
./output/mqtt-v5-basic-demo
executable file is generated.For more information, see Prepare an environment.
For more information about the execution result, see View logs.