【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

基于深度学习图像分割的无人机洪水灾害图像分割检测与水量估算 洪水分割数据集 图像分割算法

基于深度学习图像分割的无人机洪水灾害图像分割检测与水量估算 洪水分割数据集 图像分割算法

🌊 洪水检测与水量估算🌊 洪水检测与水量估算 🌊 洪水检测与水域估算 该项目专注于利用深度学习技术,从卫星或航空图像中检测受洪水影响的区域,并估算水域覆盖范围。它整合了多种卷积神经网络架构,包括LeNet、ResNet、VGG和U-Net,以执行图像分割和分类任务。该项目专注于利用深度学习技术,从卫星或航空图像中检测受洪水影响的区域,并估算水域覆盖范围。它整合了多种卷积神经网络架构,包括LeNet、ResNet、VGG和U-Net,以执行图像分割和分类任务。该项目专注于利用深度学习技术,从卫星或航空图像中检测受洪水影响的区域,并估算水域覆盖范围。它整合了多种卷积神经网络架构,包括LeNet、ResNet、VGG和U-Net,以执行图像分割和分类任务。 🔍 主要特点🔍 主要特点 🔍 主要特点 * 使用U-Net进行图像分割,以识别水体和洪水淹没区域。使用U-Net进行图像分割,以识别水体和洪水淹没区域。使用U-Net进行图像分割,以识别水体和洪水淹没区域。 * LeNet、ResNet和VGG模型的比较,以评估洪水检测的性能。LeNet、ResNet和VGG模型的

By Ne0inhk
Spatial Joy 2025 全球 AR&AI 赛事:开发者要的资源、玩法、避坑攻略都在这

Spatial Joy 2025 全球 AR&AI 赛事:开发者要的资源、玩法、避坑攻略都在这

Spatial Joy 2025 全球 AR&AI 赛事:开发者要的资源、玩法、避坑攻略都在这 * 引言: * 正文: * 一、赛事核心价值:资源、履历、落地全具备 * 1.1 硬核资源支持 * 1.2 行业背书与机遇 * 1.3 低门槛试错 * 二、赛道核心玩法:AI 和 AR 创作方向解析 * 2.1 AI 赛道:拼的是 "空间认知协作" 能力 * 2.1.1 应用示例 * 2.2 AR 赛道:

By Ne0inhk

OpenClaw对接飞书机器人高频踩坑实战指南:从插件安装到回调配对全解析

前言 当前企业办公场景中,将轻量级AI框架OpenClaw与飞书机器人结合,能够快速实现智能交互、流程自动化等功能。然而,在实际对接过程中,开发者常常因权限配置、环境依赖、回调设置等细节问题陷入反复试错。本文以“问题解决”为核心,梳理了10个典型踩坑点,每个问题均配套原因分析、排查步骤和实操案例。同时,补充高效调试技巧与功能扩展建议,帮助开发者系统性地定位并解决对接障碍,提升落地效率。所有案例基于Windows 11环境、OpenClaw最新稳定版及飞书开放平台最新界面验证,解决方案可直接复用。 一、前置准备(快速自查) 为避免基础环境问题浪费时间,建议在开始前确认以下三点: * OpenClaw已正确安装,终端执行 openclaw -v 可查看版本(建议使用最新版,旧版本可能存在插件兼容风险)。 * Node.js版本不低于v14,npm版本不低于v6,通过 node -v 和 npm -v 验证,防止因依赖版本过低导致插件安装失败。 * 飞书账号需具备企业开发者权限(企业账号需管理员授权,个人账号默认具备)

By Ne0inhk
【CS创世SD NAND征文】为无人机打造可靠数据仓:工业级存储芯片CSNP32GCR01-AOW在飞控系统中的应用实践

【CS创世SD NAND征文】为无人机打造可靠数据仓:工业级存储芯片CSNP32GCR01-AOW在飞控系统中的应用实践

一、引言:无人机时代的数据存储挑战 在无人机(UAV)技术飞速发展的今天,其应用范畴早已突破消费级航拍的界限,深度渗透至测绘勘察、基础设施巡检、精准农业、安防监控乃至国防军事等工业级领域。每一次精准的自动巡航、每一帧高清图像的实时图传、每一条飞行轨迹的忠实记录,都离不开飞控系统这颗"大脑"的精密运算。然而,大脑的决策依赖于记忆与学习,而承担这一"记忆"任务的存储单元,其可靠性直接决定了飞行任务的成败与数据的价值。一次意外的数据丢失或存储故障,不仅可能导致珍贵的测绘数据付诸东流,造成重大的经济损失,甚至可能引发严重的飞行安全事故。因此,为无人机飞控系统选择一款高性能、高可靠的存储芯片,已成为行业设计中不可或缺的关键一环。 本文将围绕基于全志MR100主控平台与CS创世SD NAND(具体型号:CSNP32GCR01-AOW)构建的新一代无人机飞控存储方案,深入探讨工业级存储芯片如何为高端无人机赋予稳定、可靠的"数据生命线",助力无人机技术在各个领域发挥更大的价值。 二、应用产品介绍:无人机飞控系统——空中机器人的智能核心

By Ne0inhk