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

在这里插入图片描述

概述

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

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

系统架构设计

整体架构图

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

核心组件设计

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

设备模型设计

基础设备抽象

/// 设备类型枚举
enum SmartDeviceType {
  light('智能灯光', Icons.lightbulb),
  curtain('智能窗帘', Icons.curtains),
  ac('空调', Icons.ac_unit),
  sensor('传感器', Icons.sensors),
  lock('门锁', Icons.lock),
  speaker('智能音箱', Icons.speaker),
  camera('摄像头', Icons.videocam),
  switch('智能开关', Icons.toggle_on),
  thermostat('温控器', Icons.thermostat),
  purifier('净化器', Icons.air);

  final String displayName;
  final IconData icon;
  const SmartDeviceType(this.displayName, this.icon);
}

/// 设备状态基类
abstract class DeviceState {
  Map<String, dynamic> toJson();
  static DeviceState fromJson(Map<String, dynamic> json) {
    final type = json['type'] as String;
    switch (type) {
      case 'light':
        return LightState.fromJson(json);
      case 'curtain':
        return CurtainState.fromJson(json);
      case 'ac':
        return ACState.fromJson(json);
      case 'sensor':
        return SensorState.fromJson(json);
      default:
        throw ArgumentError('Unknown device type: $type');
    }
  }
}

/// 智能设备基类
abstract class SmartDevice {
  final String deviceId;
  final String deviceName;
  final SmartDeviceType type;
  final String roomId;
  final bool isOnline;
  final DateTime lastSeen;

  const SmartDevice({
    required this.deviceId,
    required this.deviceName,
    required this.type,
    required this.roomId,
    this.isOnline = true,
    DateTime? lastSeen,
  }) : lastSeen = lastSeen ?? const Duration();

  /// 获取当前状态
  DeviceState get currentState;

  /// 执行控制命令
  Future<bool> executeCommand(DeviceCommand command);

  /// 订阅状态变化
  Stream<DeviceState> get stateStream;

  /// 工厂构造方法
  static SmartDevice fromJson(Map<String, dynamic> json) {
    final type = SmartDeviceType.values.firstWhere(
      (e) => e.name == json['type'],
      orElse: () => SmartDeviceType.switch,
    );

    switch (type) {
      case SmartDeviceType.light:
        return SmartLight.fromJson(json);
      case SmartDeviceType.curtain:
        return SmartCurtain.fromJson(json);
      case SmartDeviceType.ac:
        return SmartAC.fromJson(json);
      case SmartDeviceType.sensor:
        return SmartSensor.fromJson(json);
      default:
        return SmartSwitch.fromJson(json);
    }
  }

  Map<String, dynamic> toJson();
}

/// 设备命令基类
abstract class DeviceCommand {
  final String deviceId;
  final DateTime timestamp;

  DeviceCommand({required this.deviceId})
      : timestamp = DateTime.now();

  Map<String, dynamic> toJson();
}

/// 设备事件
class DeviceEvent {
  final String deviceId;
  final SmartDeviceType type;
  final String eventType;
  final Map<String, dynamic> data;
  final DateTime timestamp;

  DeviceEvent({
    required this.deviceId,
    required this.type,
    required this.eventType,
    required this.data,
  }) : timestamp = DateTime.now();
}

具体设备实现

/// 灯光状态
()
class LightState extends DeviceState {
  final bool isOn;
  final int brightness; // 0-100
  final int colorTemp; // 色温 2700-6500K
  final int? hue; // 色相 0-360
  final int? saturation; // 饱和度 0-100

  const LightState({
    this.isOn = false,
    this.brightness = 100,
    this.colorTemp = 4000,
    this.hue,
    this.saturation,
  });

  
  Map<String, dynamic> toJson() => _$LightStateToJson(this);

  factory LightState.fromJson(Map<String, dynamic> json) =>
      _$LightStateFromJson(json);

  LightState copyWith({
    bool? isOn,
    int? brightness,
    int? colorTemp,
    int? hue,
    int? saturation,
  }) {
    return LightState(
      isOn: isOn ?? this.isOn,
      brightness: brightness ?? this.brightness,
      colorTemp: colorTemp ?? this.colorTemp,
      hue: hue ?? this.hue,
      saturation: saturation ?? this.saturation,
    );
  }
}

/// 灯光控制命令
class LightCommand extends DeviceCommand {
  final bool? isOn;
  final int? brightness;
  final int? colorTemp;
  final int? hue;
  final int? saturation;

  LightCommand({
    required super.deviceId,
    this.isOn,
    this.brightness,
    this.colorTemp,
    this.hue,
    this.saturation,
  });

  
  Map<String, dynamic> toJson() => {
        'deviceId': deviceId,
        'command': 'light_control',
        'params': {
          'isOn': isOn,
          'brightness': brightness,
          'colorTemp': colorTemp,
          'hue': hue,
          'saturation': saturation,
        },
        'timestamp': timestamp.toIso8601String(),
      };
}

/// 智能灯光设备
class SmartLight extends SmartDevice {
  LightState _state;

