【OpenHarmony】鸿蒙Flutter智能家居应用开发实战指南

【OpenHarmony】鸿蒙Flutter智能家居应用开发实战指南

鸿蒙Flutter智能家居应用开发实战指南

在这里插入图片描述

概述

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

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net

系统架构设计

整体架构图

┌────────────────────────────────────────────────────────────┐ │ 用户交互层 (Flutter) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ 设备控制面板 │ │ 场景编排 │ │ 语音交互 │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ │ └───────────────────────┬────────────────────────────────────┘ │ RPC/事件总线 ┌───────────────────────┴────────────────────────────────────┐ │ 智能家庭业务逻辑层 (Dart) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 设备管理器 │ │ 场景引擎 │ │ 自动化规则 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └───────────────────────┬────────────────────────────────────┘ │ 分布式软总线 ┌───────────────────────┴────────────────────────────────────┐ │ 鸿蒙IoT服务层 (ArkTS) │ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ 设备发现 │ │ 协议适配 │ │ 分布式联动 │ │ │ └──────────────┘ └──────────────┘ └──────────────┘ │ └───────────────────────┬────────────────────────────────────┘ │ HiLink/WiFi/蓝牙 ┌───────────────────────┴────────────────────────────────────┐ │ 智能设备层 │ │ 灯光 · 窗帘 · 空调 · 传感器 · 门锁 · 音响 · ... │ └────────────────────────────────────────────────────────────┘ 

核心组件设计

组件技术方案职责
设备模型抽象基类 + 具体实现统一设备抽象
控制协议统一命令格式跨设备控制
状态同步分布式数据对象实时状态更新
场景引擎规则匹配系统自动化场景
语音交互AI意图识别自然语言控制

设备模型设计

基础设备抽象

/// 设备类型枚举enumSmartDeviceType{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);finalString displayName;finalIconData icon;constSmartDeviceType(this.displayName,this.icon);}/// 设备状态基类abstractclassDeviceState{Map<String,dynamic>toJson();staticDeviceStatefromJson(Map<String,dynamic> json){final type = json['type']asString;switch(type){case'light':returnLightState.fromJson(json);case'curtain':returnCurtainState.fromJson(json);case'ac':returnACState.fromJson(json);case'sensor':returnSensorState.fromJson(json);default:throwArgumentError('Unknown device type: $type');}}}/// 智能设备基类abstractclassSmartDevice{finalString deviceId;finalString deviceName;finalSmartDeviceType type;finalString roomId;final bool isOnline;finalDateTime lastSeen;constSmartDevice({ required this.deviceId, required this.deviceName, required this.type, required this.roomId,this.isOnline =true,DateTime? lastSeen,}): lastSeen = lastSeen ??constDuration();/// 获取当前状态DeviceStateget currentState;/// 执行控制命令Future<bool>executeCommand(DeviceCommand command);/// 订阅状态变化Stream<DeviceState>get stateStream;/// 工厂构造方法staticSmartDevicefromJson(Map<String,dynamic> json){final type =SmartDeviceType.values.firstWhere((e)=> e.name == json['type'], orElse:()=>SmartDeviceType.switch,);switch(type){caseSmartDeviceType.light:returnSmartLight.fromJson(json);caseSmartDeviceType.curtain:returnSmartCurtain.fromJson(json);caseSmartDeviceType.ac:returnSmartAC.fromJson(json);caseSmartDeviceType.sensor:returnSmartSensor.fromJson(json);default:returnSmartSwitch.fromJson(json);}}Map<String,dynamic>toJson();}/// 设备命令基类abstractclassDeviceCommand{finalString deviceId;finalDateTime timestamp;DeviceCommand({required this.deviceId}): timestamp =DateTime.now();Map<String,dynamic>toJson();}/// 设备事件classDeviceEvent{finalString deviceId;finalSmartDeviceType type;finalString eventType;finalMap<String,dynamic> data;finalDateTime timestamp;DeviceEvent({ required this.deviceId, required this.type, required this.eventType, required this.data,}): timestamp =DateTime.now();}

