【BQ3568HM开发板】智能家居中控屏连接华为云IoTDA物联网平台

目录

引言

安装OpenHarmony的MQTT库

华为云平台的操作

建立设备

建立物模型

连接华为云平台

发布LED灯状态

代码重构

测试结果

接收平台发送的属性修改命令

设备侧API

Topic

下行请求参数说明

上行响应参数说明

程序修改

应用侧API

测试设备属性设置功能

结语


本文首发于电子发烧友论坛:https://bbs.elecfans.com/jishu_2475289_1_1.html

引言

前段时间进行了BQ3568HM开发板的测评,设计了智能家居中控屏并进行了LED灯的控制操作。今天为其加入物联网平台的功能,使其真正成为一个智能家居产品。

安装OpenHarmony的MQTT库

官方有个MQTT软件包:ohpm/mqtt,它的最新版本针对的是API12,而BQ3568HM开发板是基于OpenHarmony 4.1,可以使用老一点的版本,使用如下命令:

ohpm install @ohos/mqtt@2.0.13

上面的操作虽然可以导入老版本的MQTT包,但是当三方包发布新版本后,点击同步工程,会出现默认更新安装的三方包版本情况。为了避免这种情况,手工修改oh-package.json5,将其中@ohos/mqtt一行版本号前面的"^"符号删除掉,这样保证安装固定版本的三方包。

{
  "name": "myapplication",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {
    "@ohos/mqtt": "2.0.13"
  },
  "devDependencies": {
    "@ohos/hypium": "1.0.6"
  },
  "dynamicDependencies": {}
}

华为云平台的操作

建立设备

我需要先在平台创建产品和设备,有关产品和设备的创建,可以参考我以前的博文:【HZHY-AI300G智能盒试用连载体验】在华为IoTDA平台上建立设备_hzhy-ai300g 多少钱-CSDN博客

建立物模型

在线开发产品模型前需要创建产品。创建产品需要输入产品名称、协议类型、数据格式、所属行业和设备类型等信息,产品模型会使用这些信息作为设备能力字段取值。物联网平台提供了标准模型和厂商模型,这些模型涉及多个领域,模型中提供了已经编辑好的产品模型文件,您可以根据自己的需要对产品模型中的字段进行修改和增删;如果选择自定义产品模型,则需要完整定义产品模型。

操作步骤

  1. 访问设备接入服务,单击"管理控制台"进入"设备接入"控制台。选择您的实例,单击实例卡片进入。

  2. 单击左侧导航栏的"产品",在产品列表中,找到对应的产品,单击产品进入产品详情页。

  3. 在产品详情基本信息页面,单击"自定义模型",添加服务。

  4. 输入"服务ID"、"服务类型"和"服务描述",然后单击"确定"。

    • "服务ID":采用首字母大写的命名方式。比如:WaterMeter、StreetLight。
    • "服务类型":建议和服务ID保持一致。
    • "服务描述":比如路灯上报的环境光强度和路灯开关状态的属性。

    添加服务后,在"添加服务"区域,对属性和命令进行定义。每个服务下,可以包含属性和命令,也可以只包含其中之一,请根据此类设备的实际情况进行配置。

  5. 单击步骤4新增的服务ID,在展开的页面单击"新增属性",在弹出窗口中配置属性的各项参数,然后单击"确定"。

    参数 说明
    属性名称 建议采用驼峰形式,如batteryLevel、internalTemperature。
    数据类型 * int:当上报的数据为整数时,可配置为此类型。 * **long:**当上报的数据为长整型时,可配置为此类型。 * decimal:当上报的数据为小数时,可配置为此类型。配置"经纬度"属性时,数据类型建议使用"decimal"。 * string:当上报的数据为字符串、枚举值时,可以配置为此类型。如果为枚举值,值之间需要用英文逗号(",")分隔。 * dateTime :当上报的数据为日期时,可以配置为此类型。 此类型属性上报格式推荐样例:2020-09-01T18:50:20Z或者2020-09-01T18:50:20.200Z * jsonObject:当上报的数据为JSON结构体时,可以配置为此类型。 * enum: 当上报的数据为枚举值时,可配置为此类型。 搭配参数enumList格式填写,比如状态属性的enumList填写为OPEN,CLOSE,那么属性上报格式样例为"OPEN"或者"CLOSE" * boolean: 当上报的数据为布尔值时,可配置为此类型。 此类型属性上报推荐格式样例:true/false 或者 0/1 * stringList: 当上报的数据为字符串数组时,可配置为此类型。 此类型属性上报推荐格式样例:["str1","str2","str3"]
    访问权限 * 可读:通过接口可以查询该属性。 * 可写:通过接口可以修改该属性值。
    取值范围 请根据此类设备的实际情况进行配置。
    步长 请根据此类设备的实际情况进行配置。
    单位 请根据此类设备的实际情况进行配置。