  SmartLight({
    required super.deviceId,
    required super.deviceName,
    required super.roomId,
    LightState? state,
    super.isOnline,
  })  : _state = state ?? const LightState(),
        super(type: SmartDeviceType.light);

  
  LightState get currentState => _state;

  
  Future<bool> executeCommand(DeviceCommand command) async {
    if (command is! LightCommand) return false;
    if (!isOnline) return false;

    try {
      // 通过鸿蒙分布式能力发送命令
      final result = await HarmonyIotChannel.sendDeviceCommand(command.toJson());

      if (result) {
        // 更新本地状态
        _state = _state.copyWith(
          isOn: command.isOn,
          brightness: command.brightness,
          colorTemp: command.colorTemp,
          hue: command.hue,
          saturation: command.saturation,
        );
        return true;
      }

      return false;
    } catch (e) {
      debugPrint('灯光控制失败: $e');
      return false;
    }
  }

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

  
  Map<String, dynamic> toJson() => {
        'deviceId': deviceId,
        'deviceName': deviceName,
        'type': type.name,
        'roomId': roomId,
        'isOnline': isOnline,
        'lastSeen': lastSeen.toIso8601String(),
        'state': _state.toJson(),
      };

  factory SmartLight.fromJson(Map<String, dynamic> json) {
    return SmartLight(
      deviceId: json['deviceId'] as String,
      deviceName: json['deviceName'] as String,
      roomId: json['roomId'] as String,
      state: json['state'] != null
          ? LightState.fromJson(json['state'] as Map<String, dynamic>)
          : null,
      isOnline: json['isOnline'] as bool? ?? true,
    );
  }
}

/// 空调状态
()
class ACState extends DeviceState {
  final bool isOn;
  final int temperature; // 16-30
  final String mode; // cool, heat, auto, dry, fan
  final int fanSpeed; // 1-3
  final bool swing;

  const ACState({
    this.isOn = false,
    this.temperature = 26,
    this.mode = 'cool',
    this.fanSpeed = 2,
    this.swing = false,
  });

  
  Map<String, dynamic> toJson() => _$ACStateToJson(this);

  factory ACState.fromJson(Map<String, dynamic> json) =>
      _$ACStateFromJson(json);

  ACState copyWith({
    bool? isOn,
    int? temperature,
    String? mode,
    int? fanSpeed,
    bool? swing,
  }) {
    return ACState(
      isOn: isOn ?? this.isOn,
      temperature: temperature ?? this.temperature,
      mode: mode ?? this.mode,
      fanSpeed: fanSpeed ?? this.fanSpeed,
      swing: swing ?? this.swing,
    );
  }
}

/// 智能空调设备
class SmartAC extends SmartDevice {
  ACState _state;

  SmartAC({
    required super.deviceId,
    required super.deviceName,
    required super.roomId,
    ACState? state,
    super.isOnline,
  })  : _state = state ?? const ACState(),
        super(type: SmartDeviceType.ac);

  
  ACState get currentState => _state;

  
  Future<bool> executeCommand(DeviceCommand command) async {
    if (command is! ACCommand) return false;

    _state = _state.copyWith(
      isOn: command.isOn,
      temperature: command.temperature,
      mode: command.mode,
      fanSpeed: command.fanSpeed,
      swing: command.swing,
    );

    return await HarmonyIotChannel.sendDeviceCommand(command.toJson());
  }

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

  
  Map<String, dynamic> toJson() => {
        'deviceId': deviceId,
        'deviceName': deviceName,
        'type': type.name,
        'roomId': roomId,
        'isOnline': isOnline,
        'state': _state.toJson(),
  };
}

/// 空调控制命令
class ACCommand extends DeviceCommand {
  final bool? isOn;
  final int? temperature;
  final String? mode;
  final int? fanSpeed;
  final bool? swing;

  ACCommand({
    required super.deviceId,
    this.isOn,
    this.temperature,
    this.mode,
    this.fanSpeed,
    this.swing,
  });

  
  Map<String, dynamic> toJson() => {
        'deviceId': deviceId,
        'command': 'ac_control',
        'params': {
          'isOn': isOn,
          'temperature': temperature,
          'mode': mode,
          'fanSpeed': fanSpeed,
          'swing': swing,
        },
        'timestamp': timestamp.toIso8601String(),
      };
}

设备管理系统

设备管理器实现

/// 智能设备管理器
class SmartDeviceManager {
  static final SmartDeviceManager _instance =
      SmartDeviceManager._internal();
  factory SmartDeviceManager() => _instance;
  SmartDeviceManager._internal();

  final Map<String, SmartDevice> _devices = {};
  final Map<String, List<SmartDevice>> _roomDevices = {};
  final StreamController<DeviceEvent> _eventController =
      StreamController.broadcast();

  /// 设备列表
  List<SmartDevice> get devices => _devices.values.toList();

  /// 设备事件流
  Stream<DeviceEvent> get eventStream => _eventController.stream;

  /// 初始化
  Future<void> initialize() async {
    // 订阅鸿蒙设备状态变化
    HarmonyIotChannel.deviceStateStream.listen((event) {
      _handleDeviceStateChange(event);
    });

    // 发现设备
    await discoverDevices();
  }