具体设备实现

/// 灯光状态@JsonSerializable()classLightStateextendsDeviceState{final bool isOn;final int brightness;// 0-100final int colorTemp;// 色温 2700-6500Kfinal int? hue;// 色相 0-360final int? saturation;// 饱和度 0-100constLightState({this.isOn =false,this.brightness =100,this.colorTemp =4000,this.hue,this.saturation,});@overrideMap<String,dynamic>toJson()=> _$LightStateToJson(this);factoryLightState.fromJson(Map<String,dynamic> json)=> _$LightStateFromJson(json);LightStatecopyWith({ bool? isOn, int? brightness, int? colorTemp, int? hue, int? saturation,}){returnLightState( isOn: isOn ??this.isOn, brightness: brightness ??this.brightness, colorTemp: colorTemp ??this.colorTemp, hue: hue ??this.hue, saturation: saturation ??this.saturation,);}}/// 灯光控制命令classLightCommandextendsDeviceCommand{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,});@overrideMap<String,dynamic>toJson()=>{'deviceId': deviceId,'command':'light_control','params':{'isOn': isOn,'brightness': brightness,'colorTemp': colorTemp,'hue': hue,'saturation': saturation,},'timestamp': timestamp.toIso8601String(),};}/// 智能灯光设备classSmartLightextendsSmartDevice{LightState _state;SmartLight({ required super.deviceId, required super.deviceName, required super.roomId,LightState? state,super.isOnline,}): _state = state ??constLightState(),super(type:SmartDeviceType.light);@overrideLightStateget currentState => _state;@overrideFuture<bool>executeCommand(DeviceCommand command)async{if(command is!LightCommand)returnfalse;if(!isOnline)returnfalse;try{// 通过鸿蒙分布式能力发送命令final result =awaitHarmonyIotChannel.sendDeviceCommand(command.toJson());if(result){// 更新本地状态 _state = _state.copyWith( isOn: command.isOn, brightness: command.brightness, colorTemp: command.colorTemp, hue: command.hue, saturation: command.saturation,);returntrue;}returnfalse;}catch(e){debugPrint('灯光控制失败: $e');returnfalse;}}@overrideStream<LightState>get stateStream {returnHarmonyIotChannel.deviceStateStream .where((event)=> event.deviceId == deviceId).map((event)=>LightState.fromJson(event.data));}@overrideMap<String,dynamic>toJson()=>{'deviceId': deviceId,'deviceName': deviceName,'type': type.name,'roomId': roomId,'isOnline': isOnline,'lastSeen': lastSeen.toIso8601String(),'state': _state.toJson(),};factorySmartLight.fromJson(Map<String,dynamic> json){returnSmartLight( deviceId: json['deviceId']asString, deviceName: json['deviceName']asString, roomId: json['roomId']asString, state: json['state']!=null?LightState.fromJson(json['state']asMap<String,dynamic>):null, isOnline: json['isOnline']as bool???true,);}}/// 空调状态@JsonSerializable()classACStateextendsDeviceState{final bool isOn;final int temperature;// 16-30finalString mode;// cool, heat, auto, dry, fanfinal int fanSpeed;// 1-3final bool swing;constACState({this.isOn =false,this.temperature =26,this.mode ='cool',this.fanSpeed =2,this.swing =false,});@overrideMap<String,dynamic>toJson()=> _$ACStateToJson(this);factoryACState.fromJson(Map<String,dynamic> json)=> _$ACStateFromJson(json);ACStatecopyWith({ bool? isOn, int? temperature,String? mode, int? fanSpeed, bool? swing,}){returnACState( isOn: isOn ??this.isOn, temperature: temperature ??this.temperature, mode: mode ??this.mode, fanSpeed: fanSpeed ??this.fanSpeed, swing: swing ??this.swing,);}}/// 智能空调设备classSmartACextendsSmartDevice{ACState _state;SmartAC({ required super.deviceId, required super.deviceName, required super.roomId,ACState? state,super.isOnline,}): _state = state ??constACState(),super(type:SmartDeviceType.ac);@overrideACStateget currentState => _state;@overrideFuture<bool>executeCommand(DeviceCommand command)async{if(command is!ACCommand)returnfalse; _state = _state.copyWith( isOn: command.isOn, temperature: command.temperature, mode: command.mode, fanSpeed: command.fanSpeed, swing: command.swing,);returnawaitHarmonyIotChannel.sendDeviceCommand(command.toJson());}@overrideStream<ACState>get stateStream {returnHarmonyIotChannel.deviceStateStream .where((event)=> event.deviceId == deviceId).map((event)=>ACState.fromJson(event.data));}@overrideMap<String,dynamic>toJson()=>{'deviceId': deviceId,'deviceName': deviceName,'type': type.name,'roomId': roomId,'isOnline': isOnline,'state': _state.toJson(),};}/// 空调控制命令classACCommandextendsDeviceCommand{final bool? isOn;final int? temperature;finalString? mode;final int? fanSpeed;final bool? swing;ACCommand({ required super.deviceId,this.isOn,this.temperature,this.mode,this.fanSpeed,this.swing,});@overrideMap<String,dynamic>toJson()=>{'deviceId': deviceId,'command':'ac_control','params':{'isOn': isOn,'temperature': temperature,'mode': mode,'fanSpeed': fanSpeed,'swing': swing,},'timestamp': timestamp.toIso8601String(),};}

