智能家电动态设计实战:从分区洗烘一体机看状态机与IoT架构

📅 2026/8/27 6:39:16
智能家电动态设计实战:从分区洗烘一体机看状态机与IoT架构
先给一个明确判断这台产品真正值得研究的不是“分区”这个卖点而是动态设计如何在分区场景里落地。很多开发者第一次接触智能家电时容易把注意力放在“能不能用 App 控制”“能不能语音开关”这些显性功能上忽略产品背后的设计逻辑。实际上米家分区洗烘一体机这类产品的复杂度已经远远超过“一个单片机 一个 Wi-Fi 模块”的范畴。它有两个独立的洗涤单元共享水电和部分烘干风道它有触摸面板也有 App 和语音入口它的程序不是出厂写死的一组固定流程而是可以根据负载、面料、用户习惯动态调整的一组参数组合。这意味着无论你是做嵌入式开发、App 开发、IoT 平台开发还是产品经理、交互设计师你都能从这台机器里拆出值得借鉴的设计方法。本文不聊参数对比也不做开箱评测。我从“动态设计”这个角度切入拆解一台分区洗烘一体机是如何通过状态机、动态配置、层级反馈和场景联动来完成一个又一个洗衣任务的。读完你会理解智能家电的“智能”不在语音而在系统设计。1. 为什么智能家电需要动态设计传统家电的设计是静态的。一台普通洗衣机出厂时程序是写死在主控板里的。你按下“标准洗”按钮它严格按照预设的时间、水位、转速、漂洗次数走完流程。它不知道衣服有多少、不知道面料是什么、不知道进水温度多少、不知道用户是不是在等一件衣服赶着穿。它的所有决策都发生在“按下按钮”之前。这种静态设计在功能上是安全的在体验上却是僵硬的。用户只能被动选择几个固定模式一旦没选对洗涤效果就打折扣。对家电厂商来说更麻烦的是产品出厂后几乎无法迭代一个新功能、一个优化点都要等下一代硬件。动态设计的出现就是为了解决这两个问题对用户让产品根据实际场景自动调整运行参数体验更细腻。对厂商让产品具备运行时升级和配置下发的能力卖出去之后还能持续优化。但动态设计不是“加一个可视化大屏”或者“做个动态壁纸”这么简单。它是一整套系统能力设备端要有能够动态调整的执行结构软件层要有参数模型和状态机云端要有配置下发通道App 端要有实时反馈的交互界面。任何一层缺失动态设计都只是表面功夫。从这个角度看米家分区洗烘一体机是一个很好的研究样本。因为分区结构天然制造了“不确定性”两个洗涤单元可能同时运行也可能一个运行一个待机烘干可能和洗涤同时发生也可能需要排队等待。设备必须根据实时状态动态决策而不是靠预设顺序硬撑。2. 分区洗烘一体机的产品形态与设计边界先明确产品形态。分区洗烘一体机通常指上滚筒与下滚筒两个独立洗涤区域整体集成一台机身下筒通常兼有烘干功能上下两筒可以独立使用也可以协同工作。这种结构解决的用户痛点是明显的内衣外衣分离、大人小孩衣物分离、浅色深色分离而不用分批洗。过去用户买两台洗衣机需要两个安装位、两套进出水分区一体机用一台机身解决空间问题。与此同时它会带来一个副产品设备内部的状态复杂度成倍增加了。一台单筒洗衣机的核心状态是一个简单的顺序状态机进水、洗涤、排水、漂洗、脱水、结束。加入第二滚筒之后状态机从“一维顺序”变成了“二维并发”上筒正在漂洗下筒正在烘干此时上下筒是否可以同时动作上筒结束早下筒还在运行整机的 App 界面应该展示什么总状态用户打开了上筒门下筒还在高速脱水整机安全和面板逻辑如何处理如果两个筒同时请求“加热”整机功率怎么分配这些问题在静态设计中可以通过“禁止同时运行”来规避但那样用户体验就很差用户买分区就是希望同时洗两批衣服结果机器说“只能先洗上筒再洗下筒”那分区就没有意义了。所以分区洗烘一体机必须走动态设计路线。它的硬件结构天生要求设备具备并发调度能力、状态统一管理和动态资源分配能力。这正是它比单筒产品更有学习价值的地方。3. 动态设计的四个层次要把一台智能家电的“动态性”看清楚可以拆成四个层次。3.1 硬件结构层的动态能力硬件层决定了动态设计的执行能力。普通波轮洗衣机的电机只能正转、反转、停止转速可调范围也有限。而分区洗烘一体机要实现动态设计硬件上必须支持双独立电机可分别控制上下筒的转速与转向。烘干系统的温度、风量可调能根据衣物状态动态调整烘干曲线。水位传感器、温度传感器、负载传感器能实时感知当前状态。加热器和电机之间有功率协调机制避免瞬时过载。从开发视角看硬件层做的事情是“把执行能力暴露给上层”。如果电机只有三档转速动态设计就无从谈起如果传感器足够丰富上层程序就可以实时感知“衣服已经快干了”或者“水太冷了”从而调整后续动作。3.2 程序调度层的动态逻辑这是动态设计的核心层。所谓“程序”可以理解为一组参数随时间变化的策略集合。标准洗、快速洗、混合洗、单烘干这些用户能看到的程序本质上是多组预设参数的组合。动态调度层要做的是在预设参数的基础上根据实时状态再次调整。举例来说一台搭载称重传感器的洗衣机它洗完一件衬衫和洗完一床被套进水量、洗涤时间、漂洗次数、脱水转速可能完全不同。这不是因为“模式”不同而是因为设备通过负载反馈动态修正了参数。这种动态调参能力会把一个简单的产品功能变成一套可演进的系统。米家分区洗烘一体机在这方面的意义在于它把动态调度从“单机内部逻辑”扩展到了“双机协同逻辑”。两个洗涤单元之间需要一套调度机制决定何时并行、何时排队、何时避让。3.3 交互反馈层的动态响应用户的体验感知最终落在交互层。传统的家电面板用几个指示灯和一段数码管显示“还有 23 分钟”用户只能看到剩余时间在减少不知道当前在做什么、为什么慢。动态设计在交互层的目标是让用户看到系统发生了什么并且让反馈变化符合用户的预期。这里面最典型的一个问题是“剩余时间跳变”。洗衣机在进水和称重阶段预估时间可能从 35 分钟跳到 42 分钟又跳到 38 分钟。如果 App 的进度条严格按时间线性推进用户就会觉得“时间越洗越久”体验很差。好的交互层会做预估时间的平滑处理或者明确告诉用户“正在称重剩余时间将根据衣物量动态调整”而不是让用户对一个不断变化的数字产生疑惑。3.4 IoT 与场景联动的动态协同动态设计的第四层是场景联动。设备不是孤立的它接入米家生态后可以和门锁、灯光、传感器、语音助手联动。最典型的是“离家自动启动洗衣”——用户早上出门时把脏衣服扔进洗衣机门锁上锁后洗衣任务自动开始等用户回到家时衣服已经洗好。这类场景的实现不是简单“设备收到一条指令”就行。系统需要判断门锁状态、用户位置、设备状态、时间窗口等多个条件形成一个“触发条件 → 决策逻辑 → 指令下发 → 设备执行”的链路。这要求设备端的状态模型足够清晰能与云端、App 端高效对齐否则联动场景很容易出现“条件满足了但设备没启动”或者“重复启动”等故障。4. 核心机制从“洗涤任务”到“运行状态机”理解了四个层次之后我们进入本文的重点一台分区洗烘一体机的核心运行机制到底是什么从开发角度看可以把整个设备抽象成一个状态机而“洗涤”“漂洗”“脱水”“烘干”这些动作都是状态之间的迁移过程。我在这里用一个高度简化的 TypeScript 版状态机来描述单筒的洗涤流程。注意这不是米家的真实源码而是用于理解设计思路的最小示例// 文件路径src/state-machine/washingStateMachine.ts export type WashingState | IDLE // 待机 | WEIGHING // 称重 | FILLING // 进水 | WASHING // 洗涤 | RINSING // 漂洗 | SPINNING // 脱水 | DRYING // 烘干 | FINISHED // 完成 | ERROR; // 异常 export type WashingEvent | START | PAUSE | RESUME | CANCEL | WEIGHED | FILLED | WASH_DONE | RINSE_DONE | SPIN_DONE | DRY_DONE | ERROR_OCCURRED; const transitions: RecordWashingState, PartialRecordWashingEvent, WashingState { IDLE: { START: WEIGHING, ERROR_OCCURRED: ERROR }, WEIGHING: { WEIGHED: FILLING, CANCEL: IDLE, ERROR_OCCURRED: ERROR }, FILLING: { FILLED: WASHING, CANCEL: IDLE, ERROR_OCCURRED: ERROR }, WASHING: { WASH_DONE: RINSING, PAUSE: WASHING, CANCEL: IDLE, ERROR_OCCURRED: ERROR }, RINSING: { RINSE_DONE: SPINNING, PAUSE: RINSING, CANCEL: IDLE, ERROR_OCCURRED: ERROR }, SPINNING: { SPIN_DONE: DRYING, PAUSE: SPINNING, CANCEL: IDLE, ERROR_OCCURRED: ERROR }, DRYING: { DRY_DONE: FINISHED, PAUSE: DRYING, CANCEL: IDLE, ERROR_OCCURRED: ERROR }, FINISHED: { START: WEIGHING, ERROR_OCCURRED: ERROR }, ERROR: { RESUME: IDLE, CANCEL: IDLE }, }; export class WashingStateMachine { private currentState: WashingState IDLE; get state(): WashingState { return this.currentState; } send(event: WashingEvent): void { const nextState transitions[this.currentState]?.[event]; if (!nextState) { throw new Error( 非法状态迁移: ${this.currentState} 收到事件 ${event} ); } this.currentState nextState; console.log(状态迁移完成: ${this.currentState}); } } // 使用示例 const machine new WashingStateMachine(); machine.send(START); // WEIGHING machine.send(WEIGHED); // FILLING machine.send(FILLED); // WASHING machine.send(WASH_DONE); // RINSING machine.send(RINSE_DONE); // SPINNING machine.send(SPIN_DONE); // DRYING如果选择带烘干 machine.send(DRY_DONE); // FINISHED这段代码揭示了一个关键点状态机明确定义了“哪些状态可以迁移到哪些状态”任何未定义的事件都会被拒绝。这比在业务代码里写大量if (state xxx event yyy)要可靠得多。对于双筒分区洗烘一体机还需要处理两个状态机之间的协同。一个简单的方式是引入一个“资源调度器”当两个筒同时发出“请求烘干”时调度器决定谁先进入 DRYING谁进入排队等待。这个设计避免了两个筒同时启动加热器造成的功率过载。下面是一个高度简化的资源锁示例// 文件路径src/coordinator/DryingCoordinator.ts export class DryingCoordinator { private dryingInUse false; private waitingQueue: Arrayupper | lower []; async requestDrying(unit: upper | lower): Promiseboolean { if (!this.dryingInUse) { this.dryingInUse true; console.log(${unit} 获得烘干资源); return true; } // 如果烘干资源被占用进入等待队列 console.log(${unit} 等待烘干资源释放); this.waitingQueue.push(unit); return false; } releaseDrying(unit: upper | lower): void { this.dryingInUse false; console.log(${unit} 释放烘干资源); const next this.waitingQueue.shift(); if (next) { this.dryingInUse true; console.log(${next} 获得烘干资源从等待队列唤醒); } } }这个示例体现的是“互斥资源”的调度思想。实际产品中比这复杂得多比如还包括滚筒门锁互斥、加热功率分配、进水阀切换等。但核心思路是一样的先定义状态再用事件驱动状态迁移最后用调度器协调并发冲突。5. 动态配置从设备到云端再到 App 的数据协议状态机解决了“流程怎么走”的问题但还没有解决“流程参数是什么”的问题。洗衣机上的每一个程序本质上是一组可以被动态配置的参数集合。传统家电把这些参数写死在固件里。用户想增加一个“夜间洗模式”只能等下一代产品。而支持动态设计的智能家电会把核心参数抽成配置由云端下发。下面是一份简化版的洗涤方案配置 JSON它描述了一个名为“自定义混合洗”的洗涤程序{ programId: custom_mix_wash_001, programName: 自定义混合洗, targetUnit: lower, version: 3, steps: [ { stepId: fill_1, action: FILL_WATER, waterLevel: AUTO }, { stepId: wash_1, action: WASH, waterTemp: 40, spinSpeed: 600, durationMinutes: 15 }, { stepId: rinse_1, action: RINSE, rinseCount: 2, waterLevel: HIGH }, { stepId: spin_1, action: SPIN, spinSpeed: 1000, durationMinutes: 8 }, { stepId: dry_1, action: DRY, dryMode: MODERATE, targetMoisture: 8 } ], enablePushNotification: true, preferEnergySaving: false }这份配置至少说明了三个关键设计程序是数据不是代码。App 或云端修改配置后设备不需要重新刷固件只需要重新读取一份参数即可。这种方式让产品在出厂后依然可以持续优化。每个步骤是独立可执行单元。这便于设备端逐条解析、逐条执行也便于在某一环节出问题时定位具体步骤。配置带版本号。如果配置升级后设备表现异常可以快速回滚到上一个版本。这在智能硬件开发里非常重要否则“云端改参数”会变成一场事故。对于开发者来说这里有一个建议动态配置的价值不只在于“远程改参数”更在于“可回滚、可灰度、可追踪”。如果配置协议没有版本号没有下发记录没有失败重试机制那它就只是把 Bug 从固件挪到了云端并不会真正改善工程质量。6. 状态同步与 App 可视化设计设备端有了状态机云端有了配置协议接下来是用户最终能看到的 App 界面。在米家 App 里用户打开洗衣机页面能看到两个滚筒的独立状态、当前运行阶段、剩余时间、水温、转速等信息。这个界面的背后是一条完整的“设备状态 → 云端推送 → App 渲染”链路。链路中容易出现的一个问题是设备端状态上报时机与 App 端界面更新时机不一致。比如设备端每分钟上报一次完整状态App 收到后更新一次界面。如果上报频率过低用户看到的时间就明显滞后如果上报频率过高对设备功耗和云端压力都不友好。实际产品通常会做分层上报关键状态变化时实时上报启动、暂停、异常、完成。运行过程中的过程属性温度、剩余时间按固定间隔批量上报。下面是一个简化版的 App 端状态订阅伪代码。这里用 Android 的 Kotlin 风格来写目的是展示订阅状态和更新 UI 的思路并不是某一款 App 的真实源码// 文件路径app/src/main/java/com/example/smartwasher/viewmodel/WashingViewModel.kt class WashingViewModel(private val deviceRepository: DeviceRepository) { private val _upperState MutableStateFlowWashingState?(null) val upperState: StateFlowWashingState? _upperState.asStateFlow() private val _lowerState MutableStateFlowWashingState?(null) val lowerState: StateFlowWashingState? _lowerState.asStateFlow() init { viewModelScope.launch { deviceRepository.observeDeviceState() .collect { snapshot - // snapshot 是从云端或局域网收到的设备状态快照 _upperState.value snapshot.upperUnit?.state _lowerState.value snapshot.lowerUnit?.state // 收到状态后界面层会通过 StateFlow 自动刷新 refreshProgress(snapshot) } } } private fun refreshProgress(snapshot: DeviceStateSnapshot) { // 这里做剩余时间的平滑处理避免进度条反复跳动 val smoothedRemainingSeconds estimateSmoothRemainingTime( rawRemainingSeconds snapshot.lowerUnit?.remainingSeconds ?: 0, previousRawSeconds lastRawRemainingSeconds ) lastRawRemainingSeconds snapshot.lowerUnit?.remainingSeconds ?: 0 _uiState.update { it.copy( lowerRemainingText formatDuration(smoothedRemainingSeconds), isUpperRunning snapshot.upperUnit?.state WASHING || snapshot.upperUnit?.state SPINNING ) } } }这段代码的核心经验是App 不要直接把设备上报的原始数据画在界面上而是要做一次“状态映射层”。设备端说“我在 WASHING”App 层根据本地状态字典翻译成“正在洗涤”设备端说“剩余时间 35 分钟”App 层做一次平滑更新为“大约还需要 35 分钟”。这样即使设备状态上报有轻微抖动用户界面也能保持稳定。7. 常见问题与排查思路智能家电开发中设备、云端、App 三层链路总会出现各种不一致的问题。下面整理几类高频问题适合产品研发、测试和售后工程师参考。问题现象可能原因排查方式解决方案App 显示离线设备面板显示正常设备网络断开或 MQTT 长连接掉线查看设备网络连接日志确认是否因 Wi-Fi 休眠断开重启设备重连网络检查路由器是否开启了 AP 隔离两个分区同时启动烘干整机掉电加热功率超限没有互斥调度检查烘干启动日志确认是否两个筒同时请求加热在设备端增加烘干互斥锁云端下发烘干预约队列洗烘过程中剩余时间大幅跳变称重阶段预估值不准确或设备动态调整了参数查看完整状态上报记录对比每个阶段的预估值与实际值App 做平滑显示设备端优化预估算法面板与 App 显示的状态不一致面板走本地状态App 走云端状态两者不同步检查设备是否上报了最新的状态快照增加状态同步确认机制设备状态变更后立即上报远程启动失败但走近设备后又正常设备处于深度睡眠或离线状态查看设备在线状态确认是否支持远程唤醒检查设备端低功耗策略配置可唤醒时间窗口还有一类常见问题在测试阶段特别明显非法状态迁移没有拦截。比如用户在漂洗阶段直接点击“开始”如果设备端状态机没有定义RINSING → WEIGHING的迁移就会出现未知行为。更稳妥的方式是把状态迁移表写成一个数据驱动结构并在开发阶段用单元测试覆盖所有合法与非法迁移路径。8. 动态设计带给开发者的启示看完这台分区洗烘一体机的设计逻辑你可能会觉得这和我做 Web 开发、做 App、做后端有什么关系实际上关系很大。现代软件系统几乎都在做同一件事把静态逻辑变成动态数据把写死的流程变成可配置、可观测、可恢复的状态系统。这和一台洗衣机的动态设计思路完全一致。第一状态机不是嵌入式开发的专利。Web 前端做复杂表单、App 做多步骤支付、后端做订单状态流转都可以用状态机来描述。你不需要引入复杂的框架只要在代码里显式定义状态、事件、迁移表就能显著减少“到处 if/else 判断状态”带来的 Bug。第二动态配置的想象力远大于远程修改参数。一台会随着使用场景自动调整策略的产品才是真正有生命力的产品。把“程序的参数”从“程序逻辑”中剥离出来让产品可以在真实用户身上不断学习和优化这正是动态设计最大的价值。第三分层反馈是好体验的基础。设备端、云端、App 端各干各的事体验一定是一团乱麻。好的系统设计必须统一“状态模型”设备端按这个模型上报云端按这个模型存储App 按这个模型渲染。任何一端私自增加状态都会造成全局混乱。第四动态设计要同时考虑降级与回滚。配置下发后如果设备表现异常是从云端撤回配置还是让设备固件自动回退如果一个新功能导致耗电量增加是直接关闭还是保留入口等用户反馈这些都不是“上线后再说”的事情而是在设计配置协议时就应该考虑好的。9. 总结与后续学习方向回到开头的问题分区洗烘一体机到底“智能”在哪里如果只用一句话回答那就是它把一辆只有“横冲直撞”功能的铁盒子变成了一个有状态、有反馈、可调整、能协同的系统。动态设计不是一个华丽的包装而是一整套从硬件到云端再到 App 的工程能力。本文给出的状态机、动态配置 JSON、资源调度器、App 状态订阅示例都是围绕同一个目标让一台复杂家电在真实场景中表现得稳定、可靠、细腻。对开发者来说下一步可以从三个方向继续深入如果做嵌入式开发可以研究状态机的工程化落地包括状态迁移测试、低功耗状态切换、异常恢复策略。如果做 App 或 Web 开发可以尝试在自己的业务里引入状态机把一个复杂流程拆成“状态 事件 迁移表”再配一个可视化状态面板。如果做产品设计可以重新审视自己手上的产品哪些功能是出厂写死的哪些参数可以配置化哪些反馈可以做得更动态。最后提醒一句智能硬件开发中任何动态设计的实现都要有日志、有监控、有回滚方案。一个新功能如果能上线也能关闭能灰度也能全量能观察也能诊断才算是一个合格的动态设计。不要为了“动态”而动态先想清楚用户能获得什么再决定系统该怎么动。