  /// 发现设备
  Future<void> discoverDevices() async {
    try {
      final deviceList = await HarmonyIotChannel.discoverDevices();

      for (final deviceJson in deviceList) {
        final device = SmartDevice.fromJson(deviceJson);
        _addDevice(device);
      }

      debugPrint('发现 ${deviceList.length} 个智能设备');
    } catch (e) {
      debugPrint('设备发现失败: $e');
    }
  }

  /// 添加设备
  void _addDevice(SmartDevice device) {
    _devices[device.deviceId] = device;

    // 按房间分组
    _roomDevices.putIfAbsent(device.roomId, () => []);
    _roomDevices[device.roomId]!.add(device);

    // 订阅设备状态变化
    device.stateStream.listen((state) {
      _eventController.add(DeviceEvent(
        deviceId: device.deviceId,
        type: device.type,
        eventType: 'state_change',
        data: state.toJson(),
      ));
    });
  }

  /// 获取设备
  SmartDevice? getDevice(String deviceId) {
    return _devices[deviceId];
  }

  /// 获取房间设备
  List<SmartDevice> getRoomDevices(String roomId) {
    return _roomDevices[roomId] ?? [];
  }

  /// 按类型获取设备
  List<SmartDevice> getDevicesByType(SmartDeviceType type) {
    return _devices.values.where((d) => d.type == type).toList();
  }

  /// 控制设备
  Future<bool> controlDevice(
    String deviceId,
    DeviceCommand command,
  ) async {
    final device = _devices[deviceId];
    if (device == null) return false;

    final success = await device.executeCommand(command);

    if (success) {
      _eventController.add(DeviceEvent(
        deviceId: deviceId,
        type: device.type,
        eventType: 'command_executed',
        data: command.toJson(),
      ));
    }

    return success;
  }

  /// 批量控制
  Future<Map<String, bool>> batchControl(
    List<String> deviceIds,
    DeviceCommand Function(String) commandBuilder,
  ) async {
    final results = <String, bool>{};

    await Future.wait(deviceIds.map((deviceId) async {
      final command = commandBuilder(deviceId);
      results[deviceId] = await controlDevice(deviceId, command);
    }));

    return results;
  }

  /// 处理设备状态变化
  void _handleDeviceStateChange(DeviceEvent event) {
    final device = _devices[event.deviceId];
    if (device != null) {
      // 更新设备状态
      _eventController.add(event);
    }
  }

  /// 释放资源
  void dispose() {
    _eventController.close();
  }
}

房间管理

/// 房间模型
()
class SmartRoom {
  final String roomId;
  final String roomName;
  final String icon;
  final List<String> deviceIds;
  final int temperature;
  final int humidity;
  final int brightness;

  const SmartRoom({
    required this.roomId,
    required this.roomName,
    this.icon = 'room',
    this.deviceIds = const [],
    this.temperature = 25,
    this.humidity = 60,
    this.brightness = 0,
  });

  /// 获取房间设备
  List<SmartDevice> getDevices(SmartDeviceManager manager) {
    return deviceIds
        .map((id) => manager.getDevice(id))
        .whereType<SmartDevice>()
        .toList();
  }

  /// 获取在线设备数量
  int getOnlineDeviceCount(SmartDeviceManager manager) {
    return getDevices(manager).where((d) => d.isOnline).length;
  }

  /// 是否有灯光设备
  bool hasLightDevices(SmartDeviceManager manager) {
    return getDevices(manager).any((d) => d.type == SmartDeviceType.light);
  }

  SmartRoom copyWith({
    String? roomId,
    String? roomName,
    String? icon,
    List<String>? deviceIds,
    int? temperature,
    int? humidity,
    int? brightness,
  }) {
    return SmartRoom(
      roomId: roomId ?? this.roomId,
      roomName: roomName ?? this.roomName,
      icon: icon ?? this.icon,
      deviceIds: deviceIds ?? this.deviceIds,
      temperature: temperature ?? this.temperature,
      humidity: humidity ?? this.humidity,
      brightness: brightness ?? this.brightness,
    );
  }

  Map<String, dynamic> toJson() => _$SmartRoomToJson(this);

  factory SmartRoom.fromJson(Map<String, dynamic> json) =>
      _$SmartRoomFromJson(json);
}

/// 房间管理器
class RoomManager {
  final List<SmartRoom> _rooms = [
    const SmartRoom(
      roomId: 'living_room',
      roomName: '客厅',
      icon: 'sofa',
      deviceIds: ['light_1', 'ac_1', 'curtain_1'],
    ),
    const SmartRoom(
      roomId: 'bedroom',
      roomName: '卧室',
      icon: 'bed',
      deviceIds: ['light_2', 'ac_2', 'curtain_2'],
    ),
    const SmartRoom(
      roomId: 'kitchen',
      roomName: '厨房',
      icon: 'chef',
      deviceIds: ['light_3', 'sensor_1'],
    ),
  ];

