跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
DartAI大前端

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

综述由AI生成基于鸿蒙 Flutter 框架开发智能家居应用的完整方案。涵盖系统架构设计、设备模型抽象、设备管理系统实现、场景自动化引擎、语音控制集成以及 UI 界面构建。通过统一设备接口、分布式数据同步及规则匹配机制,实现了设备发现、控制、联动及语音交互功能,为开发者提供了一套可复用的全场景智慧生活解决方案。

AiEngineer发布于 2026/4/6更新于 2026/5/2627 浏览
鸿蒙 Flutter 智能家居应用开发实战指南

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

图片描述

概述

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

系统架构设计

整体架构图
┌────────────────────────────────────────────────────────────┐
│ 用户交互层 (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().inMilliseconds == 0 ? DateTime.now() : lastSeen!;

  /// 获取当前状态
  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();
}
具体设备实现
/// 灯光状态
@JsonSerializable()
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,
  });

  @override
  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,
  });

  @override
  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);

  @override
  LightState get currentState => _state;

  @override
  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;
    }
  }

  @override
  Stream<LightState> get stateStream {
    return HarmonyIotChannel.deviceStateStream
        .where((event) => event.deviceId == deviceId)
        .map((event) => LightState.fromJson(event.data));
  }

  @override
  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,
    );
  }
}

/// 空调状态
@JsonSerializable()
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,
  });

  @override
  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);

  @override
  ACState get currentState => _state;

  @override
  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());
  }

  @override
  Stream<ACState> get stateStream {
    return HarmonyIotChannel.deviceStateStream
        .where((event) => event.deviceId == deviceId)
        .map((event) => ACState.fromJson(event.data));
  }

  @override
  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,
  });

  @override
  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();
  }
}
房间管理
/// 房间模型
@JsonSerializable()
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,
      );
    }
  }
}

场景自动化

场景引擎
/// 智能场景
@JsonSerializable()
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');
    }
  }
}

/// 设备控制动作
@JsonSerializable()
class DeviceControlAction extends SceneAction {
  final String deviceId;
  final Map<String, dynamic> params;

  const DeviceControlAction({
    required this.deviceId,
    required this.params,
  });

  @override
  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');
  }

  @override
  Map<String, dynamic> toJson() => _$DeviceControlActionToJson(this);
  factory DeviceControlAction.fromJson(Map<String, dynamic> json) => _$DeviceControlActionFromJson(json);
}

/// 延迟动作
@JsonSerializable()
class DelayAction extends SceneAction {
  final int delayMs;

  const DelayAction({required this.delayMs});

  @override
  Future<void> execute(SmartDeviceManager manager) async {
    await Future.delayed(Duration(milliseconds: delayMs));
  }

  @override
  Map<String, dynamic> toJson() => _$DelayActionToJson(this);
  factory DelayAction.fromJson(Map<String, dynamic> json) => _$DelayActionFromJson(json);
}

/// 场景触发器
@JsonSerializable()
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});

  @override
  ConsumerState<SmartHomePage> createState() => _SmartHomePageState();
}

class _SmartHomePageState extends ConsumerState<SmartHomePage> {
  @override
  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});

  @override
  ConsumerState<VoiceControlDialog> createState() => _VoiceControlDialogState();
}

class _VoiceControlDialogState extends ConsumerState<VoiceControlDialog> {
  bool _isListening = false;
  String _recognizedText = '';
  VoiceResult? _result;

  @override
  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 开发智能家居应用的完整方案:

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

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


相关资源

  • 鸿蒙 IoT 开发指南
  • HiLink 协议规范
  • 智能家居应用开发最佳实践

目录

  1. 鸿蒙 Flutter 智能家居应用开发实战指南
  2. 概述
  3. 系统架构设计
  4. 整体架构图
  5. 核心组件设计
  6. 设备模型设计
  7. 基础设备抽象
  8. 具体设备实现
  9. 设备管理系统
  10. 设备管理器实现
  11. 房间管理
  12. 场景自动化
  13. 场景引擎
  14. 语音控制集成
  15. 语音意图识别
  16. UI 实现
  17. 主界面
  18. 语音控制对话框
  19. 鸿蒙端 IoT 服务
  20. 设备通信实现
  21. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Ubuntu 系统 Docker 完整安装及国内镜像加速配置
  • HelloGitHub 第 119 期:多语言开源项目精选
  • 大模型微调需要多少 Token?基于 Llama-Factory 的计算分析
  • 通义万相 2.1 模型升级与应用拓展实践
  • OpenAI 集成 LangChain 操作实战详解
  • Flutter 三方库 shelf_web_socket 在 OpenHarmony 的适配指南
  • 大模型分布式训练与 LoRA/LISA 微调技术详解
  • Photoshop 集成 ComfyUI AI 绘画功能指南
  • 算法入门:时间复杂度与基础排序算法
  • DFS 算法简介
  • GitHub Pages 零代码搭建免费网站实战指南
  • Bash 脚本中哈希符号(#)的注释用法详解
  • 2024 蓝桥杯省赛 C/C++ 大学 B 组题解与复盘
  • 使用 LLaMA-Factory 进行大语言模型微调的全流程实战
  • 链式二叉树知识补充:层序遍历与创建销毁
  • 智能在线考试系统设计与实现:AI 辅助开发实践
  • Whisper-WebUI 语音转文字工具搭建与功能解析
  • 结构化谱推理:频率自适应多模态推荐方法解读
  • 开源 AI 伴侣:从技术选型到生产环境部署的完整指南
  • 基于 Spring AI 和 Claude 构建企业智能客服系统:从架构到实践

相关免费在线工具

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online