设备管理系统

设备管理器实现

/// 智能设备管理器classSmartDeviceManager{staticfinalSmartDeviceManager _instance =SmartDeviceManager._internal();factorySmartDeviceManager()=> _instance;SmartDeviceManager._internal();finalMap<String,SmartDevice> _devices ={};finalMap<String,List<SmartDevice>> _roomDevices ={};finalStreamController<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);});// 发现设备awaitdiscoverDevices();}/// 发现设备Future<void>discoverDevices()async{try{final deviceList =awaitHarmonyIotChannel.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)returnfalse;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,DeviceCommandFunction(String) commandBuilder,)async{final results =<String, bool>{};awaitFuture.wait(deviceIds.map((deviceId)async{final command =commandBuilder(deviceId); results[deviceId]=awaitcontrolDevice(deviceId, command);}));return results;}/// 处理设备状态变化void_handleDeviceStateChange(DeviceEvent event){final device = _devices[event.deviceId];if(device !=null){// 更新设备状态 _eventController.add(event);}}/// 释放资源voiddispose(){ _eventController.close();}}

房间管理

/// 房间模型@JsonSerializable()classSmartRoom{finalString roomId;finalString roomName;finalString icon;finalList<String> deviceIds;final int temperature;final int humidity;final int brightness;constSmartRoom({ 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){returngetDevices(manager).where((d)=> d.isOnline).length;}/// 是否有灯光设备 bool hasLightDevices(SmartDeviceManager manager){returngetDevices(manager).any((d)=> d.type ==SmartDeviceType.light);}SmartRoomcopyWith({String? roomId,String? roomName,String? icon,List<String>? deviceIds, int? temperature, int? humidity, int? brightness,}){returnSmartRoom( 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);factorySmartRoom.fromJson(Map<String,dynamic> json)=> _$SmartRoomFromJson(json);}/// 房间管理器classRoomManager{finalList<SmartRoom> _rooms =[constSmartRoom( roomId:'living_room', roomName:'客厅', icon:'sofa', deviceIds:['light_1','ac_1','curtain_1'],),constSmartRoom( roomId:'bedroom', roomName:'卧室', icon:'bed', deviceIds:['light_2','ac_2','curtain_2'],),constSmartRoom( 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){returnnull;}}voidupdateRoomEnvironment({ 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,);}}}

