泉缘泉 发表于 5 天前

鸿蒙版《智慧农业APP》通过华为云IoT平台实现软件硬件互联

一、原理图



https://i-blog.csdnimg.cn/img_convert/6144f8dbfa28c07db0a7aea106cd35e3.png
本篇不涉及硬件相干的功能开辟,硬件装备使用MQTT客户端模仿,假如有硬件相干经验的可以直接使用真实硬件代替MQTT客户端。
1、华为云物联网服务器

华为云物联网平台是硬件装备端跟移动APP端数据的中转平台,硬件装备端定时上报收罗都的数据到云平台,移动APP端可以从云平台定时的拉取硬件装备端上报的数据并且表现给管理员,移动APP端可以发送指令到云平台,硬件装备端通过”订阅“云平台指定的服务,从而得到移动APP端发送的指令,从而对装备端举行相应的操作。
2、硬件装备端

(1)订阅

硬件装备端可以”订阅“云平台装备的服务,从而获取到移动APP端通过云平台下发给硬件装备端的指令。
(2)发布

硬件装备端可以定时的通过自身的4G或者WIFI模块向云平台上报自己收罗的数据。
3、移动APP端

(1)数据展示

移动APP端通过丰富直观的页面效果将传感器收罗到的数据展示给管理员。
(2)拉取影子数据

移动APP端可以通过平台提供的接口,通过HTTP哀求获取硬件装备端上报的数据。
(3)发送指令

移动APP端可以通过平台提供的接口,通过HTTP哀求向硬件装备端发送操作指令。
二、华为IOT云平台

1、注册登录

需要先注册并且登录完成实名认证(共建智能世界云底座-华为云)
2、购买免费版的I0TDA


https://i-blog.csdnimg.cn/img_convert/eeb63ed3f858a3b08f9f6b56bd317340.png

https://i-blog.csdnimg.cn/img_convert/73b5426c3891cea4115a213222623a51.png
3、创建产物

相当于java的类概念,在物联网平台中,某一类具有相同本领或特性的装备的合集被称为一款产物,比如智慧农业中全部的温度传感器,或者湿度传感器等。

https://i-blog.csdnimg.cn/img_convert/67e6b3a3ff1d8c8910512d44d3b55d2b.png

https://i-blog.csdnimg.cn/img_convert/d9ac32457fdad1d42180b7b9ee4b9ecc.png
4、给产物创建模子

所谓的模子就是该产物需要上传那些数据,这些数据在云平台对应的存储变量,比如温度计需要上传温度。

https://i-blog.csdnimg.cn/img_convert/2161014f4c7dc917a9269451a6afa6ff.png
4.1、创建服务ID


https://i-blog.csdnimg.cn/img_convert/69ea2861c06997b31afc56e0831db02d.png
4.2、添加属性


https://i-blog.csdnimg.cn/img_convert/91010a13fc0c600f4c6ef7451bc699fb.png
5、创建装备

相当于java的对象概念。
5.1、装备注册


https://i-blog.csdnimg.cn/img_convert/1ef4ff9e29905c82004fdec9aedb0e67.png
5.2、保存装备id以及暗码(紧张)


https://i-blog.csdnimg.cn/img_convert/bdde62253ffbc7aaac0aad5491cc78d1.png
三、模仿硬件装备客户端

我们目前不考虑硬件装备端的开辟过程,我们使用模仿客户端实现硬件装备的模仿。(全部的硬件装备都会遵循相同的数据交互规范,即MQTT协议)
1、模仿客户端下载

一位大佬自研开辟的客户端,大家多多支持。
链接:百度网盘 请输入提取码 提取码:qgm2
https://i-blog.csdnimg.cn/img_convert/999dd003fb5b8400bcd4e7d6980280d4.png
2、得到云平台IP以及登录端口


https://i-blog.csdnimg.cn/img_convert/1c8b9a2086aae79c0ab9187a5acb6f94.png
2.1、云平台IP