我建立了一个smarthome的物模型,包括温度、湿度和LED状态3个属性,其中LED状态属性是平台可以修改的,另外两个都是设备上报的。

连接华为云平台

先建立IoTDA.ets,内容如下:

TypeScript 复制代码
import { MqttAsync, MqttClient, MqttPublishOptions, MqttResponse, MqttSubscribeOptions } from '@ohos/mqtt'

export class MQTT{
  private serverUrl: string = 'tcp://bde4cbe7aa.st1.iotda-device.cn-north-4.myhuaweicloud.com:1883'
  private clientId: string = 'xxxxx_test_0_0_2025020502'
  private userName: string = 'xxxxx_test'
  private password: string = 'xxxxxxxxxxxxxx'
  public mqttAsyncClient: MqttClient = MqttAsync.createMqtt({
    url: this.serverUrl,
    clientId: this.clientId,
    persistenceType: 1,
  })

  private topic: string = "light002"

  connectMqtt() {
    this.mqttAsyncClient.connect({
      userName: this.userName,
      password: this.password,
    }).then(() => {
      this.mqttAsyncClient.isConnected()
        .then((data: boolean) => {
          console.log("连接状态: " + data)
        });
    }).catch(() => {
      console.warn('连接失败')
    })
  }

  subscribeMqtt(topic: string) {
    let subscribeOption: MqttSubscribeOptions = {
      topic: topic,//主题名称
      qos: 0            //消息的服务质量设置
    }
    this.mqttAsyncClient.subscribe(subscribeOption)
      .then((data: MqttResponse) => {
        console.log("订阅成功 " + JSON.stringify(data));
      }).catch((err: MqttResponse) => {
      console.log("订阅失败" + JSON.stringify(err));
    })
  }

  messageArrived() {
    this.mqttAsyncClient.messageArrived((err, data) => {
      if (err) {
        console.error("接收消息时发生错误:", err);
      } else {
        console.log("接收到的消息:",JSON.stringify(data));
      }
    });
  }

  publish(topic:string, message:string) {
    let publishOption: MqttPublishOptions = {
      topic: topic,               //主题名称
      qos: 0,                     //消息的服务质量设置
      payload: message,//发布的消息
    };

    this.mqttAsyncClient.publish(publishOption)
      .then((data: MqttResponse) => {
        console.log("推送成功" + JSON.stringify(data));
      })
      .catch((err: Error) => {
        console.log("推送失败" + JSON.stringify(err));
      });
  }

  disconnect() {
    this.mqttAsyncClient.disconnect()
      .then((data: MqttResponse) => {
        console.log("断开成功:" + JSON.stringify(data));
      })
      .catch((err: MqttResponse) => {
        console.log("断开失败:" + JSON.stringify(err));
      })
  }
}
export const mqtt = new MQTT();

在index.ets开头加上下面的语句:

TypeScript 复制代码
import {mqtt} from './IoTDA'

在SmartHomeControlPanel部分加上:

TypeScript 复制代码
  deviceId: string = "XXXX_test";

  aboutToAppear() {
    // 创建MQTT客户端
    mqtt.connectMqtt()
  }

