引言
上个帖子介绍了贝启科技BQ3568HM开源鸿蒙开发板的简单情况,今天进行正式的软件开发。
在智能家居日益普及的今天,一个直观、易用的中控屏界面对于用户来说至关重要。今天,我将向大家介绍我所完成的智能家居中控屏界面设计,它旨在为用户提供便捷、高效的家居控制体验。
界面布局与组件设计
整体布局
中控屏界面采用了简洁明了的布局,主要分为三个部分:标题栏、信息展示区和控制按钮区。
标题栏:位于界面顶部,显示“智能家居中控屏”字样,突出了应用的主题。
信息展示区:位于标题栏下方,用于显示当前房间的温度和湿度信息。
控制按钮区:位于界面底部,包含灯光控制按钮和窗帘控制按钮,方便用户进行操作。
温度和湿度信息展示
在信息展示区,我使用了两个 Text 组件来分别显示温度和湿度信息。为了使信息更加直观,我在温度和湿度文本前面添加了相应的图标,使用户一眼就能了解当前的环境状况。
Row() {
Image($r('app.media.temperature_icon'))
.width(30)
.height(30)
.margin({ right: 10 })
Text(`温度: ${this.roomTemperature}°C`)
.fontSize(20)
.margin({ right: 20 })
.fontColor('#FF0000')
Image($r('app.media.humidity_icon'))
.width(30)
.height(30)
.margin({ right: 10 })
Text(`湿度: ${this.roomHumidity}%`)
.fontSize(20)
.fontColor('#00FF00')
}
.margin({ top: 20 })
灯光和窗帘控制按钮
在控制按钮区,我使用了两个 Button 组件来分别控制灯光和窗帘。为了使按钮更加美观和易用,我们将按钮类型设置为 ButtonType.Capsule,使其呈现为胶囊形状,并在按钮上添加了相应的图标和文字。
Button({
type: ButtonType.Capsule,
stateEffect: true,
}) {
Row() {
Image(this.lightStatus ? $r('app.media.light_off_icon') : $r('app.media.light_on_icon'))
.width(30)
.height(30)
.margin({ right: 10 })
Text(this.lightStatus ? '关闭灯光' : '打开灯光')
.fontSize(20)
}
}
.width('80%')
.height(60)
.margin({ top: 20 })
.onClick(() => {
this.lightStatus = !this.lightStatus;
})
Button({
type: ButtonType.Capsule,
stateEffect: true,
}) {
Row() {
Image(this.curtainStatus ? $r('app.media.curtain_closed_icon') : $r('app.media.curtain_open_icon'))
.width(30)
.height(30)
.margin({ right: 10 })
Text(this.curtainStatus ? '关闭窗帘' : '打开窗帘')
.fontSize(20)
}
}
.width('80%')
.height(60)
.margin({ top: 20 })
.onClick(() => {
this.curtainStatus = !this.curtainStatus;
})
界面交互设计
按钮点击事件
为了实现对灯光和窗帘的控制,我们为每个按钮添加了点击事件。当用户点击按钮时,按钮的状态会发生变化,同时相应的控制逻辑会被执行。
.onClick(() => {
this.lightStatus = !this.lightStatus;
})
.onClick(() => {
this.curtainStatus = !this.curtainStatus;
})
按钮状态变化
为了使用户能够直观地了解灯光和窗帘的当前状态,我们根据按钮的状态来动态改变按钮的文字和图标。例如,当灯光打开时,灯光控制按钮的文字显示为“关闭灯光”,图标显示为关闭状态的图标;当灯光关闭时,按钮的文字显示为“打开灯光”,图标显示为打开状态的图标。
Text(this.lightStatus ? '关闭灯光' : '打开灯光')
.fontSize(20)
Image(this.lightStatus ? $r('app.media.light_off_icon') : $r('app.media.light_on_icon'))
.width(30)
.height(30)
.margin({ right: 10 })
Text(this.curtainStatus ? '关闭窗帘' : '打开窗帘')
.fontSize(20)
Image(this.curtainStatus ? $r('app.media.curtain_closed_icon') : $r('app.media.curtain_open_icon'))
.width(30)
.height(30)
.margin({ right: 10 })
界面样式设计
文字样式
为了使界面更加美观和易读,我们对文字的样式进行了设置。标题栏的文字使用了较大的字体和加粗的样式,突出了应用的主题;温度和湿度信息的文字使用了适中的字体和不同的颜色,以便用户能够快速区分;按钮上的文字使用了适中的字体和白色的颜色,与按钮的背景颜色形成鲜明的对比。
按钮样式
为了使按钮更加美观和易用,我们对按钮的样式进行了设置。按钮的类型设置为 ButtonType.Capsule,使其呈现为胶囊形状;按钮的背景颜色根据按钮的状态动态变化,以便用户能够直观地了解当前的控制状态;按钮的文字颜色设置为白色,与按钮的背景颜色形成鲜明的对比。
Button({
type: ButtonType.Capsule,
stateEffect: true,
}) {
Row() {
Image(this.lightStatus ? $r('app.media.light_off_icon') : $r('app.media.light_on_icon'))
.width(30)
.height(30)
.margin({ right: 10 })
Text(this.lightStatus ? '关闭灯光' : '打开灯光')
.fontSize(20)
}
}
.width('80%')
.height(60)
.margin({ top: 20 })
Button({
type: ButtonType.Capsule,
stateEffect: true,
}) {
Row() {
Image(this.curtainStatus ? $r('app.media.curtain_closed_icon') : $r('app.media.curtain_open_icon'))
.width(30)
.height(30)
.margin({ right: 10 })
Text(this.curtainStatus ? '关闭窗帘' : '打开窗帘')
.fontSize(20)
}
}
.width('80%')
.height(60)
.margin({ top: 20 })
界面效果
下面是显示的预览效果:

添加硬件控制能力
在智能家居中控屏工程中,我们还需要增加对硬件的控制能力,NAPI(Native API)接口扮演着至关重要的角色,它实现了ArkTS与原生代码(如C++)之间的交互,为应用提供了底层的硬件控制能力。下面将深入分析当前工程的NAPI接口设计,并探讨其在智能家居中控屏中的应用。
NAPI接口概述
NAPI接口是OpenHarmony提供的一种机制,用于在ArkTS中调用C++编写的原生模块。通过NAPI接口,开发者可以利用C++的高性能和底层硬件访问能力,同时保持ArkTS的灵活性和易用性。在智能家居中控屏工程中,NAPI接口主要用于控制灯光和窗帘等硬件设备。
NAPI接口设计
接口定义
在当前工程中,NAPI接口定义在index.d.ts文件中,主要包括以下几个函数:
export const gpio_on: (ledPath: string) => string;
export const gpio_off: (ledPath: string) => string;
- gpio_on:用于打开指定路径的GPIO(通用输入输出)引脚,控制灯光或其他设备的开启。
- gpio_off:用于关闭指定路径的GPIO引脚,控制灯光或其他设备的关闭。
接口实现
NAPI接口的实现通常在C++代码中完成。在当前工程中,具体的实现细节位于hello.cpp文件中。以下是一个简化的示例,展示了如何实现gpio_on和gpio_off函数:
#include <napi.h>
#include <iostream>
#include <fstream>
Napi::String GpioOn(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 1 || !info[0].IsString()) {
Napi::TypeError::New(env, "String expected").ThrowAsJavaScriptException();
return Napi::String::New(env, "");
}
std::string ledPath = info[0].As<Napi::String>().Utf8Value();
std::ofstream file(ledPath);
if (file.is_open()) {
file << "1";
file.close();
return Napi::String::New(env, "GPIO on success");
} else {
return Napi::String::New(env, "Failed to open GPIO file");
}
}
Napi::String GpioOff(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() < 1 || !info[0].IsString()) {
Napi::TypeError::New(env, "String expected").ThrowAsJavaScriptException();
return Napi::String::New(env, "");
}
std::string ledPath = info[0].As<Napi::String>().Utf8Value();
std::ofstream file(ledPath);
if (file.is_open()) {
file << "0";
file.close();
return Napi::String::New(env, "GPIO off success");
} else {
return Napi::String::New(env, "Failed to open GPIO file");
}
}
Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set(Napi::String::New(env, "gpio_on"), Napi::Function::New(env, GpioOn));
exports.Set(Napi::String::New(env, "gpio_off"), Napi::Function::New(env, GpioOff));
return exports;
}
NODE_API_MODULE(addon, Init)
![]()
在这个示例中,GpioOn和GpioOff函数分别实现了打开和关闭GPIO引脚的功能。它们通过读取和写入文件来控制GPIO引脚的电平,从而实现对灯光的控制。
NAPI接口在智能家居中控屏中的应用
在智能家居中控屏工程中,NAPI接口主要用于控制灯光和窗帘等硬件设备。通过ArkTS调用NAPI接口,开发者可以轻松地实现对硬件设备的控制,而无需深入了解底层的硬件细节。
灯光控制
在界面设计中,我们为灯光控制按钮添加了点击事件,当用户点击按钮时,会调用相应的NAPI接口来控制灯光的开启和关闭。
.onClick(() => {
this.lightStatus = !this.lightStatus;
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);
}
})
运行效果
实际运行效果如下图所示,照片左上角电源灯下方的那个绿色的LED灯代表我们用来控制的灯光。

总结
OpenHarmony的开发效率还是很高的,借助于ArkTS和NAPI接口,我们快速实现了一个智能家居中控屏原型工程,并成功在BQ3568HM开发板上运行。这种设计模式不仅提高了开发效率,还保证了应用的性能和稳定性。
后面我们将把智能家居中控屏连接到华为云IoTDA平台上,实现真正的智能家居功能。
希望本文能够帮助你更好地理解智能家居中控屏工程的设计,如果你有任何问题或建议,欢迎留言。