基于OpenHarmony的智能阳台
一、概述
基于OpenHarmony智能阳台可以实时监控室外环境是否下雨。当超过设定阈值时,当地启动窗户关闭电机,并报告窗户关闭信息;并与华为对接IoT本设备属于环境监测设备,实时查看当前状态(窗户开关、室外是否下雨等)。
1.实物展示图
我们使用拓维信息-OpenHarmony开发板 雨滴传感器 电机模拟智能阳台设备。
2.系统架构图
基于系统架构图,可以看出OpenHarmony智能阳台主要由三部分组成:
-
数据采集:雨滴传感器采集室外情况并发送给开发板;
-
信号传输:开发板接收传感器数据进行判断,将判断信号发送到电机驱动模块,并将数据上传到华为IoT平台;
-
执行部件:电机控制模块根据单片机信号控制电机。
3.系统流程图
4.系统原理图
二、快速上手
1.硬件准备:
1)预装windows系统的PC机
3)一套雨滴传感器模块
4)一套电机和驱动电机模块(步进电机、直流电机、舵机等)
5)USB Type-C线(Windows工作台通过USB与Niobe Wifi IoT 开发板连接)
具体硬件的详细信息如下:
硬件一:Niobe Wifi IoT开发板
拓维Niobe开发板是专门基于开发板的OpenHarmony 3.0LTS开发板的版本设计,板载高度集成2.4GHz WLAN SoC芯片Hi3861V100。
Hi3861V100芯片集成高性能32bit外设界面包括微处理器、硬件安全引擎和丰富的外设界面SPI、UART、I2C、PWM、 GPIO和多路ADC
Hi3861V100芯片适用于物联网智能终端领域,如智能家电。
拓维信息-OpenHarmony开发板(Talkweb Niobe)官方文件可查看相关资料:开发板相关资料
硬件二:雨滴传感器模块
本项目选用雨滴传感器,目的是监测天气状况并转化为AO电压输出。
(1)雨滴传感器采用FR-04双面材料,镀镍表面,具有抗氧化、导电等性能。
(2)输出形式:模拟量AO电压输出。
(3)AO模拟输出,连接单片机AD检测滴在上面的雨量(雨量越大,输出电压越小)。
硬件3:电机模块
(1)本项目采用直流电机模拟窗开关场景(步进电机或舵机也可根据自身需要选择)。
电机正转一定角度表示开窗,反转一定角度表示关窗。
(2)本项目选用直流电机,故另选L298N直流电机驱动模块的目的是驱动直流电机的运行。
该模块与控制端口的接口:控制直流电机时IN1、IN2和ENA为一组,IN1和IN2是逻辑信号,控制电机的正反转;OUT1和OUT它们控制电机A,接在A 和A-。
2.软件准备:
1)下载并安装虚拟机VMware Workstation:
- VMware Workstation Player(免费版)
- VMware Workstation Pro(专业版)
2)下载Ubuntu20.04镜像:Ubuntu20.04镜像
3)下载安装MobaXterm工具:MobaXterm工具
4)下载并安装开发板USB驱动(CH341SER.EXE–CH340/CH341-USB转串口Windows驱动程序:USB驱动
5)下载安装VS Code编译器:Visual Studio Code
6)下载HiBurn烧录工具:HiBurn烧录工具
3.Linux编译环境配置:
基发基本环境windows 工作台和Linux由服务器组成。windows 可通过工作台samba 服务或ssh 方式访问Linux服务器的编译。其中windows 工作台用来烧录和代码编辑,Linux编译服务器OpenHarmony为了简化步骤,代码,Linux推荐安装编译服务器Ubuntu20.04。
(1)Ubuntu安装
-
在VMware中安装下载Ubuntu20.04。
-
安装后,在终端窗口输入句子ip地址:
ifconfig
获取IP地址记录下来,每个人IP地址不同。
如果获取不成功(虚拟机无法连接到网络),尝试更改网络路径:虚拟机 --> 设置 --> 网络适配器 --> 网络路径
*注:如果查看IP地址如下:
① 根据提示,输入以下命令,安装网络工具:
sudo apt install net-tools
② 如果没有,也可以安装VMware tools工具。
(2)安装samba服务共享文件夹
-
在/home/niobe/(niobe是我的虚拟机的名字,根据个人虚拟机的情况进行调整)目录下新建的文件夹命名为niobecode。
-
配置niobecode读写文件夹的权限。
sudo chmod 777 /home/niobe/niobecode
-
将新建的niobecode文件夹配置/etc/samba/smb.conf中。
使用以下命令输入spt-get安装:
sudo apt-get install samba
查看sanba安装成功的版本:
samba
进入smb.conf文件配置:
sudo vi /etc/samba/smb.conf
-
在smb.conf文件最后加以下句子:
[niobecode] comment = samba home directory path = /home/niobe/ public = yes browseable = yes public = yes writeable = yes read only = no valid users = niobe create mask = 0777 directory mask = 0777 #force user = nobody #force group = nogroup available = yes
添加上述句子后按下ESC保存后退出:
:wq
设置samba的密码:
sudo smbpasswd -a niobe
重新启动samba:
sudo service smbd restart
-
然后在Windows在环境下,右键我的电脑 -> 映射网络驱动器 -> 输入IP地址(在Ubuntu在安装步骤中获得IP地址),将共享文件夹映射到本地。
-
成功后,我们可以在电脑的网络位置看到niobecode文件夹。
(3)MobaXterm通过ssh连接Ubuntu
-
在MobaXterm工具里 Session -> SSH 输入信息,远程地址(获得的IP地址)。
-
登录相关信息。
login as:输入虚拟机用户名
Password:输入虚拟机密码
成功登录后如下:
(4)配置docker编译环境
-
可在官网文档中独立查看Docker环境一节:Docker编译环境
-
加docker的官方GPC密钥:
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
-
添加仓库:
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
-
安装docker:
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
-
运行测试docker:
sudo docker run hello-world
运行成功结果:
Hello from Docker! This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. (amd64) 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker ID: https://hub.docker.com/ For more examples and ideas, visit: https://docs.docker.com/get-started/
-
获取docker镜像:
docker pull swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:0.0.5
如果安装完docker后,执行docker相关的命令,可能会出现以下报错:
可能就是docker 进程使用 Unix Socket 而不是 TCP 端口。
在默认情况下,Unix socket 属于 root 用户,需要 root 权限才能访问。
方法1:使用 sudo 获取管理员权限,运行 docker 命令时在前面加上 sudo。
方法2:docker 守护进程启动的时候,会默认赋予名字为 docker 的用户组读写 Unix socket 的权限,因此只要创建 docker 用户组,并将当前用户加入到 docker 用户组中,那么当前用户就有权限访问 Unix socket 了,进而也就可以执行 docker 相关命令了。
具体操作命名如下:
sudo groupadd docker # 添加docker用户组 sudo gpasswd -a $USER docker # 将登陆用户加入到docker用户组中 newgrp docker # 更新用户组 docker images # 测试docker命令在不加sudo时是否可以使用
-
到此步环境的搭建基本上已经完成了,下面就下载源码进行编写。
4.下载源码
-
首先注册好Gitee账号。
-
进入共享文件夹niobecode:
cd /home/niobe/niobecode
-
安装 git:
sudo apt install git
-
安装 git-lfs:
curl -s https://packagecloud.io/install/repositories/github/git-lfs/script.deb.sh | sudo bash
sudo apt-get install git-lfs
git lfs install
-
repo下载
安装repo python3版本 向下兼容:
curl https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 > /usr/local/bin/repo
赋予脚本可执行权限:
chmod a+x /usr/local/bin/repo
安装requests依赖,或在执行命令时依据提示自动安装:
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple requests
-
使用git https的方式下载开发板源码:
git clone https://gitee.com/talkweb_oh/niobe.git
-
下载本下项目的代码:
在openharmony-sig/knowledge_demo_smart_home仓库中下载本demo的代码
直接下载仓库对应zip包文件,具体下载地址:smart_balcony
-
将对应的代码添加到开发板源码的相应位置:
① 在源码文件下applications\app下新建一个工程文件balcony
② 我们将knowledge_demo_smart_home\tree\master\dev\team_x\smart_balcony\demo_balcony目录下的文件拷贝到balcony文件夹目录下
③ 将knowledge_demo_smart_home\tree\master\dev\team_x\smart_balcony目录下的BUILD.gn文件拷贝applications\app目录下
如果源码文件applications\app目录下有BUILD.gn文件,我们可以在BUILD.gn的基础上添加一条:"balcony:balcony",
,指定balcony
参与编译,将其他不需要编译的工程前加个#就可。
"balcony:balcony",
#"TW001_OS_helloworld:helloworld",
#"TW002_OS_thread:os_thread_example",
#"TW003_OS_timer:os_timer_example",
#"TW004_OS_event:os_event_example",
- 源码目录的简介:
目录名 | 描述 |
---|---|
applications | Niobe WiFi IoT应用程序样例 |
base | 基础软件服务子系统集&硬件服务子系统集 |
build | 组件化编译、构建和配置脚本 |
domains | 增强软件服务子系统集 |
device | 设备适配层以及SDK |
foundation | 系统基础能力子系统集 |
kernel | 内核子系统 |
prebuilts | 编译器及工具链子系统 |
test | 测试子系统 xts套件 |
third_party | 开源第三方组件 |
utils | 常用的工具集 |
vendor | 厂商提供的软件 |
build.py | 编译脚本文件 |
5.编译代码
-
进入niobecode文件夹(OpenHarmony代码的根目录下)执行命令进入Docker构建环境
cd /home/niobe/niobecode
-
进入docker环境来编译源码,Niobe使用的是小型系统的docker编译环境:docker-openharmony:0.0.5
docker run -it -v $(pwd):/home/openharmony swr.cn-south-1.myhuaweicloud.com/openharmony-docker/openharmony-docker:0.0.5
-
此时已经在Docker编译环境下:
-
编译hb文件
输入命令进入niobe文件下:
cd niobe
输入命令:
hb set
-
设置工作目录:
输入 .
输入源码所在目录,点(.)表示当前目录。
通过回车确定选择,选择talkweb niobe_wifi_iot开发板。
-
输入以下命令进行编译:
hb build -b release -f
回车等待编译过程,直到屏幕出现 build success 说明编译成功。
-
查看编译出的固件位置:
当编译完后,在Windows中可以直接查看到最终编译的固件,具体路径在:
Z:\niobe\out\niobe\niobe_wifi_iot\Hi3861_wifiiot_app_allinone.bin
*注意,路劲最前的Z:\是安装samba服务共享文件夹映射在Windows上的磁盘路径。
当然我们可以直接
-
在菜单栏 --> 终端 --> 新建一个终端
-
输入虚拟机账号及密码
这里要注意的是:
ssh niobe@192.168.80.128
6.连接开发板
-
安装CH340驱动。
-
使用TypeC数据线,将拓维niobe开发板与电脑连接起来。
-
连接电脑时需要注意将虚拟机捕获USB的功能关闭。(会导致Windows查看不到串口)
-
查看开发板的串口号
我的电脑–>右键–>管理–>设备管理器–>端口(COM和LPT)–>USB-SERIAL CH340(COMx)
7.烧录程序
在Windows下打开Hiburn工具:
- 点击Refresh就会出现串口号,COM会自动寻找到烧录端口。
-
点击菜单Setting,选择 Com settings设置。
-
在Com settings中设置波特率Baud为:921600,点击确定 。
-
点击Select file,在弹出的文件框中,out目录下(编译出的固件位置),并选中:Hi3861_wifiiot_app_allinone.bin 镜像文件
-
点击Auto burn复选框,然后点击Connect,此时Connect按钮变成Disconnect
-
按一下开发板上的复位按钮,开始烧录程序
- 出现Execution Successful字样,程序烧录完成。
- 烧录完后,点击Disconnect按钮断开串口连接,便于后面调测使用。
8.操作体验
- 能在华为IoT平台上下发命令控制电机的转动。
- 可在雨滴传感器上滴上水珠,达到预定的阈值时,电机转动模拟关窗。
- 能够在华为IoT平台上查看相关传感器测得的数值以及窗户(是否开窗)、环境(是否下雨)状态的情况。
- Wi-Fi连接成功串口显示:
- 华为IoT平台在线调试—可看到数据接收和命令发送的情况:
- 华为IoT平台查看到最新的上报数据:
- 以下分别对四个情景进行分析与说明:
情景一:无雨天气并且使用华为IoT平台下发命令开窗。
当华为IoT平台下发命令Balcony_Control_Motor—>ON;则会执行MotorStatusSet(ON);
语句窗户马达则会转动将窗户打开并且将g_app_cb.Window_flag = 1;
和g_app_cb.motor = 1;
等数据信息上传回华为IoT平台。(Window_flag = ON 表示窗户开着)
华为IoT平台数据信息同步更新:
硬件图如下:
情景二:无雨天气并且使用华为IoT平台下发命令关窗。
当华为IoT平台下发命令Balcony_Control_Motor—>OFF;则会执行MotorStatusSet(OFF);
语句窗户马达则会转动将窗户关闭并且将g_app_cb.Window_flag = 0;
和g_app_cb.motor = 0;
等数据信息上传回华为IoT平台。(Window_flag = OFF 表示窗户关着)
华为IoT平台数据信息同步更新:
硬件图如下:
情景三:窗户开着,检测到下雨天气,则会关窗并且上报数据。
当窗户开着的情况,天气从晴朗天气变成下雨天气,当雨滴检测板检测到雨滴,并且超过设定的阈值的时候,则会执行MotorStatusSet(OFF);
语句,窗户马达将转动将窗户关闭并且将g_app_cb.Rain_flag = 1;g_app_cb.Window_flag = 0;g_app_cb.motor = 0;
等数据信息上传回华为IoT平台。(Rain_flag = ON 表示下雨天气;Window_flag = OFF 表示窗户关着)
(天气情况:晴朗天气变下雨天气,窗户情况:开着窗户变关着窗户)
华为IoT平台数据信息同步更新:
硬件图如下:
情景四:下完雨后,雨滴检测板没有雨滴。
当天气从下雨天气变成晴朗天气,雨滴检测板没有检测到雨滴(此处为了方便实验,使用了纸巾擦除雨滴检测板上的水),g_app_cb.Rain_flag = 0;
等数据信息上传回华为IoT平台。(Rain_flag = OFF 表示无雨天气)
华为IoT平台数据信息同步更新:
硬件图如下:
三、代码分析
1.电机配置部分
(1)电机的初始化
使用开发板上的GPIO7、GPIO8管脚控制电机正反转,使用PWM输出电压控制电机转动速度。
GPIO7和GPIO8的配置一样,但GPIO7使用PWM0,而GPIO8使用PWM1。
IoTGpioInit(IOT_GPIO_IO_GPIO_7);//GPIO初始化
IoTIoSetFunc(IOT_GPIO_IO_GPIO_7, IOT_IO_FUNC_GPIO_7_PWM0_OUT);//GPIO使能
IoTGpioSetDir(IOT_GPIO_IO_GPIO_7, IOT_GPIO_DIR_OUT);//设置GPIO方向---IOT_GPIO_DIR_OUT---输出
IoTGpioSetOutputVal(IOT_GPIO_IO_GPIO_7, IOT_GPIO_VALUE0);//设置GPIO输出电平---低电平
IoTPwmInit(IOT_PWM_PORT_PWM0);//初始化PWM设备
(2)设置电机的开关状态
开窗情景由MotorStatusSet(ON); 电机正转。
关窗情景由MotorStatusSet(OFF); 电机反转。
启动PWM信号输出:使用PWM给定输出频率和相应的占空比指定给端口。
if (status == ON)//正转
{
IoTPwmStart(IOT_PWM_PORT_PWM1, 30, 15000);//PWM1开始工作(GPIO8)---正转---开窗
usleep(400000);//延时400ms
IoTPwmStop(IOT_PWM_PORT_PWM1);//停止PWM1
}
if (status == OFF)//反转
{
IoTPwmStart(IOT_PWM_PORT_PWM0, 30, 15000);//PWM0开始工作(GPIO7)---反转---关窗
usleep(400000);//延时400ms
IoTPwmStop(IOT_PWM_PORT_PWM0);//停止PWM0
}
2.雨滴传感器部分
(1)雨滴传感器初始化
使用开发板上的GPIO4管脚控制雨滴传感器(有雨输出低电平,雨量越大电压越低)
IoTGpioInit(IOT_GPIO_IO_GPIO_4);//GPIO初始化
IoTIoSetFunc(IOT_GPIO_IO_GPIO_4, IOT_IO_FUNC_GPIO_4_GPIO);//GPIO使能
IoTGpioSetDir(IOT_GPIO_IO_GPIO_4, IOT_GPIO_DIR_IN);//设置GPIO方向---IOT_GPIO_DIR_IN---输入
(2)使用ADC采集数据
//ADC转换通道号为ADC1
ret = IoTAdcRead(IOT_ADC_CHANNEL_1, &val, IOT_ADC_EQU_MODEL_8, IOT_ADC_CUR_BAIS_DEFAULT, 256);
//将电压数值转化为百位数,以便数据分析与观察
val = IOTAdcConvertToVoltage(val);
val = 3.4-val;
voltage = (float)((float)val)/3.5*100;
3.连接华为IoT平台部分
(1)华为IoT平台相关配置
设备端与云端通讯采用的相关协议为MQTT协议。
首先在华为IoT平台选择MQTT协议的接入地址,并复制接入地址在本地电脑上ping一下接入地址。得到一个地址为121.36.42.100的地址,此地址为华为IoT平台的地址。
需先在华为云IoT平台上创建产品并且注册对应的设备,华为IoT平台就会分配给设备一个设备ID,设备端可通过设备ID和相应的密钥来确保安全可信的连接到华为IoT平台。
连接华为IoT平台后,设备端可向华为IoT平台上传设备状态、数据等信息。同时华为IoT平台也可以下发命令给设备端,设备端收到命令后进行响应。
(2)华为IoT平台的搭建
在华为云平台—设备接入IoT—创建一个产品,并添加服务、属性、命令等内容。
服务信息:(服务ID、服务类型) 属性信息:(属性名称、数据类型) 命令信息:(命令名称、参数名称、数据类型、长度、枚举)
新增测试设备–填写设备名称、设备标识码–创建成功则会得到两条信息:设备ID、设备密钥
注:代码中的服务ID、属性名称、命令名称等与华为IoT平台一一对应
设备对接信息网站填写设备ID、设备密钥:Huaweicloud IoTDA Mqtt ClientId Generator
生成相应信息:Clienid、Username、Password。(每个人生成的信息都是不一样的)
#define CLIENT_ID "62062355de9933029be769ff_0_0_2022021109"
#define USERNAME "62062355de9933029be769ff"
#define PASSWORD "2d524c6fdd13a6c2392e61e16bac91053272c5cc3dcad72d7b87"
引用开源代码上的oc_mqtt.c和oc_mqtt_profile_package.c函数编写代码。
Wi-Fi连接配置:引用源码上的wifi_connect.c函数编写代码,连接Wi-Fi需要用到本地的Wi-Fi账号密码。
(3)上传数据的配置
static void deal_report_msg(report_t *report)
{
oc_mqtt_profile_service_t service;//定义Service级别数据,该处对应云平台配置的Balcony服务下的数据
oc_mqtt_profile_kv_t voltage;//定义属性级别数据,该处对应云平台配置的属性voltage信息
oc_mqtt_profile_kv_t Window_flag;//定义属性级别数据,该处对应云平台配置的属性Window_flag信息
oc_mqtt_profile_kv_t Rain_flag;//定义属性级别数据,该处对应云平台配置的属性Rain_flag信息
oc_mqtt_profile_kv_t motor;//定义属性级别数据,该处对应云平台配置的属性motor信息
service.event_time = NULL;
service.service_id = "Balcony";//对应云平台配置的服务ID
service.service_property = &voltage;//在Balcony服务下添加属性信息
service.nxt = NULL;//该产品上报数据中仅存在Balcony一种服务,所以next指针为空
voltage.key = "voltage";//对应云平台配置的属性名称
voltage.value = &report->voltage;//voltage的取值由设备实际状态voltage决定。
voltage.type = EN_OC_MQTT_PROFILE_VALUE_FLOAT;//对应云平台配置的数据类型
voltage.nxt = &Window_flag;//继续添加Balcony服务下的另一属性。
Window_flag.key = "Window_flag";
Window_flag.value = g_app_cb.Window_flag ? "ON" : "OFF";
Window_flag.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
Window_flag.nxt = &Rain_flag;
Rain_flag.key = "Rain_flag";
Rain_flag.value = g_app_cb.Rain_flag ? "ON" : "OFF";
Rain_flag.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
Rain_flag.nxt = &motor;
motor.key = "Motor_Status";
motor.value = g_app_cb.motor ? "ON" : "OFF";//Motor_Status的ON,OFF取值由设备实际
motor.type = EN_OC_MQTT_PROFILE_VALUE_STRING;
motor.nxt = NULL;//Balcony服务下没有其它属性了,next置为null。
oc_mqtt_profile_propertyreport(USERNAME, &service);//打包数据
return;
}
(4)下发命令控制电机的配置
if (0 == strcmp(cJSON_GetStringValue(obj_cmdname), "Balcony_Control_Motor"))
{
obj_paras = cJSON_GetObjectItem(obj_root, "Paras");
if (NULL == obj_paras)
{
goto EXIT_OBJPARAS;
}
obj_para = cJSON_GetObjectItem(obj_paras, "Motor");
if (NULL == obj_para)
{
goto EXIT_OBJPARA;
}
//操作电动马达
if (0 == strcmp(cJSON_GetStringValue(obj_para), "ON"))
{
g_app_cb.motor = 1;
MotorStatusSet(ON);//开窗--电机正转
g_app_cb.Window_flag = 1;
Window_flag = 1;
}
else
{
g_app_cb.motor = 0;
MotorStatusSet(OFF);//关窗--电机反转
g_app_cb.Window_flag = 0;
Window_flag = 0;
}
经过层层解析,最终解出对应的命令,并设置到设备中。
四、问题总结及解决过程
问题一:环境搭建
搭建好一个开发环境是非常有必要的,搭建好环境对后面开发板的学习及OpenHarmony的开发都有一个事半功倍的作用,从安装虚拟机,下载源码,代码编写以及编译调试等步骤,若其中一步出现错误则可能在往后的开发过程中会出现不能预知的错误。
对此经过几天的查阅资料与观看一些导师的课程等,最终完成了环境的搭建以及烧录过程。对此也编写了一篇《基于OpenHarmony开发板的环境搭建及烧录过程(拓维Niobe开发板)》的文章,具体文章已发布于Gitee上:基于OpenHarmony开发板的环境搭建及烧录过程。
问题二:硬件连接
在硬件连接的过程,电机驱动模块的GND没有和开发板的GND相连,导致电机不转,输出端电压为0V。
查阅了资料发现L298N供电的12V如果是用另外电源供电的话,那么需要将单片机的GND和驱动模块的GND连接起来,这样单片机上过来的逻辑信号才有个参考点,板载12V稳压芯片的输入引脚和电机供电驱动接线端子导通的。
问题三:烧录问题
在烧录的时候,如果外接的传感器(雨滴传感器)的VCC接口接在开发板的5V上可能会导致烧录的时候复位不成功。
所以我们在烧录的时候需要将传感器接在开发板的5V及GND先断开,等待烧录成功后就可连接起来。
问题四:连接华为云
在连接华为IoT平台的过程中,我们需要注意的问题是代码中的服务ID、属性名称、命令名称等信息与华为IoT平台一一对应,否则会导致数据上传不成功或者命令下发不成功。