HarmonyOS实战项目:打造智能家居控制中心(设备发现与控制)
概述:智能家居控制中心的核心价值
随着物联网技术的快速发展,智能家居设备数量激增,用户迫切需要统一的控制中心来管理各类设备。基于HarmonyOS的分布式能力,我们可以构建一个能够自动发现、统一管理、跨设备控制的智能家居控制中心。
本项目将实现以下核心功能:智能设备自动发现与认证、设备状态实时同步、跨设备控制指令下发、场景化智能联动。这些功能基于HarmonyOS的分布式设备管理和分布式任务调度能力实现。
环境配置与项目初始化
开发环境要求
- DevEco Studio 4.0或更高版本
- HarmonyOS 5.0 SDK,API Version 12+
- 支持分布式能力的真机设备(手机、平板、智慧屏等)
创建项目与配置权限
在module.json5中配置智能家居控制中心所需的权限:
{"module": {"requestPermissions": [{"name": "ohos.permission.DISTRIBUTED_DATASYNC","reason": "$string:distributed_datasync_reason","usedScene": {"ability": [".MainAbility"],"when": "inuse"}},{"name": "ohos.permission.GET_DISTRIBUTED_DEVICE_INFO"},{"name": "ohos.permission.ACCESS_SERVICE_DM","reason": "用于设备发现和认证"},{"name": "ohos.permission.DISCOVER_HARDWARE","reason": "用于发现智能家居设备"}]}
}
项目架构设计
分层架构规划
entry/src/main/ets/
├── common
│ ├── constants
│ └── utils
├── model
│ ├── DeviceInfo.ets # 设备信息模型
│ └── SceneInfo.ets # 场景信息模型
├── pages
│ ├── DeviceListPage.ets # 设备列表页
│ ├── DeviceDetailPage.ets # 设备详情页
│ └── SceneManagePage.ets # 场景管理页
├── view
│ ├── DeviceCard.ets # 设备卡片组件
│ ├── SceneCard.ets # 场景卡片组件
│ └── ControlPanel.ets # 控制面板组件
├── viewmodel
│ ├── DeviceManager.ets # 设备管理视图模型
│ └── SceneManager.ets # 场景管理视图模型
└── service├── DeviceService.ets # 设备服务└── DistributedService.ets # 分布式服务
设备信息模型设计
定义统一的设备数据模型,支持多种类型的智能家居设备:
// model/DeviceInfo.ets
export enum DeviceType {LIGHT = 'light',THERMOSTAT = 'thermostat',PLUG = 'plug',SENSOR = 'sensor',CAMERA = 'camera'
}export enum DeviceStatus {ONLINE = 'online',OFFLINE = 'offline',BUSY = 'busy'
}export class DeviceInfo {deviceId: string = '';deviceName: string = '';deviceType: DeviceType = DeviceType.LIGHT;status: DeviceStatus = DeviceStatus.OFFLINE;capabilities: string[] = []; // 设备能力列表room: string = ''; // 所属房间lastSeen: number = 0; // 最后在线时间isDistributed: boolean = false; // 是否支持分布式控制properties: Map<string, any> = new Map(); // 设备属性constructor(data?: any) {if (data) {this.deviceId = data.deviceId || '';this.deviceName = data.deviceName || '';this.deviceType = data.deviceType || DeviceType.LIGHT;this.status = data.status || DeviceStatus.OFFLINE;this.capabilities = data.capabilities || [];this.room = data.room || '';this.isDistributed = data.isDistributed || false;if (data.properties) {Object.keys(data.properties).forEach(key => {this.properties.set(key, data.properties[key]);});}}}// 更新设备属性updateProperty(key: string, value: any): void {this.properties.set(key, value);}// 获取设备属性getProperty(key: string): any {return this.properties.get(key);}// 转换为可序列化对象toObject(): any {const obj: any = {deviceId: this.deviceId,deviceName: this.deviceName,deviceType: this.deviceType,status: this.status,capabilities: this.capabilities,room: this.room,lastSeen: this.lastSeen,isDistributed: this.isDistributed};// 转换Map为普通对象const props: any = {};this.properties.forEach((value, key) => {props[key] = value;});obj.properties = props;return obj;}
}
设备发现与管理服务
设备发现服务实现
// service/DeviceService.ets
import deviceManager from '@ohos.distributedHardware.deviceManager';export class DeviceService {private deviceMag: deviceManager.DeviceManager;private discoveredDevices: deviceManager.DeviceInfo[] = [];private trustedDevices: deviceManager.DeviceInfo[] = [];// 初始化设备管理服务async initialize(): Promise<void> {return new Promise((resolve, reject) => {deviceManager.createDeviceManager('com.example.smarthome', (err, data) => {if (err) {console.error('创建设备管理器失败:', err);reject(err);return;}this.deviceMag = data;// 注册设备状态监听this.registerDeviceListeners();// 获取已信任设备列表this.getTrustedDevices();resolve();});});}// 注册设备状态监听器private registerDeviceListeners(): void {// 监听设备发现this.deviceMag.on('deviceFound', (data) => {this.onDeviceFound(data);});// 监听设备离线this.deviceMag.on('deviceOffline', (data) => {this.onDeviceOffline(data);});// 监听设备状态变化this.deviceMag.on('deviceStateChange', (data) => {this.onDeviceStateChange(data);});}// 开始设备发现startDiscovery(): void {if (!this.deviceMag) {console.error('设备管理器未初始化');return;}try {const discoverParams = {// 发现智能家居设备deviceFilter: ['light', 'thermostat', 'plug', 'sensor'],// 5分钟超时timeout: 300000};this.deviceMag.startDeviceDiscovery(discoverParams);console.info('开始设备发现');} catch (error) {console.error('启动设备发现失败:', error);}}// 停止设备发现stopDiscovery(): void {if (this.deviceMag) {this.deviceMag.stopDeviceDiscovery();console.info('停止设备发现');}}// 设备发现回调private onDeviceFound(data: deviceManager.DeviceInfo): void {const existingIndex = this.discoveredDevices.findIndex(device => device.deviceId === data.deviceId);if (existingIndex === -1) {this.discoveredDevices.push(data);console.info(`发现新设备: ${data.deviceName}, ID: ${data.deviceId}`);// 通知UI更新this.notifyDeviceUpdate();}}// 获取可信设备列表private getTrustedDevices(): void {try {this.trustedDevices = this.deviceMag.getTrustedDeviceListSync();console.info(`获取到 ${this.trustedDevices.length} 个可信设备`);} catch (error) {console.error('获取可信设备列表失败:', error);}}// 设备认证async authenticateDevice(deviceId: string): Promise<boolean> {return new Promise((resolve) => {try {this.deviceMag.authenticateDevice(deviceId, (err, data) => {if (err) {console.error('设备认证失败:', err);resolve(false);return;}console.info('设备认证成功');resolve(true);});} catch (error) {console.error('设备认证异常:', error);resolve(false);}});}// 通知UI更新private notifyDeviceUpdate(): void {// 通过AppStorage或EventHub通知UI层AppStorage.setOrCreate('discoveredDevices', this.discoveredDevices);AppStorage.setOrCreate('trustedDevices', this.trustedDevices);}
}
设备列表页面实现
多端适配的设备列表布局
// pages/DeviceListPage.ets
@Entry
@Component
struct DeviceListPage {@State currentTab: number = 0;@StorageLink('discoveredDevices') discoveredDevices: deviceManager.DeviceInfo[] = [];@StorageLink('trustedDevices') trustedDevices: deviceManager.DeviceInfo[] = [];@State isLoading: boolean = true;private deviceService: DeviceService = new DeviceService();async aboutToAppear() {await this.deviceService.initialize();this.deviceService.startDiscovery();this.isLoading = false;}aboutToDisappear() {this.deviceService.stopDiscovery();}build() {Column() {// 顶部标题和搜索栏this.buildHeader()// 标签页Tabs({ index: this.currentTab }) {// 全部设备标签页TabContent() {this.buildAllDevicesTab()}.tabBar('全部设备')// 按房间分类标签页TabContent() {this.buildRoomsTab()}.tabBar('房间')// 场景标签页TabContent() {this.buildScenesTab()}.tabBar('场景')}.onChange((index: number) => {this.currentTab = index;}).layoutWeight(1)}.height('100%').width('100%').backgroundColor('#F5F5F5')}@BuilderbuildHeader() {Column() {Row() {Text('智能家居控制中心').fontSize(24).fontWeight(FontWeight.Bold).layoutWeight(1)Button('扫描').fontSize(14).onClick(() => {this.deviceService.startDiscovery();})}.padding(16).width('100%')// 搜索栏TextInput({ placeholder: '搜索设备...' }).width('90%').height(40).backgroundColor(Color.White).padding(8).margin({ bottom: 16 }).borderRadius(20)}.backgroundColor(Color.White)}@BuilderbuildAllDevicesTab() {if (this.isLoading) {LoadingProgress().width(50).height(50).margin({ top: 100 })} else if (this.trustedDevices.length === 0) {this.buildEmptyState()} else {GridRow({columns: { sm: 4, md: 8, lg: 12 },breakpoints: { value: ['320vp', '600vp', '840vp'] },gutter: { x: 12, y: 12 }}) {GridCol({span: { sm: 4, md: 8, lg: 12 }}) {List({ space: 12 }) {ForEach(this.trustedDevices, (device: deviceManager.DeviceInfo) => {ListItem() {DeviceCard({ device: device }).onClick(() => {this.navigateToDetail(device);})}}, (device: deviceManager.DeviceInfo) => device.deviceId)}.width('100%').layoutWeight(1)}}.padding(16)}}@BuilderbuildEmptyState() {Column() {Image($rawfile('ic_empty_devices')).width(120).height(120).margin({ bottom: 24 })Text('未发现设备').fontSize(18).fontColor('#666666').margin({ bottom: 8 })Text('请确保设备已开启并在同一网络下').fontSize(14).fontColor('#999999').margin({ bottom: 24 })Button('重新扫描').backgroundColor('#0A59F7').fontColor(Color.White).onClick(() => {this.deviceService.startDiscovery();})}.width('100%').height(400).justifyContent(FlexAlign.Center)}private navigateToDetail(device: deviceManager.DeviceInfo): void {router.pushUrl({url: 'pages/DeviceDetailPage',params: { deviceId: device.deviceId }});}
}
设备控制卡片组件
可复用的设备控制UI
// view/DeviceCard.ets
@Component
export struct DeviceCard {@Prop device: deviceManager.DeviceInfo;@State isConnected: boolean = false;build() {Column() {// 设备图标和状态Row() {this.buildDeviceIcon()Column() {Text(this.device.deviceName).fontSize(16).fontColor('#000000').maxLines(1).textOverflow({ overflow: TextOverflow.Ellipsis })Text(this.isConnected ? '在线' : '离线').fontSize(12).fontColor(this.isConnected ? '#00B96B' : '#999999')}.layoutWeight(1).margin({ left: 12 })// 连接状态指示器Circle({ width: 8, height: 8 }).fill(this.isConnected ? '#00B96B' : '#FF4D4F').margin({ right: 8 })}.width('100%').margin({ bottom: 16 })// 设备控制区域this.buildControlPanel()}.padding(16).backgroundColor(Color.White).borderRadius(12).shadow({ radius: 4, color: '#10000000', offsetX: 0, offsetY: 2 }).width('100%').height(180).onClick(() => {// 处理设备点击事件})}@BuilderbuildDeviceIcon() {const iconConfig = this.getDeviceIconConfig();Column() {Image(iconConfig.icon).width(32).height(32).objectFit(ImageFit.Contain)}.width(56).height(56).backgroundColor(iconConfig.bgColor).borderRadius(28).justifyContent(FlexAlign.Center)}@BuilderbuildControlPanel() {const deviceType = this.getDeviceType();if (deviceType === DeviceType.LIGHT) {this.buildLightControl()} else if (deviceType === DeviceType.THERMOSTAT) {this.buildThermostatControl()} else if (deviceType === DeviceType.PLUG) {this.buildPlugControl()} else {this.buildDefaultControl()}}@BuilderbuildLightControl() {Row() {Toggle({ type: ToggleType.Checkbox, isOn: false }).onChange((isOn) => {this.controlDevice(isOn ? 'turnOn' : 'turnOff');})Text('开关').fontSize(14).margin({ left: 8 }).layoutWeight(1)Slider({ value: 50, min: 0, max: 100, style: SliderStyle.OutSet }).onChange((value) => {this.controlDevice('setBrightness', { brightness: value });}).width(80)}.width('100%').alignItems(VerticalAlign.Center)}private getDeviceType(): DeviceType {// 根据设备信息判断设备类型// 实际项目中应从设备属性中获取if (this.device.deviceName.includes('灯') || this.device.deviceName.includes('Light')) {return DeviceType.LIGHT;} else if (this.device.deviceName.includes('空调') || this.device.deviceName.includes('Thermostat')) {return DeviceType.THERMOSTAT;} else if (this.device.deviceName.includes('插座') || this.device.deviceName.includes('Plug')) {return DeviceType.PLUG;}return DeviceType.LIGHT;}private getDeviceIconConfig(): { icon: Resource, bgColor: Resource } {const deviceType = this.getDeviceType();switch (deviceType) {case DeviceType.LIGHT:return { icon: $r('app.media.ic_light'), bgColor: $r('app.color.light_bg') };case DeviceType.THERMOSTAT:return { icon: $r('app.media.ic_thermostat'), bgColor: $r('app.color.thermostat_bg') };case DeviceType.PLUG:return { icon: $r('app.media.ic_plug'), bgColor: $r('app.color.plug_bg') };default:return { icon: $r('app.media.ic_device'), bgColor: $r('app.color.default_bg') };}}private controlDevice(command: string, params?: any): void {// 发送设备控制指令console.info(`控制设备: ${this.device.deviceId}, 命令: ${command}`, params);}
}
分布式设备控制服务
跨设备控制指令下发
// service/DistributedService.ets
import distributedDeviceManager from '@ohos.distributedHardware.deviceManager';export class DistributedService {private deviceMag: distributedDeviceManager.DeviceManager;// 发送控制指令到设备async sendControlCommand(deviceId: string, command: string, params?: any): Promise<boolean> {return new Promise((resolve) => {try {const want = {deviceId: deviceId,bundleName: 'com.example.smarthome.device',abilityName: 'DeviceControlAbility',parameters: {command: command,params: params || {},timestamp: new Date().getTime()}};featureAbility.startAbility(want).then(() => {console.info(`控制指令发送成功: ${command} to ${deviceId}`);resolve(true);}).catch((error) => {console.error(`控制指令发送失败: ${error}`);resolve(false);});} catch (error) {console.error('发送控制指令异常:', error);resolve(false);}});}// 批量控制设备async batchControlDevices(deviceIds: string[], command: string, params?: any): Promise<boolean[]> {const results: Promise<boolean>[] = deviceIds.map(deviceId => this.sendControlCommand(deviceId, command, params));return Promise.all(results);}// 创建设备组async createDeviceGroup(deviceIds: string[], groupName: string): Promise<string> {return new Promise((resolve) => {try {const groupId = this.generateGroupId();// 保存设备组信息到分布式数据this.saveDeviceGroup(groupId, deviceIds, groupName).then(() => {console.info(`设备组创建成功: ${groupName}`);resolve(groupId);}).catch((error) => {console.error('设备组创建失败:', error);resolve('');});} catch (error) {console.error('创建设备组异常:', error);resolve('');}});}private generateGroupId(): string {return `group_${new Date().getTime()}_${Math.random().toString(36).substr(2, 9)}`;}private async saveDeviceGroup(groupId: string, deviceIds: string[], groupName: string): Promise<void> {// 使用分布式数据管理保存设备组信息const kvManager = distributedData.createKVManager({bundleName: 'com.example.smarthome',userInfo: {userId: 'defaultUser',userType: distributedData.UserType.SAME_USER_ID}});const kvStore = await kvManager.getKVStore('device_groups', {createIfMissing: true});const groupInfo = {groupId: groupId,groupName: groupName,deviceIds: deviceIds,createTime: new Date().getTime()};await kvStore.put(groupId, JSON.stringify(groupInfo));}
}
场景化智能联动
智能场景管理
// model/SceneInfo.ets
export enum SceneTriggerType {TIME = 'time', // 时间触发DEVICE = 'device', // 设备状态触发MANUAL = 'manual' // 手动触发
}export class SceneAction {deviceId: string = '';command: string = '';params: any = {};constructor(deviceId: string, command: string, params?: any) {this.deviceId = deviceId;this.command = command;this.params = params || {};}
}export class SceneInfo {sceneId: string = '';sceneName: string = '';triggerType: SceneTriggerType = SceneTriggerType.MANUAL;triggerCondition: any = {}; // 触发条件actions: SceneAction[] = []; // 场景动作isEnabled: boolean = true;createTime: number = 0;constructor(data?: any) {if (data) {this.sceneId = data.sceneId || this.generateSceneId();this.sceneName = data.sceneName || '';this.triggerType = data.triggerType || SceneTriggerType.MANUAL;this.triggerCondition = data.triggerCondition || {};this.actions = (data.actions || []).map((action: any) => new SceneAction(action.deviceId, action.command, action.params));this.isEnabled = data.isEnabled !== undefined ? data.isEnabled : true;this.createTime = data.createTime || new Date().getTime();}}private generateSceneId(): string {return `scene_${new Date().getTime()}_${Math.random().toString(36).substr(2, 9)}`;}// 添加场景动作addAction(deviceId: string, command: string, params?: any): void {this.actions.push(new SceneAction(deviceId, command, params));}// 执行场景async execute(): Promise<boolean[]> {const distributedService = new DistributedService();const results: Promise<boolean>[] = [];for (const action of this.actions) {results.push(distributedService.sendControlCommand(action.deviceId, action.command, action.params));}return Promise.all(results);}
}
多端适配与响应式布局
基于栅格系统的布局适配
// common/constants/Breakpoints.ets
export class CommonConstants {// 断点定义static readonly BREAKPOINT_SM: string = 'sm'; // 小屏设备 < 600vpstatic readonly BREAKPOINT_MD: string = 'md'; // 中屏设备 600vp - 840vpstatic readonly BREAKPOINT_LG: string = 'lg'; // 大屏设备 > 840vp// 设备类型static readonly DEVICE_TYPE_PHONE: string = 'phone';static readonly DEVICE_TYPE_TABLET: string = 'tablet';static readonly DEVICE_TYPE_TV: string = 'tv';static readonly DEVICE_TYPE_WEARABLE: string = 'wearable';// 布局配置static readonly GRID_COLUMNS_SM: number = 4;static readonly GRID_COLUMNS_MD: number = 8;static readonly GRID_COLUMNS_LG: number = 12;static getCurrentBreakpoint(): string {const screenWidth = display.getDefaultDisplaySync().width;if (screenWidth < 600) {return this.BREAKPOINT_SM;} else if (screenWidth < 840) {return this.BREAKPOINT_MD;} else {return this.BREAKPOINT_LG;}}static getGridColumns(): number {const breakpoint = this.getCurrentBreakpoint();switch (breakpoint) {case this.BREAKPOINT_SM:return this.GRID_COLUMNS_SM;case this.BREAKPOINT_MD:return this.GRID_COLUMNS_MD;case this.BREAKPOINT_LG:return this.GRID_COLUMNS_LG;default:return this.GRID_COLUMNS_MD;}}
}
测试与优化建议
分布式功能测试要点
- 设备发现测试:验证在不同网络环境下设备的发现能力
- 控制指令测试:测试控制指令的发送成功率和响应时间
- 跨设备同步测试:验证设备状态在多设备间的同步一致性
- 性能测试:测试大量设备同时在线时的系统性能
性能优化建议
// 设备状态缓存优化
export class DeviceStateCache {private static instance: DeviceStateCache;private cache: Map<string, any> = new Map();private maxSize: number = 1000;private ttl: number = 300000; // 5分钟static getInstance(): DeviceStateCache {if (!DeviceStateCache.instance) {DeviceStateCache.instance = new DeviceStateCache();}return DeviceStateCache.instance;}set(key: string, value: any): void {if (this.cache.size >= this.maxSize) {this.evictOldest();}this.cache.set(key, {value: value,timestamp: new Date().getTime()});}get(key: string): any {const item = this.cache.get(key);if (!item) return null;// 检查是否过期if (new Date().getTime() - item.timestamp > this.ttl) {this.cache.delete(key);return null;}return item.value;}private evictOldest(): void {let oldestKey: string = '';let oldestTime: number = Infinity;this.cache.forEach((value, key) => {if (value.timestamp < oldestTime) {oldestTime = value.timestamp;oldestKey = key;}});if (oldestKey) {this.cache.delete(oldestKey);}}
}
项目总结与扩展方向
本智能家居控制中心项目展示了HarmonyOS在物联网领域的强大能力。通过本项目,你已掌握:
- 分布式设备管理的完整实现流程
- 跨设备控制指令的下发机制
- 场景化智能联动的业务逻辑设计
- 多端适配的响应式布局方案
扩展功能建议
- 实现语音控制集成(集成语音助手)
- 添加能耗统计功能
- 实现自动化规则引擎
- 添加设备固件OTA升级功能
- 实现家庭安防联动功能
这个项目为智能家居生态开发提供了坚实基础,下一步可以探索更复杂的AIoT场景集成和商业化应用部署。