复制第三步的域名,打开cmd,输入命令:ping 域名

https://i-blog.csdnimg.cn/img_convert/4f6c94dba1ade34538467f870dc86643.png
2.2、端标语

MQTT默认端标语1883
3、换取硬件装备登录云平台的三元组

所谓的三原则就是客户端id、用户名、以及暗码,此中需要两个紧张的数据就是5.2末节保存的文件内里的device_id跟secret,通过以下链接换取:
Huaweicloud IoTDA Mqtt ClientId Generator

https://i-blog.csdnimg.cn/img_convert/fcfc670179d3d7e813f0e2f48def00c8.png
4、把三元组信息填入模仿客户端

装备上线乐成

https://i-blog.csdnimg.cn/img_convert/8fc0e9fc501a0c48f1fdc00b5257c554.png
四、硬件装备端连接云平台

1、订阅

1.1、订阅地址

装备端订阅云平台数据,当移动APP端发送指令,装备端可以得到该指令数据。
固定的订阅地址格式:$oc/devices/{device_Id}/sys/commands/#
在该案例中device_Id更换为668758a55830dc113ecaf2f0_temperature_sen##_###,完备的订阅路径为:
$oc/devices/668758a55830dc113ecaf2f0_temperature_sen##_###/sys/commands/#

https://i-blog.csdnimg.cn/img_convert/686084475554a837672d6e2f6344a3e0.png
2、上报数据

2.1、上报地址

装备端可以上报自己收罗到的数据,上报的数据格式是JSON格式。
固定的上报地址格式:$oc/devices/{device_Id}/sys/properties/report
在该案例中device_Id更换为668758a55830dc113ecaf2f0_temperature_sen###_###,完备的上报路径为:
$oc/devices/668758a55830dc113ecaf2f0_temperature_sen###_###/sys/properties/report
2.2、上报数据格式

{
    "services":[
      {
            "service_id":"all_temperature_sensor",
            "properties":{
                "temperature":11
            }
      }
    ]
} {"services":[{"service_id":"all_temperature_sensor","properties":{"temperature":11}}]} 此中的service_id为:

https://i-blog.csdnimg.cn/img_convert/82a10d910e6aac6fee981a6b80e0a831.png

properties为模子内里的数据:

https://i-blog.csdnimg.cn/img_convert/57e15360d69008dff702fe684b317ee2.png

2.3、模仿客户端


https://i-blog.csdnimg.cn/img_convert/2b237c05243a7a3f2bf2acc1d73fd97f.png
云平台检察

https://i-blog.csdnimg.cn/img_convert/6574f95b8b12e44d191bf16075ecd28c.png

五、移动APP端连接云平台


https://i-blog.csdnimg.cn/img_convert/cf07fb38f95e9f6b9c164c4d26a6f60c.png
移动APP端基本有两个操作,一个是获取平台存储的装备端上传的数据,二是通过云平台给装备端发送指定。
1、创建IAM账号

我们每次从云平台上获取装备端上传的数据都需要身份认证,认证的令牌就是token,我们需要调用指定的接口,上传我们个人信息获取token,在线调试以及官方文档:https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCreateAgencyToken。
1.1、创建IAM账号(要求必须新建一个用户)


https://i-blog.csdnimg.cn/img_convert/8c723378dab85a433a0332b4cc421713.png


https://i-blog.csdnimg.cn/img_convert/b49ed36e73d87793d97de19a67918c3b.png

https://i-blog.csdnimg.cn/img_convert/1f6019ff586d9ca5bf362e1081dc83ba.png

https://i-blog.csdnimg.cn/img_convert/a336fa038375cdc17c90da2018303328.png
赋予管理员权限(实际生产根据自身情况赋予权限)

https://i-blog.csdnimg.cn/img_convert/5d71eaf299a8d93eb100b1cc46091d70.png

