更新时间:2024-12-25 GMT+08:00

C Demo使用说明

概述

本文以C语言为例,介绍通过MQTTS/MQTT协议接入平台,基于平台接口实现“属性上报”“订阅接收命令”等功能。

本文中使用的代码为样例代码,仅用于体验平台通信功能,如需进行商用,可以参考资源获取获取对应语言的IoT Device SDK进行集成。

前提条件

准备工作

  • 编译openssl库
    1. 访问openssl官网(https://www.openssl.org/source/)下载最新版本openssl(如openssl-1.1.1d.tar.gz),上传到linux编译机上(以上传到/home/test目录下为例),并使用如下命令解压:
      tar -zxvf openssl-1.1.1d.tar.gz
    2. 配置生成makefile文件。
      执行以下命令进入openssl源码目录
      cd openssl-1.1.1d
      运行如下配置命令:
      ./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

    3. 编译出库。

      在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都删除,再进行编译即可。

  • 编译paho库文件
    1. 访问github下载地址:https://github.com/eclipse/paho.mqtt.c,下载paho.mqtt.c源码。
    2. 解压后上传到linux编译机。
    3. 修改makefile
      1. 通过如下命令进行编辑Makefile
        vim Makefile
      2. 查找字符串
        /DOXYGEN_COMMAND =
      3. 在/DOXYGEN_COMMAND =doxygen的下一行添加下面两行(自定义的openssl的头文件和库文件)
        CFLAGS += -I/home/test/openssl/include
        LDFLAGS += -L/home/test/openssl/lib -lrt

      4. 把如下图的CCDLAGS_SO、LDFLAGS_CS、LDFLAGS_AS、FLAGS_EXES的openssl地址都改成对应的地址

    4. 编译
      1. 执行清空命令
        make clean
      2. 执行编译命令
        make
    5. 编译完成后,可以在build/output目录下看到编译成功的库。

    6. 复制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相关的头文件都添加进去。

导入代码样例

  1. 下载quickStart(C)样例。
  2. 将代码复制到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文件

建立连接

设备或网关在接入物联网平台时首先需要和平台建立连接,从而将设备或网关与平台进行关联。开发者通过传入设备信息,将设备或网关连接到物联网平台。

  1. 设置参数。
    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 ”参数,心跳时间范围具体可参考使用限制

  2. 连接。
    • 在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);
      }
  3. 连接成功后,打印“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”字样。

同时在“设备详情”页面查看到上报的属性:

图2 查看上报数据-parameter

如果在“设备详情”页面没有最新上报数据,请确认设备上报的服务/属性和产品模型中的服务/属性一致。

接收下发命令

订阅了命令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
}

由于是同步命令需要端侧回复响应可参考接口