Usage example
This topic uses the ./demos/mqtt_v5_basic_demo.c file in the C Link software development kit (SDK) as an example to describe how to call the C Link SDK APIs to connect a device that uses the Message Queuing Telemetry Transport (MQTT) 5.0 protocol to IoT Platform and send and receive messages.
Background information
For more information about connecting to MQTT 5.0, see Overview.
Step 1: Initialization
You can add the header files.
#include "aiot_state_api.h" #include "aiot_sysdep_api.h" #include "aiot_mqtt_api.h"You can configure underlying dependencies and log output.
aiot_sysdep_set_portfile(&g_aiot_sysdep_portfile); aiot_state_set_logcb(demo_state_logcb);You can call aiot_mqtt_init to create an ApsaraMQ for 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 features
You can call aiot_mqtt_setopt to configure the following features. For more information about configuration items for other features, see aiot_mqtt_option_t.
You can 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"; ... ... /* Set the MQTT protocol version. */ protocol_version = AIOT_MQTT_VERSION_5_0; aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_VERSION, (void *)&protocol_version); /* Set the MQTT server address. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_HOST, (void *)url); /* Set the MQTT server port. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PORT, (void *)&port); /* Set the device ProductKey. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_PRODUCT_KEY, (void *)product_key); /* Set the device DeviceName. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_NAME, (void *)device_name); /* Set the device DeviceSecret. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_DEVICE_SECRET, (void *)device_secret); /* Set the security credentials for the network connection. */ aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_NETWORK_CRED, (void *)&cred); /* To use the assigned clientId feature of MQTT 5.0, set use_assigned_clientid to 1. */ uint8_t use_assigned_clientid = 0; aiot_mqtt_setopt(mqtt_handle, AIOT_MQTTOPT_ASSIGNED_CLIENTID, (void *)(&use_assigned_clientid));Related parameters:
Parameter
Example
Description
mqtt_host
iot-06z00ax1o******.mqtt.iothub.aliyuncs.com
The domain name for device connection.
Enterprise instances and new public instances: On the Instance Details page, view the domain name on the Development Configurations panel.
Legacy public instances: The domain name format is
${YourProductKey}.iot-as-mqtt.${YourRegionId}.aliyuncs.com.
For more information about new and legacy public instances, Enterprise instances, and connection domain names, see View instance endpoints.
product_key
a18wP******
Device authentication information. For more information, see Obtain device credentials.
This example uses one-secret-per-device authentication.
device_name
LightSwitch
device_secret
uwMTmVAMnGGHaAkqmeDY6cHxxB******
protocol_version
AIOT_MQTT_VERSION_5_0
Set the MQTT protocol version to 5.0.
use_assigned_clientid
1
When you use the
assigned clientIdfeature of MQTT 5.0, setuse_assigned_clientidto 1.Description of MQTT keepalive:
ImportantThe device must send at least one message, such as a ping request, within each keepalive interval.
The heartbeat timer starts when IoT Platform sends a CONNACK message in response to a CONNECT message. The timer is reset when a PUBLISH, SUBSCRIBE, PING, or PUBACK message is received. IoT Platform checks the device's keepalive heartbeat every 30 seconds. The waiting time for the check is the duration from when the device comes online to the next scheduled check. The maximum timeout period is defined as:
Keepalive heartbeat time × 1.5 + Waiting time for the check. If no message is received from the device before the maximum timeout period elapses, the server automatically disconnects the device.
The C Link SDK has a keepalive feature. You can set the following configuration items to customize the keepalive heartbeat for the device connection. If you do not configure them, the default values are used.
Configuration item
Default value
Description
AIOT_MQTTOPT_HEARTBEAT_MAX_LOST
2
The threshold for tolerable heartbeat loss. After the number of heartbeat request messages reaches the specified threshold, a reconnection is initiated.
AIOT_MQTTOPT_HEARTBEAT_INTERVAL_MS
25,000
The interval between reconnection attempts. Unit: milliseconds. Valid values: 1,000 to 1,200,000.
AIOT_MQTTOPT_KEEPALIVE_SEC
1,200
The time threshold for tolerable heartbeat loss. After a heartbeat is lost, reconnection is allowed within the specified time. Unit: seconds. Valid values: 30 to 1,200. A value greater than 300 is recommended.
You can configure status monitoring and message callbacks.
Step 3: Request a connection
You can call aiot_mqtt_connect_v5 to send a connection authentication request to IoT Platform based on the configured connection parameters.
For more information about the user property (MQTT_PROP_ID_USER_PROPERTY) added in the 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 with the server using 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 connection attempt fails, destroy the MQTT instance and release resources. */
aiot_mqtt_deinit(&mqtt_handle);
printf("aiot_mqtt_connect failed: -0x%04X\n\r\n", -res);
printf("please check variables like mqtt_host, product_key, device_name, device_secret in demo\r\n");
return -1;
}Step 4: Start the keepalive thread
You can call aiot_mqtt_process to send heartbeat messages to the server. This keeps the device in a persistent connection state and resends unacknowledged messages with a QoS=1 setting.
You can start the keepalive thread.
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; }You can set the keepalive thread handler 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: Start the receiving thread
You can call aiot_mqtt_recv to receive MQTT messages from the server and process them based on the message callback function. If the device is disconnected, it automatically reconnects and performs actions based on the event callback function.
You can start the receiving thread.
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; }You can set the receiving thread handler 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
You can call aiot_mqtt_sub_v5 to subscribe to a specified topic.
Sample code:
/* This is an example of the MQTT topic subscription feature. Use it as needed for your business. */ { 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); /* 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 user property (
MQTT_PROP_ID_USER_PROPERTY) added in the sample code, see mqtt_property_identify_t.For more information about subscription options, see sub_options_t.
Related parameters:
Parameter
Example
Description
sub_topic
/a18wP******/LightSwitch/user/get
A topic that you have permission to subscribe to. In this topic:
a18wP******is the ProductKey of the device.LightSwitchis the DeviceName of the device.
This example uses a default custom topic.
The device can receive messages from IoT Platform through this topic.
For more information about topics, see What is a topic?.
sub_props
aiot_mqtt_props_init()
Additional subscription properties.
opts
.no_local = 1,
.qos = 1,
.retain_as_publish = 1,
.retain_handling = 1,
Subscription options.
Step 7: Send a message
You can call aiot_mqtt_pub_v5 to send a message to a specified topic.
Sample code:
mqtt_properties_t *pub_props = aiot_mqtt_props_init(); /* This is an example of the MQTT message publishing feature. Use it as needed for your business. */ 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 user property (
MQTT_PROP_ID_USER_PROPERTY) added in the sample code, see mqtt_property_identify_t.Related parameters:
Parameter
Example
Description
pub_topic
/a18wP******/LightSwitch/user/update
A topic that you have permission to publish to. In this topic:
a18wP******is the ProductKey of the device.LightSwitchis the DeviceName of the device.
The device sends messages to IoT Platform through this topic.
For more information about topics, see What is a topic?.
pub_payload
{\"id\":\"1\",\"version\":\"1.0\",\"params\":{\"LightSwitch\":0}}
The content of the message reported to IoT Platform.
Because the topic category for the sample message is a custom topic, the data format can be customized.
For more information about data formats, see Data formats.
pub_props
See the sample code.
Properties carried in the published message.
After the device establishes MQTT communication with IoT Platform, the communication volume must not exceed the threshold.
For more information about communication limits, see Connection and communication.
If the communication volume exceeds the threshold, you can log on to the IoT Platform console to view stacked messages. For more information, see View and monitor consumer groups.
Step 8: Disconnect
You can call aiot_mqtt_disconnect_v5 to send a disconnection message to IoT Platform and then disconnect from the network.
For more information about the user property (MQTT_PROP_ID_USER_PROPERTY) added in the sample code, see mqtt_property_identify_t.
MQTT is often used for devices with persistent connections, so the program usually does not run to this step. The main thread's task in this example is to configure parameters and establish a connection. After the connection is established, the main thread can enter hibernation.
{
mqtt_properties_t *disconn_props = aiot_mqtt_props_init();
/* 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
You can call aiot_mqtt_deinit to destroy the ApsaraMQ for MQTT client instance and release 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 file, you can compile it to generate the executable file
./output/mqtt-v5-basic-demo.For more information, see Compile and run.
For a detailed description of the run results, see the operational log.