在该过程中包罗获取token三个非常紧张的数据:
IAMDomain:IAM用户所属账号名,就是主账号名称
IAMUser:IAM用户名,就是刚才创建的用户的用户名
IAMPassword:IAM用户密码,就是刚才创建的用户的密码
https://i-blog.csdnimg.cn/img_convert/117ba6662024cf71f001e1cac600a8bd.png
另外一个参数是项目名称:根据自己创建IoTDA实例的地区取对应的值
cn-north-1:项目名称,取值就是cn-north-4
https://i-blog.csdnimg.cn/img_convert/f79c1c56c9dc0ff327af13e6d0ff1e57.png
然后到统一身份认证内里的项目分类中检察

https://i-blog.csdnimg.cn/img_convert/0bf3681b3e60f81a2bbce5880872e3e8.png
1.2、哀求地址

POST https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens?nocatalog=true 1.3、哀求参数格式

请求的header参数:
{
    "Content-Type": "application/json"
}
请求的body参数:
{
   "auth": {
       "identity": {
           "methods": [
               "password"                         //固定写法
         ],
           "password": {
               "user": {
                   "domain": {
                       "name": "IAMDomain"        //IAM用户所属账号名
                 },
                   "name": "IAMUser",             //IAM用户名
                   "password": "IAMPassword"      //IAM用户密码
             }
         }
     },
       "scope": {
           "project": {
               "name": "cn-north-4"               //项目名称
         }
     }
 }
}
​ 2、应用内获取token

2.1、安装axios模块

本次项目的HTTP哀求使用了axios模块,以是需要先给项目安装axios模块
打开编辑器终端输入命令回车即可:

ohpm install @ohos/axios
https://i-blog.csdnimg.cn/img_convert/3f0b408d269e1052dbc46fc30327d537.png
2.2、构建哀求体数据模子

由于harmony OS NEXT严格要求数据类型,以是需要创建用于构建哀求body参数的数据模子对象
代码简单并且没有技术含量这里省略代码
https://i-blog.csdnimg.cn/img_convert/c47644ddea2fb998af030003c486bcee.png
2.3、发送哀求获取token

由于token的有用期是24小时,以是我们没有必须每次跟云平台交货都哀求token,以是在移动App端把第一次获取到的token存储到首选项中,然后通过定时器每隔24小时以后再次获取一次即可。获取token是全局的方式,以是可以把获取token相干的操作放到项目启动的时间经行,对应到步调中就是写在EntryAbility的onWindowStageCreate方法内里即可
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';
import { IAMTokenPreferencesDataUtil } from '../utils/IAMTokenPreferencesDataUtil';
import { AuthInfo } from '../IAMAuth/AuthInfo';
import { Auth } from '../IAMAuth/Auth';
import { Identity } from '../IAMAuth/Identity';
import { Password } from '../IAMAuth/Password';
import { User } from '../IAMAuth/User';
import { Domain } from '../IAMAuth/Domain';
import { Scope } from '../IAMAuth/Scope';
import axios, { AxiosError, AxiosResponse } from '@ohos/axios';
import { Project } from '../IAMAuth/Project';