这样就可以在程序一启动时先连接上华为云的服务器。

发布LED灯状态

代码重构

我们将原来的LED灯控制逻辑进行一下重构,添加如下函数:

TypeScript 复制代码
  // 控制LED灯的状态并发布消息
  private setLedStatusAndPublish() {
    if (this.lightStatus) {
      console.info("this toggle is On.");
      let res: string = testNapi.gpio_on(this.ledPath);
      console.info(res);
    } else {
      console.info("this.toggle is Off.");
      let res: string = testNapi.gpio_off(this.ledPath);
      console.info(res);
    }
    let ledstatus: string = this.lightStatus ? 'ON' : 'OFF';
    const topic = `$oc/devices/${this.deviceId}/sys/properties/report`;
    const message = `{"services": [{"serviceId": "smarthome", "properties": {"LED状态": "${ledstatus}"}}]}`;
    mqtt.publish(topic, message);
  }

然后将灯光控制按钮修改为:

TypeScript 复制代码
      // 灯光控制按钮
      Button({
        type: ButtonType.Capsule,
        stateEffect: true,
      }) {
        Row() {
          Image(this.lightStatus ? $r('app.media.light_off_icon') : $r('app.media.light_on_icon'))
            .width(48)
            .height(48)
            .margin({ right: 10 })
          Text(this.lightStatus ? '关闭灯光' : '打开灯光')
            .fontSize(20)
            .fontColor('#FFFFFF')
        }
      }
      .width('80%')
      .height(80)
      .margin({ top: 20 })
      .onClick(() => {
        this.lightStatus = !this.lightStatus;
        this.setLedStatusAndPublish();
      })

这样我们每按下灯光控制按钮,就会自动向云平台发送一下最新的状态。

测试结果

我们可以测试一下,看到云平台显示的状态信息如下:

接收平台发送的属性修改命令

设备侧API

当平台向设备设置属性信息时,首先设备必须在线。

设备侧会自动收到特定Topic的查询请求(无需订阅),设备收到属性查询请求后,需要将设备的属性数据返回给平台,如果设备没回响应平台会认为属性查询请求执行超时。

有关文档可以参考:平台设置设备属性_设备接入 IoTDA_华为云

Topic

下行: $oc/devices/{device_id}/sys/properties/set/request_id={request_id}

上行: $oc/devices/{device_id}/sys/properties/set/response/request_id={request_id}

下行请求参数说明
字段名 必选/可选 类型 参数描述
object_device_id 可选 String 参数解释: * 平台下发时,若为直连设备,不携带该参数。 * 平台下发时,若为网关子设备,该参数为Topic中设备的子设备ID。
services 必选 List<ServiceProperty> 设备服务数据列表。

ServiceProperty结构定义:

字段名 必选/可选 类型 参数描述
service_id 必选 String 参数解释: 设备的服务ID,由创建的产品模型确定。
properties 必选 Object 参数解释: 设备服务的属性列表,具体字段在产品模型里定义,可以设置多个字段。
上行响应参数说明
字段名 必选/可选 类型 参数描述
result_code 可选 Integer 参数解释: 命令的执行结果,0表示成功,其他表示失败。不带默认认为成功。
result_desc 可选 String 参数解释: 属性设置的响应描述。

程序修改

我们需要在aboutToAppear中加上接收云端消息的函数,同时在其中进行JSON解析。ArkTS的JSON解析有点特殊,参见我写的博文。下面就是修改好的代码:

TypeScript 复制代码
// 定义设备属性类
class DeviceProperties {
  温度: number;
  湿度: number;
  LED状态: string;

  constructor(温度: number, 湿度: number, LED状态: string) {
    this.温度 = 温度;
    this.湿度 = 湿度;
    this.LED状态 = LED状态;
  }
}

// 定义服务类
class Service {
  serviceId: string;
  properties: DeviceProperties;