  List<SmartRoom> get rooms => List.unmodifiable(_rooms);

  SmartRoom? getRoom(String roomId) {
    try {
      return _rooms.firstWhere((r) => r.roomId == roomId);
    } catch (e) {
      return null;
    }
  }

  void updateRoomEnvironment({
    required String roomId,
    int? temperature,
    int? humidity,
    int? brightness,
  }) {
    final index = _rooms.indexWhere((r) => r.roomId == roomId);
    if (index >= 0) {
      _rooms[index] = _rooms[index].copyWith(
        temperature: temperature,
        humidity: humidity,
        brightness: brightness,
      );
    }
  }
}

场景自动化

场景引擎

/// 智能场景
()
class SmartScene {
  final String sceneId;
  final String sceneName;
  final String icon;
  final List<SceneAction> actions;
  final SceneTrigger? trigger;
  final bool isEnabled;

  const SmartScene({
    required this.sceneId,
    required this.sceneName,
    this.icon = 'scene',
    this.actions = const [],
    this.trigger,
    this.isEnabled = true,
  });

  /// 执行场景
  Future<void> execute(SmartDeviceManager manager) async {
    if (!isEnabled) return;

    for (final action in actions) {
      await action.execute(manager);
    }
  }

  SmartScene copyWith({
    String? sceneId,
    String? sceneName,
    String? icon,
    List<SceneAction>? actions,
    SceneTrigger? trigger,
    bool? isEnabled,
  }) {
    return SmartScene(
      sceneId: sceneId ?? this.sceneId,
      sceneName: sceneName ?? this.sceneName,
      icon: icon ?? this.icon,
      actions: actions ?? this.actions,
      trigger: trigger ?? this.trigger,
      isEnabled: isEnabled ?? this.isEnabled,
    );
  }

  Map<String, dynamic> toJson() => _$SmartSceneToJson(this);

  factory SmartScene.fromJson(Map<String, dynamic> json) =>
      _$SmartSceneFromJson(json);
}

/// 场景动作
abstract class SceneAction {
  Future<void> execute(SmartDeviceManager manager);
  Map<String, dynamic> toJson();
  static SceneAction fromJson(Map<String, dynamic> json) {
    final type = json['type'] as String;
    switch (type) {
      case 'device_control':
        return DeviceControlAction.fromJson(json);
      case 'delay':
        return DelayAction.fromJson(json);
      case 'scene':
        return SceneCallAction.fromJson(json);
      default:
        throw ArgumentError('Unknown action type: $type');
    }
  }
}

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

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

  
  Future<void> execute(SmartDeviceManager manager) async {
    final command = _createCommand();
    await manager.controlDevice(deviceId, command);
  }

  DeviceCommand _createCommand() {
    final type = params['deviceType'] as String?;
    if (type == 'light') {
      return LightCommand(
        deviceId: deviceId,
        isOn: params['isOn'] as bool?,
        brightness: params['brightness'] as int?,
        colorTemp: params['colorTemp'] as int?,
      );
    }
    throw UnimplementedError('Unknown device type');
  }

  
  Map<String, dynamic> toJson() => _$DeviceControlActionToJson(this);

  factory DeviceControlAction.fromJson(Map<String, dynamic> json) =>
      _$DeviceControlActionFromJson(json);
}

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

  const DelayAction({required this.delayMs});

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

  
  Map<String, dynamic> toJson() => _$DelayActionToJson(this);

  factory DelayAction.fromJson(Map<String, dynamic> json) =>
      _$DelayActionFromJson(json);
}

/// 场景触发器
()
class SceneTrigger {
  final TriggerType type;
  final Map<String, dynamic> conditions;

  const SceneTrigger({
    required this.type,
    required this.conditions,
  });

  /// 检查触发条件
  bool check(Map<String, dynamic> eventData) {
    switch (type) {
      case TriggerType.time:
        return _checkTimeTrigger();
      case TriggerType.device:
        return _checkDeviceTrigger(eventData);
      case TriggerType.location:
        return _checkLocationTrigger(eventData);
    }
  }

  bool _checkTimeTrigger() {
    final now = DateTime.now();
    final hour = conditions['hour'] as int? ?? -1;
    final minute = conditions['minute'] as int? ?? 0;

    if (hour >= 0 && now.hour == hour && now.minute == minute) {
      return true;
    }

    return false;
  }

  bool _checkDeviceTrigger(Map<String, dynamic> eventData) {
    final deviceId = conditions['deviceId'] as String?;
    final expectedState = conditions['state'] as Map<String, dynamic>?;

    if (deviceId == null || expectedState == null) return false;

    // 检查设备状态匹配
    return true; // 简化实现
  }

  bool _checkLocationTrigger(Map<String, dynamic> eventData) {
    // 位置触发检查
    return false;
  }

  Map<String, dynamic> toJson() => _$SceneTriggerToJson(this);

  factory SceneTrigger.fromJson(Map<String, dynamic> json) =>
      _$SceneTriggerFromJson(json);
}

enum TriggerType { time, device, location }