场景自动化

场景引擎

/// 智能场景@JsonSerializable()classSmartScene{finalString sceneId;finalString sceneName;finalString icon;finalList<SceneAction> actions;finalSceneTrigger? trigger;final bool isEnabled;constSmartScene({ 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);}}SmartScenecopyWith({String? sceneId,String? sceneName,String? icon,List<SceneAction>? actions,SceneTrigger? trigger, bool? isEnabled,}){returnSmartScene( 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);factorySmartScene.fromJson(Map<String,dynamic> json)=> _$SmartSceneFromJson(json);}/// 场景动作abstractclassSceneAction{Future<void>execute(SmartDeviceManager manager);Map<String,dynamic>toJson();staticSceneActionfromJson(Map<String,dynamic> json){final type = json['type']asString;switch(type){case'device_control':returnDeviceControlAction.fromJson(json);case'delay':returnDelayAction.fromJson(json);case'scene':returnSceneCallAction.fromJson(json);default:throwArgumentError('Unknown action type: $type');}}}/// 设备控制动作@JsonSerializable()classDeviceControlActionextendsSceneAction{finalString deviceId;finalMap<String,dynamic> params;constDeviceControlAction({ required this.deviceId, required this.params,});@overrideFuture<void>execute(SmartDeviceManager manager)async{final command =_createCommand();await manager.controlDevice(deviceId, command);}DeviceCommand_createCommand(){final type = params['deviceType']asString?;if(type =='light'){returnLightCommand( deviceId: deviceId, isOn: params['isOn']as bool?, brightness: params['brightness']as int?, colorTemp: params['colorTemp']as int?,);}throwUnimplementedError('Unknown device type');}@overrideMap<String,dynamic>toJson()=> _$DeviceControlActionToJson(this);factoryDeviceControlAction.fromJson(Map<String,dynamic> json)=> _$DeviceControlActionFromJson(json);}/// 延迟动作@JsonSerializable()classDelayActionextendsSceneAction{final int delayMs;constDelayAction({required this.delayMs});@overrideFuture<void>execute(SmartDeviceManager manager)async{awaitFuture.delayed(Duration(milliseconds: delayMs));}@overrideMap<String,dynamic>toJson()=> _$DelayActionToJson(this);factoryDelayAction.fromJson(Map<String,dynamic> json)=> _$DelayActionFromJson(json);}/// 场景触发器@JsonSerializable()classSceneTrigger{finalTriggerType type;finalMap<String,dynamic> conditions;constSceneTrigger({ required this.type, required this.conditions,});/// 检查触发条件 bool check(Map<String,dynamic> eventData){switch(type){caseTriggerType.time:return_checkTimeTrigger();caseTriggerType.device:return_checkDeviceTrigger(eventData);caseTriggerType.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){returntrue;}returnfalse;} bool _checkDeviceTrigger(Map<String,dynamic> eventData){final deviceId = conditions['deviceId']asString?;final expectedState = conditions['state']asMap<String,dynamic>?;if(deviceId ==null|| expectedState ==null)returnfalse;// 检查设备状态匹配returntrue;// 简化实现} bool _checkLocationTrigger(Map<String,dynamic> eventData){// 位置触发检查returnfalse;}Map<String,dynamic>toJson()=> _$SceneTriggerToJson(this);factorySceneTrigger.fromJson(Map<String,dynamic> json)=> _$SceneTriggerFromJson(json);}enumTriggerType{ time, device, location }/// 场景引擎classSceneEngine{finalSmartDeviceManager _deviceManager;finalList<SmartScene> _scenes;finalStreamController<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(constDuration(minutes:1),(_){_checkTimeTriggers();});}/// 执行场景Future<void>executeScene(String sceneId)async{final scene = _scenes.firstWhere((s)=> s.sceneId == sceneId, orElse:()=>throwArgumentError('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);}}}}voiddispose(){ _triggerController.close();}}

