← 返回信息流
AI 资讯Hacker News·4 小时前

我的主页有了脉搏

原标题:My Homepage Has a Pulse

速览

主页通过引入AI驱动的动态内容更新和交互机制,实现了类似生命体征的实时反馈。用户每次访问都能感受到页面的“脉搏”,即根据行为或数据自动变化的界面元素。这项技术提升了用户体验,使网站更具活力和个性化。

AI 深度解读

背景

一位名叫 Snehankekre 的开发者在他的个人主页上添加了一颗跳动的红色小爱心,旁边显示的数字是他真实的实时心率——每 48 bpm 就意味着每 1.25 秒跳动一次,80 bpm 则是每 0.75 秒一次。这个想法源于他想让自己的网站拥有一个比传统“在线状态”绿点更有人情味的指示器:不是告诉访客“他的浏览器开着连接”,而是“他还活着,这是证明”。他戴着 Garmin Descent Mk3i 潜水电脑表,这块表已经跟随他完成了超过 400 次潜水(包括 100 米深度的洞穴潜水),全天候追踪心率、睡眠、HRV、步数等数据,并同步到 Garmin Connect 应用。他想把这些数据“取出来”,放到自己的个人主页上。

核心内容

数据源的局限与探索

作者一开始想到,Twitch 主播们早已通过 Pulsoid、HypeRate 等服务将实时心率显示在直播画面上,这些服务都支持 Garmin 手表。原理是手表进入广播心率模式(Broadcast HR Mode),通过 BLE/ANT+ 将数据流式传输到手机 App,再由 App 转发到服务器。但这对作者来说行不通:广播模式会显著缩短电池续航,而这块手表是他的潜水电脑——在洞穴深达 75 米的地方,没电意味着生命危险。他不愿意为了一个网页小部件,让原本能用 10 天的表变成每晚充电。况且广播模式需要手动开启并保持范围内,太过麻烦。

他还尝试了 Web Bluetooth API,但该 API 只能连接访问者浏览器附近的设备,只在他自己的机器上、Chromium 浏览器里、且手表处于广播模式时才能工作,完全无法让远程访客看到。

接着他发现了 Garmin Health API,但访问权限需要企业申请和审核——它面向的是将可穿戴设备集成到产品中的公司,而不是“一个想在家页上放颗心的人”。这条路也封死了。

最终方案:每天一次批量抓取 + 回放

作者在 GitHub 和 Reddit 上找到两个项目:GarminDB(将全部历史数据下载到本地 SQLite 数据库)和 python-garminconnect(一个用 Python 调用 Garmin Connect 私有 API 的客户端)。后者更轻量,能直接获取手机上看到的所有数据(心率、运动、睡眠、HRV 等),恰好也解决了作者未来想公开更多生理数据(工作、睡眠、步数等)的计划。

然而,作者的网站是静态的,基于 Astro 构建,托管在 GitHub Pages 上,没有服务器维持 WebSocket。手表默认也不流式传输任何数据——心率数据累积在手腕上,只在手表与手机同步时批量上传到 Garmin 服务器。因此“实时”根本不可行。唯一的折中方案是:每天获取一次数据,然后回放前一天的记录。

具体实现:当你在某天的 14:32 加载页面时,看到的是作者前一天同一时间(14:32)的心率,由真实样本插值得到。页面上的“Live”标签是善意的“白色谎言”,但作者强调这个谎言很精确:偏移恰好 24 小时,数据真实,除了测量点之间用直线连接之外没有捏造。

认证与部署

python-garminconnect 通过邮箱和密码登录,返回一对 OAuth token:OAuth1 token 有效期约一年,OAuth2 token 有效期几小时。库自动用 OAuth1 刷新 OAuth2。作者只在本地笔记本上输入一次凭据,生成 token 后,将其序列化为一个 base64 字符串,作为 GitHub Actions 的 secret 保存。这样 CI 环境中只持有可自刷新一年的 token,凭据永远不会出现在构建流程中。

登录过程中还遇到了 Garmin 的 IP 速率限制(429 错误),即使切换 Mullvad VPN 服务器也被限制。库内置的多重登录策略中,前两个(mobile+cffi、mobile+requests)都被拒,最终第三个备选策略成功完成。

关键要点

  • 非实时设计:由于手表默认不流式传输心率、网站静态无 WebSocket,最终方案是每天获取一次前一天的完整心率数据,并在页面上回放——访客看到的是昨天同一时刻的心率。
  • 电池与安全优先:不牺牲潜水电脑的续航(不开启广播模式),不引入实时流式传输的复杂度和安全风险。
  • 隐私取舍明确:作者承认公开全天心率会泄露作息(入睡、醒来时间)、旅行(时区变化)、健康状况(静息心率波动)、精神状态(HRV 趋势)以及不在家的时间(健身房规律)。他经过深思熟虑后选择接受,并声明“如果你对此有意见,那是你的问题,不是我的”。
  • 技术栈:Garmin Descent Mk3i 手表 → Garmin Connect → python-garminconnect 客户端 → 本地 token 管理 → GitHub Actions 定时任务 → 静态站点更新。使用 OAuth token(一年有效)避免凭据暴露在 CI 中。
  • 解决方案的局限性:只能回放昨天数据,不是真正实时;但精度足够,偏移恰好 24 小时,数据真实。
  • API 限制的绕过:Garmin 官方 Health API 对个人开发者关闭,作者借助逆向工程的非官方 API(python-garminconnect)实现数据获取;同时遭遇 IP 限流,依靠库的 fallback 策略完成登录。

意义与影响

这个项目表面上是一个个人技术玩具,但背后触及了多个深层次议题:

  1. 重新定义“在线”状态:传统绿点只是连接状态的抽象符号,而心跳是“活着”的具象证明。作者将生理信号数字直接嵌入个人主页,创造了一种更亲密、更真实的网络存在标识,挑战了“在线”与“离线”的二元边界。

  2. 个人数据的主动公开与隐私权衡:作者故意选择公开敏感生理信息(心率、作息、健康状况),并坦诚面对隐私泄露的风险。这不同于被动被采集数据——他是在行使数据主权:明知泄露什么,依然选择开放。这种行为在数据隐私敏感的时代,为数字身份管理提供了新视角。

  3. 对 API 经济与可及性的讽刺:Garmin 明明存储着用户的完整生理记录,但除企业合作外不提供个人开发者接口。作者不得不依赖逆向工程的非官方库,这反映了可穿戴设备生态中“用户数据归平台所有”的普遍困境。类似案例(如 Fitbit、Apple Health)也常遇到——个人想用自己的数据做点小创造,却被商业 API 墙挡住。

  4. 技术上的创意妥协:在无法实现实时的前提下,用“回放昨天”的方案创造了“伪实时”体验,并通过精确说明(24 小时偏移、真实插值)保持诚实。这展示了静态网站 + 定时任务如何变通地实现动态感知功能,为其他希望整合个性化数据(如天气、健康、位置)的个人站点提供了参考模式。

  5. 社区协作的价值:作者依靠 GitHub 上的开源项目 (python-garminconnect, GarminDB) 和 Reddit 上的讨论找到了可行路径。即使在官方渠道受阻时,开发者社区通过逆向工程和共享工具,仍然能让个体实现大胆想法。这也反向推动 Garmin 等公司可能未来考虑开放更友好的个人数据 API。

查看原文 →snehankekre.com