<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Jiacheng]]></title><description><![CDATA[Jiacheng]]></description><link>https://blog.ajaxjiang.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 05 Jun 2026 21:54:09 GMT</lastBuildDate><atom:link href="https://blog.ajaxjiang.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Hearth 开发日记：一个智能家居中控的从 0 到 1]]></title><description><![CDATA[TL;DR
我用 Swift + SwiftUI 写了一个 iPad 智能家居中控 App，核心解决一个问题：比旋钮和语音更方便地控制灯光。这是一套完全基于个人需求、非常"自我"的实现，文章记录了从灵感诞生到踩坑落地的全过程。

起源：一面墙引发的思考
早在装修新家之前，我就盯上了 iPad 上墙这个「行为艺术」。
市面上的解决方案大多搭配小米平板控制米家设备。但作为多年果粉，我对 HomeKit 和 Matter 的大一统有种莫名的迷信，于是装修时选择了 Aqara 全屋 + Matter 单...]]></description><link>https://blog.ajaxjiang.com/hearth-dev-diary</link><guid isPermaLink="true">https://blog.ajaxjiang.com/hearth-dev-diary</guid><dc:creator><![CDATA[Jiacheng Jiang]]></dc:creator><pubDate>Mon, 02 Feb 2026 03:20:02 GMT</pubDate><content:encoded><![CDATA[<h1 id="heading-tldr">TL;DR</h1>
<p>我用 Swift + SwiftUI 写了一个 iPad 智能家居中控 App，核心解决一个问题：<strong>比旋钮和语音更方便地控制灯光</strong>。这是一套完全基于个人需求、非常"自我"的实现，文章记录了从灵感诞生到踩坑落地的全过程。</p>
<hr />
<h2 id="heading-6lw35rqq77ya5lia6z2i5akz5byv5yr55qe5ocd6icd">起源：一面墙引发的思考</h2>
<p>早在装修新家之前，我就盯上了 iPad 上墙这个「行为艺术」。</p>
<p>市面上的解决方案大多搭配小米平板控制米家设备。但作为多年果粉，我对 HomeKit 和 Matter 的大一统有种莫名的迷信，于是装修时选择了 <strong>Aqara 全屋 + Matter 单品</strong> 的方案——这也意味着我的上墙方案只能用 iPad。</p>
<p>我在客餐厅边上的墙体留了一处 86 底盒，从旁边的智能开关并联取电，给磁吸墙充供电，加上魔改磁吸壳，把一台闲置的 iPad Pro 改成了磁吸充电的形式。</p>
<p>装修入住后，一套「手扶拖拉机」般的方案诞生了：</p>
<ul>
<li>引导式访问把 Apple 家庭固定在主屏</li>
<li>隔壁 Aqara 面板的接近感应 + Matter 桥接，人靠近时给 iPad 上的 HA 发通知点亮屏幕</li>
<li>实现「我来 → 我开关灯 → 我离开」的简单逻辑</li>
</ul>
<p>但很快发现问题：<strong>绝大多数智能家居控制通过语音或自动化完成</strong>，真正需要靠近 iPad 操作的情况，用隔壁面板直接点按反而更方便。</p>
<p>如果需要整体调节客餐厅亮度，语音没那么方便，我会用 Aqara 旋钮 V1 加上预设好的灯组直接转动——但这个旋钮也有局限，比如进度 100% 时顺时针转没法改变灯光状态，需要先点按开灯再旋转（此处 @Aqara）。</p>
<h2 id="heading-vibe-coding">转折点：Vibe Coding</h2>
<p>入住半年后，转机出现——<strong>Vibe Coding</strong> 火了。</p>
<p>看着大量非专业开发者用 AI 把想法变成现实，我心里痒痒的。作为多年全栈开发，虽然没什么原生 iOS 经验，但抱着对 Swift 的憧憬，我敲下了第一行 Prompt。</p>
<h3 id="heading-5qc45bd5yqf6io9">核心功能</h3>
<p>开门见山，这个 App 就做三件事：</p>
<ol>
<li><strong>快速调节 Apple 家庭某一空间的亮度/温度/窗帘开合度</strong></li>
<li><strong>全天候显示日期时间</strong>（给 iPad 这类没有 AOD 的设备强行实现）</li>
<li><strong>绑定二元传感器实现人来亮屏</strong></li>
</ol>
<p>这款 App 是完全基于自身需求出发、非常「自我」的一套实现，希望能吸引到有相同需求、相同脑回路的智能家居玩家。</p>
<h2 id="heading-react-native">技术选型：为什么不用 React Native？</h2>
<p>很多人问：你跨平台经验那么丰富，为什么不用 RN？</p>
<p>答案很简单：<strong>HomeKit 仅支持 iOS</strong>，而且 HomeKit 相关的开源库年久失修。与其在跨平台框架里折腾原生桥接，不如直接上手 Swift。</p>
<p>最终选择 <strong>Swift + SwiftUI</strong>：</p>
<ul>
<li>上手快，AI 生成的代码我能直接阅读</li>
<li>SwiftUI 声明式 UI 接近我熟悉的 Flutter 经验</li>
<li>出于对开发效率和代码质量的考虑，选择了自己更能接受的技术栈</li>
</ul>
<p>AI 工具方面没有特别偏好：Cursor → Claude Code → Gemini，甚至 CodeX 和 OpenCode 都用过。</p>
<h2 id="heading-6lip5z2r6k6w5b2v">踩坑记录</h2>
<h3 id="heading-1-swift">1. Swift 版本地狱</h3>
<p>AI 大模型训练素材主要是开源大户，Swift 作为苹果闭源语言，知识储备明显不足。</p>
<p>典型例子：AI 不清楚我用的是 Swift 6 和 iOS 26，经常引用 deprecated 接口。最搞笑的是 Gemini 3 刚接入时，坚称我代码里的 iOS 26 是 typo，要给我改成 17。</p>
<p><strong>解决</strong>：在 agent 文档里写清楚版本约束，配合 Context7 这类 MCP 查询最新文档。</p>
<h3 id="heading-2-homekit">2. HomeKit 协议坑</h3>
<p>滑动调节房间亮度时，总有一组灯带不受控制。让 AI 单独 debug，它很容易把自己绕进去。</p>
<p>后来深入了解协议才知道：设备下面还分「服务」，对应物理设备上的「回路」。最早只把指令发到灯带上，实际只控制了每个驱动的第一个回路。应该下发到服务上才能实现预期效果。</p>
<p><strong>感悟</strong>：把原因描述清楚后，AI 很快就能修复问题。人类的领域知识仍然关键。</p>
<h3 id="heading-3">3. 手势交互的调试地狱</h3>
<p>这部分大概率受限于我的表达能力，AI 产出的结果总不能令我满意，微调起来也很麻烦，半人工半自动改了很久。</p>
<p>另外，最初本着 MVP 原则对数据结构做了很多简化，导致 Xcode 里的 Canvas 预览工具没能充分利用——几乎所有组件都直接依赖 HomeKit SDK，很难 mock。最后专门分了精力做依赖封装和抽象，才让关键组件的预览可以 mock 家庭实例。</p>
<h3 id="heading-4-swift-concurrency">4. Swift Concurrency</h3>
<p>对于之前 JS 经验为主的我来说十分陌生（上学学的早就生疏了），这里只能劝自己相信 AI，至少目前为止还没出严重问题。</p>
<h2 id="heading-app">App 里的小设计</h2>
<h3 id="heading-5lq65p2l5lqu5bgp">人来亮屏</h3>
<p>受很多大佬启发，原型是通过传感器触发点亮屏幕，在 App 里变成了直接监听指定传感器状态，除了传感器外没有其他第三方依赖。</p>
<h3 id="heading-5lqk5lqs">交互</h3>
<p>结合「人来亮屏」，只需抬手一划就能将空间内的灯开到想要的亮度，比旋钮更直观。</p>
<h3 id="heading-6ieq6ycc5bqu5asw6kec">自适应外观</h3>
<p>不同于传统的「暗黑模式跟随系统」，App 里有一个「自适应」选项，根据当前房间背景图片的「明度」自动选择明暗外观，确保文字可读性。</p>
<h3 id="heading-6k65ash44cb5oi6ze0562b6ycj">设备、房间筛选</h3>
<p>虽然希望一次操作控制所有灯，但难免有例外。用户可以在房间设置里取消勾选对应设备，或在制冷、制热季节分别勾选空调、地暖设备。</p>
<p>另外，针对卫生间、储藏间等琐碎空间，用户也可以选择隐藏。我自己就只在 App 里显示客餐厅、阳台、走廊这样的公区可调光空间。</p>
<h2 id="heading-5zcn5a2x55qe5pwf5lql">名字的故事</h2>
<p>App 最初叫「WallFlow」，是起项目时 AI 自己取的，主要因为早期 Prompt 过度强调了「上墙」属性。</p>
<p>经过多番深入交流，定了一个更贴切的名字 <strong>「Hearth」（壁炉）</strong>。考虑到中式家庭和很多现代家庭不再配置壁炉，就算有也是假的，希望这个 App 能像最早的壁炉一样给家庭带来温暖和便利。</p>
<p>中文名还没想好。</p>
<h2 id="heading-ai">AI 编程工具链总结</h2>
<h3 id="heading-cursor">Cursor</h3>
<p>最早用的 AI 编辑器，tab tab 的体验记忆犹新。后来出了 Agent 模式也用了一段时间。自动模式下处理文档还可以，实际上手开发时需要手动指定 Claude Sonnet 才有理想效果，去年订阅到期后没再续了。</p>
<h3 id="heading-claude-code">Claude Code</h3>
<p>一开始用 CC 加 Kimi-k2，后来发现 token 烧得挺快，转而订阅。目前用下来是当之无愧的王者，Claude 一直在引领 AI 编程的方向。</p>
<p>最大的问题是用量——5 小时限制卡得死死的，到了就得歇，要不就继续氪金，每周也有上限。开多个项目基本不够用，得开 5x。</p>
<h3 id="heading-codex-kimi-k2">CodeX + Kimi-k2</h3>
<p>早期跟风用来做 Code Review，确实发现了不少问题。后来更新后需要重新配置 API，懒得折腾，没再用了。</p>
<h3 id="heading-gemini-3">Gemini 3</h3>
<p>后起之秀，最近刚开了一年 Gemini Pro。目前体验非常好，但不太稳定，有时会陷入循环或报错。</p>
<p>好处是用量很慷慨，按天设上限，用完了还能回退到 Gemini 2.5 flash。此处继续吐槽 Claude Code 五小时上限简直反人类，经常激情编程时戛然而止。</p>
<h3 id="heading-speckit">SpecKit</h3>
<p>除了 AI 工具外，也用了一些其他工具确保产出可控，首当其冲的是 SpecKit。通过「宪章」确定项目基础（编程风格、技术选型等），减少 Code Smell。其次将每个功能模块以 Spec 形式定义，从需求描述到任务划分、验收标准，框死开发内容。</p>
<p>实际开发大型模块时有一定帮助，小改动反而浪费。目前被 Claude Code 的 plan 模式取代——先用 Opus 指定计划，再交给 Gemini 实现，是我现在比较接受的模式。</p>
<hr />
<p>从第一次接触 GitHub Copilot 和 Cursor，到现在 Agent 模式为主，AI 编程已经发生巨大变化。相信再过几个月，我的工作模式又会大相径庭，就像现在的 Vibe Coding 之于之前的 Tab Tab。</p>
<p>这个项目还有大量手动干预，一方面是在熟悉 Vibe Coding 流程，另一方面也是想借此机会上手憧憬已久的 Swift。基于这个体验，后续可能还是会走向更激进的 AI 编程之路。</p>
]]></content:encoded></item></channel></rss>