1. 项目概述将你的Garmin健康数据变成AI可读的笔记如果你和我一样是个对量化自我Quantified Self有点上瘾的人每天醒来第一件事就是看手表上的睡眠分数和身体电量那么你肯定也想过这些宝贵的数据除了躺在Garmin Connect的App里还能干点啥能不能让我的AI助手也“知道”我昨晚睡得怎么样今天跑了多少公里从而在对话中给我更个性化的建议这正是freakyflow/garminskill这个项目要解决的核心问题。简单来说这是一个为OpenClaw一个新兴的AI Agent平台开发的技能Skill。它的工作流程非常清晰像一个勤劳的搬运工每天定时登录你的Garmin Connect账户把你所有的健康与运动数据——从睡眠阶段到跑步配速从压力水平到最大摄氧量——统统抓取下来然后整理成结构清晰、人类和机器都能轻松阅读的Markdown文件。这样一来OpenClaw就能在与你聊天时随时引用这些数据实现真正基于你个人状态的智能交互。比如你可以问它“根据我过去一周的睡眠数据建议我今天进行高强度训练还是恢复性训练” 它不再需要你手动输入一堆数字而是直接“看”到了你的健康笔记。这个项目完美地踩在了几个趋势的交汇点上AI Agent的个性化能力、健康数据的价值挖掘以及开源工具的自动化魅力。它不是为了替代Garmin Connect而是为其数据打通了一条流向更智能应用场景的“高速公路”。接下来我会带你从零开始完整部署并使用这个技能并分享我在这个过程中趟过的坑和总结的经验。2. 核心思路与技术选型解析在动手之前我们先拆解一下这个项目的设计哲学和技术栈。理解“为什么这么做”能让你在遇到问题时更快地定位和解决。2.1 为什么选择Markdown作为数据载体你可能会问为什么不是JSON、CSV或者直接存数据库项目作者选择Markdown我认为是深思熟虑后的结果主要基于以下几点人类可读与机器可读的平衡Markdown文件本身是纯文本你用任何编辑器都能打开直观看到“睡眠8小时39分评分85”这样的信息。同时其简单的标题##和列表-结构又非常易于程序如OpenClaw进行解析。它兼顾了数据存储和直接查阅的双重需求。低耦合与可移植性生成独立的.md文件意味着数据不依赖于某个特定的数据库或服务。你可以轻松地将这些文件备份、同步到网盘或用其他脚本进行二次处理比如生成周报、月报图表。这种“文件即接口”的设计极大地提升了项目的灵活性。对AI Agent友好当前的大语言模型LLM在处理结构化的自然语言文本方面表现优异。Markdown格式的标题和段落能很好地提示AI理解数据的层次和语义。比起让AI直接解析Garmin复杂的API原始JSON响应让AI阅读整理好的Markdown摘要准确率和效率都会高得多。2.2 技术栈深度剖析uv, garminconnect 与 cloudscraper项目的技术选型非常“现代”且务实几乎没有冗余。uv 作为 Python 项目管理器这是近两年冉冉升起的新星由 Astral 团队也是 Ruff 的创造者开发。它集成了虚拟环境管理、依赖解析、包安装和脚本运行于一身速度极快。项目选择uv而非传统的pipvenv意味着更简洁的依赖管理依赖直接内联在pyproject.toml中和更快的启动速度这对于需要定时运行的脚本来说是个巨大优势。garminconnect 库这是与Garmin服务器通信的核心。它是一个非官方的Python客户端库通过模拟浏览器行为来登录和获取数据。需要明确的是由于Garmin没有公开官方的、完善的API尤其是针对个人健康数据的所有类似的第三方工具都存在因Garmin更新其网页结构或反爬机制而失效的风险。这个库是社区维护的其稳定性是整个项目的最大潜在风险点。cloudscraper 库这是应对Garmin登录挑战的关键。Garmin的登录页面使用了Cloudflare的反爬虫保护。cloudscraper是一个专门用于绕过Cloudflare挑战的库它可以解析JavaScript挑战并返回有效的会话。没有它自动化登录几乎不可能成功。它的存在也印证了与Garmin交互的“非官方”和“脆弱”特性。2.3 认证策略一次设置长期无忧项目的认证设计非常巧妙充分考虑了安全性和便利性分离的“设置”与“同步”阶段通过--setup参数触发初始认证。在这个阶段你需要输入邮箱和密码。关键点在于密码是通过Python的getpass模块交互式输入的这意味着密码不会显示在屏幕上也不会被保存在终端历史记录中大大提升了安全性。令牌缓存机制成功登录后脚本会从Garmin获取OAuth令牌Token并将其缓存在用户主目录下的~/.garminconnect/文件夹中。这些令牌的有效期长达约一年。此后日常的同步操作完全使用缓存的令牌无需再次输入密码。这既安全又方便非常适合配置到cron定时任务中。自动令牌刷新当旧的OAuth1令牌即将过期时库内部会自动尝试将其交换为新的OAuth2令牌。这个过程不需要用户干预只要初始认证成功在令牌有效期内同步流程可以完全自动化运行。注意正因为依赖令牌缓存所以你必须确保运行脚本的机器或服务器上的~/.garminconnect/目录是安全且持久的。如果你在Docker容器或无状态环境中运行需要额外考虑如何持久化这个令牌文件。3. 从零开始的完整部署与配置指南理论说得再多不如动手做一遍。下面我将以一台干净的Linux系统Ubuntu 22.04为例展示从环境准备到每日自动同步的全过程。macOS和WSL下的步骤几乎完全相同。3.1 基础环境准备与项目获取首先我们需要确保系统有合适的Python版本并安装项目核心依赖uv。# 更新系统包列表 sudo apt update # 安装 Python 3.10 或更高版本Ubuntu 22.04 默认是3.10 sudo apt install python3 python3-pip -y # 安装 uv这是项目指定的依赖管理工具 curl -LsSf https://astral.sh/uv/install.sh | sh安装完成后需要将uv添加到当前shell的PATH中。根据安装脚本的提示通常需要重新打开终端或者执行source $HOME/.cargo/env如果uv通过rustup安装。你可以通过运行uv --version来验证安装是否成功。接下来获取项目代码。由于这是一个开源技能我们可以直接从GitHub克隆。# 克隆项目仓库到本地假设我们放在 ~/projects 目录下 mkdir -p ~/projects cd ~/projects git clone https://github.com/freakyflow/garminskill.git cd garminskill此时项目目录结构大致如下garminskill/ ├── scripts/ │ └── sync_garmin.py # 核心同步脚本 ├── pyproject.toml # 项目依赖定义uv直接读取这个文件 └── README.mduv的强大之处在于你不需要手动执行pip install -r requirements.txt。它的所有依赖都内联在pyproject.toml中运行脚本时会自动处理。3.2 关键一步Garmin账户准备与初始认证这是整个流程中唯一需要手动交互且最容易出错的一步。请严格按照以下步骤操作。第一步禁用Garmin账户的两步验证2FA这是硬性要求。因为garminconnect库目前不支持处理2FA的验证码如短信、Authenticator App。你需要暂时关闭它。在电脑浏览器上登录 connect.garmin.com 。点击右上角头像进入“账户设置”。选择“安全”选项卡。找到“两步验证”或“Two-Step Verification”将其状态切换为“禁用”。重要提醒在公开或不信任的服务器上运行此脚本时禁用2FA会降低账户安全性。请确保你只在受控的私人环境中运行此脚本并在脚本稳定运行后根据个人情况权衡是否重新开启2FA。或者更好的做法是使用一个专门为数据同步创建的、不包含支付信息等敏感数据的Garmin子账户如果支持的话。第二步执行一次性设置命令在项目根目录下运行以下命令。请将youexample.com替换为你真实的Garmin账户邮箱。uv run scripts/sync_garmin.py --setup --email youexample.com执行后脚本会停顿等待你在终端输入密码。getpass模块会让这个输入过程不可见不会显示*号光标也不会移动这是正常的。直接输入密码后按回车即可。可能的输出与问题排查成功你会看到类似Login successful! Tokens cached.的信息并在~/.garminconnect/目录下生成缓存文件。失败 - “No profile from connectapi”这是最常见的错误。它不一定代表密码错误更多时候是Garmin服务器端的临时限制或Cloudflare拦截。首先等待2-5分钟再重试。这通常能解决。仔细检查密码是否正确注意大小写。尝试在浏览器中登录Garmin Connect确保账户本身状态正常没有被锁定。失败 - Cloudflare挑战如果脚本卡住或报错提及Cloudflare说明cloudscraper未能成功绕过。可以尝试更新依赖虽然uv会自动处理或者等待一段时间后重试因为Garmin的反爬策略可能正在更新。3.3 首次数据同步测试设置成功后就可以进行第一次数据同步了。默认情况下脚本会同步“今天”的数据。# 同步今天的数据 uv run scripts/sync_garmin.py如果一切顺利你会在当前目录下看到一个名为health/的新文件夹里面有一个以今天日期命名的Markdown文件例如health/2025-01-26.md。用文本编辑器打开它你应该能看到如项目介绍中那样格式工整的健康数据摘要。你可以尝试同步其他日期的数据以验证功能# 同步昨天数据 uv run scripts/sync_garmin.py --date $(date -d yesterday %Y-%m-%d) # 同步过去7天数据 uv run scripts/sync_garmin.py --days 7 # 指定输出目录 uv run scripts/sync_garmin.py --output-dir /path/to/my_health_journal3.4 安装为OpenClaw技能如果你已经在使用OpenClaw可以将其链接到OpenClaw的技能目录以便在AI对话中调用。# 假设你的OpenClaw技能目录是默认的 ~/.openclaw/skills/ # 创建一个符号链接 ln -s $(pwd) ~/.openclaw/skills/garmin-connect链接后理论上OpenClaw就能感知到这个技能。具体的调用方式取决于OpenClaw的设计可能需要你在与AI对话时通过特定指令触发或者AI会自动在需要健康数据上下文时读取指定目录下的Markdown文件。你需要查阅OpenClaw的文档来确认具体集成方式。4. 实现自动化配置定时同步任务数据的价值在于持续和及时。手动运行脚本显然不现实我们需要让它自动运行。这里提供两种主流方法传统的Linuxcron和 OpenClaw 内置的定时工具。4.1 使用系统Cron推荐更通用cron是Linux/macOS系统上最经典的定时任务工具。我们的目标是让脚本每天早晨自动同步前一天的数据。编辑当前用户的cron表crontab -e如果是第一次使用可能会让你选择编辑器推荐选择nano或vim。添加定时任务 在打开的文件末尾添加一行。以下例子设定每天上午7点整执行同步脚本。# 分 时 日 月 周 命令 0 7 * * * cd /home/yourusername/projects/garminskill /home/yourusername/.cargo/bin/uv run scripts/sync_garmin.py /tmp/garmin_sync.log 21cd /path/to/garminskill确保在项目目录下执行路径依赖正确。/home/yourusername/.cargo/bin/uv这里是uv的绝对路径。你可以通过which uv命令来获取你的实际路径。 /tmp/garmin_sync.log 21将脚本的标准输出和错误输出都重定向到一个日志文件中方便日后排查问题。你可以将其更改为更永久的路径如~/garmin_sync.log。保存并退出在nano中是CtrlX然后按Y确认再回车。验证cron任务crontab -l这会列出你设置的所有cron任务检查是否正确添加。4.2 使用OpenClaw的Cron工具如果OpenClaw提供了内置的定时任务管理功能并且你希望将所有自动化逻辑都集中在OpenClaw生态内这也是一个选择。具体命令可能类似于# 假设OpenClaw提供了类似下面的命令来添加定时任务 openclaw cron add --name sync_garmin --schedule 0 7 * * * --command cd /path/to/garminskill uv run scripts/sync_garmin.py你需要参考OpenClaw的官方文档来使用其专属的定时功能。4.3 自动化策略建议同步时间建议设置在清晨如7点。因为Garmin的数据尤其是睡眠数据通常在夜间生成早晨同步能获取到前一天完整的数据。同步范围在cron命令中你可以考虑添加--days 1来明确同步前一天的数据避免歧义。但默认脚本行为就是同步“当天”而cron在早晨7点运行时“当天”实际上就是“昨天”所以通常不需要额外参数。日志与监控务必配置日志重定向如上面的 logfile。当同步失败时日志是你排查问题的唯一依据。你可以定期检查日志文件或者配置更高级的日志监控如logrotate管理、失败时发送邮件通知等。5. 实战问题排查与维护心得即使一切设置顺利在长期运行中你也难免会遇到问题。下面是我在实战中遇到的一些典型情况及其解决方法。5.1 认证失效与令牌更新问题现象某天定时任务突然失败日志中提示认证错误例如Token expired或Login failed。原因与解决令牌自然过期缓存的OAuth令牌有效期约为1年。到期后需要重新认证。解决重新运行一次设置命令即可。因为密码已缓存在第一次输入后通常只需要uv run scripts/sync_garmin.py --setup --email youexample.com。脚本会提示你输入密码然后获取新令牌。Garmin主动撤销令牌出于安全原因如果你在别处修改了密码或者Garmin检测到异常活动可能会使所有现有令牌失效。解决同样重新运行设置命令。如果还不行请检查账户密码是否已更改。Cloudflare策略更新这是最棘手的情况。garminconnect和cloudscraper需要不断更新以应对Garmin的防护。解决首先尝试清理uv的缓存并重新运行这能确保拉取到最新的库版本。uv cache clean uv run scripts/sync_garmin.py --setup --email youexample.com如果问题持续需要去garminconnect库的GitHub Issues页面查看是否有其他人报告相同问题以及是否有临时解决方案或新版本发布。5.2 数据缺失或字段不全问题现象生成的Markdown文件中某些板块如“Training Readiness”、“Stress”没有数据。原因与解决设备或功能未支持并非所有Garmin设备都提供所有指标。例如“训练准备程度”可能需要特定型号的手表且开启相关功能。解决这是正常现象。脚本的逻辑是“有数据则显示无数据则忽略”。请对照你的Garmin Connect App或网页版确认该日期下是否有相应数据。同步时间点问题有些数据如“身体电量”是全天动态变化的而脚本抓取的是某个瞬间的快照。另一些数据如“睡眠分数”可能在凌晨某个时间点才最终计算完成。解决确保在数据已生成后再运行同步。早晨同步是个好习惯。对于动态数据理解其快照性质即可。5.3 性能与网络考虑问题现象同步速度慢或者在国内网络环境下连接Garmin服务器超时。分析与建议网络延迟Garmin服务器可能在海外国内直连可能不稳定。建议如果脚本部署在国内服务器或家庭网络考虑在网络条件更好的时段如深夜运行同步任务或者为运行脚本的机器配置更稳定的网络环境。抓取数据量同步多日数据如--days 30时脚本会逐日请求耗时较长。建议日常自动化只需同步前一天数据默认。批量同步历史数据可在网络空闲时手动执行。5.4 长期维护建议关注上游仓库在GitHub上Star或Watch原项目freakyflow/garminskill以及其核心依赖cyberjunky/python-garminconnect。这样当Garmin进行大更新导致脚本失效时你能第一时间获知修复情况。定期检查日志将检查同步日志纳入你的每周或每月例行维护清单。一个简单的tail -n 20 /tmp/garmin_sync.log就能了解近期运行状态。数据备份health/目录下的Markdown文件是你的宝贵资产。建议将其纳入你的常规备份计划如使用rsync,rclone同步到云存储或其他硬盘。版本控制你可以考虑将health/目录初始化为一个Git仓库定期提交变更。这不仅能备份还能清晰看到健康指标随时间的变化历史。通过以上步骤你应该已经拥有了一个完全自动化、稳定运行的Garmin健康数据同步管道。这些结构化的Markdown笔记不仅是AI Agent的“眼睛”未来也可以成为你进行个人健康回顾与分析的基础数据源。