export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
}
getIAMToken = ():void => {
    /**
   * 封装请求body参数
   */
    const authInfo: AuthInfo= new AuthInfo();
    const auth: Auth = new Auth();

    const identity: Identity = new Identity();
    identity.methods = ['password'];

    const password: Password = new Password();

    const user: User = new User();
    user.name = 'IAM用户名';
    user.password = 'IAM用户密码';
    const domain: Domain = new Domain();
    domain.name = 'IAM用户所属账号名';
    user.domain = domain;
    password.user = user;
    identity.password = password;

    constscope: Scope = new Scope();
    const project: Project = new Project();
    project.name = 'cn-north-4';
    scope.project = project;

    auth.identity = identity;
    auth.scope = scope;
    authInfo.auth = auth;

    /**
   * 通过axios发送请求
   */
    const url: string = 'https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens?nocatalog=true';
    const axiosInstance = axios.create({
      headers:{
      "Content-Type": "application/json"
      }
    });
    axiosInstance.post(url, authInfo).then((response: AxiosResponse) => {
      /**
       * 相应头里面的x-subject-token就是我们要的token
       */
      const token: string = response.headers['x-subject-token'];
      console.log('testTag','getIAMToken获得的token是:', token);
      /**
       * 将token存储到首选项中
       */
      IAMTokenPreferencesDataUtil.init().setPreferencesData('token', token);
    }).catch((error: AxiosError) => {
      console.log('testTag',JSON.stringify(error));
    })
}


onDestroy(): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}

onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
        /**
                定时器默认不会先执行先执行一次,必须要到24小时以后才会执行,所以自己手动先调用下
        */
    this.getIAMToken();
    setInterval(this.getIAMToken.bind(this), 24 * 60 * 59 * 10000);

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
      hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
      return;
      }
      hilog.info(0x0000, 'testTag', 'Succeeded in loading the content.');
    });
}

onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}

onForeground(): void {
    // Ability has brought to foreground
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}

onBackground(): void {
    // Ability has back to background
    hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}
2.4、保存token到首选项

在上面的代码中涉及到的通过首选项保存用户数据的操作,一下是工具类
import { preferences } from '@kit.ArkData';

export class IAMTokenPreferencesDataUtil{
private static initObject: IAMTokenPreferencesDataUtil = new IAMTokenPreferencesDataUtil();
private constructor() {
}
static init(): IAMTokenPreferencesDataUtil{
    return IAMTokenPreferencesDataUtil.initObject;
}

private getPreferencesObject(): preferences.Preferences {
    const preferencesObject = preferences.getPreferencesSync(getContext(), {name: 'iamToken'});
    return preferencesObject;
}

getPreferencesData(name: string) {
    const obj: preferences.Preferences = this.getPreferencesObject();
    const token = obj.getSync(name, '') as string;
    return token;
}
setPreferencesData(name: string, value: string) {
    const obj: preferences.Preferences = this.getPreferencesObject();
    obj.put(name, value)
}
} 3、获取云平台装备上传的数据

3.1、哀求地址

先通过测试地址表现的配置参数,从而获取真实的哀求地址,测试地址如下:
https://console.huaweicloud.com/apiexplorer/#/openapi/IoTDA/doc?api=ShowDeviceShadow

https://i-blog.csdnimg.cn/img_convert/a51d2e971729ecc941aadead9d16279f.png

https://i-blog.csdnimg.cn/img_convert/5ac966aba2ec900edb37a8698384df58.png
3.2、哀求参数格式

只需要带两个headers参数:
{
    "Content-Type": "application/json",
    "X-Auth-Token": token
} 3.3、获取云平台数据

我们可以每隔5秒获取一下数据,包管移动APP端和装备端数据同步
import { SensorInfo } from '../../models/SensorInfo';
import { WeatherDetailsCard } from './WeatherDetailsCard'
import { IAMTokenPreferencesDataUtil } from '../../utils/IAMTokenPreferencesDataUtil';
import axios, { AxiosError, AxiosResponse } from '@ohos/axios';
import { hilog } from '@kit.PerformanceAnalysisKit';

