设备使用ArkTS SDK轻松连接华为云IoT平台
随着鸿蒙生态的蓬勃发展,使用ArkTS接入物联网平台的需求越来越多,为了开发者使用ArkTS原生连接到华为云IoT物联网平台,华为云IoT开发了huaweicloud-iot-device-sdk-arkts,针对设备接入华为云IoT物联网平台场景,提供设备和平台之间通讯能力,并且针对各种场景提供了丰富的demo代码。IoT设备开发者使用SDK可以大大简化开发复杂度,快速的接入平台。
本文介绍使用huaweicloud-iot-device-sdk-arkts连接华为云IoT平台,并实现设备连接鉴权、设备命令、设备消息和设备属性等功能。
工具安装
- 已安装 DevEco Studio 5.0.0及以上版本。
- 已安装配套的Node.js。
使用说明
-
下载安装:在DevEco Studio中执行以下命令引入并安装SDK。
ohpm install @huaweicloud/iot-device-sdk
-
权限配置:使用SDK需要网络连接的权限,需要在module.json5的requestPermissions中增加"ohos.permission.INTERNET"的权限,如下所示:
{ "module": { "requestPermissions": [ { "name": "ohos.permission.INTERNET" } ] } }
准备工作
1. 创建产品
-
访问设备接入服务,单击“管理控制台”进入设备接入控制台,选择您的实例,单击实例卡片进入。查看MQTTS设备接入域名,保存该地址。
-
单击左侧导航栏“产品”,单击页面左侧的“创建产品”。
-
根据页面提示填写参数,然后单击“确定”完成产品的创建。
参数名称 参数描述 所属资源空间 下拉选择所属的资源空间。如无对应的资源空间,请先创建资源空间。 产品名称 自定义。支持字母、数字、下划线(_)、连字符(-)的字符组合。 协议类型 选择“MQTT”。 数据格式 选择“JSON”。 设备类型选择 选择”自定义类型” 设备类型 填写“smokeDetector”
2. 添加产品模型
-
找到上述创建的产品,单击产品进入产品详情页。
-
在模型定义中定义如下产品模型
图1 产品-创建产品模型
3. 注册设备
-
选择左侧导航栏“设备 > 所有设备”,单击“注册设备”。
-
根据页面提示信息填写参数,然后单击“确定”。
-
设备注册成功后保存设备标识码、设备ID、密钥。
参数名称 参数描述 所属资源空间 选择与上述创建的产品相同的资源空间。 所属产品 选择上述创建的产品。 设备标识码 设备唯一物理标识。可自定义,由英文字母和数字组成。 设备名称 设备名称,可自定义 设备认证类型 选择”密钥” 密钥 设备密钥,可自定义。若不填写密钥,物联网平台会自动生成密钥。
SDK使用说明
1. 设备初始化
设备初始化Demo,可参考entry/src/main/ets/pages/Index.ets。
-
创建设备需要输入注册设备时获取的设备ID、密钥,以及设备对接信息,注意格式为 ssl://域名信息:端口号 或 ssl://IP地址:端口号
private device: IoTDevice | null = null; // 用户请替换为自己的接入地址, 设备ID,设备密钥及证书路径(证书文件放在resource/resfile下,连接华为云时请使用对应的证书,可以在资源获取中下载证书文件)。 this.device = new IoTDevice("ssl://域名信息:8883","deviceId", "mySecret", "filePath");
-
调用init建立连接。您可以使用异步方式初始化或使用同步方式初始化。
// 使用异步方式初始化 this.device.init().then((data: boolean) => { // 连接成功处理 }).catch((err: string) => { // 连接失败处理 }) // 或使用同步方式初始化 // await this.device.init();
-
查看设备日志打印,设备连接成功。
`IoTDA_SDK# connect result is {"code":0,"message":"Connect Success"}`
-
创建设备并连接成功后,可以开始进行设备通信。调用IoT Device 的client接口获取设备客户端,客户端提供了消息、属性、命令等通讯接口。
2. 消息上报
消息上报Demo,可参考entry/src/main/ets/pages/MessageSample.ets。
消息上报是指设备向平台上报消息。
-
在初始化并连接平台成功后,调用客户端的reportDeviceMessage接口上报设备消息,publishRawMessage上报自定义Topic的消息。
// 上报系统topic消息 const reportMessage: DeviceMessage = { content: this.message } this.device.client.reportDeviceMessage(reportMessage) .then((data: IoTMqttResponse) => { LogUtil.info(TAG, `report deviceMessage success ${JSON.stringify(data)}. DeviceMessage is ${JSON.stringify(reportMessage)}`); }) .catch((error: IoTMqttResponse | string) => { LogUtil.error(TAG, `report deviceMessage failed ${JSON.stringify(error)}`); }) // 上报自定义topic消息($oc开头,注意需要先在平台配置自定义topic) const topic = `$oc/devices/${this.device?.deviceId}/user/test`; const rawMessage: RawMessage = { topic: topic, qos: 0, payload: this.message } this.device?.client.publishRawMessage((rawMessage)).then((res: IoTMqttResponse) => { LogUtil.info(TAG, `publish rawMessage(${rawMessage.topic}) success, message is ${JSON.stringify(rawMessage)}}`); }).catch((error: IoTMqttResponse | string) => { LogUtil.error(TAG, `publish rawMessage(${rawMessage.topic}) failed, error is ${JSON.stringify(error)}}`); }); // 上报自定义topic消息(非$oc开头,可用设备topic策略控制权限) const topic = "hello/world"; const rawMessage: RawMessage = { topic: topic, qos: 0, payload: this.message } this.device?.client.publishRawMessage((rawMessage)).then((res: IoTMqttResponse) => { LogUtil.info(TAG, `publish rawMessage(${rawMessage.topic}) success, message is ${JSON.stringify(rawMessage)}}`); }).catch((error: IoTMqttResponse | string) => { LogUtil.error(TAG, `publish rawMessage(${rawMessage.topic}) failed, error is ${JSON.stringify(error)}}`); });
-
上报成功,查看日志发送消息成功。
图2 上报系统Topic消息日志
图3 上报自定义Topic($oc开头)消息日志
图4 上报自定义Topic(非$oc开头)消息日志
-
在设备接入控制台,选择“设备 > 所有设备”-查看设备是否在线。
图5 设备列表-设备在线
-
选择对应设备,单击“详情”,进入设备详情页面启动设备消息跟踪。
图6 消息跟踪-启动消息跟踪
-
消息跟踪显示平台成功接收到设备的消息。
图7 消息跟踪-查看device_sdk_java消息跟踪
3. 属性上报
属性上报Demo,可参考entry/src/main/ets/pages/PropertySample.ets。
-
在初始化并连接平台成功后,调用客户端的reportProperties接口上报设备属性。
const properties: ServiceProperty[] = [ { "service_id": "smokeDetector", "properties": { "alarm": 1, "temperature": Math.random() * 100, "humidity": Math.random() * 100, "smokeConcentration": Math.random() * 100, } } ]; this.device.client.reportProperties(properties) .then((data: IoTMqttResponse) => { LogUtil.info(TAG, `report properties success ${JSON.stringify(data)}, properties is ${JSON.stringify(properties)}}`); }) .catch((error: IoTMqttResponse | string) => { LogUtil.error(TAG, `report properties failed ${JSON.stringify(error)}`); })
-
上报成功,查看日志发送属性成功。
图8 上报属性日志
-
在设备接入控制台,选择“设备 > 所有设备”,选择对应设备,单击“详情”,进入设备详情页面可以看到最新上报的属性值。
图9 物模型-属性上报
4. 属性读写
属性读写Demo,可参考entry/src/main/ets/pages/PropertySample.ets。
- 在初始化连接成功后,调用客户端的propertyListener方法来设置属性回调接口。
-
写属性处理:实现了alarm属性的写操作,其他属性不支持写操作。
-
读属性处理:将本地属性值按照接口格式进行拼装。如果设备不支持平台主动到设备读,onPropertiesGet接口可以空实现。
let propertyListener: PropertyListener = { onPropertiesSet: (requestId: string, services: ServiceProperty[]): void => { this.logArr.unshift(`${new Date()}: onPropertiesSet requestId is ${requestId}, services is ${JSON.stringify(services)}`) // 遍历services services.forEach(serviceProperty => { LogUtil.info("onPropertiesSet, serviceId is ", serviceProperty.service_id); // 遍历属性 Object.keys(serviceProperty.properties).forEach(name => { LogUtil.log(TAG, `property name is ${name}`); LogUtil.log(TAG, `set property value is ${serviceProperty.properties[name]}`); }) }) // 修改本地的属性 this.device?.client.respondPropsSet(requestId, IotResult.SUCCESS); }, onPropertiesGet: (requestId: string, serviceId?: string): void => { this.logArr.unshift(`${new Date()}: onPropertiesGet requestId is ${requestId}, serviceId is ${serviceId} and respondPropsGet`) LogUtil.info(TAG, `onPropertiesGet, the serviceId is ${serviceId}`); const serviceProperties: ServiceProperty[] = [ { "service_id": "smokeDetector", "properties": { "alarm": 1, "temperature": Math.random() * 100, "humidity": Math.random() * 100, "smokeConcentration": Math.random() * 100, } } ]; this.device?.client.respondPropsGet(requestId, serviceProperties); } } // 设置属性监听器 this.device.client.propertyListener = propertyListener;
- 执行上述代码,设置属性监听器,在平台上设备影子页面查看当前alarm属性值为1,修改alarm属性为0后,查看设备侧日志,看到设备收到属性设置alarm属性为0。
图10 设备影子-查看alarm属性
图11 设备影子-属性配置alarm
图12 查看属性设置alarm为0
5. 命令下发
命令下发Demo,可参考entry/src/main/ets/pages/CommandSample.ets。
设置命令监听器用来接收平台下发的命令,在回调接口里,需要对命令进行处理,并上报响应。
- 在CommandSample例子中实现了命令的处理,收到命令后仅进行打印,然后调用respondCommand上报响应。
let commandListener: CommandListener = { onCommand: (requestId: string, serviceId: string, commandName: string, paras: object): void => { const command = `requestId is ${requestId}, serviceId is ${serviceId}, commandName is ${commandName}, paras is ${JSON.stringify(paras)}`; LogUtil.info(TAG, `received command is ${command}`); // 用户可以在该处进行命令处理 const commandRsp: CommandRsp = { result_code: 0 } this.device?.client.respondCommand(requestId, commandRsp).then((data: IoTMqttResponse) => { LogUtil.info(TAG, `respond command success ${JSON.stringify(data)}, commandRsp is ${commandRsp}}`); }).catch((err: IoTMqttResponse | string) => { LogUtil.error(TAG, `respond command failed ${JSON.stringify(err)}`); }) } } this.device.client.commandListener = commandListener;
- 执行上述代码设置命令监听后,在平台执行命令下发,其中serviceId为“smokeDetector”、命令名为“ringAlarm”、参数携带duration为整数20。
- 查看日志,设备收到命令并成功上报响应。
图13 命令接收与响应
6. 面向物模型编程
面向物模型编程Demo,可参考entry/src/main/ets/pages/ProfileSample.ets。
前面介绍了直接调用设备客户端的接口和平台进行通讯的方法,这种方式比较灵活,但用户需要妥善处理每一个接口,实现比较复杂。
SDK提供了一种更简单的方式,即面向物模型编程。面向物模型编程指基于SDK提供的物模型抽象能力,设备代码按照物模型定义设备服务,然后可以直接访问设备服务(即调用设备服务的属性读写接口),SDK就能自动和平台通讯,完成属性的同步和命令的调用。
相比直接调用客户端接口和平台进行通讯,面向物模型编程更简单,它简化了设备侧代码的复杂度,让设备代码只需要关注业务,而不用关注和平台的通讯过程。这种方式适合多数场景。
ProfileSample例子演示了如何面向物模型编程:
- 首先定义一个烟感服务类,继承自AbstractService。(如果有多个服务,则需要定义多个服务类):
class SmokeDetector extends AbstractService { }
- 定义服务属性,私有变量以下划线开头,使用@Reflect.metadata(“Property”, { name: “string”, writeable: boolean })注解表示一个属性,其中中name和产品模型中属性名保持一致。writeable用来标识属性是否可写
@Reflect.metadata("Property", { name: "alarm", writeable: true }) private _smokeAlarm: number = 1; @Reflect.metadata("Property", { name: "smokeConcentration", writeable: false }) private _concentration: number = 0; @Reflect.metadata("Property", { name: "humidity", writeable: false }) private _humidity: number = 0; @Reflect.metadata("Property", { name: "temperature", writeable: false }) private _temperature: number = 10;
- 定义服务的命令。设备收到平台下发的命令时,SDK会自动调用这里定义的命令。注解中name对应物模型的command_name,method对应接收命令的处理方法,命令的入参和返回值类型固定不能修改。
这里定义的是一个响铃报警命令,命令名为ringAlarm,下发参数为”duration”,表示响铃报警的持续时间。@Reflect.metadata("DeviceCommand", { name: "ringAlarm", method: (paras: object): CommandRsp => { let duration: number = paras['duration']; LogUtil.log(TAG, `duration is ${duration}`); return IotResult.SUCCESS; } }) private _alarm: Function = () => {};
- 定义getter和setter接口。
- 当设备收到平台下发的查询属性以及设备上报属性时,会自动调用getter方法。getter方法需要读取设备的属性值,可以实时到传感器读取或者读取本地的缓存
- 当设备收到平台下发的设置属性时,会自动调用setter方法。setter方法需要更新设备本地的值。如果属性不支持写操作,setter保留空实现。
- setter和getter接口使用DevEco Studio右键的Generate的Getter and Setter自动生成,然后修改方法实现。
public set smokeAlarm(value: number) { this._smokeAlarm = value; if (value == 0) { LogUtil.info(TAG, "alarm is cleared by app"); } } public get smokeAlarm(): number { return this._smokeAlarm; } public set concentration(value: number) { // 只读字段不需要实现set接口 } public get concentration(): number { return Math.floor(Math.random() * 100); } public set humidity(value: number) { // 只读字段不需要实现set接口 } public get humidity(): number { return Math.floor(Math.random() * 100); } public set temperature(value: number) { // 只读字段不需要实现set接口 } public get temperature(): number { return Math.floor(Math.random() * 100); }
-
实现构造函数,完成属性和命令的初始化。
constructor() { super(); const fields = Object.getOwnPropertyNames(this); this.init(fields); }
-
注册烟感服务。
//创建设备服务 const smokeDetector = new SmokeDetector(); this.device.addService("smokeDetector", smokeDetector);
-
开启周期上报。
//启动自动周期上报 this.device.getService("smokeDetector")?.enableAutoReport(10000);
-
执行上述代码,查看日志上报属性。
图14 上报属性
-
在平台侧查看设备影子中属性alarm为1,修改alarm为0后,查看设备日志收到属性设置
图15 设备影子-查看alarm属性
图16 查看设备日志属性设置成功
-
在平台下发ringAlarm命令,查看设备日志看到ringAlarm命令被调用,并且成功上报响应。
图17 查看设备日志命令响应成功
模拟器体验
本文所有的样例均可使用模拟器运行,可参考使用模拟器运行应用/元服务。
通过上面的介绍,您已经基本了解设备接入ArkTS SDK的使用方法了,接下来,我们使用模拟器体验一下上述的功能吧。
- SDK源码中包含Demo,下载SDK源码并使用DevEco Studio打开。
- 点击“Build - Build Happ(s)/APP(s) - Build Hap(s)”来编译Hap(s)。
- 编译完成后会在“entry/build/outputs/default”目录下生成entry-default-unsigned.hap文件。
- 安装并启动模拟器后,将生成的hap文件拖至模拟器中安装,安装成功后,显示如图所示的图标。
- 点击安装好的程序,进入IoTDA MQTT,并填写对应的地址,设备ID和设备秘钥,点击连接平台。
- 连接成功后,进入操作页面,接下来您可以体验属性,消息,命令等功能。以属性为例,点击“属性”按钮进入属性页面,页面中已经填写好需要上报的属性,您也可以按照格式修改,修改完后,点击上报属性。
- 在日志栏中打印“report properties ”,并且在华为云IoTDA控制台的设备详情中,可以看到设备上报的属性。
- 接下来您可以通过此Demo继续体验其他功能。
结语
至此,您已经使用ArkTS的SDK将设备成功连接上云,并完成了基本的属性、消息上报和命令下发等功能。同时SDK还提供了自定义选项、断线重连以及获取设备影子等功能,您可以通过阅读SDK指导并参考对应的Demo体验这些功能。
如果您有什么需求/疑问,欢迎在Github上的项目中提交issue。
- 点赞
- 收藏
- 关注作者
评论(0)