本文介绍如何使用Paho提供的嵌入式C语言MQTT开源工程,将设备接入阿里云物联网平台,并进行消息收发。
前提条件
已在物联网平台控制台创建产品和设备,并获取设备证书信息(ProductKey、DeviceName和DeviceSerect)。具体操作,请参见:
准备开发环境
本示例使用Ubuntu 16.04-LTS作为开发环境。执行以下命令构建开发环境。
sudo apt-get update
sudo apt-get install build-essential git sed cmake
下载C语言Paho MQTT库
执行以下命令,克隆C语言版本的Paho MQTT库。
git clone https://github.com/eclipse/paho.mqtt.embedded-c.git
说明 编写本Demo示例时,使用master分支,commit id为29ab2aa29c5e47794284376d7f8386cfd54c3eed
。
Paho嵌入式C工程提供了以下三个子项目:
- MQTTPacket:提供MQTT数据包的序列化与反序列化,以及部分辅助函数。
- MQTTClient:封装MQTTPacket生成的高级别C++客户端程序。
- MQTTClient-C:封装MQTTPacket生成的高级别C客户端程序。
MQTTClient-C中包含:
├── CMakeLists.txt
├── samples
│ ├── CMakeLists.txt
│ ├── FreeRTOS
│ └── linux
├── src
│ ├── CMakeLists.txt
│ ├── FreeRTOS
│ ├── MQTTClient.c
│ ├── MQTTClient.h
│ ├── cc3200
│ └── linux
└── test
├── CMakeLists.txt
└── test1.c
- samples目录提供FreeRTOS和Linux两个例程,分别支持FreeRTOS和Linux系统。
- src目录提供MQTTClient的代码实现能力,以及用于移植到FreeRTOS、cc3200和Linux的网络驱动。
了解Paho MQTT的更多API细节,可以查看MQTTClient.h。
接入物联网平台
- 单击打开aiot_mqtt_sign.c,复制阿里云提供的计算MQTT连接参数所需的源码,然后粘贴保存为本地的aiot_mqtt_sign.c文件。
aiot_mqtt_sign.c文件定义了函数aiotMqttSign(),函数说明如下:
- 原型:
int aiotMqttSign(const char *productKey, const char *deviceName, const char *deviceSecret,
char clientId[150], char username[65], char password[65]);
- 功能:
用于计算设备接入物联网平台的MQTT连接参数username、password和clientid。
- 输入参数:
参数 |
类型 |
说明 |
productKey |
const char * |
设备所属产品的ProductKey,该设备在物联网平台上的身份证书信息之一。 |
deviceName |
const char * |
设备名称,该设备在物联网平台上的身份证书信息之一。 |
deviceSecret |
const char * |
设备密钥,该设备在物联网平台上的身份证书信息之一。 |
- 输出参数:
参数 |
类型 |
说明 |
username |
char * |
MQTT连接所需的用户名。 |
password |
char * |
MQTT连接所需的密码。 |
clientId |
char * |
MQTT客户端ID。 |
- 返回码说明:
- 添加实现设备接入物联网平台的程序文件。
您需编写程序调用aiot_mqtt_sign.c中的aiotMqttSign()函数计算MQTT连接参数,实现接入物联网平台和通信。
开发说明和示例代码如下:
- 调用aiotMqttSign()接口,生成连接MQTT服务端的三个建连参数clientId、username和password。
#define EXAMPLE_PRODUCT_KEY "a11xsrW****"
#define EXAMPLE_DEVICE_NAME "paho_****"
#define EXAMPLE_DEVICE_SECRET "Y877Bgo8X5owd3lcB5wWDjryNPoB****"
extern int aiotMqttSign(const char *productKey, const char *deviceName, const char *deviceSecret,
char clientId[150], char username[65], char password[65]);
/* invoke aiotMqttSign to generate mqtt connect parameters */
char clientId[150] = {0};
char username[65] = {0};
char password[65] = {0};
if ((rc = aiotMqttSign(EXAMPLE_PRODUCT_KEY, EXAMPLE_DEVICE_NAME, EXAMPLE_DEVICE_SECRET, clientId, username, password) < 0)) {
printf("aiotMqttSign -%0x4x\n", -rc);
return -1;
}
printf("clientid: %s\n", clientId);
printf("username: %s\n", username);
printf("password: %s\n", password);
- 接入物联网平台。
需配置以下内容:
- 调用NetworkInit和NetworkConnect建立TCP连接。
- 调用MQTTClientInit初始化MQTT客户端。
- 配置MQTT建连参数结构体MQTTPacket_connectData。
示例代码:
/* network init and establish network to aliyun IoT platform */
NetworkInit(&n);
rc = NetworkConnect(&n, host, port);
printf("NetworkConnect %d\n", rc);
/* init mqtt client */
MQTTClientInit(&c, &n, 1000, buf, sizeof(buf), readbuf, sizeof(readbuf));
/* set the default message handler */
c.defaultMessageHandler = messageArrived;
/* set mqtt connect parameter */
MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
data.willFlag = 0;
data.MQTTVersion = 3;
data.clientID.cstring = clientId;
data.username.cstring = username;
data.password.cstring = password;
data.keepAliveInterval = 60;
data.cleansession = 1;
printf("Connecting to %s %d\n", host, port);
rc = MQTTConnect(&c, &data);
printf("MQTTConnect %d, Connect aliyun IoT Cloud Success!\n", rc);
- 发布消息。
调用MQTTPublish()接口,向指定的自定义Topic发布自定义格式消息。
通信Topic介绍,请参见什么是Topic。
char *pubTopic = "/"EXAMPLE_PRODUCT_KEY"/"EXAMPLE_DEVICE_NAME"/user/update";
int cnt = 0;
unsigned int msgid = 0;
while (!toStop)
{
MQTTYield(&c, 1000);
if (++cnt % 5 == 0) {
MQTTMessage msg = {
QOS1,
0,
0,
0,
"Hello world",
strlen("Hello world"),
};
msg.id = ++msgid;
rc = MQTTPublish(&c, pubTopic, &msg);
printf("MQTTPublish %d, msgid %d\n", rc, msgid);
}
}
- 订阅Topic,获取云端下发的消息。
void messageArrived(MessageData* md)
{
MQTTMessage* message = md->message;
printf("%.*s\t", md->topicName->lenstring.len, md->topicName->lenstring.data);
printf("%.*s\n", (int)message->payloadlen, (char*)message->payload);
}
char *subTopic = "/"EXAMPLE_PRODUCT_KEY"/"EXAMPLE_DEVICE_NAME"/user/get";
printf("Subscribing to %s\n", subTopic);
rc = MQTTSubscribe(&c, subTopic, 1, messageArrived);
printf("MQTTSubscribe %d\n", rc);
关于设备、服务器和物联网平台的通信方式介绍,请参见通信方式概述。
- 将第一步下载的aiot_mqtt_sign.c文件和第二步编辑的文件放到../paho.mqtt.embedded-c/MQTTClient-C/samples/linux中,然后编译工程。
示例代码
使用Demo代码程序接入物联网平台。
- 下载Demo包,并解压缩。
解压缩后,代码包里有以下两个文件:
文件 |
说明 |
aiot_mqtt_sign.c |
该文件中的代码用于生成MQTT建连参数。aiot_c_demo.c运行时,会调用该文件中定义的aiotMqttSign()函数,计算出连接参数username、password和clientId。
|
aiot_c_demo.c |
该文件包含设备与物联网平台连接和通信的逻辑代码。 |
- 在aiot_c_demo.c中,将设备信息修改为您的设备信息。
- 将aiot_mqtt_sign.c和已修改的aiot_c_demo.c文件放到Paho工程的目录../paho.mqtt.embedded-c/MQTTClient-C/samples/linux中。
- 编译工程,并运行程序。
有两种方法可以编译出可执行的程序:
- 使用CMake。
- 在/paho.mqtt.embedded-c/MQTTClient-C/samples/linux目录下的CMakeLists.txt文件中,增加aiot_c_demo.c和aiot_mqtt_sign.c。
修改后的CMakeLists.txt文件内容如下。
add_executable(
stdoutsubc
stdoutsub.c
)
add_executable(
aiot_c_demo
aiot_c_demo.c
aiot_mqtt_sign.c
)
target_link_libraries(stdoutsubc paho-embed-mqtt3cc paho-embed-mqtt3c)
target_include_directories(stdoutsubc PRIVATE "../../src" "../../src/linux")
target_compile_definitions(stdoutsubc PRIVATE MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h)
target_link_libraries(aiot_c_demo paho-embed-mqtt3cc paho-embed-mqtt3c)
target_include_directories(aiot_c_demo PRIVATE "../../src" "../../src/linux")
target_compile_definitions(aiot_c_demo PRIVATE MQTTCLIENT_PLATFORM_HEADER=MQTTLinux.h)
- 回到/paho.mqtt.embedded-c目录,执行以下命令,完成编译。
mkdir build.paho
cd build.paho
cmake ..
make
- 编译完成后,在/paho.mqtt.embedded-c/build.paho目录下执行以下命令,运行程序。
./MQTTClient-C/samples/linux/aiot_c_demo
- 使用build.sh。
- 打开/paho.mqtt.embedded-c/MQTTClient-C/samples/linux目录下的build.sh文件。
- 将build.sh中的
stdoutsub.c
替换为aiot_mqtt_sign.c aiot_c_demo.c
,-o stdoutsub
替换为-o aiot_c_demo
,然后保存build.sh。
- 修改完成后,在/paho.mqtt.embedded-c/MQTTClient-C/samples/linux目录下,执行命令
./build.sh
,完成编译。
完成编译后,生成aiot_c_demo可执行文件。
- 执行命令
./aiot_c_demo
,运行程序。
运行成功,接入物联网平台的本地日志如下:
clientid: paho_mqtt&a11xsrW****|timestamp=2524608000000,_v=sdk-c-1.0.0,securemode=3,signmethod=hmacsha256,lan=C|
username: paho_mqtt&a11xsrW****
password: 36E955DC3D9D012EF62C80657A29328B1CFAE6186C611A17DC7939FAB637****
NetworkConnect 0
Connecting to a11xsrW****.iot-as-mqtt.cn-shanghai.aliyuncs.com 443
MQTTConnect 0, Connect aliyun IoT Cloud Success!
Subscribing to /a11xsrW****/paho_mqtt/user/get
MQTTSubscribe 0
MQTTPublish 0, msgid 1
MQTTPublish 0, msgid 2
MQTTPublish 0, msgid 3
MQTTPublish 0, msgid 4
MQTTPublish 0, msgid 5
...
登录物联网平台控制台,可查看设备状态和日志。
- 选择,可看到该设备的状态显示为在线。
- 选择,可查看云端运行日志和设备本地日志日志。详细内容,请参见云端运行日志、设备本地日志。
错误码
如果设备通过MQTT协议接入物联网平台失败,请根据错误码排查问题。服务端错误码说明,请参见错误排查。