摘要: 过去十年里,我一直在为自家打造一套理想的家庭仪表盘系统,取名 Timeframe。它把日历、天气和智能家居数据整合在一起,已成为我们日常生活中很重要的一部分。
参见 https://news.ycombinator.com/item?id=47113728 了解这篇文章的热烈讨论。

十年前我和 Caitlin 结婚时,我们就希望在家里和科技保持一种健康的关系。卧室里不放任何屏幕,设备都在别处过夜充电。但我们又很想用日历和天气应用。
于是我开始动手解决这个问题。首先,我用一个现成的药柜和去掉边框的 LCD 屏做了一面 Magic Mirror,用来显示我们需要的日历和天气:

但文字很难看清,尤其在科罗拉多白天自然光很强的时候。到了晚上,它又像任何背光屏一样发亮,在生活空间里很扎眼。
之后我花了大约一年时间折腾各种越狱的 Kindle,最后定下一套方案:用两块屏显示日历和天气。Kindle 刷新要几秒钟,还要闪屏重置墨水屏,所以只能每半小时更新一次。我为它们设计了木壳,在本地图书馆创客空间用激光切割出来:

软件方面,我写了一个 Ruby on Rails 应用,从 Google Calendar 和 Dark Sky 拉数据。Kindle 按计划唤醒,打开应用里的一个 URL,由 IMGKit 渲染成 PNG。这个原型证明电子纸是正确方向:在什么光线下都不刺眼:

Kindle 毕竟是 hack,得经常维护才能用。是时候找更稳定的方案了。我试过 OLED 屏,看没有全局背光会不会好一点,结果和 Magic Mirror 差不多:

所以还是回到电子纸。我找到了 Visionect 的显示系统,有 6 寸/10 寸/13 寸/32 寸,充一次电能每十分钟更新一次,撑 2~3 个月:

32 寸用的是老一代低对比度面板,分辨率也偏低,文字不够顺滑。小尺寸用的是高对比、高 PPI 面板。最后我在家里混用了几款:玄关放 6 寸看天气,厨房冰箱侧面用带磁吸背板的 13 寸,卧室放 10 寸。

Visionect 需要跑他们自家的闭源软件,可以是 SaaS 或本地 Docker。我选在已经跑 Rails 后端的树莓派上本地部署。效果最好的是用定时任务每五分钟推送一次图片到 Visionect:用 IMGKit 生成 PNG 再通过 Visionect API 发送,这部分逻辑我抽成了 visionect-ruby。这套配置非常稳定,连续几个月没出过问题。
来做客的朋友常问能不能在自己家也搞一套。最初原型做完三年后,我和一位潜在客户做了第一次市场测试。应对方要求,我试了不同布局,包括在 13 寸屏上做月视图:

可惜对方觉得 13 寸设备 1000 美元(2019 年!)都不值,更别说我还想收订阅费。差不多同时,Visionect 开始对在本地用 Docker 跑他们后端收费,每设备每月 7 美元,而之前多年都是免费的。光一块屏我就得收每月 10 美元甚至更多!
2021 年底,Marshall 大火烧毁了我们家以及约一千户人家。房屋保险给了我们两年重建期,于是我们从头设计新家:

差不多那时,Boox 发布了 25.3 寸 Mira Pro,第一款高分辨率大尺寸电子纸屏。更重要的是,它能实时更新!和 Visionect 不同,它就是一块带 HDMI 的显示器,需要接电。用一台旧 Mac Mini 做了个简单原型,立刻能看出能力上了一大截,大屏可以展示更多信息:

但最吸引人的是可以实时更新。我加上了时钟、Sonos 当前播放(用 jishi/node-sonos-http-api)以及 Dark Sky 未来一小时的降水预报:

这个能用的原型足以让我在新家里给它留位置。我们在主层设计了一个「电话角」,给这块屏配了画灯:

我们还为另外两块 13 寸 Visionect 预留了电源:一块在卧室,一块在车库门旁:

Mira Pro 的实时需求立刻把后端的性能和复杂度问题暴露出来,逼得我几乎重写了一遍。
Visionect 那套几秒响应没问题,但改成每两秒长轮询后,响应就不能再慢了。首先我不再生成图片。Visionect 那边增加了在后端直接渲染 URL 的能力,把资源腾出来处理长轮询。
更重要的是,我开始把 Home Assistant(HA)当作主要数据源。HA 已经接好了 Google Calendar、Dark Sky(现 Apple Weather)和 Sonos,让我能删掉 Timeframe 里一半以上的代码。我还在 Home Assistant 提了一个 PR 以支持我需要的日历行为,要让它成为唯一数据源可能还得再提几个。
数据拉取逻辑少了之后,我从 Rails 应用里移除了数据库和 Redis,复杂度大降。现在用 Rufus Scheduler 跑定时任务,用 Rails 的文件存储缓存后端存拉取结果。
除了取数,我还尽量把业务逻辑迁到 Home Assistant。现在只要传感器名以 sensor.timeframe 开头,就会自动显示其状态,格式是简单的 图标,标签 CSV。
比如前几天我想在晚上 8 点后如果洗碗机没在运行就提醒启动或预约。用插座功率写个模板传感器,一分钟搞定:
{% if states('sensor.kitchen_dishwasher_switched_outlet_power')|float < 2 and now().hour > 19 %}
utensils,Run the dishwasher!
{% endif %}
加上这个助手后的一个月里,它提醒了我两次,否则我会忘。而且不用改代码、不用部署。
搬进新家后,我们更依赖实时能力。实际上,我们把每块屏左上角当成了整栋房子的状态区。比如显示哪些门没关/没锁:
或者洗衣是否完成:

有一个很关键的设计:如果显示上的状态区是空的,就表示房子处于「健康」状态,不需要任何关注。这种「只显示当前时刻有用信息」的做法,和多数智能家居展示状态的方式正好相反:

单一状态区不用扫整屏。能做到这一点,是因为我们把设备的控制和状态展示分开了。

这个项目一直有很多人感兴趣,我也在认真考虑推向市场。还有几件事要解决:
虽然在优雅处理运行时错误上已经做了不少,但要做成几乎不用维护的嵌入式系统,还有很多要学。
目前仍有几个数据源是绕过 Home Assistant 直接拉的。等 HA 成为唯一数据源,就可以把 Timeframe 做成 Home Assistant 应用,分发会简单很多。
当前硬件对普通用户还不友好。25 寸 Boox 屏很好,但约 2000 美元!而且不包含驱动显示的主机。有一些可能方向,比如 Boox 和 Philips 的安卓设备,或 TRMNL 等低成本方案。
做 Timeframe 一直是我很投入的事。白天的工作是给上亿人做软件,能有一个项目实实在在地改善自家日常生活,感觉很不一样。