鸿蒙App灯光控制(开关/亮度/色温调节)全解析【华为根技术】
【摘要】 1. 引言随着物联网(IoT)和智能家居技术的飞速发展,灯光控制已从传统的物理开关演变为集成了智能感知、远程控制、场景联动等功能于一体的智能系统。鸿蒙操作系统凭借其分布式架构、软总线技术和原子化服务能力,为智能灯光控制提供了理想的平台,能够实现跨设备无缝协同、低延迟精准控制和丰富的场景化体验。本方案基于鸿蒙系统的分布式能力、设备管理能力、UI框架及后台服务机制,构建一个完整的智能灯光控制系统...
1. 引言
2. 技术背景
2.1 鸿蒙智能设备控制能力基础
|
|
|
|
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2.2 灯光控制技术架构
graph TD
subgraph 控制终端层(多设备)
A[手机] --> A1[灯光控制App]
B[平板] --> B1[灯光控制App]
C[智慧屏] --> C1[灯光控制App]
D[智能手表] --> D1[快捷控制Widget]
end
subgraph 鸿蒙分布式中间件
E[分布式软总线] --> F[设备发现服务]
F --> G[设备连接管理]
G --> H[命令路由中心]
H --> I[状态同步服务]
J[原子化服务框架] --> K[快捷控制入口]
end
subgraph 智能灯具层
L[智能灯泡] --> L1[通信模块(WiFi/Zigbee)]
M[灯带控制器] --> M1[通信模块]
N[吸顶灯网关] --> N1[通信模块]
L1 --> O[灯光驱动]
M1 --> P[灯光驱动]
N1 --> Q[灯光驱动]
end
subgraph 云服务与AI层
R[华为云IoT平台] --> S[设备管理]
S --> T[数据存储与分析]
U[AI引擎] --> V[场景智能推荐]
V --> W[自动化规则学习]
end
A1 --> H
B1 --> H
C1 --> H
D1 --> K
K --> H
H --> L1
H --> M1
H --> N1
L1 --> O
M1 --> P
N1 --> Q
O --> S
P --> S
Q --> S
S --> T
T --> U
2.3 关键技术特性
-
多协议兼容:支持WiFi、蓝牙BLE、Zigbee、红外等多种通信协议,适配主流智能灯具品牌 -
分布式协同:手机设置的灯光状态实时同步到平板和智慧屏,多终端控制无冲突 -
精细控制:亮度调节精度达1%,色温调节步长100K,支持1600万色RGB调节 -
低延迟响应:本地控制延迟<100ms,远程控制延迟<300ms,接近物理开关体验 -
场景化联动:与人体感应、光线传感器联动,实现"回家开灯"、"日落调暗"等自动化场景 -
能耗监测:实时统计各灯具用电量,提供节能建议,支持峰谷电价时段自动调节 -
安全可靠:端到端加密通信,设备绑定认证,异常操作预警,保障家庭安全 -
离线控制:局域网内设备可直接通信,无互联网时仍可实现基本控制功能
3. 应用使用场景
3.1 典型应用场景分类
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3.2 场景复杂度分析
-
简单场景:单房间单灯具控制,本地WiFi网络,基础开关/亮度调节 -
中级场景:多房间多灯具分组控制,场景模式切换,定时任务,局域网内多终端协同 -
复杂场景:跨空间联动(如客厅与阳台灯光协同),传感器融合(人体+光线+时间),云端备份与恢复,第三方平台对接(如HomeKit、天猫精灵) -
企业级场景:大型商场/办公楼分区控制,能耗分析与优化,设备批量配置与维护,多用户权限管理
4. 核心原理与流程图
4.1 灯光控制系统架构图
graph TD
subgraph 应用层
A[灯光控制App] --> B[设备列表页]
A --> C[灯光控制页]
A --> D[场景管理页]
A --> E[定时任务页]
F[原子化服务卡片] --> G[快捷开关]
F --> H[亮度调节]
end
subgraph 服务层
I[DeviceManager] --> J[设备发现与连接]
K[LightController] --> L[开关/亮度/色温控制]
M[SceneManager] --> N[场景配置与执行]
O[SchedulerService] --> P[定时任务调度]
Q[NetworkManager] --> R[网络通信与协议适配]
S[SensorMonitor] --> T[传感器数据采集]
end
subgraph 核心能力层
U[DistributedData] --> V[设备状态分布式同步]
W[Preferences] --> X[用户配置本地存储]
Y[BackgroundTask] --> Z[后台服务管理]
AA[Crypto] --> BB[通信加密]
end
subgraph 驱动层
CC[WiFiDriver] --> DD[WiFi设备控制]
EE[BleDriver] --> FF[蓝牙设备控制]
GG[ZigbeeDriver] --> HH[Zigbee网关控制]
end
subgraph 硬件层
II[智能灯泡] --> JJ[LED驱动电路]
KK[灯带控制器] --> LL[PWM调光电路]
MM[吸顶灯] --> NN[电源管理模块]
end
A --> I
A --> K
A --> M
A --> O
F --> K
I --> J
J --> R
R --> CC
R --> EE
R --> GG
CC --> II
EE --> KK
GG --> MM
K --> L
L --> V
M --> N
N --> X
O --> P
P --> Z
T --> S
S --> M
V --> U
U --> B
U --> C
4.2 灯光控制工作流程
4.2.1 设备发现与控制流程
sequenceDiagram
participant User as 用户
participant App as 灯光控制App
participant DeviceMgr as DeviceManager
participant LightCtrl as LightController
participant Device as 智能灯具
participant Cloud as 云平台(可选)
User->>App: 打开设备列表/添加设备
App->>DeviceMgr: 扫描附近设备
DeviceMgr->>DeviceMgr: 通过WiFi/BLE/Zigbee扫描
DeviceMgr->>Device: 发送设备发现请求
Device->>DeviceMgr: 响应设备信息(型号、状态)
DeviceMgr->>App: 返回发现的设备列表
App->>User: 显示设备列表(未绑定/已绑定)
User->>App: 选择设备并绑定
App->>DeviceMgr: 发起绑定请求
DeviceMgr->>Device: 发送绑定指令(含认证信息)
Device->>DeviceMgr: 确认绑定成功
DeviceMgr->>App: 绑定成功通知
App->>User: 提示绑定成功,设备添加到列表
User->>App: 调节灯光(开关/亮度/色温)
App->>LightCtrl: 发送控制指令(设备ID, 参数)
LightCtrl->>LightCtrl: 参数校验(范围、合法性)
LightCtrl->>DeviceMgr: 获取设备通信协议
DeviceMgr->>LightCtrl: 返回协议信息(WiFi/BLE等)
LightCtrl->>Device: 发送控制命令(编码为协议格式)
Device->>LightCtrl: 执行结果反馈(成功/失败)
LightCtrl->>App: 返回控制结果
App->>User: 更新UI状态(如开关图标、亮度滑块)
LightCtrl->>DeviceMgr: 更新设备状态缓存
DeviceMgr->>DistributedData: 同步状态到其他设备
4.2.2 场景模式执行流程
sequenceDiagram
participant User as 用户
participant App as 灯光控制App
participant SceneMgr as SceneManager
participant LightCtrl as LightController
participant Device as 智能灯具
participant Scheduler as 定时任务服务
User->>App: 创建/编辑场景(如"阅读模式")
App->>SceneMgr: 打开场景编辑器
SceneMgr->>User: 显示场景配置界面(选择设备、设置参数)
User->>SceneMgr: 配置场景参数(客厅灯:开,亮度80%,色温4000K)
SceneMgr->>SceneMgr: 验证参数有效性
SceneMgr->>Preferences: 保存场景配置(JSON格式)
Preferences->>SceneMgr: 保存成功确认
SceneMgr->>App: 场景保存成功通知
App->>User: 提示场景创建成功
User->>App: 触发场景("阅读模式")
App->>SceneMgr: 执行场景(场景ID)
SceneMgr->>Preferences: 读取场景配置
Preferences->>SceneMgr: 返回场景参数
SceneMgr->>LightCtrl: 遍历场景中的设备控制指令
loop 对每个设备
LightCtrl->>Device: 发送控制命令(按场景参数)
Device->>LightCtrl: 执行结果反馈
end
LightCtrl->>SceneMgr: 所有设备控制完成
SceneMgr->>App: 场景执行结果
App->>User: 显示场景执行成功(如所有灯已调至阅读模式)
Scheduler->>Scheduler: 定时检查任务(如每天19:00执行"晚餐模式")
Scheduler->>SceneMgr: 触发定时场景
SceneMgr->>LightCtrl: 执行场景控制指令
LightCtrl->>Device: 批量控制设备
Device->>LightCtrl: 执行反馈
LightCtrl->>SceneMgr: 场景执行完成
4.3 工作原理详解
-
设备发现与绑定: -
应用启动时, DeviceManager通过分布式软总线和各通信协议(WiFi/BLE/Zigbee)扫描附近智能灯具 -
发现设备后,通过设备型号匹配预置的设备驱动,发起绑定请求(含认证密钥) -
绑定成功后,设备信息(ID、型号、支持的功能)存储于本地 Preferences和分布式数据库中,供多设备同步
-
-
控制指令下发: -
用户在UI界面操作(如拖动亮度滑块), LightController接收控制参数(设备ID、开关状态、亮度值、色温值) -
参数经校验后,根据设备ID从 DeviceManager获取通信协议,编码为对应协议的指令格式(如WiFi设备的JSON指令、BLE的特征值写入) -
指令通过对应驱动发送至设备,设备执行后返回状态反馈,更新本地状态和分布式缓存
-
-
状态同步机制: -
采用鸿蒙 DistributedData实现设备状态的分布式同步,任一终端控制灯光后,状态变更会广播至同一超级终端内的其他设备 -
设备离线时,状态暂存于本地,上线后通过心跳包或主动查询同步最新状态 -
本地 Preferences作为一级缓存,存储用户配置(场景、定时任务),分布式数据库作为二级同步,确保数据一致性
-
-
场景与自动化: -
SceneManager负责场景配置的CRUD操作,场景参数以JSON格式存储,包含设备列表及各设备的目标状态 -
定时任务由 SchedulerService(基于鸿蒙BackgroundTask)管理,通过系统闹钟触发场景执行 -
传感器数据(如人体红外、光线强度)通过 SensorMonitor采集,结合规则引擎(如"光线<50lux且有人移动时开灯")触发自动化控制
-
-
安全与可靠性: -
设备绑定采用密钥对认证,通信过程使用AES-128加密,防止指令篡改和窃听 -
控制指令添加序列号和校验和,避免重复执行和错误执行 -
网络异常时,指令缓存于本地队列,网络恢复后重发,确保控制可靠性
-
5. 环境准备
5.1 开发环境配置
# 1. 安装DevEco Studio 4.0+ (支持API 9+)
# 下载地址: https://developer.harmonyos.com/cn/develop/deveco-studio
# 2. 创建鸿蒙应用项目
# 步骤: File -> New -> Create Project -> 选择"Application" -> "Empty Ability"
# 配置项目信息:
# - Project name: SmartLightControl
# - Bundle name: com.example.smartlightcontrol
# - Save location: 自定义路径
# - Compile SDK: 9 (或更高版本)
# - Device type: Phone + Tablet (勾选支持的设备类型)
# - Language: ArkTS
# - UI Framework: ArkUI (声明式开发范式)
# 3. 目录结构规划
SmartLightControl/
├── entry/ # 主模块(灯光控制应用)
│ ├── src/
│ │ ├── main/
│ │ │ ├── ets/ # ArkTS源代码
│ │ │ │ ├── pages/ # 页面组件
│ │ │ │ │ ├── Index.ets # 首页(设备列表)
│ │ │ │ │ ├── LightControl.ets # 灯光控制页
│ │ │ │ │ ├── SceneManagement.ets # 场景管理页
│ │ │ │ │ ├── ScheduleTask.ets # 定时任务页
│ │ │ │ │ └── Settings.ets # 设置页
│ │ │ │ ├── components/ # 公共组件
│ │ │ │ │ ├── DeviceCard.ets # 设备卡片组件
│ │ │ │ │ ├── BrightnessSlider.ets # 亮度滑块组件
│ │ │ │ │ ├── ColorTempPicker.ets # 色温选择器组件
│ │ │ │ │ ├── RgbColorPicker.ets # RGB颜色选择器组件
│ │ │ │ │ └── SceneItem.ets # 场景项组件
│ │ │ │ ├── model/ # 数据模型
│ │ │ │ │ ├── LightDevice.ets # 灯光设备模型
│ │ │ │ │ ├── Scene.ets # 场景模型
│ │ │ │ │ ├── Schedule.ets # 定时任务模型
│ │ │ │ │ └── ControlCommand.ets # 控制指令模型
│ │ │ │ ├── service/ # 业务逻辑服务
│ │ │ │ │ ├── DeviceManager.ets # 设备管理服务
│ │ │ │ │ ├── LightController.ets # 灯光控制服务
│ │ │ │ │ ├── SceneManager.ets # 场景管理服务
│ │ │ │ │ ├── SchedulerService.ets # 定时任务服务
│ │ │ │ │ ├── NetworkAdapter.ets # 网络适配器(协议适配)
│ │ │ │ │ ├── DistributedSync.ets # 分布式同步服务
│ │ │ │ │ └── SensorMonitor.ets # 传感器监控服务
│ │ │ │ ├── utils/ # 工具类
│ │ │ │ │ ├── Logger.ets # 日志工具
│ │ │ │ │ ├── PreferencesUtil.ets # 偏好设置工具
│ │ │ │ │ ├── CryptoUtil.ets # 加密工具
│ │ │ │ │ ├── ColorUtil.ets # 颜色转换工具
│ │ │ │ │ └── TimeUtil.ets # 时间工具
│ │ │ │ ├── application/ # 应用生命周期管理
│ │ │ │ │ ├── MainApplication.ets # 主应用入口
│ │ │ │ │ └── Ability.ets # 能力基类
│ │ │ │ └── entryability/ # 应用入口能力
│ │ │ │ └── EntryAbility.ets # 主入口能力
│ │ │ ├── resources/ # 资源文件
│ │ │ │ ├── base/
│ │ │ │ │ ├── element/ # 颜色、字符串、尺寸等资源
│ │ │ │ │ │ ├── color.json
│ │ │ │ │ │ ├── string.json
│ │ │ │ │ │ └── float.json
│ │ │ │ │ ├── media/ # 图片、图标资源
│ │ │ │ │ │ ├── icon_light_on.png
│ │ │ │ │ │ ├── icon_light_off.png
│ │ │ │ │ │ └── bg_scene_reading.jpg
│ │ │ │ │ ├── profile/ # 配置文件
│ │ │ │ │ │ ├── main_pages.json # 页面路由配置
│ │ │ │ │ │ └── module.json5 # 模块配置(权限、 abilities等)
│ │ │ │ │ └── rawfile/ # 原始资源文件(如设备协议文档)
│ │ │ └── module.json5 # 模块配置文件(权限声明等)
│ ├── build-profile.json5 # 构建配置
│ └──hvigorfile.ts # 构建脚本
└── library/ # 可选: 公共库模块(如设备协议解析库)
├── src/
│ ├── main/
│ │ ├── ets/
│ │ │ └── utils/
│ │ │ └── ProtocolParser.ets # 协议解析工具
│ │ └── module.json5
└── build-profile.json5
5.2 权限配置
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": ["phone", "tablet"],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ets",
"description": "$string:EntryAbility_desc",
"icon": "$media:icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": ["entity.system.home"],
"actions": ["action.system.home"]
}
]
},
{
"name": "LightControlAbility",
"srcEntry": "./ets/application/LightControlAbility.ets",
"description": "灯光控制能力",
"icon": "$media:light_control_icon",
"label": "$string:LightControlAbility_label",
"exported": true,
"backgroundModes": ["dataTransfer", "location"] // dataTransfer用于后台设备通信
}
],
"requestPermissions": [
{
"name": "ohos.permission.DISTRIBUTED_DATASYNC",
"reason": "$string:distributed_datasync_reason",
"usedScene": {
"abilities": ["EntryAbility", "LightControlAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_reason",
"usedScene": {
"abilities": ["LightControlAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.ACCESS_NETWORK_STATE",
"reason": "$string:access_network_state_reason",
"usedScene": {
"abilities": ["LightControlAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.BLUETOOTH",
"reason": "$string:bluetooth_reason",
"usedScene": {
"abilities": ["LightControlAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.DISCOVER_BLUETOOTH",
"reason": "$string:discover_bluetooth_reason",
"usedScene": {
"abilities": ["LightControlAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.USE_BLUETOOTH",
"reason": "$string:use_bluetooth_reason",
"usedScene": {
"abilities": ["LightControlAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.LOCATION",
"reason": "$string:location_reason",
"usedScene": {
"abilities": ["LightControlAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
"reason": "$string:keep_background_running_reason",
"usedScene": {
"abilities": ["LightControlAbility"],
"when": "always"
}
},
{
"name": "ohos.permission.READ_MEDIA",
"reason": "$string:read_media_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.WRITE_MEDIA",
"reason": "$string:write_media_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
],
"extensionAbilities": [
{
"name": "SchedulerExtAbility",
"type": "service",
"srcEntry": "./ets/service/SchedulerService.ets",
"description": "定时任务后台服务",
"exported": true,
"backgroundModes": ["dataTransfer"]
}
],
"definePermissions": [
{
"name": "com.example.smartlightcontrol.permission.LIGHT_CONTROL",
"grantMode": "system_grant",
"availableLevel": "normal",
"description": "灯光控制权限"
}
]
}
}
5.3 依赖配置
{
"apiType": "stageMode",
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
},
"arkOptions": {
"debug": false,
"optimize": true
}
},
"buildOptionSet": [
{
"name": "release",
"arkOptions": {
"debug": false,
"optimize": true
}
}
],
"targets": [
{
"name": "default",
"applyToProducts": ["default"]
}
],
"products": [
{
"name": "default",
"compatibleSdkVersion": "9",
"runtimeOS": "HarmonyOS",
"signingConfig": "default"
}
],
"dependencies": {
"@ohos.data.preferences": "9.0.0",
"@ohos.distributedData": "9.0.0",
"@ohos.bluetooth": "9.0.0",
"@ohos.net.connection": "9.0.0",
"@ohos.sensor": "9.0.0",
"@ohos.utils": "9.0.0",
"@ohos.backgroundTaskManager": "9.0.0",
"library": "file:../library" // 引用公共库(如果有)
}
}
6. 详细代码实现
6.1 数据模型定义
/**
* 灯光设备数据模型
*/
/**
* 设备基本信息
*/
export interface DeviceInfo {
deviceId: string; // 设备唯一标识(UUID或MAC地址)
deviceName: string; // 设备名称(用户自定义或默认)
deviceType: DeviceType; // 设备类型
brand: string; // 品牌
model: string; // 型号
firmwareVersion: string; // 固件版本
isOnline: boolean; // 是否在线
isBound: boolean; // 是否已绑定
bindTime: number; // 绑定时间(时间戳)
lastActiveTime: number; // 最后活跃时间(时间戳)
location: string; // 设备位置(如"客厅"、"卧室")
roomId?: string; // 所属房间ID(可选)
}
/**
* 设备类型枚举
*/
export enum DeviceType {
LED_BULB = "led_bulb", // LED灯泡
LED_STRIP = "led_strip", // LED灯带
CEILING_LIGHT = "ceiling_light", // 吸顶灯
TABLE_LAMP = "table_lamp", // 台灯
SPOTLIGHT = "spotlight", // 射灯
STRIP_LIGHT = "strip_light", // 灯条
PANEL_LIGHT = "panel_light" // 面板灯
}
/**
* 灯光能力描述
*/
export interface LightCapability {
supportSwitch: boolean; // 支持开关
supportBrightness: boolean; // 支持亮度调节(0-100%)
minBrightness: number; // 最小亮度(%)
maxBrightness: number; // 最大亮度(%)
supportColorTemperature: boolean; // 支持色温调节(2500K-6500K)
minColorTemp: number; // 最暖色温(K)
maxColorTemp: number; // 最冷色温(K)
supportRGB: boolean; // 支持RGB彩色调节
supportDimmingCurve: boolean; // 支持调光曲线(线性/对数)
supportTiming: boolean; // 支持独立定时
supportScene: boolean; // 支持场景模式
maxScenes: number; // 最大支持场景数
}
/**
* 灯光状态
*/
export interface LightState {
powerOn: boolean; // 开关状态
brightness: number; // 亮度(0-100, 仅支持亮度时有效)
colorTemperature: number; // 色温(2500-6500K, 仅支持色温时有效)
rgbColor?: { r: number; g: number; b: number }; // RGB颜色(0-255, 仅支持RGB时有效)
hue?: number; // 色调(0-360, 可选)
saturation?: number; // 饱和度(0-100, 可选)
temperatureUnit: TemperatureUnit; // 色温单位
dimmingCurve: DimmingCurve; // 调光曲线
transitionTime: number; // 状态切换过渡时间(毫秒)
lastUpdateTime: number; // 状态最后更新时间(时间戳)
}
/**
* 色温单位枚举
*/
export enum TemperatureUnit {
KELVIN = "kelvin", // 开尔文(K)
MIREDS = "mireds" // 微倒度(mireds, 1e6/K)
}
/**
* 调光曲线枚举
*/
export enum DimmingCurve {
LINEAR = "linear", // 线性调光
LOGARITHMIC = "logarithmic", // 对数调光(符合人眼感知)
S_CURVE = "s_curve" // S型曲线(平滑过渡)
}
/**
* 完整的灯光设备信息
*/
export interface LightDevice extends DeviceInfo {
capability: LightCapability; // 设备能力
state: LightState; // 当前状态
networkInfo: NetworkInfo; // 网络信息
energyConsumption?: EnergyConsumption; // 能耗信息(可选)
groupIds: string[]; // 所属分组ID列表
}
/**
* 网络信息
*/
export interface NetworkInfo {
protocol: NetworkProtocol; // 通信协议
ipAddress?: string; // IP地址(仅WiFi设备)
port?: number; // 端口号(仅WiFi设备)
bleAddress?: string; // BLE地址(仅BLE设备)
zigbeeNodeId?: string; // Zigbee节点ID(仅Zigbee设备)
signalStrength: number; // 信号强度(0-100, -1表示未知)
connectionType: ConnectionType; // 连接方式
}
/**
* 网络协议枚举
*/
export enum NetworkProtocol {
WiFi = "wifi", // WiFi
BluetoothLE = "ble", // 蓝牙低功耗(BLE)
Zigbee = "zigbee", // Zigbee
Infrared = "infrared", // 红外(需网关)
Matter = "matter" // Matter协议(新兴标准)
}
/**
* 连接方式枚举
*/
export enum ConnectionType {
DIRECT = "direct", // 直连(设备直接与手机通信)
GATEWAY = "gateway", // 网关中继(通过网关连接)
CLOUD = "cloud" // 云端中继(通过云平台连接)
}
/**
* 能耗信息
*/
export interface EnergyConsumption {
todayConsumption: number; // 今日耗电量(kWh)
monthlyConsumption: number; // 本月耗电量(kWh)
averagePower: number; // 平均功率(W)
voltage?: number; // 电压(V, 可选)
current?: number; // 电流(A, 可选)
powerFactor?: number; // 功率因数(可选)
}
/**
* 控制指令类型
*/
export enum ControlCommandType {
SWITCH = "switch", // 开关指令
BRIGHTNESS = "brightness", // 亮度调节指令
COLOR_TEMP = "color_temp", // 色温调节指令
RGB_COLOR = "rgb_color", // RGB颜色调节指令
SCENE = "scene", // 场景切换指令
TIMING = "timing" // 定时设置指令
}
/**
* 控制指令基类
*/
export interface BaseControlCommand {
commandId: string; // 指令唯一ID(用于去重和追踪)
deviceId: string; // 目标设备ID
commandType: ControlCommandType; // 指令类型
timestamp: number; // 指令生成时间戳
transitionTime?: number; // 过渡时间(可选, 覆盖设备默认)
priority: CommandPriority; // 指令优先级
}
/**
* 指令优先级枚举
*/
export enum CommandPriority {
HIGH = 0, // 高(立即执行, 如安全相关)
NORMAL = 1, // 普通(默认)
LOW = 2 // 低(可合并或延迟执行)
}
/**
* 开关指令
*/
export interface SwitchCommand extends BaseControlCommand {
commandType: ControlCommandType.SWITCH;
powerOn: boolean; // 目标开关状态
}
/**
* 亮度调节指令
*/
export interface BrightnessCommand extends BaseControlCommand {
commandType: ControlCommandType.BRIGHTNESS;
brightness: number; // 目标亮度(0-100)
curve?: DimmingCurve; // 调光曲线(可选)
}
/**
* 色温调节指令
*/
export interface ColorTemperatureCommand extends BaseControlCommand {
commandType: ControlCommandType.COLOR_TEMP;
colorTemperature: number; // 目标色温(2500-6500K)
unit: TemperatureUnit; // 色温单位
}
/**
* RGB颜色调节指令
*/
export interface RgbColorCommand extends BaseControlCommand {
commandType: ControlCommandType.RGB_COLOR;
rgbColor: { r: number; g: number; b: number }; // 目标RGB颜色(0-255)
brightness?: number; // 可选: 同时设置亮度(0-100)
}
/**
* 场景切换指令
*/
export interface SceneCommand extends BaseControlCommand {
commandType: ControlCommandType.SCENE;
sceneId: string; // 场景ID
sceneParams?: Record<string, any>; // 场景参数(可选)
}
/**
* 定时设置指令
*/
export interface TimingCommand extends BaseControlCommand {
commandType: ControlCommandType.TIMING;
taskId?: string; // 定时任务ID(更新时需指定)
action: "add" | "update" | "delete"; // 操作类型
schedule: Schedule; // 定时计划
}
/**
* 定时计划
*/
export interface Schedule {
name: string; // 任务名称
triggerTime: number; // 触发时间(时间戳)
repeatType: RepeatType; // 重复类型
repeatDays?: number[]; // 重复日期(0-6, 0=周日, 可选)
enabled: boolean; // 是否启用
action: Omit<BaseControlCommand, "commandId" | "timestamp">; // 执行的动作
}
/**
* 重复类型枚举
*/
export enum RepeatType {
ONCE = "once", // 单次
DAILY = "daily", // 每天
WEEKLY = "weekly", // 每周
MONTHLY = "monthly" // 每月
}
/**
* 设备发现结果
*/
export interface DeviceDiscoveryResult {
devices: LightDevice[]; // 发现的设备列表
protocol: NetworkProtocol; // 发现使用的协议
timestamp: number; // 发现时间
}
6.2 工具类实现
/**
* 日志工具类 - 封装系统日志接口,提供分级日志功能
*/
export class Logger {
private static readonly TAG_PREFIX: string = 'SmartLightControl';
private static readonly IS_DEBUG: boolean = true; // 发布版本应设为false
/**
* 调试日志
* @param message 日志内容
* @param tag 日志标签(默认为TAG_PREFIX)
*/
static d(message: string, tag: string = Logger.TAG_PREFIX): void {
if (Logger.IS_DEBUG) {
console.debug(`[${tag}] ${message}`);
}
}
/**
* 信息日志
* @param message 日志内容
* @param tag 日志标签
*/
static i(message: string, tag: string = Logger.TAG_PREFIX): void {
console.info(`[${tag}] ${message}`);
}
/**
* 警告日志
* @param message 日志内容
* @param tag 日志标签
*/
static w(message: string, tag: string = Logger.TAG_PREFIX): void {
console.warn(`[${tag}] ${message}`);
}
/**
* 错误日志
* @param message 日志内容
* @param tag 日志标签
* @param error 错误对象(可选)
*/
static e(message: string, tag: string = Logger.TAG_PREFIX, error?: Error): void {
let logMsg = `[${tag}] ${message}`;
if (error) {
logMsg += `, Error: ${error.message}, Stack: ${error.stack || 'no stack'}`;
}
console.error(logMsg);
}
/**
* 关键日志(用于记录严重问题)
* @param message 日志内容
* @param tag 日志标签
*/
static wtf(message: string, tag: string = Logger.TAG_PREFIX): void {
console.error(`[${tag}] WTF: ${message}`);
}
/**
* 性能计时开始
* @param label 计时标签
*/
static timeStart(label: string): void {
if (Logger.IS_DEBUG) {
console.time(`[${Logger.TAG_PREFIX}] ${label}`);
}
}
/**
* 性能计时结束
* @param label 计时标签
*/
static timeEnd(label: string): void {
if (Logger.IS_DEBUG) {
console.timeEnd(`[${Logger.TAG_PREFIX}] ${label}`);
}
}
/**
* 设备相关日志
* @param message 日志内容
* @param deviceId 设备ID
*/
static device(message: string, deviceId: string): void {
Logger.i(`Device[${deviceId.substring(0, 8)}...]: ${message}`, 'Device');
}
/**
* 控制指令日志
* @param message 日志内容
* @param command 控制指令
*/
static command(message: string, command: import('./LightDevice').BaseControlCommand): void {
Logger.i(`Command[${command.commandId.substring(0, 8)}...][${command.commandType}]: ${message}`, 'Command');
}
}
import preferences from '@ohos.data.preferences';
import Logger from './Logger';
/**
* 偏好设置工具类 - 封装Preferences API,提供设备配置、场景、定时任务的本地存储
*/
export class PreferencesUtil {
private static readonly DB_NAME: string = 'SmartLightPrefs'; // 数据库名称
private static prefsInstance: preferences.Preferences | null = null;
/**
* 获取Preferences实例(单例模式)
*/
private static async getPrefsInstance(): Promise<preferences.Preferences> {
if (!PreferencesUtil.prefsInstance) {
try {
// 获取应用上下文(实际开发中需通过AbilityContext获取)
const context = globalThis.abilityContext; // 假设在Ability中设置了全局上下文
PreferencesUtil.prefsInstance = await preferences.getPreferences(context, PreferencesUtil.DB_NAME);
Logger.d('Preferences实例初始化成功', 'PreferencesUtil');
} catch (error) {
Logger.e('获取Preferences实例失败', 'PreferencesUtil', error as Error);
throw new Error('Failed to get preferences instance');
}
}
return PreferencesUtil.prefsInstance;
}
/**
* 存储键值对
* @param key 键名
* @param value 值(支持string/number/boolean/Array/object)
*/
static async put(key: string, value: any): Promise<void> {
try {
const prefs = await PreferencesUtil.getPrefsInstance();
let valueToPut: string;
// 非字符串类型需序列化
if (typeof value !== 'string') {
valueToPut = JSON.stringify(value);
} else {
valueToPut = value;
}
await prefs.put(key, valueToPut);
await prefs.flush(); // 立即持久化
Logger.d(`存储键值对成功: key=${key}`, 'PreferencesUtil');
} catch (error) {
Logger.e(`存储键值对失败: key=${key}`, 'PreferencesUtil', error as Error);
throw error;
}
}
/**
* 获取字符串值
* @param key 键名
* @param defaultValue 默认值
*/
static async getString(key: string, defaultValue: string = ''): Promise<string> {
try {
const prefs = await PreferencesUtil.getPrefsInstance();
const value = await prefs.get(key, defaultValue) as string;
Logger.d(`获取字符串值成功: key=${key}, value=${value}`, 'PreferencesUtil');
return value;
} catch (error) {
Logger.e(`获取字符串值失败: key=${key}`, 'PreferencesUtil', error as Error);
return defaultValue;
}
}
/**
* 获取数值
* @param key 键名
* @param defaultValue 默认值
*/
static async getNumber(key: string, defaultValue: number = 0): Promise<number> {
try {
const prefs = await PreferencesUtil.getPrefsInstance();
const valueStr = await prefs.get(key, defaultValue.toString()) as string;
const value = parseFloat(valueStr);
Logger.d(`获取数值成功: key=${key}, value=${value}`, 'PreferencesUtil');
return isNaN(value) ? defaultValue : value;
} catch (error) {
Logger.e(`获取数值失败: key=${key}`, 'PreferencesUtil', error as Error);
return defaultValue;
}
}
/**
* 获取布尔值
* @param key 键名
* @param defaultValue 默认值
*/
static async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {
try {
const prefs = await PreferencesUtil.getPrefsInstance();
const valueStr = await prefs.get(key, defaultValue.toString()) as string;
const value = valueStr.toLowerCase() === 'true';
Logger.d(`获取布尔值成功: key=${key}, value=${value}`, 'PreferencesUtil');
return value;
} catch (error) {
Logger.e(`获取布尔值失败: key=${key}`, 'PreferencesUtil', error as Error);
return defaultValue;
}
}
/**
* 获取对象(自动反序列化JSON)
* @param key 键名
* @param defaultValue 默认值
*/
static async getObject<T>(key: string, defaultValue: T): Promise<T> {
try {
const prefs = await PreferencesUtil.getPrefsInstance();
const valueStr = await prefs.get(key, '') as string;
if (!valueStr) {
return defaultValue;
}
const value = JSON.parse(valueStr) as T;
Logger.d(`获取对象成功: key=${key}`, 'PreferencesUtil');
return value;
} catch (error) {
Logger.e(`获取对象失败: key=${key}`, 'PreferencesUtil', error as Error);
return defaultValue;
}
}
/**
* 删除键
* @param key 键名
*/
static async delete(key: string): Promise<void> {
try {
const prefs = await PreferencesUtil.getPrefsInstance();
await prefs.delete(key);
await prefs.flush();
Logger.d(`删除键成功: key=${key}`, 'PreferencesUtil');
} catch (error) {
Logger.e(`删除键失败: key=${key}`, 'PreferencesUtil', error as Error);
throw error;
}
}
/**
* 清空所有键值对
*/
static async clear(): Promise<void> {
try {
const prefs = await PreferencesUtil.getPrefsInstance();
const allKeys = await prefs.keys();
for (const key of allKeys) {
await prefs.delete(key);
}
await prefs.flush();
Logger.d('清空所有键值对成功', 'PreferencesUtil');
} catch (error) {
Logger.e('清空所有键值对失败', 'PreferencesUtil', error as Error);
throw error;
}
}
/**
* 获取所有键名
*/
static async getAllKeys(): Promise<string[]> {
try {
const prefs = await PreferencesUtil.getPrefsInstance();
const keys = await prefs.keys();
Logger.d(`获取所有键名成功, 共${keys.length}个`, 'PreferencesUtil');
return keys;
} catch (error) {
Logger.e('获取所有键名失败', 'PreferencesUtil', error as Error);
return [];
}
}
/**
* 存储设备列表
* @param devices 设备列表
*/
static async saveDeviceList(devices: import('./LightDevice').LightDevice[]): Promise<void> {
await PreferencesUtil.put('device_list', devices);
Logger.i(`保存设备列表成功, 共${devices.length}台设备`, 'PreferencesUtil');
}
/**
* 获取设备列表
*/
static async getDeviceList(): Promise<import('./LightDevice').LightDevice[]> {
const defaultDevices: import('./LightDevice').LightDevice[] = [];
return await PreferencesUtil.getObject('device_list', defaultDevices);
}
/**
* 存储场景配置
* @param scenes 场景列表
*/
static async saveScenes(scenes: any[]): Promise<void> { // 实际应使用Scene模型
await PreferencesUtil.put('scenes', scenes);
Logger.i(`保存场景配置成功, 共${scenes.length}个场景`, 'PreferencesUtil');
}
/**
* 获取场景配置
*/
static async getScenes(): Promise<any[]> { // 实际应使用Scene模型
const defaultScenes: any[] = [];
return await PreferencesUtil.getObject('scenes', defaultScenes);
}
/**
* 释放资源
*/
static async release(): Promise<void> {
if (PreferencesUtil.prefsInstance) {
await PreferencesUtil.prefsInstance.close();
PreferencesUtil.prefsInstance = null;
Logger.d('Preferences资源已释放', 'PreferencesUtil');
}
}
}
import Logger from './Logger';
/**
* 颜色转换工具类 - 提供RGB、HSV、色温(K)之间的转换
*/
export class ColorUtil {
/**
* RGB转HSV
* @param r 红色(0-255)
* @param g 绿色(0-255)
* @param b 蓝色(0-255)
* @returns HSV对象{hue: 0-360, saturation: 0-100, value: 0-100}
*/
static rgbToHsv(r: number, g: number, b: number): { hue: number; saturation: number; value: number } {
// 归一化到0-1
const normalizedR = r / 255;
const normalizedG = g / 255;
const normalizedB = b / 255;
const max = Math.max(normalizedR, normalizedG, normalizedB);
const min = Math.min(normalizedR, normalizedG, normalizedB);
const delta = max - min;
let hue = 0;
const saturation = max === 0 ? 0 : (delta / max) * 100; // 饱和度0-100
const value = max * 100; // 明度0-100
if (delta !== 0) {
switch (max) {
case normalizedR:
hue = ((normalizedG - normalizedB) / delta) % 6;
break;
case normalizedG:
hue = (normalizedB - normalizedR) / delta + 2;
break;
case normalizedB:
hue = (normalizedR - normalizedG) / delta + 4;
break;
}
hue = Math.round(hue * 60);
if (hue < 0) {
hue += 360;
}
}
Logger.d(`RGB(${r},${g},${b})转HSV: H=${hue}, S=${saturation.toFixed(1)}, V=${value.toFixed(1)}`, 'ColorUtil');
return { hue, saturation, value };
}
/**
* HSV转RGB
* @param hue 色调(0-360)
* @param saturation 饱和度(0-100)
* @param value 明度(0-100)
* @returns RGB对象{r: 0-255, g: 0-255, b: 0-255}
*/
static hsvToRgb(hue: number, saturation: number, value: number): { r: number; g: number; b: number } {
// 归一化到0-1
const normalizedHue = hue / 60;
const normalizedSaturation = saturation / 100;
const normalizedValue = value / 100;
const c = normalizedValue * normalizedSaturation;
const x = c * (1 - Math.abs((normalizedHue % 2) - 1));
const m = normalizedValue - c;
let r = 0, g = 0, b = 0;
const i = Math.floor(normalizedHue);
switch (i) {
case 0:
r = c; g = x; b = 0;
break;
case 1:
r = x; g = c; b = 0;
break;
case 2:
r = 0; g = c; b = x;
break;
case 3:
r = 0; g = x; b = c;
break;
case 4:
r = x; g = 0; b = c;
break;
case 5:
r = c; g = 0; b = x;
break;
default:
r = c; g = x; b = 0;
}
// 还原并取整
r = Math.round((r + m) * 255);
g = Math.round((g + m) * 255);
b = Math.round((b + m) * 255);
Logger.d(`HSV(H=${hue}, S=${saturation}, V=${value})转RGB: (${r},${g},${b})`, 'ColorUtil');
return { r, g, b };
}
/**
* 色温(K)转RGB近似值
* @param kelvin 色温(2500-6500K)
* @returns RGB对象{r: 0-255, g: 0-255, b: 0-255}
* 注: 此为近似转换,实际色温转RGB需更复杂算法
*/
static colorTempToRgb(kelvin: number): { r: number; g: number; b: number } {
// 限制色温范围
const clampedKelvin = Math.max(2500, Math.min(6500, kelvin));
let temp = clampedKelvin / 100;
let r: number, g: number, b: number;
// 基于Tanner Helland的简单近似公式
if (temp <= 66) {
r = 255;
g = temp;
g = 99.4708025861 * Math.log(g) - 161.1195681661;
} else {
r = temp - 60;
r = 329.698727446 * Math.pow(r, -0.1332047592);
g = temp - 60;
g = 288.1221695283 * Math.pow(g, -0.0755148492);
}
if (temp >= 66) {
b = 255;
} else if (temp <= 19) {
b = 0;
} else {
b = temp - 10;
b = 138.5177312231 * Math.log(b) - 305.0447927307;
}
// 限制RGB值在0-255范围内
r = Math.max(0, Math.min(255, Math.round(r)));
g = Math.max(0, Math.min(255, Math.round(g)));
b = Math.max(0, Math.min(255, Math.round(b)));
Logger.d(`色温${kelvin}K转RGB: (${r},${g},${b})`, 'ColorUtil');
return { r, g, b };
}
/**
* RGB转十六进制颜色字符串
* @param r 红色(0-255)
* @param g 绿色(0-255)
* @param b 蓝色(0-255)
* @returns 十六进制字符串(如"#RRGGBB")
*/
static rgbToHex(r: number, g: number, b: number): string {
const hexR = r.toString(16).padStart(2, '0');
const hexG = g.toString(16).padStart(2, '0');
const hexB = b.toString(16).padStart(2, '0');
const hex = `#${hexR}${hexG}${hexB}`.toUpperCase();
Logger.d(`RGB(${r},${g},${b})转十六进制: ${hex}`, 'ColorUtil');
return hex;
}
/**
* 十六进制颜色字符串转RGB
* @param hex 十六进制字符串(如"#RRGGBB"或"RRGGBB")
* @returns RGB对象{r: 0-255, g: 0-255, b: 0-255}
*/
static hexToRgb(hex: string): { r: number; g: number; b: number } {
// 去除前缀并转为大写
let pureHex = hex.startsWith('#') ? hex.substring(1) : hex;
pureHex = pureHex.toUpperCase();
// 验证长度
if (pureHex.length !== 6) {
throw new Error('Invalid hex color format, must be 6 characters');
}
// 解析RGB分量
const r = parseInt(pureHex.substring(0, 2), 16);
const g = parseInt(pureHex.substring(2, 4), 16);
const b = parseInt(pureHex.substring(4, 6), 16);
if (isNaN(r) || isNaN(g) || isNaN(b)) {
throw new Error('Invalid hex color format, contains non-hex characters');
}
Logger.d(`十六进制${hex}转RGB: (${r},${g},${b})`, 'ColorUtil');
return { r, g, b };
}
/**
* 计算颜色的相对亮度(用于WCAG对比度检查)
* @param r 红色(0-255)
* @param g 绿色(0-255)
* @param b 蓝色(0-255)
* @returns 相对亮度(0-1)
*/
static calculateRelativeLuminance(r: number, g: number, b: number): number {
// 归一化并应用伽马校正
const gammaCorrect = (channel: number) => {
const normalized = channel / 255;
return normalized <= 0.03928
? normalized / 12.92
: Math.pow((normalized + 0.055) / 1.055, 2.4);
};
const rLinear = gammaCorrect(r);
const gLinear = gammaCorrect(g);
const bLinear = gammaCorrect(b);
// 计算相对亮度(ITU-R BT.709系数)
const luminance = 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear;
return luminance;
}
/**
* 计算两种颜色的对比度
* @param rgb1 第一种颜色的RGB
* @param rgb2 第二种颜色的RGB
* @returns 对比度比值(≥1)
*/
static calculateContrastRatio(
rgb1: { r: number; g: number; b: number },
rgb2: { r: number; g: number; b: number }
): number {
const lum1 = ColorUtil.calculateRelativeLuminance(rgb1.r, rgb1.g, rgb1.b);
const lum2 = ColorUtil.calculateRelativeLuminance(rgb2.r, rgb2.g, rgb2.b);
const lighter = Math.max(lum1, lum2);
const darker = Math.min(lum1, lum2);
const contrastRatio = (lighter + 0.05) / (darker + 0.05);
Logger.d(`颜色对比度: ${contrastRatio.toFixed(2)}:1`, 'ColorUtil');
return contrastRatio;
}
}
import cryptoFramework from '@ohos.security.cryptoFramework';
import util from '@ohos.util';
import Logger from './Logger';
/**
* 加密工具类 - 提供AES对称加密、SHA哈希等安全功能
*/
export class CryptoUtil {
private static readonly ALGORITHM_AES_GCM = "AES128|GCM|PKCS7";
private static readonly KEY_ALIAS = "SmartLightControl_AES_Key";
private static readonly IV_LENGTH = 12; // GCM推荐IV长度12字节
private static readonly TAG_LENGTH = 16; // 认证标签长度16字节
/**
* 生成随机字节数组
* @param length 字节长度
* @returns 随机字节数组
*/
static async generateRandomBytes(length: number): Promise<Uint8Array> {
try {
const randomGenerator = cryptoFramework.createRandomGenerator();
const randomBytes = new Uint8Array(length);
await randomGenerator.fill(randomBytes);
Logger.d(`生成${length}字节随机数据`, 'CryptoUtil');
return randomBytes;
} catch (error) {
Logger.e('生成随机字节失败', 'CryptoUtil', error as Error);
throw error;
}
}
/**
* 获取或生成AES密钥
* @returns AES密钥材料
*/
private static async getOrCreateAesKey(): Promise<cryptoFramework.Key> {
try {
const keyStore = cryptoFramework.createKeyStore('cryptoFrameworkKeyStore');
await keyStore.open();
// 尝试获取现有密钥
try {
const existingKey = await keyStore.getKey(CryptoUtil.KEY_ALIAS);
Logger.d('获取现有AES密钥成功', 'CryptoUtil');
await keyStore.close();
return existingKey;
} catch (e) {
// 密钥不存在,创建新密钥
Logger.d('创建新的AES密钥', 'CryptoUtil');
const symKeyGenerator = cryptoFramework.createSymKeyGenerator('AES128');
const keyBlob = await CryptoUtil.generateRandomBytes(16); // AES-128需要16字节密钥
const key = await symKeyGenerator.convertKey(keyBlob, null);
// 存储密钥
await keyStore.addKey(CryptoUtil.KEY_ALIAS, key, null);
await keyStore.close();
return key;
}
} catch (error) {
Logger.e('获取或创建AES密钥失败', 'CryptoUtil', error as Error);
throw error;
}
}
/**
* AES-GCM加密数据
* @param plaintext 明文数据(string或Uint8Array)
* @returns 加密后的密文(包含IV和认证标签)
*/
static async encryptAesGcm(plaintext: string | Uint8Array): Promise<{ iv: Uint8Array; ciphertext: Uint8Array; authTag: Uint8Array }> {
try {
// 准备明文数据
let plainData: Uint8Array;
if (typeof plaintext === 'string') {
const textEncoder = new util.TextEncoder();
plainData = textEncoder.encodeInto(plaintext);
} else {
plainData = plaintext;
}
// 生成随机IV
const iv = await CryptoUtil.generateRandomBytes(CryptoUtil.IV_LENGTH);
// 获取AES密钥
const key = await CryptoUtil.getOrCreateAesKey();
// 创建加密器
const cipher = cryptoFramework.createCipher(CryptoUtil.ALGORITHM_AES_GCM);
await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, key, {
iv: iv,
aad: new Uint8Array(0) // 附加认证数据(此处为空)
});
// 执行加密
const encryptedData = await cipher.doFinal(plainData);
// 提取认证标签(GCM模式下doFinal返回的密文包含认证标签)
const ciphertext = encryptedData.slice(0, encryptedData.byteLength - CryptoUtil.TAG_LENGTH);
const authTag = encryptedData.slice(encryptedData.byteLength - CryptoUtil.TAG_LENGTH);
Logger.d(`AES-GCM加密成功, 明文长度=${plainData.byteLength}, 密文长度=${ciphertext.byteLength}`, 'CryptoUtil');
return { iv, ciphertext, authTag };
} catch (error) {
Logger.e('AES-GCM加密失败', 'CryptoUtil', error as Error);
throw error;
}
}
/**
* AES-GCM解密数据
* @param iv 初始化向量
* @param ciphertext 密文
* @param authTag 认证标签
* @returns 解密后的明文(string)
*/
static async decryptAesGcm(iv: Uint8Array, ciphertext: Uint8Array, authTag: Uint8Array): Promise<string> {
try {
// 组合密文和认证标签
const encryptedData = new Uint8Array([...ciphertext, ...authTag]);
// 获取AES密钥
const key = await CryptoUtil.getOrCreateAesKey();
// 创建解密器
const decipher = cryptoFramework.createCipher(CryptoUtil.ALGORITHM_AES_GCM);
await decipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, key, {
iv: iv,
aad: new Uint8Array(0)
});
// 执行解密
const decryptedData = await decipher.doFinal(encryptedData);
// 转换为字符串
const textDecoder = new util.TextDecoder();
const plaintext = textDecoder.decodeToString(decryptedData);
Logger.d(`AES-GCM解密成功, 密文长度=${ciphertext.byteLength}, 明文长度=${decryptedData.byteLength}`, 'CryptoUtil');
return plaintext;
} catch (error) {
Logger.e('AES-GCM解密失败', 'CryptoUtil', error as Error);
throw new Error('Decryption failed, invalid ciphertext or authentication failed');
}
}
/**
* SHA-256哈希计算
* @param data 输入数据(string或Uint8Array)
* @returns 哈希值(十六进制字符串)
*/
static async sha256(data: string | Uint8Array): Promise<string> {
try {
let inputData: Uint8Array;
if (typeof data === 'string') {
const textEncoder = new util.TextEncoder();
inputData = textEncoder.encodeInto(data);
} else {
inputData = data;
}
// 创建哈希器
const hash = cryptoFramework.createHash("SHA256");
await hash.update(inputData);
// 获取哈希结果
const digest = await hash.digest();
const hashHex = Array.from(new Uint8Array(digest.data))
.map(b => b.toString(16).padStart(2, '0'))
.join('')
.toUpperCase();
Logger.d(`SHA-256哈希计算成功, 输入长度=${inputData.byteLength}, 哈希长度=${hashHex.length}`, 'CryptoUtil');
return hashHex;
} catch (error) {
Logger.e('SHA-256哈希计算失败', 'CryptoUtil', error as Error);
throw error;
}
}
/**
* 生成设备认证令牌(基于设备ID和密钥)
* @param deviceId 设备ID
* @returns 认证令牌
*/
static async generateAuthToken(deviceId: string): Promise<string> {
const secretKey = "SmartLight_Control_Secret_Key"; // 实际应用中应从安全存储获取
const data = `${deviceId}:${Date.now()}`;
const token = await CryptoUtil.sha256(`${data}:${secretKey}`);
Logger.d(`生成设备认证令牌: deviceId=${deviceId}`, 'CryptoUtil');
return token;
}
}
6.3 设备管理服务实现
import { LightDevice, DeviceDiscoveryResult, NetworkProtocol, DeviceType } from '../model/LightDevice';
import { Logger } from '../utils/Logger';
import { PreferencesUtil } from '../utils/PreferencesUtil';
import distributedDeviceManager from '@ohos.distributedHardware.deviceManager';
import bluetooth from '@ohos.bluetooth';
import network from '@ohos.net.connection';
import { BusinessError } from '@ohos.base';
/**
* 设备管理服务 - 负责设备发现、绑定、状态管理和分布式同步
*/
export class DeviceManager {
private static instance: DeviceManager;
private deviceManager: distributedDeviceManager.DeviceManager | null = null;
private discoveredDevices: Map<string, LightDevice> = new Map(); // 发现的设备(未绑定)
private boundDevices: Map<string, LightDevice> = new Map(); // 已绑定的设备
private context: any; // 应用上下文(AbilityContext)
private isInitialized: boolean = false;
private deviceStateListeners: Map<string, Set<DeviceStateListener>> = new Map();
private constructor(context: any) {
this.context = context;
this.initDeviceManager();
}
/**
* 获取单例实例
*/
static getInstance(context: any): DeviceManager {
if (!DeviceManager.instance) {
DeviceManager.instance = new DeviceManager(context);
}
return DeviceManager.instance;
}
/**
* 初始化设备管理器(分布式设备管理和蓝牙管理)
*/
private async initDeviceManager(): Promise<void> {
try {
Logger.d('初始化设备管理器', 'DeviceManager');
// 初始化分布式设备管理器
this.deviceManager = distributedDeviceManager.createDeviceManager(this.context);
this.registerDeviceStateCallbacks();
// 加载已绑定设备
await this.loadBoundDevices();
this.isInitialized = true;
Logger.i('设备管理器初始化成功', 'DeviceManager');
} catch (error) {
Logger.e('设备管理器初始化失败', 'DeviceManager', error as BusinessError);
this.isInitialized = false;
}
}
/**
* 注册设备状态回调(分布式设备上线/离线通知)
*/
private registerDeviceStateCallbacks(): void {
if (!this.deviceManager) return;
// 设备上线回调
this.deviceManager.on('deviceOnline', (device: distributedDeviceManager.DeviceInfo) => {
Logger.i(`分布式设备上线: ${device.deviceName}(${device.deviceId}), 类型: ${device.deviceTypeId}`, 'DeviceManager');
this.handleDeviceOnline(device);
});
// 设备离线回调
this.deviceManager.on('deviceOffline', (device: distributedDeviceManager.DeviceInfo) => {
Logger.i(`分布式设备离线: ${device.deviceName}(${device.deviceId})`, 'DeviceManager');
this.handleDeviceOffline(device);
});
// 设备信息变更回调
this.deviceManager.on('deviceInfoChanged', (device: distributedDeviceManager.DeviceInfo) => {
Logger.d(`分布式设备信息变更: ${device.deviceName}`, 'DeviceManager');
this.updateDistributedDeviceInfo(device);
});
}
/**
* 处理分布式设备上线
*/
private handleDeviceOnline(device: distributedDeviceManager.DeviceInfo): void {
// 检查是否为已知的灯光设备
const knownDevice = this.boundDevices.get(device.deviceId);
if (knownDevice) {
// 更新设备在线状态
const updatedDevice: LightDevice = {
...knownDevice,
isOnline: true,
lastActiveTime: Date.now()
};
this.boundDevices.set(device.deviceId, updatedDevice);
this.notifyDeviceStateChanged(updatedDevice, 'online');
Logger.device(`设备上线: ${knownDevice.deviceName}`, device.deviceId);
}
}
/**
* 处理分布式设备离线
*/
private handleDeviceOffline(device: distributedDeviceManager.DeviceInfo): void {
const knownDevice = this.boundDevices.get(device.deviceId);
if (knownDevice) {
const updatedDevice: LightDevice = {
...knownDevice,
isOnline: false,
lastActiveTime: Date.now()
};
this.boundDevices.set(device.deviceId, updatedDevice);
this.notifyDeviceStateChanged(updatedDevice, 'offline');
Logger.device(`设备离线: ${knownDevice.deviceName}`, device.deviceId);
}
}
/**
* 更新分布式设备信息
*/
private updateDistributedDeviceInfo(device: distributedDeviceManager.DeviceInfo): void {
const knownDevice = this.boundDevices.get(device.deviceId);
if (knownDevice) {
const updatedDevice: LightDevice = {
...knownDevice,
deviceName: device.deviceName,
lastActiveTime: Date.now()
};
this.boundDevices.set(device.deviceId, updatedDevice);
this.notifyDeviceStateChanged(updatedDevice, 'info_updated');
}
}
/**
* 加载已绑定的设备(从本地存储)
*/
private async loadBoundDevices(): Promise<void> {
try {
const savedDevices = await PreferencesUtil.getDeviceList();
savedDevices.forEach(device => {
this.boundDevices.set(device.deviceId, device);
Logger.i(`加载已绑定设备: ${device.deviceName}(${device.deviceId})`, 'DeviceManager');
});
Logger.i(`共加载${savedDevices.length}台已绑定设备`, 'DeviceManager');
} catch (error) {
Logger.e('加载已绑定设备失败', 'DeviceManager', error as BusinessError);
}
}
/**
* 发现附近的智能灯具设备
* @param protocols 要发现的协议类型(默认发现所有支持的协议)
* @returns 发现的设备列表
*/
async discoverDevices(protocols: NetworkProtocol[] = [NetworkProtocol.WiFi, NetworkProtocol.BluetoothLE]): Promise<DeviceDiscoveryResult> {
if (!this.isInitialized) {
await this.initDeviceManager();
}
Logger.d(`开始发现设备, 协议: ${protocols.join(',')}`, 'DeviceManager');
const discoveredDevices: LightDevice[] = [];
const timestamp = Date.now();
try {
// 根据协议类型选择发现方式
for (const protocol of protocols) {
let protocolDevices: LightDevice[] = [];
switch (protocol) {
case NetworkProtocol.WiFi:
protocolDevices = await this.discoverWiFiDevices();
break;
case NetworkProtocol.BluetoothLE:
protocolDevices = await this.discoverBleDevices();
break;
// 可扩展其他协议(Zigbee需网关配合)
default:
Logger.w(`不支持的协议类型: ${protocol}`, 'DeviceManager');
continue;
}
discoveredDevices.push(...protocolDevices);
}
// 去重(基于deviceId)
const uniqueDevicesMap = new Map<string, LightDevice>();
discoveredDevices.forEach(device => {
uniqueDevicesMap.set(device.deviceId, device);
});
const uniqueDevices = Array.from(uniqueDevicesMap.values());
// 更新发现的设备缓存
this.discoveredDevices.clear();
uniqueDevices.forEach(device => {
this.discoveredDevices.set(device.deviceId, device);
});
const result: DeviceDiscoveryResult = {
devices: uniqueDevices,
protocol: protocols.length === 1 ? protocols[0] : NetworkProtocol.WiFi, // 简化表示
timestamp
};
Logger.i(`设备发现完成, 共发现${uniqueDevices.length}台设备`, 'DeviceManager');
return result;
} catch (error) {
Logger.e('设备发现失败', 'DeviceManager', error as BusinessError);
return { devices: [], protocol: NetworkProtocol.WiFi, timestamp };
}
}
/**
* 发现WiFi设备(通过UDP广播或mDNS)
* 注: 实际实现需根据设备厂商协议调整,此处为简化示例
*/
private async discoverWiFiDevices(): Promise<LightDevice[]> {
Logger.d('发现WiFi设备', 'DeviceManager');
const devices: LightDevice[] = [];
// 模拟发现过程 - 实际应通过UDP socket发送发现请求并解析响应
// 此处模拟发现2台WiFi设备
const mockDevice1: LightDevice = {
deviceId: `wifi_${Date.now()}_1`,
deviceName: 'Living Room LED Bulb',
deviceType: DeviceType.LED_BULB,
brand: 'SmartLight',
model: 'SL-W001',
firmwareVersion: '1.0.2',
isOnline: true,
isBound: false,
bindTime: 0,
lastActiveTime: Date.now(),
location: '客厅',
capability: {
supportSwitch: true,
supportBrightness: true,
minBrightness: 1,
maxBrightness: 100,
supportColorTemperature: true,
minColorTemp: 2700,
maxColorTemp: 6500,
supportRGB: true,
supportDimmingCurve: true,
supportTiming: true,
supportScene: true,
maxScenes: 10
},
state: {
powerOn: false,
brightness: 80,
colorTemperature: 4000,
temperatureUnit: TemperatureUnit.KELVIN,
dimmingCurve: DimmingCurve.LOGARITHMIC,
transitionTime: 500,
lastUpdateTime: Date.now()
},
networkInfo: {
protocol: NetworkProtocol.WiFi,
ipAddress: '192.168.1.100',
port: 8080,
signalStrength: 85,
connectionType: ConnectionType.DIRECT
},
groupIds: ['living_room_group']
};
const mockDevice2: LightDevice = {
deviceId: `wifi_${Date.now()}_2`,
deviceName: 'Bedroom Ceiling Light',
deviceType: DeviceType.CEILING_LIGHT,
brand: 'SmartLight',
model: 'SL-C002',
firmwareVersion: '1.1.0',
isOnline: true,
isBound: false,
bindTime: 0,
lastActiveTime: Date.now(),
location: '卧室',
capability: {
supportSwitch: true,
supportBrightness: true,
minBrightness: 10,
maxBrightness: 100,
supportColorTemperature: true,
minColorTemp: 2500,
maxColorTemp: 6000,
supportRGB: false,
supportDimmingCurve: true,
supportTiming: true,
supportScene: true,
maxScenes: 5
},
state: {
powerOn: true,
brightness: 50,
colorTemperature: 3000,
temperatureUnit: TemperatureUnit.KELVIN,
dimmingCurve: DimmingCurve.LOGARITHMIC,
transitionTime: 800,
lastUpdateTime: Date.now()
},
networkInfo: {
protocol: NetworkProtocol.WiFi,
ipAddress: '192.168.1.101',
port: 8080,
signalStrength: 70,
connectionType: ConnectionType.DIRECT
},
groupIds: ['bedroom_group']
};
devices.push(mockDevice1, mockDevice2);
Logger.i(`模拟发现${devices.length}台WiFi设备`, 'DeviceManager');
return devices;
}
/**
* 发现BLE设备(蓝牙低功耗)
*/
private async discoverBleDevices(): Promise<LightDevice[]> {
Logger.d('发现BLE设备', 'DeviceManager');
const devices: LightDevice[] = [];
try {
// 检查蓝牙权限
// 实际开发中需先申请BLUETOOTH、DISCOVER_BLUETOOTH权限
// 开始BLE扫描
await bluetooth.startBLEScan(null); // 扫描所有BLE设备
Logger.d('BLE扫描已启动', 'DeviceManager');
// 注册扫描结果回调(实际应通过事件监听获取扫描结果)
// 此处简化处理,模拟发现1台BLE设备
const mockBleDevice: LightDevice = {
deviceId: `ble_${Date.now()}_1`,
deviceName: 'Desk Lamp BLE',
deviceType: DeviceType.TABLE_LAMP,
brand: 'SmartLight',
model: 'SL-B003',
firmwareVersion: '2.0.1',
isOnline: true,
isBound: false,
bindTime: 0,
lastActiveTime: Date.now(),
location: '书房',
capability: {
supportSwitch: true,
supportBrightness: true,
minBrightness: 0,
maxBrightness: 100,
supportColorTemperature: false,
supportRGB: true,
supportDimmingCurve: false,
supportTiming: false,
supportScene: true,
maxScenes: 3
},
state: {
powerOn: false,
brightness: 100,
rgbColor: { r: 255, g: 100, b: 50 },
temperatureUnit: TemperatureUnit.KELVIN,
dimmingCurve: DimmingCurve.LINEAR,
transitionTime: 300,
lastUpdateTime: Date.now()
},
networkInfo: {
protocol: NetworkProtocol.BluetoothLE,
bleAddress: 'AA:BB:CC:DD:EE:FF',
signalStrength: 90,
connectionType: ConnectionType.DIRECT
},
groupIds: ['study_group']
};
devices.push(mockBleDevice);
Logger.i(`模拟发现${devices.length}台BLE设备`, 'DeviceManager');
// 停止扫描(实际应在适当时候停止)
// await bluetooth.stopBLEScan();
} catch (error) {
Logger.e('BLE设备发现失败', 'DeviceManager', error as BusinessError);
}
return devices;
}
/**
* 绑定设备(将发现的设备添加到已绑定列表)
* @param deviceId 设备ID
* @returns 是否绑定成功
*/
async bindDevice(deviceId: string): Promise<boolean> {
const device = this.discoveredDevices.get(deviceId);
if (!device) {
Logger.w(`未找到要绑定的设备: ${deviceId}`, 'DeviceManager');
return false;
}
try {
// 模拟绑定过程(实际应与设备通信进行认证和配对)
Logger.i(`开始绑定设备: ${device.deviceName}(${deviceId})`, 'DeviceManager');
// 更新设备绑定状态
const now = Date.now();
const boundDevice: LightDevice = {
...device,
isBound: true,
bindTime: now,
lastActiveTime: now
};
// 添加到已绑定设备列表
this.boundDevices.set(deviceId, boundDevice);
this.discoveredDevices.delete(deviceId);
// 保存到本地存储
await this.saveBoundDevices();
// 通知设备状态变化
this.notifyDeviceStateChanged(boundDevice, 'bound');
Logger.i(`设备绑定成功: ${device.deviceName}`, 'DeviceManager');
return true;
} catch (error) {
Logger.e(`设备绑定失败: ${deviceId}`, 'DeviceManager', error as BusinessError);
return false;
}
}
/**
* 解绑设备
* @param deviceId 设备ID
* @returns 是否解绑成功
*/
async unbindDevice(deviceId: string): Promise<boolean> {
const device = this.boundDevices.get(deviceId);
if (!device) {
Logger.w(`未找到要解绑的设备: ${deviceId}`, 'DeviceManager');
return false;
}
try {
Logger.i(`开始解绑设备: ${device.deviceName}(${deviceId})`, 'DeviceManager');
// 模拟解绑过程
const unboundDevice: LightDevice = {
...device,
isBound: false,
bindTime: 0
};
// 从已绑定列表移除,添加到发现列表(可选)
this.boundDevices.delete(deviceId);
this.discoveredDevices.set(deviceId, unboundDevice);
// 保存更新
await this.saveBoundDevices();
// 通知状态变化
this.notifyDeviceStateChanged(unboundDevice, 'unbound');
Logger.i(`设备解绑成功: ${device.deviceName}`, 'DeviceManager');
return true;
} catch (error) {
Logger.e(`设备解绑失败: ${deviceId}`, 'DeviceManager', error as BusinessError);
return false;
}
}
/**
* 保存已绑定设备到本地存储
*/
private async saveBoundDevices(): Promise<void> {
try {
const devices = Array.from(this.boundDevices.values());
await PreferencesUtil.saveDeviceList(devices);
Logger.d(`保存已绑定设备成功, 共${devices.length}台`, 'DeviceManager');
} catch (error) {
Logger.e('保存已绑定设备失败', 'DeviceManager', error as BusinessError);
}
}
/**
* 获取所有已绑定的设备
*/
getBoundDevices(): LightDevice[] {
return Array.from(this.boundDevices.values());
}
/**
* 获取设备信息(已绑定或发现的)
* @param deviceId 设备ID
*/
getDevice(deviceId: string): LightDevice | undefined {
return this.boundDevices.get(deviceId) || this.discoveredDevices.get(deviceId);
}
/**
* 更新设备状态(通常由LightController调用)
* @param deviceId 设备ID
* @param newState 新状态
*/
updateDeviceState(deviceId: string, newState: Partial<LightDevice['state']>): boolean {
const device = this.boundDevices.get(deviceId);
if (!device) {
Logger.w(`更新状态失败: 设备未绑定 ${deviceId}`, 'DeviceManager');
return false;
}
// 更新状态
const updatedState: LightDevice['state'] = {
...device.state,
...newState,
lastUpdateTime: Date.now()
};
const updatedDevice: LightDevice = {
...device,
state: updatedState
};
this.boundDevices.set(deviceId, updatedDevice);
// 通知状态变化
this.notifyDeviceStateChanged(updatedDevice, 'state_updated');
Logger.device(`更新设备状态: ${JSON.stringify(newState)}`, deviceId);
return true;
}
/**
* 注册设备状态监听器
* @param deviceId 设备ID(可选, 不填则监听所有设备)
* @param listener 监听器
*/
addDeviceStateListener(deviceId: string | null, listener: DeviceStateListener): void {
const key = deviceId || 'all_devices';
if (!this.deviceStateListeners.has(key)) {
this.deviceStateListeners.set(key, new Set());
}
this.deviceStateListeners.get(key)!.add(listener);
Logger.d(`注册设备状态监听器: ${key}`, 'DeviceManager');
}
/**
* 移除设备状态监听器
* @param deviceId 设备ID(可选)
* @param listener 监听器
*/
removeDeviceStateListener(deviceId: string | null, listener: DeviceStateListener): void {
const key = deviceId || 'all_devices';
const listeners = this.deviceStateListeners.get(key);
if (listeners) {
listeners.delete(listener);
if (listeners.size === 0) {
this.deviceStateListeners.delete(key);
}
Logger.d(`移除设备状态监听器: ${key}`, 'DeviceManager');
}
}
/**
* 通知设备状态变化
* @param device 设备信息
* @param changeType 变化类型
*/
private notifyDeviceStateChanged(device: LightDevice, changeType: DeviceStateChangeType): void {
// 通知特定设备的监听器
const deviceListeners = this.deviceStateListeners.get(device.deviceId);
if (deviceListeners) {
deviceListeners.forEach(listener => {
try {
listener.onDeviceStateChanged(device, changeType);
} catch (error) {
Logger.e(`设备状态监听器回调异常: ${device.deviceId}`, 'DeviceManager', error as BusinessError);
}
});
}
// 通知所有设备的监听器
const allListeners = this.deviceStateListeners.get('all_devices');
if (allListeners) {
allListeners.forEach(listener => {
try {
listener.onDeviceStateChanged(device, changeType);
} catch (error) {
Logger.e(`全局设备状态监听器回调异常`, 'DeviceManager', error as BusinessError);
}
});
}
}
/**
* 释放资源
*/
release(): void {
if (this.deviceManager) {
this.deviceManager.off('deviceOnline');
this.deviceManager.off('deviceOffline');
this.deviceManager.off('deviceInfoChanged');
this.deviceManager.release();
this.deviceManager = null;
}
this.discoveredDevices.clear();
this.boundDevices.clear();
this.deviceStateListeners.clear();
this.isInitialized = false;
Logger.i('设备管理器资源已释放', 'DeviceManager');
}
}
/**
* 设备状态变化类型
*/
export enum DeviceStateChangeType {
ONLINE = 'online',
OFFLINE = 'offline',
BOUND = 'bound',
UNBOUND = 'unbound',
STATE_UPDATED = 'state_updated',
INFO_UPDATED = 'info_updated'
}
/**
* 设备状态监听器接口
*/
export interface DeviceStateListener {
onDeviceStateChanged(device: LightDevice, changeType: DeviceStateChangeType): void;
}
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)