语音控制集成

语音意图识别

/// 语音意图类型enumVoiceIntent{ turnOnDevice,// 打开设备 turnOffDevice,// 关闭设备 setBrightness,// 设置亮度 setTemperature,// 设置温度 openCurtain,// 打开窗帘 closeCurtain,// 关闭窗帘 executeScene,// 执行场景 queryStatus,// 查询状态}/// 语音命令解析器classVoiceCommandParser{staticconstMap<String,VoiceIntent> _intentKeywords ={'打开':VoiceIntent.turnOnDevice,'开启':VoiceIntent.turnOnDevice,'关闭':VoiceIntent.turnOffDevice,'亮度':VoiceIntent.setBrightness,'温度':VoiceIntent.setTemperature,'拉开':VoiceIntent.openCurtain,'拉上':VoiceIntent.closeCurtain,'执行':VoiceIntent.executeScene,'运行':VoiceIntent.executeScene,'状态':VoiceIntent.queryStatus,};/// 解析语音命令staticParsedCommand?parse(String text){// 简化的解析逻辑for(final entry in _intentKeywords.entries){if(text.contains(entry.key)){final intent = entry.value;final params =_extractParameters(text, intent);returnParsedCommand( intent: intent, parameters: params, originalText: text,);}}returnnull;}staticMap<String,dynamic>_extractParameters(String text,VoiceIntent intent,){final params =<String,dynamic>{};switch(intent){caseVoiceIntent.turnOnDevice:caseVoiceIntent.turnOffDevice: params['deviceType']=_extractDeviceType(text); params['room']=_extractRoom(text);break;caseVoiceIntent.setBrightness: params['value']=_extractNumber(text);break;caseVoiceIntent.setTemperature: params['value']=_extractNumber(text);break;default:break;}return params;}staticSmartDeviceType?_extractDeviceType(String text){if(text.contains('灯')|| text.contains('照明')){returnSmartDeviceType.light;}elseif(text.contains('空调')){returnSmartDeviceType.ac;}elseif(text.contains('窗帘')){returnSmartDeviceType.curtain;}returnnull;}staticString?_extractRoom(String text){if(text.contains('客厅'))return'living_room';if(text.contains('卧室'))return'bedroom';if(text.contains('厨房'))return'kitchen';returnnull;}static int?_extractNumber(String text){final regex =RegExp(r'\d+');final match = regex.firstMatch(text);return match !=null? int.tryParse(match.group(0)!):null;}}/// 解析后的命令classParsedCommand{finalVoiceIntent intent;finalMap<String,dynamic> parameters;finalString originalText;ParsedCommand({ required this.intent, required this.parameters, required this.originalText,});}/// 语音控制执行器classVoiceController{finalSmartDeviceManager _deviceManager;finalSceneEngine _sceneEngine;VoiceController(this._deviceManager,this._sceneEngine);/// 执行语音命令Future<VoiceResult>execute(String text)async{final command =VoiceCommandParser.parse(text);if(command ==null){returnVoiceResult( success:false, message:'抱歉,我没有理解您的指令',);}try{await_executeCommand(command);returnVoiceResult( success:true, message:_generateSuccessMessage(command),);}catch(e){returnVoiceResult( success:false, message:'执行失败:$e',);}}Future<void>_executeCommand(ParsedCommand command)async{switch(command.intent){caseVoiceIntent.turnOnDevice:await_handleTurnOn(command);break;caseVoiceIntent.turnOffDevice:await_handleTurnOff(command);break;caseVoiceIntent.setBrightness:await_handleSetBrightness(command);break;caseVoiceIntent.executeScene:await_handleExecuteScene(command);break;default:throwUnimplementedError('Intent not implemented');}}Future<void>_handleTurnOn(ParsedCommand command)async{final room = command.parameters['room']asString?;final deviceType = command.parameters['deviceType']asSmartDeviceType?;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']asString?;if(sceneName ==null)return;// 通过场景名称查找并执行// await _sceneEngine.executeScene(sceneId);}String_generateSuccessMessage(ParsedCommand command){switch(command.intent){caseVoiceIntent.turnOnDevice:return'已为您打开设备';caseVoiceIntent.turnOffDevice:return'已为您关闭设备';caseVoiceIntent.setBrightness:return'已调整亮度';default:return'执行成功';}}}/// 语音执行结果classVoiceResult{final bool success;finalString message;VoiceResult({required this.success, required this.message});}

