【HarmonyOS】鸿蒙Flutter智能家居应用开发实战指南
智能家居是鸿蒙全场景生态的重要应用场景。本文讲解如何基于鸿蒙Flutter框架,开发一套完整的智能家居应用,实现设备发现、控制、场景联动、语音交互等核心功能。
·
鸿蒙Flutter智能家居应用开发实战指南

概述
智能家居是鸿蒙全场景生态的重要应用场景。本文讲解如何基于鸿蒙Flutter框架,开发一套完整的智能家居应用,实现设备发现、控制、场景联动、语音交互等核心功能。
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
系统架构设计
整体架构图
┌────────────────────────────────────────────────────────────┐
│ 用户交互层 (Flutter) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ 设备控制面板 │ │ 场景编排 │ │ 语音交互 │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└───────────────────────┬────────────────────────────────────┘
│ RPC/事件总线
┌───────────────────────┴────────────────────────────────────┐
│ 智能家庭业务逻辑层 (Dart) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 设备管理器 │ │ 场景引擎 │ │ 自动化规则 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└───────────────────────┬────────────────────────────────────┘
│ 分布式软总线
┌───────────────────────┴────────────────────────────────────┐
│ 鸿蒙IoT服务层 (ArkTS) │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 设备发现 │ │ 协议适配 │ │ 分布式联动 │ │
│ └──────────────┘ └──────────────┘ └──────────────┘ │
└───────────────────────┬────────────────────────────────────┘
│ HiLink/WiFi/蓝牙
┌───────────────────────┴────────────────────────────────────┐
│ 智能设备层 │
│ 灯光 · 窗帘 · 空调 · 传感器 · 门锁 · 音响 · ... │
└────────────────────────────────────────────────────────────┘
核心组件设计
| 组件 | 技术方案 | 职责 |
|---|---|---|
| 设备模型 | 抽象基类 + 具体实现 | 统一设备抽象 |
| 控制协议 | 统一命令格式 | 跨设备控制 |
| 状态同步 | 分布式数据对象 | 实时状态更新 |
| 场景引擎 | 规则匹配系统 | 自动化场景 |
| 语音交互 | AI意图识别 | 自然语言控制 |
设备模型设计
基础设备抽象
/// 设备类型枚举
enum SmartDeviceType {
light('智能灯光', Icons.lightbulb),
curtain('智能窗帘', Icons.curtains),
ac('空调', Icons.ac_unit),
sensor('传感器', Icons.sensors),
lock('门锁', Icons.lock),
speaker('智能音箱', Icons.speaker),
camera('摄像头', Icons.videocam),
switch('智能开关', Icons.toggle_on),
thermostat('温控器', Icons.thermostat),
purifier('净化器', Icons.air);
final String displayName;
final IconData icon;
const SmartDeviceType(this.displayName, this.icon);
}
/// 设备状态基类
abstract class DeviceState {
Map<String, dynamic> toJson();
static DeviceState fromJson(Map<String, dynamic> json) {
final type = json['type'] as String;
switch (type) {
case 'light':
return LightState.fromJson(json);
case 'curtain':
return CurtainState.fromJson(json);
case 'ac':
return ACState.fromJson(json);
case 'sensor':
return SensorState.fromJson(json);
default:
throw ArgumentError('Unknown device type: $type');
}
}
}
/// 智能设备基类
abstract class SmartDevice {
final String deviceId;
final String deviceName;
final SmartDeviceType type;
final String roomId;
final bool isOnline;
final DateTime lastSeen;
const SmartDevice({
required this.deviceId,
required this.deviceName,
required this.type,
required this.roomId,
this.isOnline = true,
DateTime? lastSeen,
}) : lastSeen = lastSeen ?? const Duration();
/// 获取当前状态
DeviceState get currentState;
/// 执行控制命令
Future<bool> executeCommand(DeviceCommand command);
/// 订阅状态变化
Stream<DeviceState> get stateStream;
/// 工厂构造方法
static SmartDevice fromJson(Map<String, dynamic> json) {
final type = SmartDeviceType.values.firstWhere(
(e) => e.name == json['type'],
orElse: () => SmartDeviceType.switch,
);
switch (type) {
case SmartDeviceType.light:
return SmartLight.fromJson(json);
case SmartDeviceType.curtain:
return SmartCurtain.fromJson(json);
case SmartDeviceType.ac:
return SmartAC.fromJson(json);
case SmartDeviceType.sensor:
return SmartSensor.fromJson(json);
default:
return SmartSwitch.fromJson(json);
}
}
Map<String, dynamic> toJson();
}
/// 设备命令基类
abstract class DeviceCommand {
final String deviceId;
final DateTime timestamp;
DeviceCommand({required this.deviceId})
: timestamp = DateTime.now();
Map<String, dynamic> toJson();
}
/// 设备事件
class DeviceEvent {
final String deviceId;
final SmartDeviceType type;
final String eventType;
final Map<String, dynamic> data;
final DateTime timestamp;
DeviceEvent({
required this.deviceId,
required this.type,
required this.eventType,
required this.data,
}) : timestamp = DateTime.now();
}
具体设备实现
/// 灯光状态
()
class LightState extends DeviceState {
final bool isOn;
final int brightness; // 0-100
final int colorTemp; // 色温 2700-6500K
final int? hue; // 色相 0-360
final int? saturation; // 饱和度 0-100
const LightState({
this.isOn = false,
this.brightness = 100,
this.colorTemp = 4000,
this.hue,
this.saturation,
});
Map<String, dynamic> toJson() => _$LightStateToJson(this);
factory LightState.fromJson(Map<String, dynamic> json) =>
_$LightStateFromJson(json);
LightState copyWith({
bool? isOn,
int? brightness,
int? colorTemp,
int? hue,
int? saturation,
}) {
return LightState(
isOn: isOn ?? this.isOn,
brightness: brightness ?? this.brightness,
colorTemp: colorTemp ?? this.colorTemp,
hue: hue ?? this.hue,
saturation: saturation ?? this.saturation,
);
}
}
/// 灯光控制命令
class LightCommand extends DeviceCommand {
final bool? isOn;
final int? brightness;
final int? colorTemp;
final int? hue;
final int? saturation;
LightCommand({
required super.deviceId,
this.isOn,
this.brightness,
this.colorTemp,
this.hue,
this.saturation,
});
Map<String, dynamic> toJson() => {
'deviceId': deviceId,
'command': 'light_control',
'params': {
'isOn': isOn,
'brightness': brightness,
'colorTemp': colorTemp,
'hue': hue,
'saturation': saturation,
},
'timestamp': timestamp.toIso8601String(),
};
}
/// 智能灯光设备
class SmartLight extends SmartDevice {
LightState _state;
SmartLight({
required super.deviceId,
required super.deviceName,
required super.roomId,
LightState? state,
super.isOnline,
}) : _state = state ?? const LightState(),
super(type: SmartDeviceType.light);
LightState get currentState => _state;
Future<bool> executeCommand(DeviceCommand command) async {
if (command is! LightCommand) return false;
if (!isOnline) return false;
try {
// 通过鸿蒙分布式能力发送命令
final result = await HarmonyIotChannel.sendDeviceCommand(command.toJson());
if (result) {
// 更新本地状态
_state = _state.copyWith(
isOn: command.isOn,
brightness: command.brightness,
colorTemp: command.colorTemp,
hue: command.hue,
saturation: command.saturation,
);
return true;
}
return false;
} catch (e) {
debugPrint('灯光控制失败: $e');
return false;
}
}
Stream<LightState> get stateStream {
return HarmonyIotChannel.deviceStateStream
.where((event) => event.deviceId == deviceId)
.map((event) => LightState.fromJson(event.data));
}
Map<String, dynamic> toJson() => {
'deviceId': deviceId,
'deviceName': deviceName,
'type': type.name,
'roomId': roomId,
'isOnline': isOnline,
'lastSeen': lastSeen.toIso8601String(),
'state': _state.toJson(),
};
factory SmartLight.fromJson(Map<String, dynamic> json) {
return SmartLight(
deviceId: json['deviceId'] as String,
deviceName: json['deviceName'] as String,
roomId: json['roomId'] as String,
state: json['state'] != null
? LightState.fromJson(json['state'] as Map<String, dynamic>)
: null,
isOnline: json['isOnline'] as bool? ?? true,
);
}
}
/// 空调状态
()
class ACState extends DeviceState {
final bool isOn;
final int temperature; // 16-30
final String mode; // cool, heat, auto, dry, fan
final int fanSpeed; // 1-3
final bool swing;
const ACState({
this.isOn = false,
this.temperature = 26,
this.mode = 'cool',
this.fanSpeed = 2,
this.swing = false,
});
Map<String, dynamic> toJson() => _$ACStateToJson(this);
factory ACState.fromJson(Map<String, dynamic> json) =>
_$ACStateFromJson(json);
ACState copyWith({
bool? isOn,
int? temperature,
String? mode,
int? fanSpeed,
bool? swing,
}) {
return ACState(
isOn: isOn ?? this.isOn,
temperature: temperature ?? this.temperature,
mode: mode ?? this.mode,
fanSpeed: fanSpeed ?? this.fanSpeed,
swing: swing ?? this.swing,
);
}
}
/// 智能空调设备
class SmartAC extends SmartDevice {
ACState _state;
SmartAC({
required super.deviceId,
required super.deviceName,
required super.roomId,
ACState? state,
super.isOnline,
}) : _state = state ?? const ACState(),
super(type: SmartDeviceType.ac);
ACState get currentState => _state;
Future<bool> executeCommand(DeviceCommand command) async {
if (command is! ACCommand) return false;
_state = _state.copyWith(
isOn: command.isOn,
temperature: command.temperature,
mode: command.mode,
fanSpeed: command.fanSpeed,
swing: command.swing,
);
return await HarmonyIotChannel.sendDeviceCommand(command.toJson());
}
Stream<ACState> get stateStream {
return HarmonyIotChannel.deviceStateStream
.where((event) => event.deviceId == deviceId)
.map((event) => ACState.fromJson(event.data));
}
Map<String, dynamic> toJson() => {
'deviceId': deviceId,
'deviceName': deviceName,
'type': type.name,
'roomId': roomId,
'isOnline': isOnline,
'state': _state.toJson(),
};
}
/// 空调控制命令
class ACCommand extends DeviceCommand {
final bool? isOn;
final int? temperature;
final String? mode;
final int? fanSpeed;
final bool? swing;
ACCommand({
required super.deviceId,
this.isOn,
this.temperature,
this.mode,
this.fanSpeed,
this.swing,
});
Map<String, dynamic> toJson() => {
'deviceId': deviceId,
'command': 'ac_control',
'params': {
'isOn': isOn,
'temperature': temperature,
'mode': mode,
'fanSpeed': fanSpeed,
'swing': swing,
},
'timestamp': timestamp.toIso8601String(),
};
}
设备管理系统
设备管理器实现
/// 智能设备管理器
class SmartDeviceManager {
static final SmartDeviceManager _instance =
SmartDeviceManager._internal();
factory SmartDeviceManager() => _instance;
SmartDeviceManager._internal();
final Map<String, SmartDevice> _devices = {};
final Map<String, List<SmartDevice>> _roomDevices = {};
final StreamController<DeviceEvent> _eventController =
StreamController.broadcast();
/// 设备列表
List<SmartDevice> get devices => _devices.values.toList();
/// 设备事件流
Stream<DeviceEvent> get eventStream => _eventController.stream;
/// 初始化
Future<void> initialize() async {
// 订阅鸿蒙设备状态变化
HarmonyIotChannel.deviceStateStream.listen((event) {
_handleDeviceStateChange(event);
});
// 发现设备
await discoverDevices();
}
/// 发现设备
Future<void> discoverDevices() async {
try {
final deviceList = await HarmonyIotChannel.discoverDevices();
for (final deviceJson in deviceList) {
final device = SmartDevice.fromJson(deviceJson);
_addDevice(device);
}
debugPrint('发现 ${deviceList.length} 个智能设备');
} catch (e) {
debugPrint('设备发现失败: $e');
}
}
/// 添加设备
void _addDevice(SmartDevice device) {
_devices[device.deviceId] = device;
// 按房间分组
_roomDevices.putIfAbsent(device.roomId, () => []);
_roomDevices[device.roomId]!.add(device);
// 订阅设备状态变化
device.stateStream.listen((state) {
_eventController.add(DeviceEvent(
deviceId: device.deviceId,
type: device.type,
eventType: 'state_change',
data: state.toJson(),
));
});
}
/// 获取设备
SmartDevice? getDevice(String deviceId) {
return _devices[deviceId];
}
/// 获取房间设备
List<SmartDevice> getRoomDevices(String roomId) {
return _roomDevices[roomId] ?? [];
}
/// 按类型获取设备
List<SmartDevice> getDevicesByType(SmartDeviceType type) {
return _devices.values.where((d) => d.type == type).toList();
}
/// 控制设备
Future<bool> controlDevice(
String deviceId,
DeviceCommand command,
) async {
final device = _devices[deviceId];
if (device == null) return false;
final success = await device.executeCommand(command);
if (success) {
_eventController.add(DeviceEvent(
deviceId: deviceId,
type: device.type,
eventType: 'command_executed',
data: command.toJson(),
));
}
return success;
}
/// 批量控制
Future<Map<String, bool>> batchControl(
List<String> deviceIds,
DeviceCommand Function(String) commandBuilder,
) async {
final results = <String, bool>{};
await Future.wait(deviceIds.map((deviceId) async {
final command = commandBuilder(deviceId);
results[deviceId] = await controlDevice(deviceId, command);
}));
return results;
}
/// 处理设备状态变化
void _handleDeviceStateChange(DeviceEvent event) {
final device = _devices[event.deviceId];
if (device != null) {
// 更新设备状态
_eventController.add(event);
}
}
/// 释放资源
void dispose() {
_eventController.close();
}
}
房间管理
/// 房间模型
()
class SmartRoom {
final String roomId;
final String roomName;
final String icon;
final List<String> deviceIds;
final int temperature;
final int humidity;
final int brightness;
const SmartRoom({
required this.roomId,
required this.roomName,
this.icon = 'room',
this.deviceIds = const [],
this.temperature = 25,
this.humidity = 60,
this.brightness = 0,
});
/// 获取房间设备
List<SmartDevice> getDevices(SmartDeviceManager manager) {
return deviceIds
.map((id) => manager.getDevice(id))
.whereType<SmartDevice>()
.toList();
}
/// 获取在线设备数量
int getOnlineDeviceCount(SmartDeviceManager manager) {
return getDevices(manager).where((d) => d.isOnline).length;
}
/// 是否有灯光设备
bool hasLightDevices(SmartDeviceManager manager) {
return getDevices(manager).any((d) => d.type == SmartDeviceType.light);
}
SmartRoom copyWith({
String? roomId,
String? roomName,
String? icon,
List<String>? deviceIds,
int? temperature,
int? humidity,
int? brightness,
}) {
return SmartRoom(
roomId: roomId ?? this.roomId,
roomName: roomName ?? this.roomName,
icon: icon ?? this.icon,
deviceIds: deviceIds ?? this.deviceIds,
temperature: temperature ?? this.temperature,
humidity: humidity ?? this.humidity,
brightness: brightness ?? this.brightness,
);
}
Map<String, dynamic> toJson() => _$SmartRoomToJson(this);
factory SmartRoom.fromJson(Map<String, dynamic> json) =>
_$SmartRoomFromJson(json);
}
/// 房间管理器
class RoomManager {
final List<SmartRoom> _rooms = [
const SmartRoom(
roomId: 'living_room',
roomName: '客厅',
icon: 'sofa',
deviceIds: ['light_1', 'ac_1', 'curtain_1'],
),
const SmartRoom(
roomId: 'bedroom',
roomName: '卧室',
icon: 'bed',
deviceIds: ['light_2', 'ac_2', 'curtain_2'],
),
const SmartRoom(
roomId: 'kitchen',
roomName: '厨房',
icon: 'chef',
deviceIds: ['light_3', 'sensor_1'],
),
];
List<SmartRoom> get rooms => List.unmodifiable(_rooms);
SmartRoom? getRoom(String roomId) {
try {
return _rooms.firstWhere((r) => r.roomId == roomId);
} catch (e) {
return null;
}
}
void updateRoomEnvironment({
required String roomId,
int? temperature,
int? humidity,
int? brightness,
}) {
final index = _rooms.indexWhere((r) => r.roomId == roomId);
if (index >= 0) {
_rooms[index] = _rooms[index].copyWith(
temperature: temperature,
humidity: humidity,
brightness: brightness,
);
}
}
}
场景自动化
场景引擎
/// 智能场景
()
class SmartScene {
final String sceneId;
final String sceneName;
final String icon;
final List<SceneAction> actions;
final SceneTrigger? trigger;
final bool isEnabled;
const SmartScene({
required this.sceneId,
required this.sceneName,
this.icon = 'scene',
this.actions = const [],
this.trigger,
this.isEnabled = true,
});
/// 执行场景
Future<void> execute(SmartDeviceManager manager) async {
if (!isEnabled) return;
for (final action in actions) {
await action.execute(manager);
}
}
SmartScene copyWith({
String? sceneId,
String? sceneName,
String? icon,
List<SceneAction>? actions,
SceneTrigger? trigger,
bool? isEnabled,
}) {
return SmartScene(
sceneId: sceneId ?? this.sceneId,
sceneName: sceneName ?? this.sceneName,
icon: icon ?? this.icon,
actions: actions ?? this.actions,
trigger: trigger ?? this.trigger,
isEnabled: isEnabled ?? this.isEnabled,
);
}
Map<String, dynamic> toJson() => _$SmartSceneToJson(this);
factory SmartScene.fromJson(Map<String, dynamic> json) =>
_$SmartSceneFromJson(json);
}
/// 场景动作
abstract class SceneAction {
Future<void> execute(SmartDeviceManager manager);
Map<String, dynamic> toJson();
static SceneAction fromJson(Map<String, dynamic> json) {
final type = json['type'] as String;
switch (type) {
case 'device_control':
return DeviceControlAction.fromJson(json);
case 'delay':
return DelayAction.fromJson(json);
case 'scene':
return SceneCallAction.fromJson(json);
default:
throw ArgumentError('Unknown action type: $type');
}
}
}
/// 设备控制动作
()
class DeviceControlAction extends SceneAction {
final String deviceId;
final Map<String, dynamic> params;
const DeviceControlAction({
required this.deviceId,
required this.params,
});
Future<void> execute(SmartDeviceManager manager) async {
final command = _createCommand();
await manager.controlDevice(deviceId, command);
}
DeviceCommand _createCommand() {
final type = params['deviceType'] as String?;
if (type == 'light') {
return LightCommand(
deviceId: deviceId,
isOn: params['isOn'] as bool?,
brightness: params['brightness'] as int?,
colorTemp: params['colorTemp'] as int?,
);
}
throw UnimplementedError('Unknown device type');
}
Map<String, dynamic> toJson() => _$DeviceControlActionToJson(this);
factory DeviceControlAction.fromJson(Map<String, dynamic> json) =>
_$DeviceControlActionFromJson(json);
}
/// 延迟动作
()
class DelayAction extends SceneAction {
final int delayMs;
const DelayAction({required this.delayMs});
Future<void> execute(SmartDeviceManager manager) async {
await Future.delayed(Duration(milliseconds: delayMs));
}
Map<String, dynamic> toJson() => _$DelayActionToJson(this);
factory DelayAction.fromJson(Map<String, dynamic> json) =>
_$DelayActionFromJson(json);
}
/// 场景触发器
()
class SceneTrigger {
final TriggerType type;
final Map<String, dynamic> conditions;
const SceneTrigger({
required this.type,
required this.conditions,
});
/// 检查触发条件
bool check(Map<String, dynamic> eventData) {
switch (type) {
case TriggerType.time:
return _checkTimeTrigger();
case TriggerType.device:
return _checkDeviceTrigger(eventData);
case TriggerType.location:
return _checkLocationTrigger(eventData);
}
}
bool _checkTimeTrigger() {
final now = DateTime.now();
final hour = conditions['hour'] as int? ?? -1;
final minute = conditions['minute'] as int? ?? 0;
if (hour >= 0 && now.hour == hour && now.minute == minute) {
return true;
}
return false;
}
bool _checkDeviceTrigger(Map<String, dynamic> eventData) {
final deviceId = conditions['deviceId'] as String?;
final expectedState = conditions['state'] as Map<String, dynamic>?;
if (deviceId == null || expectedState == null) return false;
// 检查设备状态匹配
return true; // 简化实现
}
bool _checkLocationTrigger(Map<String, dynamic> eventData) {
// 位置触发检查
return false;
}
Map<String, dynamic> toJson() => _$SceneTriggerToJson(this);
factory SceneTrigger.fromJson(Map<String, dynamic> json) =>
_$SceneTriggerFromJson(json);
}
enum TriggerType { time, device, location }
/// 场景引擎
class SceneEngine {
final SmartDeviceManager _deviceManager;
final List<SmartScene> _scenes;
final StreamController<SmartScene> _triggerController =
StreamController.broadcast();
Stream<SmartScene> get triggerStream => _triggerController.stream;
SceneEngine(this._deviceManager, this._scenes) {
_initialize();
}
void _initialize() {
// 订阅设备事件
_deviceManager.eventStream.listen((event) {
_checkSceneTriggers(event);
});
// 启动定时检查
Timer.periodic(const Duration(minutes: 1), (_) {
_checkTimeTriggers();
});
}
/// 执行场景
Future<void> executeScene(String sceneId) async {
final scene = _scenes.firstWhere(
(s) => s.sceneId == sceneId,
orElse: () => throw ArgumentError('Scene not found: $sceneId'),
);
await scene.execute(_deviceManager);
_triggerController.add(scene);
}
/// 检查场景触发
void _checkSceneTriggers(DeviceEvent event) {
for (final scene in _scenes) {
if (scene.trigger?.check(event.toJson()) ?? false) {
executeScene(scene.sceneId);
}
}
}
/// 检查时间触发
void _checkTimeTriggers() {
for (final scene in _scenes) {
if (scene.trigger?.type == TriggerType.time) {
if (scene.trigger?.check({}) ?? false) {
executeScene(scene.sceneId);
}
}
}
}
void dispose() {
_triggerController.close();
}
}
语音控制集成
语音意图识别
/// 语音意图类型
enum VoiceIntent {
turnOnDevice, // 打开设备
turnOffDevice, // 关闭设备
setBrightness, // 设置亮度
setTemperature, // 设置温度
openCurtain, // 打开窗帘
closeCurtain, // 关闭窗帘
executeScene, // 执行场景
queryStatus, // 查询状态
}
/// 语音命令解析器
class VoiceCommandParser {
static const Map<String, VoiceIntent> _intentKeywords = {
'打开': VoiceIntent.turnOnDevice,
'开启': VoiceIntent.turnOnDevice,
'关闭': VoiceIntent.turnOffDevice,
'亮度': VoiceIntent.setBrightness,
'温度': VoiceIntent.setTemperature,
'拉开': VoiceIntent.openCurtain,
'拉上': VoiceIntent.closeCurtain,
'执行': VoiceIntent.executeScene,
'运行': VoiceIntent.executeScene,
'状态': VoiceIntent.queryStatus,
};
/// 解析语音命令
static ParsedCommand? parse(String text) {
// 简化的解析逻辑
for (final entry in _intentKeywords.entries) {
if (text.contains(entry.key)) {
final intent = entry.value;
final params = _extractParameters(text, intent);
return ParsedCommand(
intent: intent,
parameters: params,
originalText: text,
);
}
}
return null;
}
static Map<String, dynamic> _extractParameters(
String text,
VoiceIntent intent,
) {
final params = <String, dynamic>{};
switch (intent) {
case VoiceIntent.turnOnDevice:
case VoiceIntent.turnOffDevice:
params['deviceType'] = _extractDeviceType(text);
params['room'] = _extractRoom(text);
break;
case VoiceIntent.setBrightness:
params['value'] = _extractNumber(text);
break;
case VoiceIntent.setTemperature:
params['value'] = _extractNumber(text);
break;
default:
break;
}
return params;
}
static SmartDeviceType? _extractDeviceType(String text) {
if (text.contains('灯') || text.contains('照明')) {
return SmartDeviceType.light;
} else if (text.contains('空调')) {
return SmartDeviceType.ac;
} else if (text.contains('窗帘')) {
return SmartDeviceType.curtain;
}
return null;
}
static String? _extractRoom(String text) {
if (text.contains('客厅')) return 'living_room';
if (text.contains('卧室')) return 'bedroom';
if (text.contains('厨房')) return 'kitchen';
return null;
}
static int? _extractNumber(String text) {
final regex = RegExp(r'\d+');
final match = regex.firstMatch(text);
return match != null ? int.tryParse(match.group(0)!) : null;
}
}
/// 解析后的命令
class ParsedCommand {
final VoiceIntent intent;
final Map<String, dynamic> parameters;
final String originalText;
ParsedCommand({
required this.intent,
required this.parameters,
required this.originalText,
});
}
/// 语音控制执行器
class VoiceController {
final SmartDeviceManager _deviceManager;
final SceneEngine _sceneEngine;
VoiceController(this._deviceManager, this._sceneEngine);
/// 执行语音命令
Future<VoiceResult> execute(String text) async {
final command = VoiceCommandParser.parse(text);
if (command == null) {
return VoiceResult(
success: false,
message: '抱歉,我没有理解您的指令',
);
}
try {
await _executeCommand(command);
return VoiceResult(
success: true,
message: _generateSuccessMessage(command),
);
} catch (e) {
return VoiceResult(
success: false,
message: '执行失败:$e',
);
}
}
Future<void> _executeCommand(ParsedCommand command) async {
switch (command.intent) {
case VoiceIntent.turnOnDevice:
await _handleTurnOn(command);
break;
case VoiceIntent.turnOffDevice:
await _handleTurnOff(command);
break;
case VoiceIntent.setBrightness:
await _handleSetBrightness(command);
break;
case VoiceIntent.executeScene:
await _handleExecuteScene(command);
break;
default:
throw UnimplementedError('Intent not implemented');
}
}
Future<void> _handleTurnOn(ParsedCommand command) async {
final room = command.parameters['room'] as String?;
final deviceType = command.parameters['deviceType'] as SmartDeviceType?;
final devices = _deviceManager.getDevicesByType(deviceType!);
final targetDevices = room == null
? devices
: devices.where((d) => d.roomId == room).toList();
for (final device in targetDevices) {
await _deviceManager.controlDevice(
device.deviceId,
LightCommand(deviceId: device.deviceId, isOn: true),
);
}
}
Future<void> _handleSetBrightness(ParsedCommand command) async {
final value = command.parameters['value'] as int?;
if (value == null) return;
final lights = _deviceManager.getDevicesByType(SmartDeviceType.light);
for (final light in lights) {
await _deviceManager.controlDevice(
light.deviceId,
LightCommand(deviceId: light.deviceId, brightness: value),
);
}
}
Future<void> _handleExecuteScene(ParsedCommand command) async {
final sceneName = command.parameters['sceneName'] as String?;
if (sceneName == null) return;
// 通过场景名称查找并执行
// await _sceneEngine.executeScene(sceneId);
}
String _generateSuccessMessage(ParsedCommand command) {
switch (command.intent) {
case VoiceIntent.turnOnDevice:
return '已为您打开设备';
case VoiceIntent.turnOffDevice:
return '已为您关闭设备';
case VoiceIntent.setBrightness:
return '已调整亮度';
default:
return '执行成功';
}
}
}
/// 语音执行结果
class VoiceResult {
final bool success;
final String message;
VoiceResult({required this.success, required this.message});
}
UI实现
主界面
/// 智能家居主页面
class SmartHomePage extends ConsumerStatefulWidget {
const SmartHomePage({super.key});
ConsumerState<SmartHomePage> createState() => _SmartHomePageState();
}
class _SmartHomePageState extends ConsumerState<SmartHomePage> {
Widget build(BuildContext context) {
final roomManager = ref.watch(roomManagerProvider);
final deviceManager = ref.watch(deviceManagerProvider);
return Scaffold(
body: CustomScrollView(
slivers: [
// 顶部AppBar
_buildAppBar(context),
// 房间卡片
SliverToBoxAdapter(
child: _buildRoomsSection(context, roomManager, deviceManager),
),
// 设备列表
_buildDevicesSection(deviceManager),
// 场景快捷方式
SliverToBoxAdapter(
child: _buildScenesSection(context),
),
],
),
// 语音按钮
floatingActionButton: _buildVoiceButton(context),
);
}
Widget _buildAppBar(BuildContext context) {
return SliverAppBar(
expandedHeight: 120,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
title: const Text('智能家居'),
background: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: [
Colors.blue.shade400,
Colors.blue.shade700,
],
),
),
child: const Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Icon(Icons.home, size: 48, color: Colors.white70),
SizedBox(height: 8),
Text(
'欢迎回家',
style: TextStyle(color: Colors.white70),
),
],
),
),
),
),
actions: [
IconButton(
icon: const Icon(Icons.settings),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (_) => const SettingsPage()),
),
),
],
);
}
Widget _buildRoomsSection(
BuildContext context,
RoomManager roomManager,
SmartDeviceManager deviceManager,
) {
return Container(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text(
'房间',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
),
const SizedBox(height: 12),
SizedBox(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 16),
itemCount: roomManager.rooms.length,
itemBuilder: (context, index) {
final room = roomManager.rooms[index];
return _buildRoomCard(context, room, deviceManager);
},
),
),
],
),
);
}
Widget _buildRoomCard(
BuildContext context,
SmartRoom room,
SmartDeviceManager deviceManager,
) {
final onlineCount = room.getOnlineDeviceCount(deviceManager);
final totalDevices = room.deviceIds.length;
return Container(
width: 160,
margin: const EdgeInsets.only(right: 12),
child: Card(
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => RoomDetailPage(room: room),
),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(_getRoomIcon(room.icon), size: 24),
const Spacer(),
Chip(
label: Text('$onlineCount/$totalDevices'),
visualDensity: VisualDensity.compact,
),
],
),
const Spacer(),
Text(
room.roomName,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
Text(
'${room.temperature}°C · ${room.humidity}%',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
),
),
);
}
IconData _getRoomIcon(String icon) {
switch (icon) {
case 'sofa':
return Icons.weekend;
case 'bed':
return Icons.bed;
case 'chef':
return Icons.kitchen;
default:
return Icons.room;
}
}
Widget _buildDevicesSection(SmartDeviceManager deviceManager) {
return SliverPadding(
padding: const EdgeInsets.symmetric(horizontal: 16),
sliver: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
final device = deviceManager.devices[index];
return _buildDeviceCard(context, device);
},
childCount: deviceManager.devices.length,
),
),
);
}
Widget _buildDeviceCard(BuildContext context, SmartDevice device) {
return Card(
margin: const EdgeInsets.only(bottom: 12),
child: ListTile(
leading: Icon(device.type.icon),
title: Text(device.deviceName),
subtitle: Text(device.isOnline ? '在线' : '离线'),
trailing: _buildDeviceControl(device),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => DeviceControlPage(device: device),
),
),
),
);
}
Widget _buildDeviceControl(SmartDevice device) {
if (device is SmartLight) {
final state = device.currentState;
return Switch(
value: state.isOn,
onChanged: (value) {
// 控制灯光
},
);
}
return const Icon(Icons.chevron_right);
}
Widget _buildScenesSection(BuildContext context) {
final scenes = ref.watch(sceneProvider);
return Container(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'场景',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 12),
Wrap(
spacing: 12,
runSpacing: 12,
children: scenes.map((scene) {
return _buildSceneChip(context, scene);
}).toList(),
),
],
),
);
}
Widget _buildSceneChip(BuildContext context, SmartScene scene) {
return ActionChip(
avatar: const Icon(Icons.flash_on),
label: Text(scene.sceneName),
onPressed: () async {
await ref.read(sceneProvider.notifier).executeScene(scene.sceneId);
},
);
}
Widget _buildVoiceButton(BuildContext context) {
return FloatingActionButton.extended(
onPressed: () => _showVoiceDialog(context),
icon: const Icon(Icons.mic),
label: const Text('语音控制'),
);
}
void _showVoiceDialog(BuildContext context) {
showDialog(
context: context,
builder: (_) => const VoiceControlDialog(),
);
}
}
语音控制对话框
/// 语音控制对话框
class VoiceControlDialog extends ConsumerStatefulWidget {
const VoiceControlDialog({super.key});
ConsumerState<VoiceControlDialog> createState() => _VoiceControlDialogState();
}
class _VoiceControlDialogState extends ConsumerState<VoiceControlDialog> {
bool _isListening = false;
String _recognizedText = '';
VoiceResult? _result;
Widget build(BuildContext context) {
return AlertDialog(
title: const Text('语音控制'),
content: SizedBox(
width: 300,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// 麦克风动画
_buildMicrophoneAnimation(),
const SizedBox(height: 24),
// 识别文本
if (_recognizedText.isNotEmpty)
Text(
_recognizedText,
textAlign: TextAlign.center,
style: const TextStyle(fontSize: 16),
),
const SizedBox(height: 16),
// 执行结果
if (_result != null)
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: _result!.success
? Colors.green.shade50
: Colors.red.shade50,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: [
Icon(
_result!.success ? Icons.check_circle : Icons.error,
color: _result!.success ? Colors.green : Colors.red,
),
const SizedBox(width: 8),
Expanded(child: Text(_result!.message)),
],
),
),
const SizedBox(height: 8),
// 提示文本
Text(
'说出指令,如:"打开客厅灯"',
style: TextStyle(
fontSize: 12,
color: Colors.grey[600],
),
),
],
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('关闭'),
),
],
);
}
Widget _buildMicrophoneAnimation() {
return GestureDetector(
onTap: _isListening ? null : _startListening,
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _isListening ? Colors.blue.shade100 : Colors.grey.shade200,
boxShadow: _isListening
? [
BoxShadow(
color: Colors.blue.withOpacity(0.3),
blurRadius: 20,
spreadRadius: 10,
),
]
: null,
),
child: Icon(
_isListening ? Icons.mic : Icons.mic_none,
size: 40,
color: _isListening ? Colors.blue : Colors.grey,
),
),
);
}
Future<void> _startListening() async {
setState(() => _isListening = true);
_result = null;
try {
// 调用鸿蒙语音识别
final text = await HarmonyVoiceChannel.startListening();
if (text != null) {
setState(() => _recognizedText = text);
// 执行语音命令
final voiceController = ref.read(voiceControllerProvider);
final result = await voiceController.execute(text);
setState(() => _result = result);
}
} catch (e) {
setState(() {
_result = VoiceResult(
success: false,
message: '识别失败:$e',
);
});
} finally {
setState(() => _isListening = false);
}
}
}
鸿蒙端IoT服务
设备通信实现
// HarmonyIotService.ets
import distributedDevice from '@ohos.distributedDevice';
import { MethodChannel } from '@ohos.flutter';
export class HarmonyIotService {
private flutterChannel: MethodChannel | null = null;
private deviceCallbacks: Map<string, (data: ESObject) => void> = new Map();
initialize(channel: MethodChannel): void {
this.flutterChannel = channel;
this._registerMethodChannel();
this._startDeviceDiscovery();
}
private _registerMethodChannel(): void {
this.flutterChannel?.setMethodCallHandler(
async (method: string, args: Record<string, Object>): Promise<Object> => {
switch (method) {
case 'discoverDevices':
return await this._handleDiscoverDevices();
case 'sendCommand':
return await this._handleSendCommand(args);
case 'startVoice':
return await this._handleStartVoice(args);
default:
return null;
}
}
);
}
private async _handleDiscoverDevices(): Promise<Object[]> {
const devices: Object[] = [];
try {
// 发现周边智能设备
const discoverInfo: distributedDevice.SubscribeInfo = {
subscribeId: 1,
mode: distributedDevice.DiscoveryMode.ACTIVE,
medium: distributedDevice.MediumType.WIFI,
freq: distributedDevice.FreqType.HIGH
};
distributedDevice.startDeviceDiscovery(discoverInfo, (err, data) => {
if (!err) {
devices.push({
'deviceId': data.deviceId,
'deviceName': data.deviceName,
'type': this._mapDeviceType(data.deviceType),
'isOnline': true
});
}
});
// 等待设备发现完成
await new Promise(resolve => setTimeout(resolve, 3000));
return devices;
} catch (e) {
console.error('设备发现失败:', e);
return [];
}
}
private _mapDeviceType(type: string): string {
// 映射鸿蒙设备类型到智能家居类型
const typeMap: Record<string, string> = {
'SMART_LIGHT': 'light',
'SMART_AC': 'ac',
'SMART_CURTAIN': 'curtain',
'SMART_SENSOR': 'sensor'
};
return typeMap[type] || 'switch';
}
private async _handleSendCommand(args: Record<string, Object>): Promise<boolean> {
try {
const deviceId = args['deviceId'] as string;
const command = args as Record<string, Object>;
// 通过HiLink协议发送控制命令
const success = await this._sendHiLinkCommand(deviceId, command);
// 通知Flutter命令结果
if (success) {
this._notifyStateChange(deviceId, command);
}
return success;
} catch (e) {
console.error('发送命令失败:', e);
return false;
}
}
private async _sendHiLinkCommand(
deviceId: string,
command: Record<string, Object>
): Promise<boolean> {
// HiLink协议实现
return true;
}
private _notifyStateChange(
deviceId: string,
command: Record<string, Object>
): void {
this.flutterChannel?.invokeMethod('onDeviceStateChanged', {
'deviceId': deviceId,
'data': command
});
}
private async _handleStartVoice(args: Record<string, Object>): Promise<string | null> {
// 调用鸿蒙语音识别
// 返回识别的文本
return '打开客厅灯';
}
private _startDeviceDiscovery(): void {
// 持续发现设备
}
destroy(): void {
distributedDevice.stopDeviceDiscovery(1);
this.flutterChannel = null;
}
}
总结
本文系统讲解了基于鸿蒙Flutter开发智能家居应用的完整方案:
- 系统架构:四层分离的智能家居系统设计
- 设备模型:统一抽象的智能设备模型
- 设备管理:发现、控制、批量操作
- 场景引擎:自动化场景编排与触发
- 语音控制:自然语言理解与执行
- UI实现:响应式的智能家居控制界面
通过这套方案,开发者可以快速构建功能完整的智能家居应用,充分利用鸿蒙分布式能力实现全场景智慧生活体验。
相关资源
更多推荐



所有评论(0)