@Component
export struct WeatherDetailsCardList {

@State sensorInfo: SensorInfo = new SensorInfo();

aboutToAppear(): void {
    this.getSensorAll();
    setInterval(this.getSensorAll.bind(this), 3000);
}
getSensorAll = (): void => {
    const token = IAMTokenPreferencesDataUtil.init().getPreferencesData('token');
      //这里记住该成自己的地址
    const url = 'https://#######:443/v5/iot/c7214059c7394275a056d234b44af71c/devices/6684b5b95830dc113eca9620_temperature_sensor_1/shadow';
    const axiosInstance = axios.create({
      headers:{
      "Content-Type": "application/json",
      "X-Auth-Token": token
      }
    });

    axiosInstance.get(url).then((response: AxiosResponse) => {
      const shadow: string = JSON.stringify(response.data['shadow']);
      const shadowObject = JSON.parse(shadow).reported.properties as SensorInfo;
      // 逐个属性进行赋值
      this.sensorInfo.outdoor_temperature = shadowObject.outdoor_temperature;
      this.sensorInfo.longhua_1_green_house_temperature = shadowObject.longhua_1_green_house_temperature;
      this.sensorInfo.longhua_1_green_house_humidity = shadowObject.longhua_1_green_house_humidity;
      this.sensorInfo.longhua_1_green_house_blower = shadowObject.longhua_1_green_house_blower;
      console.log('获取的影子数据是: : ', JSON.stringify(shadow))
      hilog.info(2311, 'testTag', '获取的影子数据是: ', JSON.stringify(this.sensorInfo))
    }).catch((error: AxiosError) => {
      console.log('testTag', JSON.stringify(error));
    })
}
build() {
    Row({space: 20}) {
      WeatherDetailsCard({
      title: '室外温度',
      value: this.sensorInfo.outdoor_temperature + '°C',
      icon: $r('app.media.wendu'),
      errorValue: '',
      errorFlagIcon: $r('app.media.shangjiantou'),
      flag: false
      });
      WeatherDetailsCard({
      title: '室内温度',
      value: this.sensorInfo.longhua_1_green_house_temperature + '°C',
      icon: $r('app.media.wendu'),
      errorValue: '10°C',
      errorFlagIcon: $r('app.media.shangjiantou'),
      flag: true
      });
    }
}
} 注意:
1、setInterval(this.getSensorAll.bind(this), 3000);定时器的这个语法会导致getSensorAll方法内丢失this,我们需要进行两步操作,第一步在定义getSensorAll方法的时候一箭头函数的方式定义: getSensorAll = (): void => {},第二步在定时器的第一个参数上绑定this:this.getSensorAll.bind(this)
2、请求响应回来的数据在获取的时候比较麻烦(相应JSON嵌套的有点多),所以建议一个一个获取。 3.4、数据表现

精确的绑定到页面组件即可
4、通过云平台给装备下发指令

由于刚才我们创建的温度计产物不需要下发指令,我们可以创建另外的产物,比如补光灯、鼓风机等,原理基本相同,这里使用鼓风机为例(产物以及装备自己创建)
4.1、哀求地址

同样的先通过测试地址测试获取真实的哀求地址,测试地址如下:
https://console.huaweicloud.com/apiexplorer/#/openapi/IoTDA/doc?api=UpdateProperties

https://i-blog.csdnimg.cn/img_convert/d25b580c85d616bb51d9995609fa5383.png

测试乐成得到真实哀求地址:

https://i-blog.csdnimg.cn/img_convert/71908b3de695487bc92e8a8b56d6d92f.png
注意: 由于是模仿装备,以是模仿装备收到指定以后无法主动回应,如许会导致当前哀求超时,但是没关系,模仿装备已经接收到的指令。

https://i-blog.csdnimg.cn/img_convert/59e6db7a78bc62809cb8c052b87eeb90.png
4.2、哀求参数格式

{
"services": {
    "longhua_1_green_house_blower": 0
}
}
https://i-blog.csdnimg.cn/img_convert/ca37bf55b2f6c00bf3a2248cb139eb82.png
4.3、移动APP下发指令

4.1、4.2已经实现了在云平台通过HTTPS哀求下发指令给装备了,把这个操作通过APP内里的一个按钮点击发送对应的HTTPS哀求即可。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 鸿蒙版《智慧农业APP》通过华为云IoT平台实现软件硬件互联