UI实现

主界面

/// 智能家居主页面classSmartHomePageextendsConsumerStatefulWidget{constSmartHomePage({super.key});@overrideConsumerState<SmartHomePage>createState()=>_SmartHomePageState();}class _SmartHomePageState extendsConsumerState<SmartHomePage>{@overrideWidgetbuild(BuildContext context){final roomManager = ref.watch(roomManagerProvider);final deviceManager = ref.watch(deviceManagerProvider);returnScaffold( 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){returnSliverAppBar( expandedHeight:120, floating:false, pinned:true, flexibleSpace:FlexibleSpaceBar( title:constText('智能家居'), background:Container( decoration:BoxDecoration( gradient:LinearGradient( begin:Alignment.topLeft, end:Alignment.bottomRight, colors:[Colors.blue.shade400,Colors.blue.shade700,],),), child:constCenter( 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:constIcon(Icons.settings), onPressed:()=>Navigator.push( context,MaterialPageRoute(builder:(_)=>constSettingsPage()),),),],);}Widget_buildRoomsSection(BuildContext context,RoomManager roomManager,SmartDeviceManager deviceManager,){returnContainer( padding:constEdgeInsets.symmetric(vertical:16), child:Column( crossAxisAlignment:CrossAxisAlignment.start, children:[constPadding( padding:EdgeInsets.symmetric(horizontal:16), child:Text('房间', style:TextStyle(fontSize:20, fontWeight:FontWeight.bold),),),constSizedBox(height:12),SizedBox( height:120, child:ListView.builder( scrollDirection:Axis.horizontal, padding:constEdgeInsets.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;returnContainer( width:160, margin:constEdgeInsets.only(right:12), child:Card( clipBehavior:Clip.antiAlias, child:InkWell( onTap:()=>Navigator.push( context,MaterialPageRoute( builder:(_)=>RoomDetailPage(room: room),),), child:Padding( padding:constEdgeInsets.all(12), child:Column( crossAxisAlignment:CrossAxisAlignment.start, children:[Row( children:[Icon(_getRoomIcon(room.icon), size:24),constSpacer(),Chip( label:Text('$onlineCount/$totalDevices'), visualDensity:VisualDensity.compact,),],),constSpacer(),Text( room.roomName, style:constTextStyle( 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':returnIcons.weekend;case'bed':returnIcons.bed;case'chef':returnIcons.kitchen;default:returnIcons.room;}}Widget_buildDevicesSection(SmartDeviceManager deviceManager){returnSliverPadding( padding:constEdgeInsets.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){returnCard( margin:constEdgeInsets.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 isSmartLight){final state = device.currentState;returnSwitch( value: state.isOn, onChanged:(value){// 控制灯光},);}returnconstIcon(Icons.chevron_right);}Widget_buildScenesSection(BuildContext context){final scenes = ref.watch(sceneProvider);returnContainer( padding:constEdgeInsets.all(16), child:Column( crossAxisAlignment:CrossAxisAlignment.start, children:[constText('场景', style:TextStyle(fontSize:20, fontWeight:FontWeight.bold),),constSizedBox(height:12),Wrap( spacing:12, runSpacing:12, children: scenes.map((scene){return_buildSceneChip(context, scene);}).toList(),),],),);}Widget_buildSceneChip(BuildContext context,SmartScene scene){returnActionChip( avatar:constIcon(Icons.flash_on), label:Text(scene.sceneName), onPressed:()async{await ref.read(sceneProvider.notifier).executeScene(scene.sceneId);},);}Widget_buildVoiceButton(BuildContext context){returnFloatingActionButton.extended( onPressed:()=>_showVoiceDialog(context), icon:constIcon(Icons.mic), label:constText('语音控制'),);}void_showVoiceDialog(BuildContext context){showDialog( context: context, builder:(_)=>constVoiceControlDialog(),);}}

