鸿蒙版《智慧农业APP》通过华为云IoT平台实现软件硬件互联
一、原理图
本篇不涉及硬件相关的功能开发,硬件设备使用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、注册登录
需要先注册并且登录完成实名认证(https://www.huaweicloud.com/)
2、购买免费版的I0TDA
3、创建产品
相当于java的类概念,在物联网平台中,某一类具有相同能力或特征的设备的合集被称为一款产品,比如智慧农业中所有的温度传感器,或者湿度传感器等。
4、给产品创建模型
所谓的模型就是该产品需要上传那些数据,这些数据在云平台对应的存储变量,比如温度计需要上传温度。
4.1、创建服务ID
4.2、添加属性
5、创建设备
相当于java的对象概念。
5.1、设备注册
5.2、保存设备id以及密码(重要)
三、模拟硬件设备客户端
我们目前不考虑硬件设备端的开发过程,我们使用模拟客户端实现硬件设备的模拟。(所有的硬件设备都会遵循相同的数据交互规范,即MQTT协议)
1、模拟客户端下载
一位大佬自研开发的客户端,大家多多支持。
链接:https://pan.baidu.com/s/1xpROACEco3CJj3Vlo3sObQ 提取码:qgm2
2、获得云平台IP以及登录端口
2.1、云平台IP
复制第三步的域名,打开cmd,输入命令:ping 域名
2.2、端口号
MQTT默认端口号1883
3、换取硬件设备登录云平台的三元组
所谓的三原则就是客户端id、用户名、以及密码,其中需要两个重要的数据就是5.2小节保存的文件里面的device_id跟secret,通过以下链接换取:
https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
4、把三元组信息填入模拟客户端
设备上线成功
四、硬件设备端连接云平台
1、订阅
1.1、订阅地址
设备端订阅云平台数据,当移动APP端发送指令,设备端可以获得该指令数据。
固定的订阅地址格式:$oc/devices/{device_Id}/sys/commands/#
在该案例中device_Id替换为668758a55830dc113ecaf2f0_temperature_sen##_###,完整的订阅路径为:
$oc/devices/668758a55830dc113ecaf2f0_temperature_sen##_###/sys/commands/#
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为:
properties为模型里面的数据:
2.3、模拟客户端
云平台查看
五、移动APP端连接云平台
移动APP端基本有两个操作,一个是获取平台存储的设备端上传的数据,二是通过云平台给设备端发送指定。
1、创建IAM账号
我们每次从云平台上获取设备端上传的数据都需要身份认证,认证的令牌就是token,我们需要调用指定的接口,上传我们个人信息获取token,在线调试以及官方文档:https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCreateAgencyToken。
1.1、创建IAM账号(要求必须新建一个用户)
赋予管理员权限(实际生产根据自身情况赋予权限)
在该过程中包含获取token三个非常重要的数据:
IAMDomain:IAM用户所属账号名,就是主账号名称
IAMUser:IAM用户名,就是刚才创建的用户的用户名
IAMPassword:IAM用户密码,就是刚才创建的用户的密码
另外一个参数是项目名称:根据自己创建IoTDA实例的地区取对应的值
cn-north-1:项目名称,取值就是cn-north-4
然后到统一身份认证里面的项目分类中查看
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
2.2、构建请求体数据模型
因为harmony OS NEXT严格要求数据类型,所以需要创建用于构建请求body参数的数据模型对象
代码简单并且没有技术含量这里省略代码
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;
const scope: 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
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)[0].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
测试成功获得真实请求地址:
注意: 因为是模拟设备,所以模拟设备收到指定以后无法自动回应,这样会导致当前请求超时,但是没关系,模拟设备已经接收到的指令。
4.2、请求参数格式
{
"services": {
"longhua_1_green_house_blower": 0
}
}
4.3、移动APP下发指令
4.1、4.2已经实现了在云平台通过HTTPS请求下发指令给设备了,把这个操作通过APP里面的一个按钮点击发送对应的HTTPS请求即可。
鸿蒙版《智慧农业APP》通过华为云IoT平台实现软件硬件互联的更多相关文章
- 聊聊如何在华为云IoT平台进行产品开发
摘要:华为云物联网平台承载着南北向数据互通的功能职责. 本文分享自华为云社区<如何基于华为云IoT物联网平台进行产品开发>,作者: Super.雯 . 华为云物联网平台承载着南北向数据互通 ...
- OpenHarmony3.0如何轻松连接华为云IoT设备接入平台?
摘要:本文主要介绍基于OpenHarmony 3.0版本来对接华为云IoT设备接入IoTDA,以小熊派BearPi-HM_Nano开发板为例,使用huaweicloud_iot_link SDK对接华 ...
- 基于华为云IoT Studio自助生成10万行代码的奥秘
华为IoT小助手们搬好板凳.备好笔记本.听了HDC.Cloud的几场华为云技术架构师的直播讲课,感觉获益匪浅却又似懂非懂,直后悔自己没有好好打下基础.为了避免再次出现这样的情况,小助手偷偷跑去找了华为 ...
- 华为云MVP熊保松谈物联网开发:华为云IoT是首选,小熊派是神器
摘要:在AI.5G的技术驱动下,物联网行业的发展愈加如火如荼,开发者在技术的快速更迭间,也得乘风破浪跟上新技术的节奏. 在AI.5G的技术驱动下,物联网行业的发展愈加如火如荼,开发者在技术的快速更迭间 ...
- CC2530_ZigBee+华为云IOT:设计一套属于自己的冷链采集系统
摘要:以CC2530单片机为核心器件,设计一个冷链环境信息采集系统,利用传感器技术对冷藏仓内的环境参数进行采集,上传到华为云物联网云平台,然后通过手机端或移动端进行显示,便于分析,观察冷链环境信息. ...
- 基于华为云IOT及无线RFID技术的智慧仓储解决方案最佳实践系列一
[摘要]仓储管理存在四大细分场景:出入库管理.盘点.分拣和货物跟踪.本系列将介绍利用华为云IOT全栈云服务,端侧采用华为收发分离式RFID解决方案,打造端到端到IOT智慧仓储解决方案的最佳实践. 仓储 ...
- 直击Huawei Mate 40产线背后的华为云IoT智能制造
摘要:数字孪生?在数字世界找到物理世界的设备! 本文分享自华为云社区<[云驻共创]Huawei Mate 40产线直击之华为云IoT智能制造助力工厂数字化转型>,原文作者:启明. Part ...
- 基于STM32+华为云IOT设计智能称重系统
摘要:选择部署多个重量传感器和必要的算法.通过WiFi 通信模块.GPS定位模块,采集车辆称重数据一地理位置信息,并通过网络发送至云平台,设计图形化UI界面展示称重.地图位置等重要信息,实现对称重系统 ...
- 手把手教你基于luatos的4G(LTE Cat.1)模组接入华为云物联网平台
摘要:本期文章采用了4G LTE Cat.1模块,编程语言用的是lua,实现对华为云物联网平台的设备通信与控制 本文分享自华为云社区<基于luatos的4G(LTE Cat.1)模组接入华为云物 ...
- 阿里云 IOT 对接设备开发 C# 开发设备对接阿里云 IOT平台
一,创建阿里云 IOT 产品.设备 目前阿里云每月赠送 100 万条流量,可以免费使用基础版.高级版,开通后即可免费使用. 阿里云 IOT 平台地址 https://iot.console.aliyu ...
随机推荐
- springboot2.1.6整合activiti6.0(二)--网页流程编辑器bpmnjs
网页流程编辑器bpmnjs 官网:https://bpmn.io/ github:https://github.com/bpmn-io/bpmn-js-examples 因为还需要做一些改造,才能使其 ...
- vue+elementUI 表格操作按钮添加loading
前言 表格操作栏,某个操作需要异步请求才能做跳转等 方案 整个列表每行都加一个loading字段,不够优雅 利用$set方法 改变当前行当前按钮loading,可行(代码如下) //按钮 row.lo ...
- 【ARM+Qt+OpenCV】基于ARM的双目图像采集系统
点击查看代码 系统使用ARM处理器,运行linux系统,Qt创建工程编写主程序,可以使用OpenCV进行图像处理. 通过两个摄像头采集会图像,在LCD上进行显示,然后通过LCD上的按钮实现退出程序.保 ...
- Docker Hub 镜像加速器——持续更新(2025年3月12日)
国内从 Docker Hub 拉取镜像有时会遇到困难,此时可以配置镜像加速器.Docker 官方和国内很多云服务商都提供了国内加速器服务. 配置加速地址 Ubuntu 16.04+.Debian 8+ ...
- 查看docker服务状态
root用户使用 #查看docker服务状态: systemctl status docker 非root用户使用 #查看docker服务: sudo systemctl status docker
- Delphi 检测鼠标键盘多久没有活动
function GetInputAwayTime():DWORD; var lpi:TLastInputInfo; begin lpi.cbSize := sizeof(lpi); GetLastI ...
- Java 8的新特性还不了解?快进来!
能坚持别人不能坚持的,才能拥有你想拥有的.关注 编程大道,让我们一起成长
- [源码系列:手写spring] IOC第五节:Bean注入Bean
主要内容 添加BeanReference类,包装一个bean对另一个bean的引用.如beanA引用beanB,那么在实例化beanA时,如果propertyValue.value是BeanRefer ...
- php通过Curl给接口上传文件。
在 PHP 中使用 cURL 上传文件至接口,你可以通过 CURLOPT_POSTFIELDS 选项来设置文件的内容.以下是一个示例: function uploadFile($url, $fileP ...
- 递归--java进阶day08
1.递归 2.案例 1.案例一 求出5的阶乘 我们会发现其中存在规律 我们先定义一个带返回值的方法,方便调用者使用 当给的数是1时,1的阶乘还是1,我们就可以直接返回 如果走了else,说明给的数不是 ...