背景
2019 年我写过一篇《家用功率监控》。那时的目标很简单:把电表接进监控系统,看看家里每天用了多少电,顺便观察空调、微波炉这些设备的功率曲线。
当时还在文章里留了一个坑:
加上点人工智能做智能家居。
几年过去,人工智能已经真的能帮我写代码了,这个坑也终于有机会继续往下填。
这一次,我不只想看总功率。手机里的个人健康指标、通知形成的生活事件、全屋不同回路的电量、冰箱和热水器的运行状态,都带着时间戳。如果能把这些分散的信号放进同一条时间线,就不只能回答“现在用了多少电”,还可以尝试回答:
- 哪个回路刚刚出现了负载变化;
- 可能是哪类电器启动或停止;
- 一次洗漱、做饭或出行,由哪些事件共同组成;
- 每天大概几点出门、路上花费多久,哪个时间段通勤更快;
- 运动、睡眠、心情和动态健康指标之间有没有值得继续观察的关联。
于是有了 HomePulse。它不是一套买来即用的智能家居产品,更像是我给家里搭的一套小型数据基础设施。
先看整体架构

这套系统目前分成四层:
- 数据来源:手机、家庭电表、智能家电和其他本地设备;
- 采集与接入:Webhook 接收器、本地设备桥接和 MQTT 消息总线;
- 存储与处理:GreptimeDB 保存原始事件、标准化指标和推断结果;
- 使用数据:Grafana 负责分析与展示,Home Assistant 负责设备状态和自动化控制。
底层运行在家里的虚拟化环境中。应用服务集中使用 Docker Compose 编排,时序数据库独立运行。这样做并不是为了把 Homelab 设计得像一个小型企业机房,而是为了把两个不同的生命周期拆开:采集程序可以频繁修改和发布,数据库则尽量稳定地保存历史。
两条数据进入路径
HomePulse 的数据大致通过两条路径进入系统。
第一条是手机侧的 HTTPS Webhook。手机上的自动化工具定期发送个人健康指标或通知事件,请求先经过安全隧道进入家庭网络,再由接收器完成鉴权、格式检查、时间统一和字段清洗。
第二条是家庭局域网里的 MQTT。电表和智能家电的协议各不相同,本地桥接服务负责和设备通信,再把状态转换成统一的 MQTT Topic。后面的采集程序不需要理解每台家电的私有协议,只需要订阅消息并写入数据库。
这两条路径最后汇合到 GreptimeDB。它们的数据形态不完全一样:
- 功率、温度、设备状态属于连续变化的时序指标;
- 通知、刷卡、来电和设备开关属于离散事件;
- 设备、回路和电器之间的关系属于变化较慢的元数据;
- “某类负载可能刚刚启动”属于算法生成的推断事件。
我没有急着把所有内容揉成一张万能表,而是同时保留原始记录和清洗后的结构化数据。解析规则以后发生变化时,原始事件还可以重新处理;Grafana 则优先查询结构化结果,不必在每个面板里重复清洗文本。
电量不只是画一条曲线
最早的电量监控只有一条全屋总功率曲线。现在强电箱里不同回路已经可以分别采集,因此能够把“家里用了多少电”进一步拆成“电用在了哪里”。
这里有一个容易踩的坑:其中一路是总进线,其他路是分支回路。做统计时不能把十路直接相加,否则总进线会被重复计算。更有意义的看法是把总进线与各分支之和放在一起:
- 两者接近,说明主要回路已经被覆盖;
- 差值长期偏大,可能还有未采集回路、测量误差或设备映射不完整;
- 某个分支突然出现阶跃,可以成为识别电器动作的候选事件。
单看某一时刻的功率,很难判断是什么设备。更可靠的特征包括功率增量、持续时间、周期、波动方式,以及其他设备在相近时间内是否也发生了变化。
例如,照明通常是较稳定的小功率阶跃;压缩机设备会周期性启停;水泵往往持续时间较短,并和用水事件相关;变频空调则会经历启动、爬升和动态调节。HomePulse 会先把这些变化记录成候选事件,再结合人工标注逐步形成负载画像。
所以这里的“人工智能”并不是一上来就训练一个神奇模型,而是先把数据、事件和反馈链路搭好。每次我告诉系统“刚才是洗漱”“刚才打开了某个设备”,都可以沉淀成一条训练样本。规则、统计模型甚至更复杂的算法,都可以在这套数据基础上逐步迭代。
从设备数据到生活事件
只有电量时,很多推断都只能是猜测。接入家电状态后,事件之间开始可以互相验证。
例如某个回路出现短时功率变化,如果同时观察到热水器进入工作状态,就比单纯依赖功率形状更可信。如果用水设备启动、照明变化和热水器状态在短时间内连续发生,它们还可能共同描述一次完整的生活场景。
通知数据也有类似价值。通知正文并不适合直接展示或长期扩散,因此接收器会尽量提取“事件发生了”以及必要的结构化字段。对于出行类事件,可以把前后两次记录关联成一段行程;对于电话类事件,可以统计发生时间、持续状态和处理结果,而不在看板上暴露号码或正文。
这样,HomePulse 里的数据不再只是互不相干的曲线,而是可以沿着时间轴相互解释:
设备状态变化
+ 回路功率变化
+ 手机侧生活事件
+ 人工场景标注
↓
一段可解释的家庭活动
这套系统在生活里能回答什么
把数据接进来只是第一步。对我来说,更重要的是它最后能不能回答一些具体、朴素,而且和每天生活有关的问题。
每天几点出门,路上花了多久
交通卡通知里通常会分别出现进站和出站记录。接收器把前后两条记录配成一段行程后,就能得到进站站点、出站站点、进站刷卡时间、出站刷卡时间和本次花费。
严格来说,进站刷卡时间并不等于走出家门的时间,所以 Dashboard 会把它叫作“进站时间”或“开始通勤时间”,而不是假装它是一个精确的出门时间。如果再结合家中最后一次活动、手机离开家庭网络等信号,才可以估算从家里出门的时间。估算值和原始事实要分开存储,也要在图表中明确标记。
有了连续几周的数据以后,可以把工作日按半小时或十五分钟分组,比较不同出发时段的通勤耗时:
进站刷卡时间 → 匹配出站记录 → 计算实际行程时长
↓
按星期和出发时间分组
↓
比较中位数、波动范围和异常天数
这里用中位数往往比平均数更有意义,因为偶尔的线路故障、临时绕行或漏刷会把平均数拉得很远。最终 Dashboard 可以回答“我通常几点开始通勤”“这个时间段一般要多久”以及“提前十五分钟是否真的更省时间”。
如果再接入公开的地铁时刻表,还可以估算从刷卡到列车到站之间的理论等待时间。但它只能是推算,因为刷卡记录并不知道我实际坐上了哪一班车,进站后的步行和换乘时间也因人而异。系统应该同时显示“实际刷卡行程时长”和“根据时刻表估算的等待时间”,不能把两者混成一个看似精确的数字。
动态血糖与运动之间的关系
动态血糖仪产生的是一条连续曲线,手机和手表则记录步数、锻炼类型、开始时间、持续时间和活动强度。两类数据对齐后,可以围绕一次运动观察多个时间窗口:
- 运动开始前一段时间的基线;
- 运动期间曲线的变化;
- 运动结束后半小时、一小时和更长时间的变化;
- 不同运动类型、时长和强度下的差异;
- 日步数、久坐时间与当天整体波动的关系。
这种分析真正有价值的地方,不是简单得出“运动越多越好”这样的结论,而是观察同一个人在相似条件下的长期规律。例如晚饭后散步是否经常对应更平缓的后续曲线,某种强度的运动是否会带来不同反应,以及这种关系在睡眠不足或生活节奏变化时是否仍然存在。
运动只是影响因素之一,饮食、药物、压力、睡眠和测量误差都会同时作用。因此这些 Dashboard 只能帮助记录和提出问题,不能替代医生建议,也不应该把一次相关性当成因果关系。
心情与睡眠之间的关系
苹果健康可以记录每天的心情或心理状态,智能手表则会产生睡眠时长、入睡和醒来时间、夜间清醒次数以及睡眠阶段等数据。它们放到同一条时间线上后,可以观察:
- 睡眠偏短的第二天,心情记录是否更容易偏低;
- 入睡时间变化和第二天主观状态是否有关;
- 夜间频繁醒来后,第二天活动量是否下降;
- 运动较多的日子,当晚睡眠和次日心情是否有变化;
- 工作日与周末的作息差异。
心情记录是主观的,而且一天可能只有一个样本,不适合画成精确的连续曲线。我更倾向于用周粒度趋势、分组箱线图或“睡眠区间对应的心情分布”来展示,并设置最小样本量。这样看到的是长期倾向,不会因为某一天的偶然情况就得出过度结论。
家庭动作如何变成生活场景
生活场景的识别也遵循同样思路:先保留事实,再逐步增加推断。
例如一次洗漱可能先出现卫生间照明和换气的功率变化,随后热水器进入工作状态,增压泵出现短时负载;冲水时水泵可能再次启动。单独看任何一个信号都不够确定,但几个事件在短时间内按照稳定顺序发生,就形成了一个更可信的场景候选。
做饭、空调启停、冰箱压缩机工作和夜间待机也可以采用相同的方法。系统先自动给出候选结果,我再通过一个简单接口确认或纠正。长期积累后,规则会逐渐从“某一路增加了多少瓦”变成“哪个设备在什么上下文中做了什么”。
这也是统一时间线最直接的价值:我不必强迫每种数据自己解释全部生活,而是让多个并不完美的信号互相印证。
Grafana 与 Home Assistant 各做什么
这两个工具看起来都能“做看板”,但在这套系统里职责不同。
Grafana 面向历史分析。它适合回答过去六小时、一天或一个月发生了什么,例如回路功率趋势、家电工作周期、通勤时间分布,以及个人健康指标的长期变化。
Home Assistant 更接近实时状态和自动化。它通过 MQTT 获得设备当前状态,并在满足条件时触发通知或控制动作。例如某个设备状态异常时提醒,或者在明确的安全条件下调用本地控制接口。
我的原则是:分析链路可以大胆试验,控制链路必须保守。控制接口默认只在家庭网络内使用,命令要有明确白名单、参数范围和审计记录。一个错误的 Dashboard 最多画错图,一个错误的控制动作可能真的影响家里的设备。
公网接入与隐私边界
手机要在家庭网络之外持续发送数据,就需要一个稳定的公网入口。我使用安全隧道只暴露少量 Webhook 路径,家庭网络不需要直接开放入站端口。
隧道解决的是网络可达性,不等于业务鉴权。手机自动上传无法使用交互式登录页,因此接收器仍然需要独立鉴权、请求大小限制、格式校验和日志脱敏。
更重要的是,家庭数据天然带有很强的隐私属性。公开这套系统时,我会遵循几个边界:
- 不公开任何内网或公网地址;
- 不公开账号、密钥、鉴权信息和设备凭据;
- 不展示通知正文、号码、精确行程和生活时间点;
- 可以介绍动态血糖、运动、睡眠和心情等分析方法,但不公开具体数值、诊断信息和个人时间点;
- 架构图只表达组件关系,不表达真实资产清单。
技术文章可以讲清楚方法,但没有必要用真实隐私来证明系统确实在运行。
为什么不用一个大程序全部完成
HomePulse 现在已经包含多个小服务:健康数据接收、通知接收、MQTT 入库、电量事件识别、本地设备桥接和设备控制。
把它们写进一个进程看起来省事,但不同数据源的变化速度和故障方式完全不同。手机上传格式变化,不应该影响电量采集;某个家电暂时离线,也不应该阻塞其他数据入库。
所以我更喜欢小服务加统一协议:
- HTTPS Webhook 负责外部设备上传;
- MQTT 负责家庭局域网内的状态和命令;
- GreptimeDB 负责统一时间线;
- Grafana 负责观察和分析;
- Home Assistant 负责实时实体与自动化;
- Docker Compose 负责把应用作为一个整体部署。
它还远远算不上完美架构,但每一层的职责已经比较清楚。以后增加空气质量、环境传感器或新的智能家电时,不需要重新改造整个系统。
当前成果与下一步
目前这套系统已经能够持续接收多类家庭数据,并形成电量、家电、通知、通勤、动态健康指标、运动和睡眠等不同视角的 Dashboard。更有意思的是,原本分散的几个小项目开始变成同一套数据系统:本地设备负责产生信号,采集层负责保留事实,推断层尝试理解发生了什么。
下一步准备继续做几件事:
- 完善回路与电器的元数据,让 Dashboard 使用人类可读的名称;
- 持续标注生活场景,积累可以验证的负载样本;
- 完善进出站配对与出门时间估算,比较不同出发时段的通勤成本;
- 建立运动、睡眠、心情与动态健康指标的关联分析,并标注样本量和置信边界;
- 将更多本地设备接入 MQTT 与 Home Assistant;
- 为数据质量、采集延迟和设备离线补充可观测性;
- 把配置、Dashboard 和部署过程继续代码化。
2019 年我想知道“家里整体功耗是多少”。现在我更想知道“这些信号合在一起,能不能描述一个家的节奏”。
HomePulse 还在很早期,但那个写了七年的 Todo,总算不是一句空话了。