如果需要打印到系统日志文件中,可以参考demo中的myPrintLog函数中设置的vsyslog(level, format, args)函数。同时需要引入头文件#include “syslog.h”,并且定义宏#define _SYS_LOG。
static void MyPrintLog(int level, char *format, va_list args)
{
vprintf(format, args);
/*
* if you want to printf log in system log files,you can do this:
* vsyslog(level, format, args);
*/
}
void main() {
IOTA_SetPrintLogCallback(MyPrintLog); // 设置日志打印
}
DEBUG device_demo: this is m2m demo
DEBUG iota_datatrans: IOTA_M2MSendMsg() with payload ==> {
“request_id”: “demoIdToDeviceB”,
“to”: “deviceB”,
“from”: “deviceA”,
“content”: “hello deviceB”
}
DEBUG device_demo: Test_M2MSendMsg() ok, messageId 0
设备B:
INFO device_demo: HandleM2mMessageDown(), requestId: demoIdToDeviceB
INFO device_demo: HandleM2mMessageDown(), to: deviceB
INFO device_demo: HandleM2mMessageDown(), from: deviceA
INFO device_demo: HandleM2mMessageDown(), content: hello deviceB
English | 简体中文
huaweicloud-iot-device-sdk-c 开发指南
0.版本更新说明
如果设备使用老域名(iot-acc.cn-north-4.myhuaweicloud.com)接入,请使用 v0.5.0版本的SDK
2025/08/01
1.前言
本文通过实例讲述huaweicloud-iot-device-sdk-c(以下简称SDK)帮助设备用MQTT协议快速连接到华为物联网平台。2.SDK简介
2.1 功能支持
SDK面向运算、存储能力较强的嵌入式终端设备,开发者通过调用SDK接口,便可实现设备与物联网平台的上下行通讯。SDK当前支持的功能有:2.2 SDK目录结构
3.准备工作
3.1 环境信息
SDK需运行在Linux操作系统上,并安装好gcc(建议4.8及以上版本)。SDK依赖openssl库和paho库,如果开发者有自己的编译链,需要自行编译openssl/paho库文件。Linux通用的gcc编译步骤请参考章节3.2/3.3。3.2编译openssl库
1. 访问[openssl官网](https://www.openssl.org/source) ,下载openssl(推荐使用openssl-1.1.1h.tar.gz,在./generatingLib目录下有openssl安装包),上传到linux编译机上(以上传到目录/home/test为例),并使用如下命令解压:配置生成makefile文件 执行以下命令进入openssl源码目录:
运行如下配置命令:
其中“prefix”是自定义安装目录,“openssldir”是自定义配置文件目录,“shared”作用是生成动态链接库(即.so库)。
如果编译有问题配置命令加上no-asm(表示不使用汇编代码)
编译出库。 在openssl源码目录下,运行make depend命令添加依赖:
运行make命令开始编译:
再运行如下命令进行安装:
在配置的openssl安装目录下home/test/openssl找到lib目录,有生成的库文件:
libcrypto.so.1.1、libssl.so.1.1和软链接libcrypto.so、libssl.so,请将这些文件拷贝到SDK的lib文件夹下(同时将home/test/openssl/include底下的openssl文件夹拷贝到SDK的include目录下)。
若需要使用国密TLS,可访问国密版本openssl,安装方法同原生openssl。该版本当前基于openssl1.1.1s,兼容openssl各类原生接口,仍支持国际TLS。
3.3 编译paho库
1. 访问github下载地址https://github.com/eclipse/paho.mqtt.c, 下载paho.mqtt.c源码(建议下载release版本中1.3.9及之前的版本的Source code (tar.gz)文件,如果使用最新的版本,下方适配的文件中的行数可能会有所改变,以及需要拷贝的头文件按照最新版本增加)。解压后上传到linux编译机。
修改makefile
编译
编译完成后,可以在build/output目录下看到编译成功的库。
拷贝paho库文件 当前SDK仅用到了libpaho-mqtt3as,请将文件libpaho-mqtt3as.so、libpaho-mqtt3as.so.1和libpaho-mqtt3as.so.1.3拷贝到SDK的lib文件夹下(同时将paho源码目录下src文件夹里的头文件(MQTTAsync.h/MQTTClient.h/MQTTClientPersistence.h/MQTTProperties.h/MQTTReasonCodes.h/MQTTSubscribeOpts.h)拷贝到SDK的include/base目录下,注意:有的paho版本会有 MQTTExportDeclarations.h 头文件,建议可以将MQTT相关的头文件都添加进去)。
3.4 编译zlib库
1. 下载zlib源码https://github.com/madler/zlib/archive/v1.2.11.zip 通过如下命令解压缩:进入源码目录下:
配置生成makefile文件
执行makefile文件
拷贝so库文件 将源码目录下生成的libz.so、libz.so.1、libz.so.1.2.11拷贝到sdk的lib文件夹下。
3.5 编译华为安全函数库
1. 下载安全函数库源码https://gitee.com/openeuler/libboundscheck.git进入源码makefile同级目录,执行makefile文件
拷贝so库文件 将源码目录下生成的lib文件夹下的libboundscheck.so拷贝到sdk的lib文件夹下。
3.6 编译libssh库
1. 下载libssh源码https://www.libssh.org/files/0.10/libssh-0.10.4.tar.xz 通过如下命令解压缩:进入源码目录下:
编译库文件:
安装库:
拷贝so库文件和头文件 将源码目录下build/lib文件夹中生成的libssh.so、libssh.so.4、libssh.so.4.9.4拷贝到sdk的lib文件夹下。 将/usr/local/include下的libssh的整个头文件目录拷贝到sdk的include文件夹下。
3.7 编译libnopoll库
1. 下载nopoll源码http://www.aspl.es/nopoll/downloads/nopoll-0.4.8.b429.tar.gz 通过如下命令解压缩:进入源码目录下:
编译与安装
拷贝so库文件 通过上一步获取到的路径,将源码目录src/.libs下生成的libnopoll.so libnopoll.so.0 libnopoll.so.0.0.0拷贝到sdk的lib文件夹下。 将/usr/local/include下的nopoll的整个头文件目录拷贝到sdk的include文件夹下。
3.8 编译curl库
在generatingLib目录下执行以下命令, 注意--with-openssl后面换成自己的openssl安装路径:3.9 上传profile及注册设备
1. profile(产品模型)定义,具体详情可见:[物模型相关问题](https://support.huaweicloud.com/iothub_faq/iot_faq_01000.html)。点击“设备”->“所有设备”,点击右上角“注册设备”,选择产品所在的“资源空间”,选择上方创建的产品,填写设备标识码(一般是IMEI、MAC地址等),自定义“设备名称”,“密钥”如果不自定义,平台会自动生成。全部填写完毕后,点击“确定”。
可以直接复制设备秘钥,点击“保存并关闭”将自动将设备ID以及设备秘钥以txt文本形式下载到本地。
在IoTDA控制台界面。点击”设备“->“所有设备”,在最上方可看到该设备的状态是未激活。当设备上线一次后,退出未激活状态。
4.快速体验
1. 将SDK压缩包拷贝到Linux环境中,通过如下命令解压:进入到解压的文件夹下:
修改配置信息: 需要修改src/device_demo/device_demo.c文件中的如下参数:
g_serverIp:平台MQTT南向IP,可在IoTDA控制台的“总览”->“接入信息”中查看。 g_username:MQTT协议需要填写username,iot平台默认设备ID为username,设备ID是设备注册时返回的值。 g_secret:设备密钥,设备注册填写的值。
执行命令进行编译,推荐使用Makefile进行编译:
4.1 用Makefile进行编译:
4.2 用gn进行编译,先安装gn以及ninja工具,再进行编译:
运行:
5.1 加载库文件
5.2 执行如下命令:
在控制台上可以看到很多打印的日志: “login success”表示设备鉴权成功
“MqttBase_onSubscribeSuccess”表示订阅成功
“MqttBase_onPublishSuccess”表示发布数据成功
查看设备运行情况:
5.设备初始化
直连设备连接demo可见代码:./demos/device_demo/basic_test.c。证书获取: [证书资源](https://support.huaweicloud.com/devg-iothub/iot_02_1004.html#section3) 。5.1 底层数据初始化
在发起业务前,需要先初始化Agent Lite相关资源,调用API接口 IOTA_Init(HW_CHAR *workPath),初始化Agent Lite资源,其中CA证书存放路径为:${workPath}/rootcert.pem。具体API接口的参数使用请参考Agent Lite API接口文档。可参考demo中main()方法对IOTA_Init()的调用。在./include/base/mqtt_base.h文件中,有MQTT连接相关参数:
5.2 设置日志打印函数
SDK以日志回调函数的方式供开发者使用,开发者可以根据自己的需求调用IOTA_SetPrintLogCallback函数设置。具体API接口的参数使用请参考SDK API接口文档。5.3 初始化连接参数
设备连接到IoT平台之前,需配置平台的地址、端口、设备Id及设备密钥。可以参考demo中main()方法中调用的setAuthConfig()函数。5.4 回调函数配置
SDK针对设备鉴权成功/失败、设备断链成功/失败、设备订阅消息成功/失败、设备发布消息成功/失败、设备接收消息/命令等动作,以回调函数的方式供开发者调用,开发者可以针对不同的事件设置回调函数来实现业务处理逻辑。5.5 设备鉴权
回调函数设置完毕后,可以调用鉴权函数。可以参考./demos/device_demo/basic_test.c中对该接口的调用:鉴权接口调用成功后,会打印“login success”的字样(建议鉴权成功后再进行数据上报,可以鉴权后sleep几秒钟,或者在鉴权成功的回调函数里进行业务处理):
可以通过ctrl + c停止程序运行,程序停止后最长等待1.5个心跳时间,可以在控制台界面上查看设备已离线。
5.6 订阅Topic
当连接成功时,华为云平台会自动订阅qos(通信质量)为0的系统Topic。若要使用自定义Topic,需要调用订阅自函数进行Topic订阅。订阅所有系统Topic:
订阅自定义的topic:
若订阅一个主题为“test/sdk/c”,通信质量为1的topic:
值得注意的是,当设备断链后重新连接,需要客户再次订阅自定义topic。可以在连接成功后的回调函数中编写代码,再次订阅。以下为示例:
5.7 编译并运行程序
1. 将huaweicloud-iot-device-sdk-c-master.zip压缩包拷贝到Linux环境中,通过如下命令解压:unzip huaweicloud-iot-device-sdk-c-master.zip
进入到文件夹下:
cd huaweicloud-iot-device-sdk-c-master
执行make命令进行编译:
make
运行SDK Demo
./MQTT_Demo
ps:如果运行./demos/文件中的demo,在SDK根目录输入 ./{文件名}。
6.SDK功能
以下是部分接口的使用指导,详细的功能请参考主目录下的**API文档**。6.1 生成SDK库文件
如果想生成so文件,可以修改Makefile的内容(可以本地用记事本打开后上传到Linux环境,也可以在Linux环境上直接通过"vim Makefile"修改,按"i"键编辑,编辑完毕后用"wq!”保存):在CFLAGS中添加-shared -fPIC。同时,把CFLAGS中的-pie -fPIE 删除。
把编译后的TARGET文件由MQTT_Demo修改为libHWMQTT.so(名称可以自定义)
修改完毕后执行make即可生成libHWMQTT.so文件
6.2 设备接入
设备连接到IoT平台,分为设备密钥认证与证书认证。需配置平台的地址(${address})、端口(${port})、设备Id(${deviceId})及设备密钥\证书私钥(${password}、${deviceKyePassword})。Demo使用示例: [./demos/device_demo/basic_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/device_demo/basic_test.c)。参考文档:密钥认证、证书认证。
Demo编译及运行:
设备密钥认证:
设备证书认证:
华为物联网平台支持设备使用自己的X.509证书进行设备接入认证。接入步骤请参考:
连接回调函数:
Topic订阅:
设备建链成功或设备重新建链(断线重连),都需要进行Topic订阅。推荐在建链成功后的回调函数中进行。
设备断链:
6.3 设备消息上报、下发
设备鉴权通过后, 可以调用SDK的“设备消息上报”接口上报数据。参考文档:消息上报、消息下发。
Demo示例:./demos/device_demo/message_test.c。Demo使用方式如下:
自定义Topic消息上报、下发:
可以通过该接口上报自定义格式的Topic及消息。平台收到的数据可以转发到其他服务或者推送到应用服务器。
自定义Topic消息上报:
HW_API_FUNC HW_INT IOTA_RawTopicMessageReport(HW_CHAR *topic, HW_CHAR *payload, int qos, void *context);其中topic是客户自定义的Topic;payload为要上报的内容;qos为通信质量,平台支持为0或1。可以参考demo中对该函数对该接口的调用。
平台下发自定义消息:
HW_API_FUNC HW_VOID IOTA_SetUndefinedMessageCallback(PFN_MESSAGE_CALLBACK_HANDLER callbackHandler);当已经订阅但并非平台设置的Topic会触发该回调函数。若是平台设置的以$oc/devices/{device_id}/user/开头的自定义消息,将不会触发该函数,转而触发IOTA_SetUserTopicMsgCallback()中设置的函数指针。具体使用可以参考demo中对该函数对该接口的调用。
系统Topic消息上报、下发:
可以通过该接口上报系统格式的Topic及消息。平台收到的数据可以转发到其他服务或者推送到应用服务器。
系统消息上报:
HW_API_FUNC HW_INT IOTA_MessageDataReport(ST_IOTA_MESS_REP_INFO mass, void *context);通过该接口上报的数据平台不解析,数据可以转发到其他服务或者推送到应用服务器。mass是消息结构体,包括:需要上报的设备id(object_device_id),消息名称(name),消息ID(id),上报内容(content);topicParas是自定义topic的参数,当为NULL时用平台默认topic上报数据。具体参数说明请查看API文档,可以参考demo中对该函数对该接口的调用。
平台下发系统消息:
HW_API_FUNC HW_VOID IOTA_SetMessageCallback(PFN_MESSAGE_CALLBACK_HANDLER callbackHandler);其中callbackHandler为函数指针,当系统下发topic为: $oc/devices/{device_id}/sys/messages/down 的消息时会运行该函数。具体参数说明请查看API文档,可以参考demo中对该函数对该接口的调用。
6.4 属性上报下发
设备鉴权通过后, 可以调用SDK的“设备属性上报”接口上报数据。参考文档:设备属性上报、平台属性下发。
Demo示例:./demos/device_demo/properties_test.c。Demo使用方式如下:
在示例中,使用的物模型为最佳实践中智慧烟感物模型,可根据文档进行物模型配置:
该物模型定义了一个服务,服务ID为 Smoke。
在该服务ID中定义了一个可读可写的整型(int)属性 Smoke_Value。
设备属性上报接口:
HW_INT IOTA_PropertiesReport(ST_IOTA_SERVICE_DATA_INFO pServiceData[], HW_INT serviceNum, HW_INT compressFlag, void *context)通过该接口上报的数据平台会解析,并且结构体中的数据需跟profile中定义的属性保持一致,ST_IOTA_SERVICE_DATA_INFO为结构体数组,可以同时上报多个服务,serviceNum为上报的服务个数。入参具体说明请参考API文档,demo中的Test_propertiesReport函数演示了对该接口的调用方法。
上报成功后可在平台设备详情界面查看最新一次上报的物模型值。
属性下发回调函数接口:
其中callbackHandler为函数指针,当属性下发时会运行该函数。具体参数说明请查看API文档,可以参考demo中对该函数对该接口的调用。
6.5 命令下发
设备鉴权通过并且配置了相关回调函数后,可以接受平台命令(SDK已自动实现相关TOPIC的订阅)。注意:平台采用了隐式订阅的功能,对于下行的系统topic,设备无需订阅,平台默认该设备订阅了qos为0的系统topic。如果需要qos为1的下行系统topic,需要设备自行调用订阅接口来订阅。参考文档:命令下发。
Demo示例:./demos/device_demo/command_test.c。Demo使用方式如下:
在示例中,使用的物模型为最佳实践中智慧烟感物模型,可根据文档进行物模型配置:
在物模型中创建一个命令名称为 Smoke_Control_Beep ;下发命令参数为string类型的枚举数据,名为Beep; 新增命令响应参数为int型,名为 Beep_State 的物模型。
设备接收命令下发(profile中定义的命令):
HW_API_FUNC HW_VOID IOTA_SetCmdCallback(PFN_CMD_CALLBACK_HANDLER callbackHandler)通过该接口设置命令回调函数,当云端下发命令或端侧规则触发执行命令时,定义的函数会被调用。以上述物模型为例:注册回调函数:
6.6 断线重连
在调用IOTA_DefaultCallbackInit()函数时,SDK会自动装载一个断线重连代码。可在文件[./src/agentlite/iota_defaultCallback.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/src/agentlite/iota_defaultCallback.c)中查看。默认断线重连初始化:
如若客户需要自行实现,可参考:./demos/device_demo/reconnection_test.c中的重连示例。
demo配置&运行:
IOTA_SetProtocolCallback() 可以设置建链失败、非主动断链后的回调函数。当设备断链后会到该回调函数内进行重连。可以第一时间感知到MQTT的断连,客户可自行编写重连机制,以下为示例。
6.7 设备影子
设备影子是一个JSON格式的数据,用于存储设备的在线状态、设备最近一次上报的设备属性值,设备可以获取上报的设备属性值。设备影子示例代码:[./demos/device_demo/shadow_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/device_demo/shadow_test.c)。设备获取设备影子:
HW_INT IOTA_GetDeviceShadow(HW_CHAR *requestId, HW_CHAR *object_device_id, HW_CHAR *service_id, void *context)通过该接口获取设备影子,平台接收到后会下发最近一次上报的属性值。requestId为请求的唯一标识,用于区分上报;object_device_id为目标设备id;service_id为物模型服务id,如果为NULL,则获取所有。入参具体说明请参考API文档,demo中演示了对该接口的调用方法。
影子设备下发回调函数:
平台设置、获取设备影子:
可见[属性上报下发](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/ https:/support.huaweicloud.com/api-iothub/iot_06_v5_3010.html)中的:平台获取查询设备属性、平台设置设备属性实现。
6.8 时间同步
设备侧可通过时间同步功能获取平台的时间,从而同步平台与设备的时间。时间同步代码示例:[./demos/device_demo/time_sync_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/device_demo/time_sync_test.c)。发起时间同步请求:
HW_API_FUNC HW_INT IOTA_GetNTPTime(void *context);可通过该接口获取平台时间。context为上下文传递指针,一般设置为NULL。下面为对接口的使用示例。
平台下发时间同步回调:
HW_API_FUNC HW_VOID IOTA_SetNtpCallback(PFN_CMD_CALLBACK_HANDLER callbackHandler)通过该接口设置时间同步回调函数,当云端下发时间同步值是触发设定的函数指针,定义的函数会被调用。下面为对该接口的使用示例。6.9 软固件升级(OTA)
用于与平台配合下载OTA升级包。实现了软固件下载,平台使用文档可见:[使用文档](https://support.huaweicloud.com/bestpractice-iothub/iot_bp_0039.html)。相关API接口上传参数可见:[API文档](https://support.huaweicloud.com/api-iothub/iot_06_v5_3028.html)。在SDK中,可以一键加载OTA功能,该功能可以把平台下发的软固包下载到SDK根目录下,从而实现安装包的下载。一键加载OTA的接口为:
若是需要自定义OTA升级代码,可见OTA代码示例:./demos/device_demo/ota_test.c。
Demo使用&编译:
平台下发获取版本信息通知 :
HW_API_FUNC HW_VOID IOTA_SetEvenOtaVersionUpCallback(PFN_OTAVERSION_CALLBACK_HANDLER_SPECIFY callbackHandler)该接口用于配置平台软固件下载的回调函数,当平台下发获取版本信息通知时,会运行设置的函数指针。具体实现方式可见:./demos/device_demo/ota_test.c。
设备上报软固件版本信息 :
HW_API_FUNC HW_INT IOTA_OTAVersionReport(ST_IOTA_OTA_VERSION_INFO otaVersionInfo, void *context)该函数用于上报软固件版本信息。otaVersionInfo为结构体,包括软件版本、固件版本等参数。具体使用方式可见:./demos/device_demo/ota_test.c。
物联网平台向设备侧下发升级通知:
HW_API_FUNC HW_VOID IOTA_SetEvenOtaUrlResponseCallback(PFN_OTAURL_CALLBACK_HANDLER_SPECIFY callbackHandler)该接口用于配置平台软固件下载的回调函数,当物联网平台向设备侧下发升级通知时,会运行设置的函数指针。具体实现方式可见:./demos/device_demo/ota_test.c。
设备上报升级状态:
HW_API_FUNC HW_INT IOTA_OTAStatusReport(ST_IOTA_UPGRADE_STATUS_INFO otaStatusInfo, void *context)该函数用于上报设备升级是否成功。otaStatusInfo为结构体,包括结果描述、结果返回值、升级版本等参数。具体API参数说明请见:API文档。
6.10 文件上传\下载
支持设备将运行日志,配置信息等文件上传至平台,便于用户进行日志分析、故障定位、设备数据备份等。平台文件上传下载配置可见:[文件上传](https://support.huaweicloud.com/usermanual-iothub/iot_01_0033.html)。设备侧API可见:[文件上传\下载API](https://support.huaweicloud.com/api-iothub/iot_06_v5_3033.html)。需要注意的是,该demo实现的是非自定义域名OBS存储配置。
使用该功能前,需要在IoTDA控制台中添加文件上传OBS桶, 可在设备 -> 所有设备 -> 文件上传中配置。
Demo路径:./demos/device_demo/file_up_down_test.c。使用&编译如下:
获取文件上传URL:
HW_API_FUNC HW_INT IOTA_GetUploadFileUrl(const ST_IOTA_UPLOAD_FILE *upload, void *context)该函数用于获取文件上传URL。upload为结构体,包括上传到OBS中的文件名称、文件hash值、文件大小(如果为0则默认为)等参数。具体API参数说明请见:API文档。
获取文件下载URL:
HW_API_FUNC HW_INT IOTA_GetDownloadFileUrl(const ST_IOTA_UPLOAD_FILE *upload, void *context)该函数用于获取文件下载URL。upload为结构体,包括上传到OBS中的文件名称、文件hash值、文件大小(如果为0则默认为)等参数。具体API参数说明请见:API文档。
文件上传下载回调函数:
HW_API_FUNC HW_INT IOTA_SetEvenFileManagerCallback(ST_IOTA_UPGRADE_STATUS_INFO otaStatusInfo, void *context)该接口用于配置平台软固件下载的回调函数,当平台下发文件上传下载的URL时,会运行该函数。
上报文件上传结果:
HW_API_FUNC HW_INT IOTA_DownloadFileResultReport(char *object_device_id, char *object_name, int result_code, int status_code, char *status_description)该接口用于上报文件上传结果。其中object_device_id为设备id,为空时默认为连接的设备;object_name为OBS中存储的文件名;result_code为上传结果,为0成功,1失败;status_code为OBS返回的状态码;status_description为OBS返回的描述。具体使用请见demo。
上报文件成功后可以在OBS中查看到上传的文件。
上报文件下载结果:
HW_API_FUNC HW_INT IOTA_UploadFileResultReport(char *object_device_id, char *object_name, int result_code, int status_code, char *status_description)该接口用于上报文件下载结果。其中object_device_id为设备id,为空时默认为连接的设备;object_name为OBS中存储的文件名;result_code为下载结果,为0成功,1失败;status_code为OBS返回的状态码;status_description为OBS返回的描述。
demo运行成功后:
6.11 泛协议&网桥
泛协议demo可见./demos/bridge_demo/目录下的文件,其中[bridge_server_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/bridge_demo/bridge_server_test.c)为网桥设备相关demo,如若使用泛协议,可以在ProcessMessageFromClient()接口处理传入的数据,把传入的数据转换成MQTT协议,再与平台通信。bidge_client_test.c文件中为TCP客户端示例,当输入对应的数据时,会传输到网关,网关解析后再上报到平台。配置&编译demo:
网关常用接口如下:
网桥相关API接口可见./include/agentlite/iota_bridge.h,具体使用方式请看demo。
6.12 国密TLS接入
当前SDK已支持国密TLS方式接入并进行数据传输。若需要采用国密通信,需要下载国密版本的openssl,具体可参考[3.2 编译openssl库](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/#3.2编译openssl库)第4点。使用国密TLS需要对paho_mqtt开源库中paho.mqtt.c-1.3.9/src/SSLSocket.c文件打补丁,补丁方法如下:
解压./generatingLib/gmtls.patch.zip得到补丁文件gmtls.patch
unzip ./generatingLib/gmtls.patch.zip
对paho.mqtt.c-1.3.9/src/SSLSocket.c文件进行打补丁
patch -b ./generatingLib/paho.mqtt.c-1.3.9/src/SSLSocket.c ./generatingLib/gmtls.patch
打完补丁后,可以查看paho.mqtt.c-1.3.9/src/SSLSocket.c中是否存在上述证书路径字段。若使用口令登录的方式则不需要填写对应的签名证书、私钥和加密证书、私钥路径,若使用证书登录的方式则需要填写对应文件的路径,并使用绝对路径来进行访问。修改完成后重新编译paho库即可。
6.13 异常存储
SDK提供断线后消息发送存储功能,对于上报失败的数据存储到内存中,当连接成功后再发送。存储条数可在:[./include/base/mqtt_base.h](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/include/base/mqtt_base.h)中可以通过设置 MAX_BUFFERED_MESSAGES 来修改存储最大条数,默认为3。当不使用该功能时,可以设置为负数。6.14 MQTT5.0
如果想使用MQTT5.0协议(默认为MQTT3.1.1),需要在文件MakeFile 中取消对 MQTTV5 := 1 的注释。可以在.[/demos/device_demo/mqttV5_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/device_demo/mqttV5_test.c)中查看使用示例。运行及编译demo:
MQTT5.0主要是在消息头部新增 Payload。支持在头部添加用户属性、 对比数据 、 主题别名、全新开始标识与会话过期间隔功能。
用户属性 (User Properties)
用户属性(User Properties)其实是一种自定义属性,允许用户向 MQTT 消息添加自己的元数据,传输额外的自定义信息以扩充更多应用场景。
使用示例:
对比数据 (Correlation Data)
在消息上报时携带,可用于标识异步数据请求与响应匹配。 请求消息中携带一个特征字段,响应方在响应时将收到的字段原封不动地返回,请求方在收到响应消息时可以根据其中的特征字段来匹配相应的请求。
使用示例:
主题别名 (Topic Alias)
MQTT v5.0 中新加入的与主题名(topic)相关的特性。它允许用户将主题长度较长且常用的主题名缩减为一个双字节整数来降低发布消息时的带宽消耗。 它是一个双字节整数,并将作为属性字段,编码在PUBLISH报文中可变报头部分。并且在实际应用中,将受到CONNECT报文和CONNACK报文中“主题别名最大长度”属性的限制 。
内容类型(Content Type)
在 MQTT 5.0 的所有报文类型中,该属性同样只存在于 PUBLISH 报文和 CONNECT 报文的遗嘱属性中。该属性存放的是 UTF-8 编码的字符串,用于描述遗嘱消息或 PUBLISH 消息的内容。 内容类型的一个比较典型的应用就是存放 MIME 类型,比如 text/plain 表示文本文件,audio/aac 表示音频文件。
6.15 MQTT_DEBUG功能
MQTT_DEBUG是用于打印底层MQTT连接参数LOG,若无出现底层连接问题,不建议打开。如果想使用 MQTT_DEBUG 功能,需要在文件./include/util/mqtt_base.h 中把 MQTT_TRACE_ON 的值改为1。 其中,MQTT_TRACE_LEVEL 是 MQTT_DEBUG 日志打印级别,默认为最高等级 MQTTASYNC_TRACE_MAXIMUM。日志打印级别说明:
LOG_FILE_ENABLE 为 1 时,的log就会输出到 LOG_FILE_NAME 设置的文件路径中。当 LOG_FILE_ENABLE 为 0 时,log会直接输出。
6.16 网关与子设备
网关设备:通过平台支持的协议,直接连接到平台的设备。子设备:针对未实现TCP/IP协议栈的设备,由于无法直接同物联网平台通信,它需要通过网关进行数据转发。当前仅支持通过mqtt协议直连到平台的设备作为网关设备。平台网关文档可见:[网关与子设备](https://support.huaweicloud.com/usermanual-iothub/iot_01_0052.html);demo可见SKD:./demos/gateway_demo/ 文件夹中的网关([gateway_server_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/gateway_demo/gateway_server_test.c))与子设备([gateway_client_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/gateway_demo/gateway_client_test.c))示例。编译及运行demo指导:
子设备上报属性
子设备可以通过网关批量设备属性上报接口进行数据上报,接口如下:
HW_INT IOTA_BatchPropertiesReport(ST_IOTA_DEVICE_DATA_INFO pDeviceData[], HW_INT deviceNum, HW_INT serviceLenList[])通过该接口上报的数据平台会解析,并且结构体中的数据需跟profile中定义的属性保持一致,ST_IOTA_DEVICE_DATA_INFO为结构体数组,可以同时上报多个子设备数据,每个子设备可以上报多个服务,deviceNum为上报的子设备个数,serviceLenList为每个子设备上报的服务个数。入参具体说明请参考API文档,demo中的Test_batchPropertiesReport函数演示了对该接口的调用方法。
上报数据:
平台可查看数据:
平台通知网关新增子设备
在平台处创建的子设备,通过事件接口下发数据。具体可见API:平台通知网关新增子设备。 设备收到平台下发数据后可以通过回调函数进行命令处理。请参考demo中IOTA_SetEvenSubDeviceCallback函数设置网关回调函数。配置接口如下:
HW_API_FUNC HW_VOID IOTA_SetEvenSubDeviceCallback(EVENT_CALLBACK_HANDLER_SPECIFY callbackHandler)当与网关相关的平台下发数据时,都会运行到接口所配置的函数中。比如说:平台通知网关子设备新增、平台通知网关子设备删除、网关更新子设备状态响应、关新增子设备请求响应、网关删除子设备请求响应。callbackHandler为函数指针。使用示例请见:./demos/gateway_demo/gateway_server_test.c。
平台通知网关删除子设备
在平台处删除的子设备,通过事件接口下发数据。可见API:平台通知网关删除子设备。 设备收到平台下发数据后可以通过回调函数进行命令处理。请参考demo中IOTA_SetEvenSubDeviceCallback函数设置网关回调函数。配置接口与平台通知网关新增子设备一致。使用示例请见:./demos/gateway_demo/gateway_server_test.c。
网关更新子设备状态 & 网关更新子设备状态响应
网关可以上报子设备是否在线,值得注意的是,子设备是否在线是由网关决定的。API接口为:网关更新子设备状态。Ps:若子设备显示未激活状态,只需要上线一次即可。
更新子设备状态接口如下:
HW_API_FUNC HW_VOID IOTA_UpdateSubDeviceStatus(ST_IOTA_DEVICE_STATUSES *device_statuses, HW_INT deviceNum, void *context)其中device_statuses为设备信息结构体,包括子设备id、状态等信息;deviceNum为上报的子设备个数。
demo运行:
状态响应可见平台通知网关新增子设备的相关配置。
网关新增子设备请求 & 网关新增子设备请求响应
网关可通过接口主动创建子设备,携带的数据API可见:网关新增子设备请求。使用示例请见:./demos/gateway_demo/gateway_server_test.c。
网关新增子设备请求接口如下:
HW_API_FUNC HW_INT IOTA_AddSubDevice(ST_IOTA_SUB_DEVICE_INFO *subDevicesInfo, HW_INT deviceNum, void *context)其中subDevicesInfo为存放新增子设备信息的结构体,具体包括子设备归属产品id、设备标识等信息;deviceNum为新增的子设备个数。
demo运行:
网关新增子设备请求响应可见平台通知网关新增子设备的相关配置。
网关删除子设备请求 & 网关删除子设备请求响应
网关可通过接口主动删除子设备,携带的数据API可见:网关删除子设备请求。使用示例请见:./demos/gateway_demo/gateway_server_test.c。
网关删除子设备请求接口如下:
HW_API_FUNC HW_INT IOTA_DelSubDevice(ST_IOTA_DEL_SUB_DEVICE *delSubDevices, HW_INT deviceNum, void *context)其中subDevicesInfo为存放需要删除子设备信息的结构体,具体包括子设备设备id等信息;deviceNum为要删除的子设备个数。
网关删除子设备请求响应可见平台通知网关新增子设备的相关配置。
6.17 远程配置
支持配置参数通过远程下发,SDK通过event/down接收相关信息,用户可通过IOTA_SetDeviceConfigCallback注册自定义的回调钩子函数,该回调函数会在接收到配置信息后进行处理相关数据。示例可见:[./demos/device_demo/device_config_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/device_demo/device_config_test.c)。编译及运行demo指导:
平台下发远程配置函数接口:
其中callbackHandler为函数指针,当平台下发远程配置时会运行该函数,使用文档:设备远程配置。具体参数说明请查看API文档,可以参考demo中对该函数对该接口的调用。
6.18 异常检测
当用户使用异常检测功能时,若开启如下功能:内存泄漏检测、异常端口检测、CPU使用率检测、磁盘空间检测、电池电量检测,可以查看SKD样例:[./demos/device_demo/sys_hal_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/device_demo/sys_hal_test.c),获取所使用的检测项数据。检测数据上报周期可以在include\agentlite\iota_datatrans.h中对宏DETECT_REPORT_FREQUENCY进行调整,默认为10分钟,单位为秒。[云平台配置使用说明参考](https://support.huaweicloud.com/usermanual-iothub/iot_01_0030_5.html)。编译及运行demo指导:
6.19 软总线功能
通过平台下发设备组,设备可通过软总线实现物物互联。IoTDA可以进行安全群组管理以及下发群成员之间通信的授信标识。进入IoTDA控制台,点击左侧“设备”->”群组”,新建子群组,“点击创建”进行创建鸿蒙软总线,自定义鸿蒙软总线名称。
创建软总线名称后进行绑定设备,在界面点击“绑定”,选择要绑定到该群组的设备,之后再点击状态中的小半圆,进行同步软总线信息。
用户可通过 IOTA_GetLatestSoftBusInfo主动获取设备软总线信息。当软总线更新时,会在影子下发的回调函数HandlePropertiesSet中获取版本。 编译及运行demo指导:
6.20 日志上传
日志上传示例为:[./src/device_demo/file_up_demo_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/src/device_demo/file_up_demo_test.c),将变量`uploadFilePath`修改为日志文件路径,启用IOTA_UploadFile(uploadFilePath, url, NULL);代码。即可开启日志上传,对应文件将被上传到obs中。具体接口可见:[文件上传、下载](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/#6.9 文件上传\下载)。
6.21 端侧规则引擎
端侧规则引擎示例:[./demos/device_demo/device_rule_test.c](/mirrors/huaweicloud-iot-device-sdk-c/tree/master/demos/device_demo/device_rule_test.c)。默认为关闭,若要使用,需要在Makefile中取消DEVICE_RULE_ENALBE与CONFIG_ENALBE_DEVICE_RULE_FILE_STORAGE的注释。编译及运行demo指导:
下发端侧规则。
端侧规则引擎使用需要先在平台配置,具体配置可见:端侧规则引擎。
在控制台中可以观察到当属性上报、
Smoke_value为”123”时,端侧规则触发执行, 从而调用HandleCommandRequest:如果是跨设备执行命令时,需要调用回调函数IOTA_SetDeviceRuleSendMsgCallback,用户需要自行实现以下功能:HandleDeviceRuleSendMsg,从中解析出命令并执行。
端侧规则引擎支持本地存储
当设备重启后若不再具备联网条件,将无法从云端拉取配置的端侧规则,进而导致设备端侧规则丢失。为满足该场景下不影响设备执行端侧规则,可以将云端配置的规则存储在文件中,设备重启后将从文件系统中读取规则。该特性要求设备支持文件系统。用户只需要提供一个路径给接口IOTA_EnableDeviceRuleStorage(该接口在./demos/device_demo/device_rule_test.c被调用),即可实现端侧规则本地存储。具体如下图,将include/agentlite/iota_datatrans.h中的宏定义DEVICE_RULE_FILE_PATH的值testdata.txt修改为自己的文件存储路径即可。
6.22 远程登录
使用SSH远程登录功能前,需参考3.6 编译libssh库和3.7 编译libnopoll库实现libssh和libnopoll库的编译,并且设备必须在线。平台操作可见:远程登录。SDK代码实现可见SDK:./demos/device_demo/remote_login_test.c。
值得注意的是:在该SDK中远程登录功能默认是关闭的,若是想要开启该功能,需要在Makefile中将以下注释打开。
编译及运行demo指导:
先运行demo,在IoTDA控制台, 选择”监控运维——远程登录——{自己的在线设备}——输入用户名密码——确认”
操作之后即可实现ssh远程登录。可输入命令进行交互。
6.23 边缘M2M功能
目前支持使用SDK对接边缘IoTEdge,边缘节点完成消息的中转到目标设备,从而实现M2M的功能。使用步骤如下:下载其中的plt-device-ca证书文件,将证书内容拷贝并替换sdk目录当中conf/rootcert.perm文件中的内容。
此证书用于设备校验边缘节点的身份。
假设源设备A和目标设备B的ID分别:tunnelDeviceA和tunnelDeviceB, 设备A向设备B发送”hello world”消息。 在A设备当中调用如下代码(demo可在main函数中调用):
在接收端(即B设备),会在回调函数HandleM2mMessageDown中打印接收的消息:
可以在终端日志中打印出如下信息: 设备A:
DEBUG device_demo: this is m2m demo DEBUG iota_datatrans: IOTA_M2MSendMsg() with payload ==> { “request_id”: “demoIdToDeviceB”, “to”: “deviceB”, “from”: “deviceA”, “content”: “hello deviceB” } DEBUG device_demo: Test_M2MSendMsg() ok, messageId 0
设备B:
INFO device_demo: HandleM2mMessageDown(), requestId: demoIdToDeviceB INFO device_demo: HandleM2mMessageDown(), to: deviceB INFO device_demo: HandleM2mMessageDown(), from: deviceA INFO device_demo: HandleM2mMessageDown(), content: hello deviceB
6.24 gn编译
gn编译一般用于鸿蒙系统中,SDK集成了gn编译的方法。具体使用如下:设定
在SDK目录:./build/BUILDCONFIG.gn中可以设定是否启用SDK功能。
编译
使用gn进行编译,先安装gn以及ninja工具,在根目录输入以下命令进行编译:
6.25 使用全局变量配置连接参数
SDK新版本支持通过全局变量配置连接参数,其中可配置的连接参数如下,值得注意的是,使用IOTA_ConnectConfigSet()时加载一次。若要禁止该功能,可以在MakeFile中对 "GLOBAL_VAR_CONFIG := 1" 进行注释。以Linux系统中配置为例:
6.26 设备发放
设备发放功能,可以将设备发放到不同的region,参考文档:设备发放示例。 注意:流程可参考“快速入门”中的各种接入示例,SDK已自动实现示例中的“引导设备”。详细的步骤可参考链接中的“用户指南”。设备发放主要分为两种发放方式,分别为手动注册发放与注册组发放。
设备发放示例可见:SDK目录:./demos/bootstrap_demo/ 。其中bootstrap_groups_test.c为注册组发放。bootstrap_test.c为手动注册发放。运行demo前,需要先在平台配置对应的发放策略。
设备发放手动发放配置:
设备发放自注册初始化配置:
设备发放获取发放IoTDA地址接口:
HW_API_FUNC HW_INT IOTA_Bootstrap(char *baseStrategyKeyword);通过该接口从IoTDP中获取IoTDA接入地址,若为注册组发放,会下发设备密钥。baseStrategyKeyword为需要上报的内容,若使用静态策略数据上报策略,baseStrategyKeyword为对应的策略标识,一般设置为NULL。可以参考demo中对该函数对该接口的调用。
设备发放下发设备IoTDA地址回调:
HW_API_FUNC HW_VOID IOTA_SetBootstrapCallback(PFN_BOOTSTRAP_CALLBACK_HANDLER callbackHandler);其中callbackHandler为函数指针,当设备发放下发时会运行该函数。可以参考demo中对该函数对该接口的调用。
当前,平台使用了 DigiCert Global Root CA. 和 GlobalSign Root CA - R3 两个权威CA签发的证书。conf目录下的证书默认是跟IoTDA的基础版域名绑定的。如果需要切换到其他IoTDA版本,请参考官方文档的 证书资源 章节。
6.27 智能站点异常检测
SDK支持智能站点的异常检测功能,默认关闭。支持智能站点 CVE漏洞库检测、恶意文件检测、不安全协议检测、 不安全功能检测、 进程异常检测。使用时需要将Makefile中的注释 #SECURITY_AWARENESS_ENABLE := 1打开,可以通过以下异常接口,上报数据。
智能站点异常检测示例可见:SDK目录:./demos/device_demo/report_anomaly_test.c 。运行demo前,需要先在平台开启异常检测功能,并打开Makefile中的注释 #SECURITY_AWARENESS_ENABLE := 1的注释。
编译及运行demo指导:
上报CVE漏洞库检测:
int IOTA_AnomalyCveValnerabilityReport(ANOMALY_CVE_VNLNERABILITY cveLoophole[], int contentNum)通过该接口可以上报CVE漏洞库数据。cveLoophole为需要上报的内容,contentNum为上报个数。可以参考demo中对该函数对该接口的调用。
上报恶意文件:
int IOTA_AnomalyFileReport(ANOMALY_MALICIOUS_FILE maliciousFile[], int contentNum)通过该接口可以上报恶意文件数据。maliciousFile为需要上报的内容,contentNum为上报个数。可以参考demo中对该函数对该接口的调用。
上报不安全协议:
int IOTA_AnomalyProtocolReport(ANOMALY_PROTOCOL unsafeProtocol[], int contentNum)通过该接口可以上报不安全协议数据。unsafeProtocol为需要上报的内容,contentNum为上报个数。可以参考demo中对该函数对该接口的调用。
上报不安全功能:
int IOTA_AnomalyUnsafeFunctionReport(ANOMALY_UNSAFE_FUNCTION unsafeFunction[], int contentNum)通过该接口可以上报不安全功能检测数据。unsafeFunction为需要上报的内容,contentNum为上报个数。可以参考demo中对该函数对该接口的调用。
上报进程异常数据:
int IOTA_AnomalyAbnormalProcessReport(ANOMALY_ABNORMAL_PROCES abnormalProcess[], int contentNum)通过该接口可以上报进程异常数据。abnormalProcess为需要上报的内容,contentNum为上报个数。可以参考demo中对该函数对该接口的调用。
7.常见问题
MQTT建链返回:
ERROR MqttBase: MqttBase_OnConnectFailure() error, messageId 0, code 4, message CONNACK return code,未错误的用户名和密码。排查方法:
设备ID,即为SDK中g_deviceId的值。密钥即为SDK中g_secret的值。若是忘记密码,可在设备详情页面重置密钥。8.开源协议