设备使用ArkTS SDK轻松连接华为云IoT平台

举报
yd_220400028 发表于 2025/03/17 15:26:15 2025/03/17
【摘要】 随着鸿蒙生态的蓬勃发展,使用ArkTS接入物联网平台的需求越来越多,为了开发者使用ArkTS原生连接到华为云IoT物联网平台,华为云IoT开发了huaweicloud-iot-device-sdk-arkts,针对设备接入华为云IoT物联网平台场景,提供设备和平台之间通讯能力,并且针对各种场景提供了丰富的demo代码。IoT设备开发者使用SDK可以大大简化开发复杂度,快速的接入平台。本文介绍...

随着鸿蒙生态的蓬勃发展,使用ArkTS接入物联网平台的需求越来越多,为了开发者使用ArkTS原生连接到华为云IoT物联网平台,华为云IoT开发了huaweicloud-iot-device-sdk-arkts,针对设备接入华为云IoT物联网平台场景,提供设备和平台之间通讯能力,并且针对各种场景提供了丰富的demo代码。IoT设备开发者使用SDK可以大大简化开发复杂度,快速的接入平台。

本文介绍使用huaweicloud-iot-device-sdk-arkts连接华为云IoT平台,并实现设备连接鉴权、设备命令、设备消息和设备属性等功能。

工具安装

使用说明

  • 下载安装:在DevEco Studio中执行以下命令引入并安装SDK。

    ohpm install @huaweicloud/iot-device-sdk
    
  • 权限配置:使用SDK需要网络连接的权限,需要在module.json5的requestPermissions中增加"ohos.permission.INTERNET"的权限,如下所示:

    {
    	"module": {
    		"requestPermissions": [
      			{
        			"name": "ohos.permission.INTERNET"
      			}
    		]
    	}
    }
    

准备工作

1. 创建产品

  1. 访问设备接入服务,单击“管理控制台”进入设备接入控制台,选择您的实例,单击实例卡片进入。查看MQTTS设备接入域名,保存该地址。

  2. 单击左侧导航栏“产品”,单击页面左侧的“创建产品”。

  3. 根据页面提示填写参数,然后单击“确定”完成产品的创建。

    参数名称 参数描述
    所属资源空间 下拉选择所属的资源空间。如无对应的资源空间,请先创建资源空间。
    产品名称 自定义。支持字母、数字、下划线(_)、连字符(-)的字符组合。
    协议类型 选择“MQTT”。
    数据格式 选择“JSON”。
    设备类型选择 选择”自定义类型”
    设备类型 填写“smokeDetector”

2. 添加产品模型

  1. 找到上述创建的产品,单击产品进入产品详情页。

  2. 在模型定义中定义如下产品模型
    图1 产品-创建产品模型
    产品-创建产品模型

3. 注册设备

  1. 选择左侧导航栏“设备 > 所有设备”,单击“注册设备”。

  2. 根据页面提示信息填写参数,然后单击“确定”。

  3. 设备注册成功后保存设备标识码、设备ID、密钥。

    参数名称 参数描述
    所属资源空间 选择与上述创建的产品相同的资源空间。
    所属产品 选择上述创建的产品。
    设备标识码 设备唯一物理标识。可自定义,由英文字母和数字组成。
    设备名称 设备名称,可自定义
    设备认证类型 选择”密钥”
    密钥 设备密钥,可自定义。若不填写密钥,物联网平台会自动生成密钥。

SDK使用说明

1. 设备初始化

设备初始化Demo,可参考entry/src/main/ets/pages/Index.ets

  1. 创建设备需要输入注册设备时获取的设备ID、密钥,以及设备对接信息,注意格式为 ssl://域名信息:端口号ssl://IP地址:端口号

    private device: IoTDevice | null = null;
    
    // 用户请替换为自己的接入地址, 设备ID,设备密钥及证书路径(证书文件放在resource/resfile下,连接华为云时请使用对应的证书,可以在资源获取中下载证书文件)。
    this.device = new IoTDevice("ssl://域名信息:8883","deviceId", "mySecret", "filePath");
    
  2. 调用init建立连接。您可以使用异步方式初始化或使用同步方式初始化。

    // 使用异步方式初始化
    this.device.init().then((data: boolean) => {
      // 连接成功处理
    }).catch((err: string) => {
      // 连接失败处理
    })
    
    // 或使用同步方式初始化
    // await this.device.init();
    
  3. 查看设备日志打印,设备连接成功。

    `IoTDA_SDK# connect result is {"code":0,"message":"Connect Success"}`
    
  4. 创建设备并连接成功后,可以开始进行设备通信。调用IoT Device 的client接口获取设备客户端,客户端提供了消息、属性、命令等通讯接口。

2. 消息上报

消息上报Demo,可参考entry/src/main/ets/pages/MessageSample.ets

消息上报是指设备向平台上报消息。

  1. 在初始化并连接平台成功后,调用客户端的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. 上报成功,查看日志发送消息成功。
    图2 上报系统Topic消息日志
    上报系统Topic消息日志
    图3 上报自定义Topic($oc开头)消息日志
    上报自定义Topic(oc开头) 消息日志
    图4 上报自定义Topic(非$oc开头)消息日志
    上报自定义Topic(非oc开头)消息日志

  3. 在设备接入控制台,选择“设备 > 所有设备”-查看设备是否在线。
    图5 设备列表-设备在线
    设备列表-设备在线

  4. 选择对应设备,单击“详情”,进入设备详情页面启动设备消息跟踪。
    图6 消息跟踪-启动消息跟踪
    消息跟踪-启动消息跟踪

  5. 消息跟踪显示平台成功接收到设备的消息。
    图7 消息跟踪-查看device_sdk_java消息跟踪
    消息跟踪-查看device_sdk_java消息跟踪

