C Demo使用说明
概述
本文以C语言为例,介绍通过MQTTS/MQTT协议接入平台,基于平台接口实现“属性上报”、“订阅接收命令”等功能。
本文中使用的代码为样例代码,仅用于体验平台通信功能,如需进行商用,可以参考资源获取获取对应语言的IoT Device SDK进行集成。
前提条件
准备工作
- 编译openssl库
- 访问openssl官网(https://www.openssl.org/source/)下载最新版本openssl(如openssl-1.1.1d.tar.gz),上传到linux编译机上(以上传到/home/test目录下为例),并使用如下命令解压:
tar -zxvf openssl-1.1.1d.tar.gz
- 配置生成makefile文件。
运行如下配置命令:
./config shared --prefix=/home/test/openssl --openssldir=/home/test/openssl/ssl
其中“prefix”是安装目录,“openssldir”是配置文件目录,“shared”作用是生成动态链接库(即.so库) 。
如果编译有问题,配置命令加上no-asm(表示不使用汇编代码)
./config no-asm shared --prefix=/home/test/openssl --openssldir=/home/test/openssl/ssl
- 编译出库。
在openssl源码目录下,运行make depend命令。
make depend
再运行make命令进行编译。
make
安装openssl。
make install
在配置的openssl安装目录下home/test/openssl找到lib目录,有生成的库文件:
“libcrypto.so.1.1”、“libssl.so.1.1”和软链接“libcrypto.so”、“libssl.so”,请将这些文件复制到demo的lib文件夹下(同时将/home/test/openssl/include/openssl里的内容复制到demo的include/openssl下)。
注:有的编译工具是32位的,如果在64位的linux机器上使用,这时只要将Makefile中的-m64都删除,再进行编译即可。
- 访问openssl官网(https://www.openssl.org/source/)下载最新版本openssl(如openssl-1.1.1d.tar.gz),上传到linux编译机上(以上传到/home/test目录下为例),并使用如下命令解压:
- 编译paho库文件
- 访问github下载地址:https://github.com/eclipse/paho.mqtt.c,下载paho.mqtt.c源码。
- 解压后上传到linux编译机。
- 修改makefile
- 编译
- 执行清空命令
make clean
- 执行编译命令
make
- 执行清空命令
- 编译完成后,可以在build/output目录下看到编译成功的库。
- 复制paho库文件。
当前SDK仅用到了libpaho-mqtt3as,请将“libpaho-mqtt3as.so”和“libpaho-mqtt3as.so.1”文件复制到demo的lib文件夹下。(同时回到paho源代码路径,进入src目录,将MQTTAsync.h、MQTTClient.h、MQTTClientPersistence.h、MQTTProperties.h、MQTTReasonCodes.h、MQTTSubscribeOpts.h复制到demo的include/base文件夹下)。
有的paho版本会有 MQTTExportDeclarations.h 头文件,建议可以将MQTT相关的头文件都添加进去。
导入代码样例
- 下载quickStart(C)样例。
- 将代码复制到linux运行环境中。可以看到代码文件层级如下图。
代码目录简述:
- src:源码目录
mqtt_c_demo:demo核心源码;
util/string_util.c:工具资源文件;
- conf:证书目录
rootcert.pem:设备校验平台身份的证书,用于设备侧接入物联网平台登录鉴权使用;如果对接的IoTDA版本非基础版,请将该证书文件中c/ap-southeast-1-device-client-rootcert.pem文件内容复制到conf/rootcert.pem文件中。
- include: 头文件目录
base目录:存放依赖的paho头文件
openssl目录:存放依赖的openssl头文件
util目录:存放依赖的工具资源头文件
- lib:依赖库文件
libcrypto.so*/libssl.so*: openssl库文件
libpaho-mqtt3as.so*: paho库文件
- Makefile:Makefile文件
- src:源码目录
建立连接
设备或网关在接入物联网平台时首先需要和平台建立连接,从而将设备或网关与平台进行关联。开发者通过传入设备信息,将设备或网关连接到物联网平台。
- 设置参数。
char *uri = "ssl://iot-mqtts.cn-north-4.myhuaweicloud.com:8883"; int port = 8883; char *username = "********"; //deviceId char *password = "********";
注意:MQTTS为8883端口接入,如果使用MQTT协议接入,url为:tcp://域名空间:1883, port为1883,其中域名空间参考平台对接信息获取,。心跳时间默认设置为120秒,用户如果想修改,可以修改代码中的“keepAliveInterval ”参数,心跳时间范围具体可参考使用限制。
- 连接。
- 在Makefile的第15行最后添加 -lm ,执行make进行编译。如果是32位的操作系统,请删除Makefile中的"-m64"。
- 执行export LD_LIBRARY_PATH=./lib/加载库文件。
- 运行./MQTT_Demo.o。
//connect int ret = mqtt_connect(); if (ret != 0) { printf("connect failed, result %d\n", ret); }
- 连接成功后,打印“connect success”,同时在控制台可看到设备已在线。
图1 设备列表-设备在线
注:如果连接失败,在mqtt_connect_failure函数中已实现退避重连,代码样例如下:
void mqtt_connect_failure(void *context, MQTTAsync_failureData *response) { retryTimes++; printf("connect failed: messageId %d, code %d, message %s\n", response->token, response->code, response->message); //退避重连 int lowBound = defaultBackoff * 0.8; int highBound = defaultBackoff * 1.2; int randomBackOff = rand() % (highBound - lowBound + 1); long backOffWithJitter = (int)(pow(2.0, (double)retryTimes) - 1) * (randomBackOff + lowBound); long waitTImeUntilNextRetry = (int)(minBackoff + backOffWithJitter) > maxBackoff ? (minBackoff + backOffWithJitter) : maxBackoff; TimeSleep(waitTImeUntilNextRetry); //connect int ret = mqtt_connect(); if (ret != 0) { printf("connect failed, result %d\n", ret); } }
订阅Topic
订阅某Topic的设备才能接收broker发布的关于该Topic的消息,关于平台预置Topic可参考Topic定义。
订阅Topic:
//subcribe char *cmd_topic = combine_strings(3, "$oc/devices/", username, "/sys/commands/#"); ret = mqtt_subscribe(cmd_topic); free(cmd_topic); cmd_topic = NULL; if (ret < 0) { printf("subscribe topic error, result %d\n", ret); }
订阅成功后,demo中会打印“subscribe success”字样。
属性上报
属性上报是指设备主动向平台上报自己的属性,更多信息请参考设备属性上报。
//publish data char *payload = "{\"services\":[{\"service_id\":\"parameter\",\"properties\":{\"Load\":\"123\",\"ImbA_strVal\":\"456\"}}]}"; char *report_topic = combine_strings(3, "$oc/devices/", username, "/sys/properties/report"); ret = mqtt_publish(report_topic, payload); free(report_topic); report_topic = NULL; if (ret < 0) { printf("publish data error, result %d\n", ret); }
设备上报属性成功后,demo中会打印“publish success”字样。
同时在“设备详情”页面查看到上报的属性:
如果在“设备详情”页面没有最新上报数据,请修改产品模型中服务和属性的内容,确保设备上报的服务/属性和产品模型中的服务/属性一致,或者进入 页面,删除所有服务。
接收下发命令
订阅了命令Topic后,可以在控制台下发同步命令。详情请参考MQTT设备同步命令下发。
命令下发后,demo中接收到命令:
demo中接收命令的代码为:
//receive message from the server int mqtt_message_arrive(void *context, char *topicName, int topicLen, MQTTAsync_message *message) { printf( "mqtt_message_arrive() success, the topic is %s, the payload is %s \n", topicName, message->payload); return 1; //can not return 0 here, otherwise the message won't update or something wrong would happen }
由于是同步命令需要端侧回复响应可参考接口。