/// 场景引擎
class SceneEngine {
  final SmartDeviceManager _deviceManager;
  final List<SmartScene> _scenes;
  final StreamController<SmartScene> _triggerController =
      StreamController.broadcast();

  Stream<SmartScene> get triggerStream => _triggerController.stream;

  SceneEngine(this._deviceManager, this._scenes) {
    _initialize();
  }

  void _initialize() {
    // 订阅设备事件
    _deviceManager.eventStream.listen((event) {
      _checkSceneTriggers(event);
    });

    // 启动定时检查
    Timer.periodic(const Duration(minutes: 1), (_) {
      _checkTimeTriggers();
    });
  }

  /// 执行场景
  Future<void> executeScene(String sceneId) async {
    final scene = _scenes.firstWhere(
      (s) => s.sceneId == sceneId,
      orElse: () => throw ArgumentError('Scene not found: $sceneId'),
    );

    await scene.execute(_deviceManager);
    _triggerController.add(scene);
  }

  /// 检查场景触发
  void _checkSceneTriggers(DeviceEvent event) {
    for (final scene in _scenes) {
      if (scene.trigger?.check(event.toJson()) ?? false) {
        executeScene(scene.sceneId);
      }
    }
  }

  /// 检查时间触发
  void _checkTimeTriggers() {
    for (final scene in _scenes) {
      if (scene.trigger?.type == TriggerType.time) {
        if (scene.trigger?.check({}) ?? false) {
          executeScene(scene.sceneId);
        }
      }
    }
  }

  void dispose() {
    _triggerController.close();
  }
}

语音控制集成

语音意图识别

/// 语音意图类型
enum VoiceIntent {
  turnOnDevice, // 打开设备
  turnOffDevice, // 关闭设备
  setBrightness, // 设置亮度
  setTemperature, // 设置温度
  openCurtain, // 打开窗帘
  closeCurtain, // 关闭窗帘
  executeScene, // 执行场景
  queryStatus, // 查询状态
}

/// 语音命令解析器
class VoiceCommandParser {
  static const Map<String, VoiceIntent> _intentKeywords = {
    '打开': VoiceIntent.turnOnDevice,
    '开启': VoiceIntent.turnOnDevice,
    '关闭': VoiceIntent.turnOffDevice,
    '亮度': VoiceIntent.setBrightness,
    '温度': VoiceIntent.setTemperature,
    '拉开': VoiceIntent.openCurtain,
    '拉上': VoiceIntent.closeCurtain,
    '执行': VoiceIntent.executeScene,
    '运行': VoiceIntent.executeScene,
    '状态': VoiceIntent.queryStatus,
  };

  /// 解析语音命令
  static ParsedCommand? parse(String text) {
    // 简化的解析逻辑
    for (final entry in _intentKeywords.entries) {
      if (text.contains(entry.key)) {
        final intent = entry.value;
        final params = _extractParameters(text, intent);

        return ParsedCommand(
          intent: intent,
          parameters: params,
          originalText: text,
        );
      }
    }

    return null;
  }

  static Map<String, dynamic> _extractParameters(
    String text,
    VoiceIntent intent,
  ) {
    final params = <String, dynamic>{};

    switch (intent) {
      case VoiceIntent.turnOnDevice:
      case VoiceIntent.turnOffDevice:
        params['deviceType'] = _extractDeviceType(text);
        params['room'] = _extractRoom(text);
        break;

      case VoiceIntent.setBrightness:
        params['value'] = _extractNumber(text);
        break;

      case VoiceIntent.setTemperature:
        params['value'] = _extractNumber(text);
        break;

      default:
        break;
    }

    return params;
  }

  static SmartDeviceType? _extractDeviceType(String text) {
    if (text.contains('灯') || text.contains('照明')) {
      return SmartDeviceType.light;
    } else if (text.contains('空调')) {
      return SmartDeviceType.ac;
    } else if (text.contains('窗帘')) {
      return SmartDeviceType.curtain;
    }
    return null;
  }

  static String? _extractRoom(String text) {
    if (text.contains('客厅')) return 'living_room';
    if (text.contains('卧室')) return 'bedroom';
    if (text.contains('厨房')) return 'kitchen';
    return null;
  }

  static int? _extractNumber(String text) {
    final regex = RegExp(r'\d+');
    final match = regex.firstMatch(text);
    return match != null ? int.tryParse(match.group(0)!) : null;
  }
}

/// 解析后的命令
class ParsedCommand {
  final VoiceIntent intent;
  final Map<String, dynamic> parameters;
  final String originalText;

  ParsedCommand({
    required this.intent,
    required this.parameters,
    required this.originalText,
  });
}

/// 语音控制执行器
class VoiceController {
  final SmartDeviceManager _deviceManager;
  final SceneEngine _sceneEngine;

  VoiceController(this._deviceManager, this._sceneEngine);

  /// 执行语音命令
  Future<VoiceResult> execute(String text) async {
    final command = VoiceCommandParser.parse(text);

    if (command == null) {
      return VoiceResult(
        success: false,
        message: '抱歉,我没有理解您的指令',
      );
    }

    try {
      await _executeCommand(command);
      return VoiceResult(
        success: true,
        message: _generateSuccessMessage(command),
      );
    } catch (e) {
      return VoiceResult(
        success: false,
        message: '执行失败:$e',
      );
    }
  }