语音控制对话框

/// 语音控制对话框classVoiceControlDialogextendsConsumerStatefulWidget{constVoiceControlDialog({super.key});@overrideConsumerState<VoiceControlDialog>createState()=>_VoiceControlDialogState();}class _VoiceControlDialogState extendsConsumerState<VoiceControlDialog>{ bool _isListening =false;String _recognizedText ='';VoiceResult? _result;@overrideWidgetbuild(BuildContext context){returnAlertDialog( title:constText('语音控制'), content:SizedBox( width:300, child:Column( mainAxisSize:MainAxisSize.min, children:[// 麦克风动画_buildMicrophoneAnimation(),constSizedBox(height:24),// 识别文本if(_recognizedText.isNotEmpty)Text( _recognizedText, textAlign:TextAlign.center, style:constTextStyle(fontSize:16),),constSizedBox(height:16),// 执行结果if(_result !=null)Container( padding:constEdgeInsets.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,),constSizedBox(width:8),Expanded(child:Text(_result!.message)),],),),constSizedBox(height:8),// 提示文本Text('说出指令,如:"打开客厅灯"', style:TextStyle( fontSize:12, color:Colors.grey[600],),),],),), actions:[TextButton( onPressed:()=>Navigator.pop(context), child:constText('关闭'),),],);}Widget_buildMicrophoneAnimation(){returnGestureDetector( onTap: _isListening ?null: _startListening, child:AnimatedContainer( duration:constDuration(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 =awaitHarmonyVoiceChannel.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.etsimport distributedDevice from'@ohos.distributedDevice';import{ MethodChannel }from'@ohos.flutter';exportclassHarmonyIotService{private flutterChannel: MethodChannel |null=null;private deviceCallbacks: Map<string,(data: ESObject)=>void>=newMap();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':returnawaitthis._handleDiscoverDevices();case'sendCommand':returnawaitthis._handleSendCommand(args);case'startVoice':returnawaitthis._handleStartVoice(args);default:returnnull;}});}privateasync_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});}});// 等待设备发现完成awaitnewPromise(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';}privateasync_handleSendCommand(args: Record<string, Object>):Promise<boolean>{try{const deviceId = args['deviceId']asstring;const command = args as Record<string, Object>;// 通过HiLink协议发送控制命令const success =awaitthis._sendHiLinkCommand(deviceId, command);// 通知Flutter命令结果if(success){this._notifyStateChange(deviceId, command);}return success;}catch(e){console.error('发送命令失败:', e);returnfalse;}}privateasync_sendHiLinkCommand( deviceId:string, command: Record<string, Object>):Promise<boolean>{// HiLink协议实现returntrue;}private_notifyStateChange( deviceId:string, command: Record<string, Object>):void{this.flutterChannel?.invokeMethod('onDeviceStateChanged',{'deviceId': deviceId,'data': command });}privateasync_handleStartVoice(args: Record<string, Object>):Promise<string|null>{// 调用鸿蒙语音识别// 返回识别的文本return'打开客厅灯';}private_startDeviceDiscovery():void{// 持续发现设备}destroy():void{ distributedDevice.stopDeviceDiscovery(1);this.flutterChannel =null;}}

总结

本文系统讲解了基于鸿蒙Flutter开发智能家居应用的完整方案:

  1. 系统架构:四层分离的智能家居系统设计
  2. 设备模型:统一抽象的智能设备模型
  3. 设备管理:发现、控制、批量操作
  4. 场景引擎:自动化场景编排与触发
  5. 语音控制:自然语言理解与执行
  6. UI实现:响应式的智能家居控制界面

