Itsyhome:SwiftUI原生客户端连接HomeKit体验与HA底座
两台设备、一个手机 App、一个浏览器后台这是很多折腾智能家居的人最终都会走到的一步客厅的灯用苹果家庭 App 控制很顺手但想做个人来灯亮、下雨关窗、出门断电的自动化光靠 HomeKit 那套图形化编排就有点憋屈了。于是 Home Assistant 上场本地部署、设备兼容性强、自动化脚本几乎无所不能可界面和日常操作体验又常常被家人吐槽太像后台管理系统。Itsyhome 这个项目之所以值得单独拿出来聊就是因为它正好卡在这两套体系的缝隙上——用原生 SwiftUI 做前端用 Home Assistant 做能力底座在 macOS 和 iOS 两端做出接近苹果家庭 App 的操作手感。这篇文章会把我的平台选型判断、Itsyhome 的双层设计思路拆解、以及从零开始的首次配置流程完整写一遍顺带把踩过的坑一并交出来。适合正在纠结 HomeKit 还是 Home Assistant 的新手也适合已经把 HA 跑起来但苦于家人不会用的老手。1. 选型之前先看清两套体系的底层差异我在帮朋友搭家庭自动化的时候最常听到的一句话是我到底该选 HomeKit 还是 Home Assistant。这个问题问得其实不太对因为这两个东西压根不在同一个抽象层级上。弄清楚它们的角色定位后面所有的选型和配置才能顺理成章。1.1 HomeKit 是协议加认证Home Assistant 是平台加编排HomeKit 的本质是一套协议规范加一套认证体系。设备厂商要把产品做成支持 HomeKit需要通过认证芯片里要装特定模块设备描述、配对流程、加密通道都有明确规定。这套机制的好处是体验极其统一不管谁家的灯加进苹果家庭 App 之后开关的样子、调光的方式、场景的触发逻辑都是一致的家人不需要学习成本。坏处也很直接——认证门槛高导致便宜好用的设备往往不支持而且它能做的事情被限制在规范允许的范围内你想读取一个自定义传感器的原始数值或者按一个复杂条件序列控制设备HomeKit 的自动化界面基本帮不上忙。Home Assistant 走的是完全相反的路子。它不要求设备认证只要能通过网络、串口、蓝牙、云 API 跟设备说上话就能把它接进来。所有实体的状态都暴露成统一的数据模型自动化、脚本、模板、仪表盘全部开放甚至可以写自定义集成。代价是你得自己维护一台常开的机器得自己配网络、配备份、配更新策略界面也偏向工程化家庭成员不看说明基本用不明白。提示把这两者理解成身份认证与协议标准和运行时与编排引擎更准确不要把它们当成竞品。两者是可以共存的甚至是互补的。1.2 两套体系各自的舒适区与雷区我把这几年实际部署下来的体验整理成了一张表这张表基本可以作为选型的第一把尺子。维度HomeKitHome Assistant上手门槛极低扫码配对即可中等偏高需要部署和维护设备兼容范围受认证限制范围较窄极广社区集成覆盖大量品牌自动化能力图形化条件表达力有限脚本、模板、条件嵌套几乎无上限本地化程度大多数走本地局域网本地为主部分集成依赖云家人使用体验统一、直观取决于仪表盘做得怎么样断网可用性本地控制可用纯本地部署下可用性高长期维护成本接近零需要定期升级、备份、排障出问题时的排查难度低但可调空间小高但日志和数据都在自己手里从表里能看出一个很现实的结论HomeKit 赢在交付体验Home Assistant 赢在能力上限。绝大多数人真正想要的是 Home Assistant 的能力配 HomeKit 的界面。这正是 Itsyhome 这类客户端存在的理由也是我后来把方案定成HA 做底座、原生客户端做门面的原因。还有一类情况需要单独说家里本来就有大量 HomeKit 认证设备比如门锁、摄像头、窗帘电机这些东西直接接入 HA 有时候体验反而不如原生。我的做法是让 HA 通过桥接把这类设备反向接进来统一在一个数据模型里管理避免出现两套系统各管一半设备的分裂局面。2. Itsyhome 的双平台设计思路拆解Itsyhome 这个项目的形态用一句话概括就是一个用 SwiftUI 写的 Home Assistant 原生客户端同时支持 macOS 和 iOS。它名字里的 HomeKit 不是指它替代了 HomeKit而是指它在交互语言上向苹果家庭 App 靠拢。下面这几层设计思路是我在读它的行为逻辑和做实际配置时感受最深的。2.1 为什么不是再造一个 Home Assistant 客户端市面上基于 WebView 套壳的 HA 客户端不少做起来也快一个容器加载网页就行。但套壳方案有三个绕不过去的问题第一滚动和手势是网页的手感长列表、卡片拖拽、侧滑操作都会有明显的迟滞第二推送和后台状态刷新依赖网页层锁屏后在锁屏界面上的控制体验很难做好第三摄像头流、媒体播放这类需要原生解码的能力网页层要么做不到要么功耗高得离谱。Itsyhome 选择原生实现本质上是在赌日常高频操作的手感值这个开发成本。这个判断我认为是对的家庭成员每天开关灯几十次每一次操作的顺滑程度会直接决定这套系统是被使用还是被抛弃。我在自己家里做过对比从锁屏小组件点一下开灯到灯真的亮起来原生客户端路径比套壳方案少了明显的等待感这种差异在晚上起夜的时候尤其明显。2.2 三层结构数据层、状态层、视图层各管什么按常见的原生客户端实现方式推断它的内部可以拆成三层这个拆法也适用于你想自己写一个客户端的情况。数据层负责跟 Home Assistant 打交道。核心是两类接口一类是 REST 接口用来做一次性操作比如拉取实体列表、调用服务、获取配置信息另一类是 WebSocket 接口用来订阅状态变化。REST 是请求-响应模型适合我要一个确定的结果WebSocket 是长连接推送模型适合状态变了告诉我一声。状态层是本地缓存和状态机。所有实体的当前状态在本地存一份收到推送就更新视图订阅这份数据。这一层的存在意义在于界面永远读本地数据不等网络所以列表滚动、开关切换不会卡。代价是要处理好本地状态和服务器状态的最终一致性这就是后面会讲到的状态回弹问题的根源。视图层是 SwiftUI 的声明式界面房间、收藏、设备卡片、场景按钮都在这一层。SwiftUI 的好处是同一套代码能在两端跑macOS 上还能直接做菜单栏常驻面板这在 iOS 上是不存在的形态。2.3 双端不是简单缩放macOS 和 iOS 的交互差异支持双端听起来像是一套代码两个壳实际做起来远不止。iOS 是触摸优先目标区域要够大信息密度要低操作路径要短macOS 是鼠标和键盘优先可以承受更高的信息密度右键菜单、快捷键、多窗口都是合理预期。Itsyhome 在 macOS 上走了菜单栏常驻的路线这个选择很聪明——桌面端最常用的场景不是打开一个 App 管理全屋而是我现在正在干别的顺手把灯调一下菜单栏面板正好匹配这个场景。我在实际使用中形成的习惯是手机上用主界面做房间级操作比如回家时一键开客厅所有灯桌面上用菜单栏面板做单设备微调比如调一下台灯亮度。两种形态对应两类需求这是套壳方案给不了的。2.4 双后端的取舍直连 HomeKit 还是走 Home Assistant标题里的HomeKit 还是 Home Assistant其实还藏着第二层含义客户端的数据源到底接谁。这两条路线的取舍很现实。直连 HomeKit 配件好处是链路短、延迟低、不依赖中间服务器坏处是只能拿到 HomeKit 规范暴露出来的能力和状态设备本来的扩展功能比如某些灯的自定义灯效、传感器的原始读数拿不到也没法跨设备做复杂编排。走 Home Assistant好处是数据模型完整、能做的事情多坏处是多了一跳HA 挂了或者网络不通客户端也就瘫了。注意这两条路线不是二选一。比较稳妥的架构是 HA 做统一底座把所有设备接进来再用桥接方式把关键设备回吐给苹果家庭 App客户端只对接 HA 一处。这样既能保证自动化能力又能保证在 HA 短暂不可用时HomeKit 那条链路还能兜底控制核心设备。3. 首次配置完整教程从装好 HA 到手机上能用这一段是实操部分我按自己实际跑通的顺序写任何一步顺序颠倒都可能让你在后面排查时多花半小时。3.1 前置清单与网络环境确认动手之前先把下面这些确认一遍能省掉后面一大半的玄学问题。项目要求说明Home Assistant已部署并可通过局域网访问版本尽量保持在较新老版本接口字段有差异访问地址固定 IP 或固定域名DHCP 变动会导致客户端连不上协议HTTPS 优先部分平台对明文 HTTP 有限制账号一个专用账号不要用管理员主账号做客户端登录客户端iOS 16 或 macOS 13 以上SwiftUI 新特性依赖较新系统端口8123 默认或你自定义的端口需要在地址里显式写明固定 IP 这一条我要单独强调。很多人装完 Home Assistant 就完事了路由器重启一次地址变了客户端全部连不上然后开始怀疑是客户端有 bug。进路由器后台做一个静态租约绑定两分钟的事能省掉后面无数次重启排查。3.2 Home Assistant 侧创建长期访问令牌客户端登录需要凭证最省事的方式是用长期访问令牌走的是标准的令牌认证机制。进 Home Assistant 网页后台点右上角个人头像进入个人资料页滚到最下面找到长期访问令牌区域点创建令牌起个能认出来的名字比如 itsyhome-iphone。创建完那一串字符只显示一次复制走关掉就再也看不到了。提示给每台设备单独创建令牌不要所有设备共用一个。以后哪台设备丢了或者不用了直接删对应令牌就能断掉访问不影响其他设备。令牌的管理建议用密码管理器存一份命名上带设备名和创建日期。我吃过亏——早期图省事用一个令牌跑所有客户端后来一台旧手机要处理掉只能把所有设备重新配一遍。3.3 服务端地址与端口的填写规则地址填写是最容易出错的一步。规则其实很简单局域网内访问填http://192.168.x.x:8123IP 换成你 HA 的实际地址如果配了域名和证书填https://ha.example.com端口不用写如果用了反向代理并改了路径前缀地址里要把路径带上不要填localhost或127.0.0.1那指的是客户端自己。自签名证书的情况要特别注意。客户端会对证书做校验自签名证书大概率被拒绝。可行的做法是局域网内先用 HTTP 把配置跑通确认功能正常再去折腾证书或者干脆把 HA 放进内网只在外网访问时走正规证书的域名两套地址分开配。3.4 首次连接与权限确认打开 Itsyhome第一次进入会要求填服务端地址和令牌。填完之后它会尝试建立两条连接REST 请求做一次握手验证WebSocket 建立状态订阅。这一步成功的标志是实体列表能拉出来。如果卡在这一步按下面的顺序排查不要瞎试用手机浏览器打开同样的地址能不能看到 HA 登录页。看不到就是网络问题跟客户端无关。浏览器能打开但客户端不行检查地址是不是漏了端口或者协议写成了 https 但服务端只有 http。地址没问题但提示认证失败回到 HA 个人资料页确认令牌是不是复制完整注意有没有把首尾的空格带进去。都正常但仍然报错去看 HA 的日志路径在配置目录下的home-assistant.log里面会有明确的拒绝原因。我遇到过最隐蔽的一次是路由器开了 AP 隔离手机和服务器在同一个 Wi-Fi 下却互相不可见。浏览器也打不开但当时我下意识以为是 HA 挂了折腾了快一个小时才发现是网络隔离。3.5 实体筛选与房间映射连接成功之后你会看到一个长长的实体列表。这时候不要急着全部加进来。HA 里的实体往往比实际设备多得多一个灯可能对应五六个实体开关、亮度、色温、场景、连接状态全加进来会让界面变成灾难。我的做法是先在 HA 里给实体做规范命名和区域分配这一步在服务端做完客户端就轻松了。命名规则我固定成区域 设备 功能三段式比如客厅 主灯 开关卧室 台灯 亮度。区域字段一定要填因为客户端通常会按区域自动分组你不填就全挤在未分配里。筛选的时候只保留真正会用手动控制的实体。传感器、诊断类实体、自动化辅助实体全部隐藏掉。判断标准很简单这个东西我一年会手动操作几次答案是零的就不要放主界面。3.6 HomeKit 桥接器的接入步骤如果还想让家人用苹果家庭 App或者想用 Siri 语音控制需要把 HA 里的设备桥接过去。HA 自带桥接功能在集成页面添加即可。关键配置有几个homekit: - name: 家庭桥接 port: 21063 filter: include_domains: - light - switch - cover - climate exclude_entities: - light.unused_strip entity_config: light.living_room_main: name: 客厅主灯filter一定要配。不配的话 HA 会尝试把所有实体都塞进桥接器苹果家庭 App 会被几百个设备淹掉配对过程也会慢得离谱。include_domains先按域白名单收窄再按需补充单个实体比一开始就全量再排除要省心。entity_config用来覆盖设备在家庭 App 里显示的名字。HA 里的技术命名和家庭 App 里给家人看的名字可以不一样这一层映射很有必要毕竟没人想在手机上看到light.living_room_main_2。配置改完记得重载桥接器不是重启整个 HA。重载之后会生成一个新的配对码在苹果家庭 App 里添加配件、扫码输入即可。注意桥接器在家庭 App 里表现为一个桥下面挂着所有设备。后期你如果新增了实体需要重新配对或者让桥接器重新发布部分设备可能会掉。频繁增删实体会让家庭 App 里的设备列表变得混乱建议一次性规划好再配对。4. 参数调优与性能细节配置跑通只是能用想用得舒服还得调。这一节讲几个我认为影响体验最大的参数和策略。4.1 状态刷新节奏推送优先轮询兜底原生客户端的状态更新有两条路WebSocket 推送和定时轮询。理想情况下全靠推送现实里长连接会断尤其手机切后台、Wi-Fi 切蜂窝、路由器重启这些场景。合理的策略是推送为主、轮询兜底。客户端在长连接断开时启动一个低频轮询比如 15 到 30 秒一次做补偿连接恢复后停掉轮询。这个节奏需要平衡两件事太密会持续耗电太疏会出现我明明关了灯界面上还亮着的错觉。我实测下来的经验值前台活跃状态下推送异常时的兜底轮询 10 秒一次比较合适切到后台后降到 30 秒或者直接停掉靠系统推送唤醒。手机端尤其要注意后台高频轮询是耗电大户一天下来能吃掉十几个点的电量。4.2 长连接保活的几个实际参数长连接不是建立之后就一劳永逸。中间的网络设备有超时机制空闲连接会被回收服务端也可能有会话超时。客户端需要做心跳。常见的配置思路是这样的心跳间隔 30 秒左右连续两次心跳无响应就判定连接失效触发重连并退避。退避要有上限不能 1 秒、2 秒、4 秒、8 秒一直翻倍到几小时一般封顶在 30 到 60 秒保证网络恢复后能较快重连上。重连的时候要注意顺序先做一次 REST 全量拉取同步状态再重新建立 WebSocket 订阅。如果反过来先订阅中间这段时间的状态变化会漏掉界面上就会显示旧数据。4.3 命名规范与分组策略这条看起来是软性建议实际对使用体验的影响比参数还大。我的命名规范是这样的区域在前设备名居中功能在后中间用空格分隔全中文不加任何编号和符号。比如客厅 主灯 开关而不是Light_LivingRoom_1。原因很实在语音控制对命名的敏感度极高Siri 和各大语音助手对下划线、数字、英文缩写的识别准确率都不如纯中文短句。分组策略我按三层走顶层是房间房间内是设备卡片卡片里才是具体功能。不要做成所有灯这种跨房间的扁平列表设备一多就完全没法用了。特殊情况可以做几个跨房间的场景按钮比如全屋关灯观影模式这些走场景入口不占设备列表。4.4 网络与证书的稳定性取舍局域网内的 HTTP 其实够用安全性在家庭内网环境下可以接受。真正需要 HTTPS 的是外网访问场景。如果你确实要从外面访问走正规域名加正规证书是最省事的别去折腾自签证书。自签证书在客户端上要么被拒要么需要额外做信任配置每台设备都要配一遍维护成本很高。而且证书到期忘了续全家的控制会同时失效那种体验相当糟糕。外网访问的具体方案这里不展开原则只有一条不要在公网直接暴露服务端口走正规的远程访问机制。5. 踩坑实录与排查速查表下面这些都是我实际遇到过的问题按出现频率排序附上排查思路。5.1 连接不上从网络到令牌的四步定位连接类问题占了所有求助的大多数但九成以上跟前三分钟就能排除的原因有关。第一步确认设备和服务端是否在同一网段。手机连的是 5G Wi-Fi服务器接的是有线如果路由器做了 AP 隔离或者划分了访客网络两者是互不可见的。判断方法很简单手机浏览器打开服务端地址打不开就是网络问题跟客户端无关。第二步确认协议和端口。写 http 却连的是 443 端口或者漏写了自定义端口都会导致握手失败。这一条看起来低级但实际发生的频率极高。第三步确认令牌有效。令牌是可以被单独撤销的装了新版本的 HA 之后有时候会导致旧令牌失效重新生成一个即可。第四步看日志。服务端日志里有明确的拒绝记录比在客户端上瞎猜快十倍。5.2 状态不同步与开关回弹这个问题的表现是点了一下开关界面上的状态先变了过一秒又弹回原样再等一秒才最终变成正确状态。原因在状态层的乐观更新机制。客户端为了让你点下去立刻有反馈会先把本地状态改掉乐观更新然后发请求给服务端等服务端返回真实状态再校正。如果服务端返回得慢或者推送和请求的返回顺序错乱就会出现回弹。排查思路先看服务端本身的响应速度HA 在设备多、集成多的情况下服务调用确实会慢这是根因。然后再看客户端是不是对同一个实体重复发起了请求。如果回弹幅度很小、很快就纠正属于正常现象如果一直来回跳那多半是同一实体被两个地方同时控制比如自动化脚本和手动操作打架。提示调试期间可以先把所有自动化临时关掉排除脚本干扰再逐个开回来。这个二分法排查自动化的效率比读脚本高得多。5.3 桥接器配对失败与设备消失桥接相关的坑集中在三个阶段配对、使用、更新。配对阶段最常见的失败是配对码过期。桥接器生成的配对码是临时的超过时间就失效需要重载桥接器重新生成。另一个常见原因是家庭 App 里已经存在同名的桥需要先删掉旧的再加新的。使用阶段的问题是设备突然从家庭 App 里消失。原因通常是 HA 重启后实体 ID 变了桥接器重新发布时对不上。避免的办法是给实体手动设置固定的唯一 ID别让系统自动生成。更新阶段最危险。HA 大版本升级后桥接器的配置格式可能有变化直接升级可能导致所有桥接设备失效。升级前的备份是硬性要求没有备份不要升。下面这张表可以贴在显示器边上出问题的时候按顺序对一遍。现象最可能原因处理方式客户端连不上浏览器能打开协议或端口写错核对地址格式补全端口浏览器也打不开网络隔离或服务未启动检查网段、AP 隔离、服务状态提示认证失败令牌复制不完整或已失效重新创建令牌注意首尾空格开关点下去弹回服务端响应慢或重复控制查自动化冲突优化服务端性能实体列表里有但界面没有实体被隐藏或未分配区域在服务端补充区域字段家庭 App 里设备消失实体 ID 变化手动固定唯一 ID重新配对配对码无效配对码超时重载桥接器生成新码控制延迟明显长连接断开走了兜底轮询检查心跳配置确认重连正常5.4 摄像头与媒体设备的特殊处理摄像头是整套系统里最容易出问题的设备类型。它涉及视频流解码、快照拉取、双向音频每一项对客户端的要求都不一样。原生客户端做摄像头有优势硬件解码效率高、延迟低。但要注意流格式的兼容性有些摄像头只提供特定编码格式的流客户端不支持就只能显示快照。配置的时候优先选支持标准协议的流地址别用厂商私有的加密流。媒体播放器同理。控制播放、暂停、音量这些走服务调用没问题但要在客户端内直接播放媒体内容涉及格式支持和版权保护实际能跑通的场景比想象中少。我的建议是控制归控制播放交给专业设备别指望一个家庭控制客户端把影音播放全包了。6. 长期维护备份、升级与多端一致性系统跑起来之后真正考验人的是半年后的一次升级。6.1 备份策略三个层次都要覆盖备份要分三层做缺一层都会在某次事故里让你后悔。第一层是 Home Assistant 的完整备份自带功能就能做建议设置成自动每周一次保留最近四份。备份文件要复制到另一台机器上别只存在同一块硬盘里。第二层是配置文件的手动版本管理。所有手写的 YAML 都放在一个目录里用 Git 管理每次改动提交一次。这一层能让你在升级后发现配置不兼容时快速对比出改了什么。第三层是客户端的配置记录。服务端地址、令牌名称、桥接器配置这些信息单独记一份文档手机丢了换手机的时候能快速恢复。6.2 升级顺序与回滚预案升级的顺序有讲究先升客户端再升服务端。理由是客户端通常向后兼容旧版本服务端但新版本服务端可能引入了客户端还不认识的字段或者行为变化。先升客户端可以保证连接始终可用。服务端升级前必做三件事确认备份已完成、确认备份能恢复、确认当前版本号记下来了。回滚靠的就是这个版本号加备份文件。大版本升级建议错开时间别在周末晚上做。真出问题的时候你需要有足够的时间和清醒的头脑去处理而不是家人在旁边问为什么灯打不开了。6.3 多端一致性的实际困扰同一个账号在手机、平板、桌面三端登录会碰到状态不同步的问题。比如在手机上把灯关了桌面菜单栏面板上还亮着。这不是 bug是多端各自维护本地状态的必然结果。解决思路是让所有端都订阅同一个状态推送通道任何一端发起操作后服务端会广播状态变化其他端收到后更新。理想情况下延迟在几百毫秒内。实际体验中桌面端常驻内存、连接稳定通常是最先更新的手机端因为后台限制可能延后几秒。如果你的使用习惯是多个端同时开着建议把不常用的端设为按需刷新不要常驻长连接减少状态冲突的概率。6.4 家人培训比技术更难的一关最后说一个非技术但最影响成败的点。系统搭得再好家人不会用等于零。我的做法是只给家人开放三个入口手机主屏幕上的房间快捷操作、语音控制、以及墙上的一个物理开关作为兜底。复杂的仪表盘、场景编辑、设备管理全部藏起来只在需要维护的时候自己打开。语音控制的设备命名一定要提前测一遍。有些名字在文字上很好念出来识别率极低。把常用设备的语音指令实际念二十遍能过就过过不了就改名重来。物理开关这条兜底看起来是技术退步实际是最重要的可靠性保障。网络会挂、服务器会重启、客户端会有 bug物理开关永远不会。任何一套智能家居方案只要没有物理兜底就不算合格。我个人折腾这套东西几年下来最大的体会是技术方案的选择远不如把手动操作路径缩短重要。一个能在锁屏界面一键完成的操作比十个功能强大但要点五下才能找到的自动化更有价值。Itsyhome 这类客户端真正解决的问题从来不是能不能控制而是控制这件事麻不麻烦。至于平台选 HomeKit 还是 Home Assistant我的答案一直是能力交给 Home Assistant手感交给原生客户端可靠性交给物理开关三样东西各司其职缺一样都会在某个深夜让你爬起来折腾。