  Future<void> _executeCommand(ParsedCommand command) async {
    switch (command.intent) {
      case VoiceIntent.turnOnDevice:
        await _handleTurnOn(command);
        break;
      case VoiceIntent.turnOffDevice:
        await _handleTurnOff(command);
        break;
      case VoiceIntent.setBrightness:
        await _handleSetBrightness(command);
        break;
      case VoiceIntent.executeScene:
        await _handleExecuteScene(command);
        break;
      default:
        throw UnimplementedError('Intent not implemented');
    }
  }

  Future<void> _handleTurnOn(ParsedCommand command) async {
    final room = command.parameters['room'] as String?;
    final deviceType = command.parameters['deviceType'] as SmartDeviceType?;

    final devices = _deviceManager.getDevicesByType(deviceType!);
    final targetDevices = room == null
        ? devices
        : devices.where((d) => d.roomId == room).toList();

    for (final device in targetDevices) {
      await _deviceManager.controlDevice(
        device.deviceId,
        LightCommand(deviceId: device.deviceId, isOn: true),
      );
    }
  }

  Future<void> _handleSetBrightness(ParsedCommand command) async {
    final value = command.parameters['value'] as int?;
    if (value == null) return;

    final lights = _deviceManager.getDevicesByType(SmartDeviceType.light);
    for (final light in lights) {
      await _deviceManager.controlDevice(
        light.deviceId,
        LightCommand(deviceId: light.deviceId, brightness: value),
      );
    }
  }

  Future<void> _handleExecuteScene(ParsedCommand command) async {
    final sceneName = command.parameters['sceneName'] as String?;
    if (sceneName == null) return;

    // 通过场景名称查找并执行
    // await _sceneEngine.executeScene(sceneId);
  }

  String _generateSuccessMessage(ParsedCommand command) {
    switch (command.intent) {
      case VoiceIntent.turnOnDevice:
        return '已为您打开设备';
      case VoiceIntent.turnOffDevice:
        return '已为您关闭设备';
      case VoiceIntent.setBrightness:
        return '已调整亮度';
      default:
        return '执行成功';
    }
  }
}

/// 语音执行结果
class VoiceResult {
  final bool success;
  final String message;

  VoiceResult({required this.success, required this.message});
}

UI实现

主界面

/// 智能家居主页面
class SmartHomePage extends ConsumerStatefulWidget {
  const SmartHomePage({super.key});

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

class _SmartHomePageState extends ConsumerState<SmartHomePage> {
  
  Widget build(BuildContext context) {
    final roomManager = ref.watch(roomManagerProvider);
    final deviceManager = ref.watch(deviceManagerProvider);

    return Scaffold(
      body: CustomScrollView(
        slivers: [
          // 顶部AppBar
          _buildAppBar(context),

          // 房间卡片
          SliverToBoxAdapter(
            child: _buildRoomsSection(context, roomManager, deviceManager),
          ),

          // 设备列表
          _buildDevicesSection(deviceManager),

          // 场景快捷方式
          SliverToBoxAdapter(
            child: _buildScenesSection(context),
          ),
        ],
      ),

      // 语音按钮
      floatingActionButton: _buildVoiceButton(context),
    );
  }