通过这套方案,开发者可以快速构建功能完整的智能家居应用,充分利用鸿蒙分布式能力实现全场景智慧生活体验。


相关资源

Read more

Flutter 三方库 collection 的鸿蒙化适配指南 - 实现具备高级集合操作与相等性深度判定算法的算法底座、支持端侧多维数据结构的高性能治理实战

Flutter 三方库 collection 的鸿蒙化适配指南 - 实现具备高级集合操作与相等性深度判定算法的算法底座、支持端侧多维数据结构的高性能治理实战

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 三方库 collection 的鸿蒙化适配指南 - 实现具备高级集合操作与相等性深度判定算法的算法底座、支持端侧多维数据结构的高性能治理实战 前言 在进行 Flutter for OpenHarmony 开发时,面对复杂的业务 JSON 转化、深层嵌套的集合对比或需要对列表执行高频的优先级排序(Priority Queue)时,原生 List 和 Map 的功能往往显得捉襟见肘。collection 是 Dart 官方维护的最权威、最核心的集合工具库。本文将探讨如何在鸿蒙端构建极致、稳健的数据处理架构。 一、原直观解析 / 概念介绍 1.1 基础原理 该库扩展了 Dart 标准库中的集合能力。它不仅提供了如 Equality(深度相等判定)、PriorityQueue(

By Ne0inhk
数据结构堆的深度解析:为什么它是高效处理最值问题的利器

数据结构堆的深度解析:为什么它是高效处理最值问题的利器

前言 在非线性数据结构的家族中,堆是兼具 “完全二叉树特性” 与 “最值优先级” 的高效工具 —— 它以数组为物理载体,却暗藏树形逻辑,能在 O (1) 时间获取最值,O (logN) 时间完成插入删除,成为解决排序、Top-K 等经典问题的 “一把好手”。 📚 初阶数据结构 【 时间复杂度+空间复杂度 】 【 顺序表 】 【 单链表 】 【 链表OJ题(上篇)】 【 链表OJ题(下篇)】 【 栈和队列 】 【 栈和队列面试题 】 【 二叉树概念解析 】 目录 一、堆的核心概念与结构特性 1. 堆的定义 2. 核心特性 3. 直观示例 二、堆的实现  1、堆的结构 2、堆的初始化 3、堆的销毁 4、

By Ne0inhk
【数据结构手札】顺序表实战指南(五):查找 | 任意位置增删

【数据结构手札】顺序表实战指南(五):查找 | 任意位置增删

🌈个人主页:聆风吟 🔥系列专栏:数据结构手札 🔖少年有梦不应止于心动,更要付诸行动。 文章目录 * 📚专栏订阅推荐 * 📋前言 - 顺序表文章合集 * 一. ⛳️顺序表:重点回顾 * 1.1 🔔顺序表的定义 * 1.2 🔔顺序表的分类 * 1.2.1 👻静态顺序表 * 1.2.2 👻动态顺序表 * 二. ⛳️顺序表的基本操作实现 * 2.1 🔔查找某个值的下标 * 2.2 🔔在下标为pos位置插入x * 2.3 🔔删除下标为pos位置的数据 * 三. ⛳️顺序表的源代码 * 3.1 🔔SeqList.h 顺序表的函数声明 * 3.2 🔔SeqList.c

By Ne0inhk

傅里叶变换 | FFT 与 DFT 原理及算法

注:本文为 “傅里叶变换 | FFT 与 DFT” 相关合辑。 英文引文,机翻未校。 中文引文,略作重排。 图片清晰度受引文原图所限。 如有内容异常,请看原文。 Fast Fourier Transform (FFT) 快速傅里叶变换(FFT) In this section we present several methods for computing the DFT efficiently. In view of the importance of the DFT in various digital signal processing applications, such as linear filtering,

By Ne0inhk