3. 属性上报

属性上报Demo,可参考entry/src/main/ets/pages/PropertySample.ets

  1. 在初始化并连接平台成功后,调用客户端的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)}`);
    	})
    
  2. 上报成功,查看日志发送属性成功。
    图8 上报属性日志
    上报属性日志

  3. 在设备接入控制台,选择“设备 > 所有设备”,选择对应设备,单击“详情”,进入设备详情页面可以看到最新上报的属性值。
    图9 物模型-属性上报
    物模型-属性上报

4. 属性读写

属性读写Demo,可参考entry/src/main/ets/pages/PropertySample.ets

  1. 在初始化连接成功后,调用客户端的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;
    
  1. 执行上述代码,设置属性监听器,在平台上设备影子页面查看当前alarm属性值为1,修改alarm属性为0后,查看设备侧日志,看到设备收到属性设置alarm属性为0。
    图10 设备影子-查看alarm属性
    设备影子-查看alarm属性
    图11 设备影子-属性配置alarm
    设备影子-属性配置alarm
    图12 查看属性设置alarm为0
    查看属性设置alarm为0

5. 命令下发

命令下发Demo,可参考entry/src/main/ets/pages/CommandSample.ets

设置命令监听器用来接收平台下发的命令,在回调接口里,需要对命令进行处理,并上报响应。

  1. 在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;
    
  2. 执行上述代码设置命令监听后,在平台执行命令下发,其中serviceId为“smokeDetector”、命令名为“ringAlarm”、参数携带duration为整数20。
  3. 查看日志,设备收到命令并成功上报响应。
    图13 命令接收与响应
    命令接收与响应

6. 面向物模型编程

面向物模型编程Demo,可参考entry/src/main/ets/pages/ProfileSample.ets

前面介绍了直接调用设备客户端的接口和平台进行通讯的方法,这种方式比较灵活,但用户需要妥善处理每一个接口,实现比较复杂。

SDK提供了一种更简单的方式,即面向物模型编程。面向物模型编程指基于SDK提供的物模型抽象能力,设备代码按照物模型定义设备服务,然后可以直接访问设备服务(即调用设备服务的属性读写接口),SDK就能自动和平台通讯,完成属性的同步和命令的调用。

相比直接调用客户端接口和平台进行通讯,面向物模型编程更简单,它简化了设备侧代码的复杂度,让设备代码只需要关注业务,而不用关注和平台的通讯过程。这种方式适合多数场景。

ProfileSample例子演示了如何面向物模型编程:

  1. 首先定义一个烟感服务类,继承自AbstractService。(如果有多个服务,则需要定义多个服务类):
    class SmokeDetector extends AbstractService  {
    
    }
    
  2. 定义服务属性,私有变量以下划线开头,使用@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;
    
  3. 定义服务的命令。设备收到平台下发的命令时,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 = () => {};
    
  4. 定义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);
    }
    
  1. 实现构造函数,完成属性和命令的初始化。

    constructor() {
    	super();
    	const fields = Object.getOwnPropertyNames(this);
    	this.init(fields);
    }
    
  2. 注册烟感服务。

    //创建设备服务
    const smokeDetector = new SmokeDetector();
    this.device.addService("smokeDetector", smokeDetector);
    
  3. 开启周期上报。

    //启动自动周期上报
    this.device.getService("smokeDetector")?.enableAutoReport(10000);
    
  4. 执行上述代码,查看日志上报属性。
    图14 上报属性
    上报属性

  5. 在平台侧查看设备影子中属性alarm为1,修改alarm为0后,查看设备日志收到属性设置
    图15 设备影子-查看alarm属性
    设备影子-查看alarm属性
    图16 查看设备日志属性设置成功
    查看设备日志属性设置成功

  6. 在平台下发ringAlarm命令,查看设备日志看到ringAlarm命令被调用,并且成功上报响应。
    图17 查看设备日志命令响应成功
    查看设备日志命令响应成功

模拟器体验

本文所有的样例均可使用模拟器运行,可参考使用模拟器运行应用/元服务

通过上面的介绍,您已经基本了解设备接入ArkTS SDK的使用方法了,接下来,我们使用模拟器体验一下上述的功能吧。

  1. SDK源码中包含Demo,下载SDK源码并使用DevEco Studio打开。
  2. 点击“Build - Build Happ(s)/APP(s) - Build Hap(s)”来编译Hap(s)。
    image.png
  3. 编译完成后会在“entry/build/outputs/default”目录下生成entry-default-unsigned.hap文件。
    image.png
  4. 安装并启动模拟器后,将生成的hap文件拖至模拟器中安装,安装成功后,显示如图所示的图标。
    安装Demo
  5. 点击安装好的程序,进入IoTDA MQTT,并填写对应的地址,设备ID和设备秘钥,点击连接平台。
    进入APP连接设备
  6. 连接成功后,进入操作页面,接下来您可以体验属性,消息,命令等功能。以属性为例,点击“属性”按钮进入属性页面,页面中已经填写好需要上报的属性,您也可以按照格式修改,修改完后,点击上报属性。
    上报属性
  7. 在日志栏中打印“report properties ”,并且在华为云IoTDA控制台的设备详情中,可以看到设备上报的属性。
    模拟器上报属性成功
  8. 接下来您可以通过此Demo继续体验其他功能。

结语

至此,您已经使用ArkTS的SDK将设备成功连接上云,并完成了基本的属性、消息上报和命令下发等功能。同时SDK还提供了自定义选项、断线重连以及获取设备影子等功能,您可以通过阅读SDK指导并参考对应的Demo体验这些功能。
如果您有什么需求/疑问,欢迎在Github上的项目中提交issue。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。