  Widget _buildAppBar(BuildContext context) {
    return SliverAppBar(
      expandedHeight: 120,
      floating: false,
      pinned: true,
      flexibleSpace: FlexibleSpaceBar(
        title: const Text('智能家居'),
        background: Container(
          decoration: BoxDecoration(
            gradient: LinearGradient(
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
              colors: [
                Colors.blue.shade400,
                Colors.blue.shade700,
              ],
            ),
          ),
          child: const Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Icon(Icons.home, size: 48, color: Colors.white70),
                SizedBox(height: 8),
                Text(
                  '欢迎回家',
                  style: TextStyle(color: Colors.white70),
                ),
              ],
            ),
          ),
        ),
      ),
      actions: [
        IconButton(
          icon: const Icon(Icons.settings),
          onPressed: () => Navigator.push(
            context,
            MaterialPageRoute(builder: (_) => const SettingsPage()),
          ),
        ),
      ],
    );
  }

  Widget _buildRoomsSection(
    BuildContext context,
    RoomManager roomManager,
    SmartDeviceManager deviceManager,
  ) {
    return Container(
      padding: const EdgeInsets.symmetric(vertical: 16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Padding(
            padding: EdgeInsets.symmetric(horizontal: 16),
            child: Text(
              '房间',
              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            ),
          ),
          const SizedBox(height: 12),
          SizedBox(
            height: 120,
            child: ListView.builder(
              scrollDirection: Axis.horizontal,
              padding: const EdgeInsets.symmetric(horizontal: 16),
              itemCount: roomManager.rooms.length,
              itemBuilder: (context, index) {
                final room = roomManager.rooms[index];
                return _buildRoomCard(context, room, deviceManager);
              },
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildRoomCard(
    BuildContext context,
    SmartRoom room,
    SmartDeviceManager deviceManager,
  ) {
    final onlineCount = room.getOnlineDeviceCount(deviceManager);
    final totalDevices = room.deviceIds.length;

    return Container(
      width: 160,
      margin: const EdgeInsets.only(right: 12),
      child: Card(
        clipBehavior: Clip.antiAlias,
        child: InkWell(
          onTap: () => Navigator.push(
            context,
            MaterialPageRoute(
              builder: (_) => RoomDetailPage(room: room),
            ),
          ),
          child: Padding(
            padding: const EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Row(
                  children: [
                    Icon(_getRoomIcon(room.icon), size: 24),
                    const Spacer(),
                    Chip(
                      label: Text('$onlineCount/$totalDevices'),
                      visualDensity: VisualDensity.compact,
                    ),
                  ],
                ),
                const Spacer(),
                Text(
                  room.roomName,
                  style: const TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  '${room.temperature}°C · ${room.humidity}%',
                  style: TextStyle(
                    fontSize: 12,
                    color: Colors.grey[600],
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  IconData _getRoomIcon(String icon) {
    switch (icon) {
      case 'sofa':
        return Icons.weekend;
      case 'bed':
        return Icons.bed;
      case 'chef':
        return Icons.kitchen;
      default:
        return Icons.room;
    }
  }

  Widget _buildDevicesSection(SmartDeviceManager deviceManager) {
    return SliverPadding(
      padding: const EdgeInsets.symmetric(horizontal: 16),
      sliver: SliverList(
        delegate: SliverChildBuilderDelegate(
          (context, index) {
            final device = deviceManager.devices[index];
            return _buildDeviceCard(context, device);
          },
          childCount: deviceManager.devices.length,
        ),
      ),
    );
  }

  Widget _buildDeviceCard(BuildContext context, SmartDevice device) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: ListTile(
        leading: Icon(device.type.icon),
        title: Text(device.deviceName),
        subtitle: Text(device.isOnline ? '在线' : '离线'),
        trailing: _buildDeviceControl(device),
        onTap: () => Navigator.push(
          context,
          MaterialPageRoute(
            builder: (_) => DeviceControlPage(device: device),
          ),
        ),
      ),
    );
  }

  Widget _buildDeviceControl(SmartDevice device) {
    if (device is SmartLight) {
      final state = device.currentState;
      return Switch(
        value: state.isOn,
        onChanged: (value) {
          // 控制灯光
        },
      );
    }
    return const Icon(Icons.chevron_right);
  }

  Widget _buildScenesSection(BuildContext context) {
    final scenes = ref.watch(sceneProvider);

    return Container(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          const Text(
            '场景',
            style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
          ),
          const SizedBox(height: 12),
          Wrap(
            spacing: 12,
            runSpacing: 12,
            children: scenes.map((scene) {
              return _buildSceneChip(context, scene);
            }).toList(),
          ),
        ],
      ),
    );
  }

  Widget _buildSceneChip(BuildContext context, SmartScene scene) {
    return ActionChip(
      avatar: const Icon(Icons.flash_on),
      label: Text(scene.sceneName),
      onPressed: () async {
        await ref.read(sceneProvider.notifier).executeScene(scene.sceneId);
      },
    );
  }

  Widget _buildVoiceButton(BuildContext context) {
    return FloatingActionButton.extended(
      onPressed: () => _showVoiceDialog(context),
      icon: const Icon(Icons.mic),
      label: const Text('语音控制'),
    );
  }

  void _showVoiceDialog(BuildContext context) {
    showDialog(
      context: context,
      builder: (_) => const VoiceControlDialog(),
    );
  }
}

语音控制对话框

/// 语音控制对话框
class VoiceControlDialog extends ConsumerStatefulWidget {
  const VoiceControlDialog({super.key});

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

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

  
  Widget build(BuildContext context) {
    return AlertDialog(
      title: const Text('语音控制'),
      content: SizedBox(
        width: 300,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            // 麦克风动画
            _buildMicrophoneAnimation(),

            const SizedBox(height: 24),

            // 识别文本
            if (_recognizedText.isNotEmpty)
              Text(
                _recognizedText,
                textAlign: TextAlign.center,
                style: const TextStyle(fontSize: 16),
              ),

            const SizedBox(height: 16),

            // 执行结果
            if (_result != null)
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: _result!.success
                      ? Colors.green.shade50
                      : Colors.red.shade50,
                  borderRadius: BorderRadius.circular(8),
                ),
                child: Row(
                  children: [
                    Icon(
                      _result!.success ? Icons.check_circle : Icons.error,
                      color: _result!.success ? Colors.green : Colors.red,
                    ),
                    const SizedBox(width: 8),
                    Expanded(child: Text(_result!.message)),
                  ],
                ),
              ),

            const SizedBox(height: 8),

            // 提示文本
            Text(
              '说出指令,如:"打开客厅灯"',
              style: TextStyle(
                fontSize: 12,
                color: Colors.grey[600],
              ),
            ),
          ],
        ),
      ),
      actions: [
        TextButton(
          onPressed: () => Navigator.pop(context),
          child: const Text('关闭'),
        ),
      ],
    );
  }

  Widget _buildMicrophoneAnimation() {
    return GestureDetector(
      onTap: _isListening ? null : _startListening,
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 300),
        width: 80,
        height: 80,
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          color: _isListening ? Colors.blue.shade100 : Colors.grey.shade200,
          boxShadow: _isListening
              ? [
                  BoxShadow(
                    color: Colors.blue.withOpacity(0.3),
                    blurRadius: 20,
                    spreadRadius: 10,
                  ),
                ]
              : null,
        ),
        child: Icon(
          _isListening ? Icons.mic : Icons.mic_none,
          size: 40,
          color: _isListening ? Colors.blue : Colors.grey,
        ),
      ),
    );
  }

  Future<void> _startListening() async {
    setState(() => _isListening = true);
    _result = null;

    try {
      // 调用鸿蒙语音识别
      final text = await HarmonyVoiceChannel.startListening();

      if (text != null) {
        setState(() => _recognizedText = text);

        // 执行语音命令
        final voiceController = ref.read(voiceControllerProvider);
        final result = await voiceController.execute(text);

        setState(() => _result = result);
      }
    } catch (e) {
      setState(() {
        _result = VoiceResult(
          success: false,
          message: '识别失败:$e',
        );
      });
    } finally {
      setState(() => _isListening = false);
    }
  }
}