  constructor(serviceId: string, properties: DeviceProperties) {
    this.serviceId = serviceId;
    this.properties = properties;
  }
}

// 定义整个数据结构类
class ServiceData {
  services: Service[];

  constructor(services: Service[]) {
    this.services = services;
  }
}

@Entry
@Component
struct SmartHomeControlPanel {
......

  aboutToAppear() {
    // 创建MQTT客户端
    mqtt.connectMqtt()
    mqtt.mqttAsyncClient.messageArrived((err, data) => {
      if (err) {
        console.error("接收消息时发生错误:", err);
      } else {
        console.log("接收到的消息:",JSON.stringify(data));

        // 处理接收到的消息
        if(data.topic.indexOf('sys/properties/set')) {
          let upTopic = this.getUpstreamTopic(data.topic)
          let resultString = '{"result_code": 0, "result_desc": "success" }'
          mqtt.publish(upTopic, resultString);
        }

        // 解析 JSON 字符串
        const parsedData = JSON.parse(data.payload) as ServiceData;

        const ledStatus = parsedData.services[0].properties.LED状态;

        // 打印结果
        console.log(`Service ID: ${parsedData.services[0].serviceId}`);
        console.log(`LED状态: ${parsedData.services[0].properties.LED状态}`);
        if(ledStatus === 'ON'){
          this.lightStatus = true;
        }else {
          this.lightStatus = false;
        }
        this.setLedStatusAndPublish();
      }
    });
  }

应用侧API

华为的物联网平台提供了应用侧API,实现设备数据采集、命令下发、设备管理等业务场景。

有关应用侧API参见:应用侧API参考_设备接入 IoTDA_华为云

为了简化应用侧程序的开发,华为提供了各种语言的SDK:SDK概述_设备接入 IoTDA_华为云。不过,今天不介绍SDK,只介绍如何用API Explorer进行API测试和学习。

华为云API Explorer为开发者提供一站式API 解决方案 统一平台,集成华为 云服务 所有开放API,支持全量快速检索、可视化调试、帮助文档、代码示例等能力,帮助开发者快速查找、学习API和使用API开发代码。API Explorer致力于帮助您更快地查找华为云Open API,您可以使用API Explorer来检索华为云开放的API并查看相应的文档,同时应用于API调试、 故障排查 等场景。

API Explorer的网站:https://console.huaweicloud.com/apiexplorer/#/openapi/overview

测试设备属性设置功能

我在API Explorer中对test设备的"LED状态"属性进行了修改。

程序可以正常收到下发的指令,并根据指令进行开灯和关灯操作。

结语

至此,我们完成了智能中控屏接入物联网的操作。我们的测试仍然将继续。

相关推荐
深圳启明云端科技9 小时前
ESP-Skainet智能语音助手,ESP32-S3物联网方案,设备高效语音交互
物联网·语音助手·乐鑫·语音交互·无线方案
wn53110 小时前
【编程简史:Eclipse 之物联网】
java·物联网·程序人生·eclipse·开源
云山工作室10 小时前
面向智慧农业的物联网监测系统设计(论文+源码+实物)
stm32·单片机·嵌入式硬件·物联网·毕业设计·毕设
梦想养猫开书店1 天前
30、Flink中操作已经配置好的远程文件系统
flink·华为云
华为云PaaS服务小智1 天前
开源安全一站式构建!开启企业开源治理新篇章
安全·开源·华为云
枫叶丹41 天前
【HarmonyOS之旅】基于ArkTS开发(三) -> 兼容JS的类Web开发(四) -> 常见组件(一)
前端·javascript·华为·华为云·harmonyos
B_DDD1 天前
昇思打卡营第五期(MindNLP特辑)番外:硅基流动 x 华为云DeepSeek V3 API推理MindTinyRAG
华为云·api·deepseek·deepseek v3·昇腾云
沐欣工作室_lvyiyi1 天前
基于单片机的智能家居设计(论文+源码)
stm32·单片机·嵌入式硬件·物联网·智能家居·指纹识别