鸿蒙端IoT服务

设备通信实现

// HarmonyIotService.ets
import distributedDevice from '@ohos.distributedDevice';
import { MethodChannel } from '@ohos.flutter';

export class HarmonyIotService {
  private flutterChannel: MethodChannel | null = null;
  private deviceCallbacks: Map<string, (data: ESObject) => void> = new Map();

  initialize(channel: MethodChannel): void {
    this.flutterChannel = channel;
    this._registerMethodChannel();
    this._startDeviceDiscovery();
  }

  private _registerMethodChannel(): void {
    this.flutterChannel?.setMethodCallHandler(
      async (method: string, args: Record<string, Object>): Promise<Object> => {
        switch (method) {
          case 'discoverDevices':
            return await this._handleDiscoverDevices();
          case 'sendCommand':
            return await this._handleSendCommand(args);
          case 'startVoice':
            return await this._handleStartVoice(args);
          default:
            return null;
        }
      }
    );
  }

  private async _handleDiscoverDevices(): Promise<Object[]> {
    const devices: Object[] = [];

    try {
      // 发现周边智能设备
      const discoverInfo: distributedDevice.SubscribeInfo = {
        subscribeId: 1,
        mode: distributedDevice.DiscoveryMode.ACTIVE,
        medium: distributedDevice.MediumType.WIFI,
        freq: distributedDevice.FreqType.HIGH
      };

      distributedDevice.startDeviceDiscovery(discoverInfo, (err, data) => {
        if (!err) {
          devices.push({
            'deviceId': data.deviceId,
            'deviceName': data.deviceName,
            'type': this._mapDeviceType(data.deviceType),
            'isOnline': true
          });
        }
      });

      // 等待设备发现完成
      await new Promise(resolve => setTimeout(resolve, 3000));

      return devices;
    } catch (e) {
      console.error('设备发现失败:', e);
      return [];
    }
  }

  private _mapDeviceType(type: string): string {
    // 映射鸿蒙设备类型到智能家居类型
    const typeMap: Record<string, string> = {
      'SMART_LIGHT': 'light',
      'SMART_AC': 'ac',
      'SMART_CURTAIN': 'curtain',
      'SMART_SENSOR': 'sensor'
    };

    return typeMap[type] || 'switch';
  }

  private async _handleSendCommand(args: Record<string, Object>): Promise<boolean> {
    try {
      const deviceId = args['deviceId'] as string;
      const command = args as Record<string, Object>;

      // 通过HiLink协议发送控制命令
      const success = await this._sendHiLinkCommand(deviceId, command);

      // 通知Flutter命令结果
      if (success) {
        this._notifyStateChange(deviceId, command);
      }

      return success;
    } catch (e) {
      console.error('发送命令失败:', e);
      return false;
    }
  }

  private async _sendHiLinkCommand(
    deviceId: string,
    command: Record<string, Object>
  ): Promise<boolean> {
    // HiLink协议实现
    return true;
  }

  private _notifyStateChange(
    deviceId: string,
    command: Record<string, Object>
  ): void {
    this.flutterChannel?.invokeMethod('onDeviceStateChanged', {
      'deviceId': deviceId,
      'data': command
    });
  }

  private async _handleStartVoice(args: Record<string, Object>): Promise<string | null> {
    // 调用鸿蒙语音识别
    // 返回识别的文本
    return '打开客厅灯';
  }

  private _startDeviceDiscovery(): void {
    // 持续发现设备
  }

  destroy(): void {
    distributedDevice.stopDeviceDiscovery(1);
    this.flutterChannel = null;
  }
}

总结

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

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

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


相关资源

Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