garmin-grafana:基于 Garmin 与 Grafana 的健康数据可视化项目

A Dockerized python Script to fetch Garmin health data and populate that in a InfluxDB Database, for visualization long term health trends with Grafana

Branch2Tags9
FilesLast commitLast update
5 months ago
5 months ago
5 months ago
1 month ago
1 year ago
6 months ago
7 months ago
1 month ago
4 months ago
1 year ago
5 months ago
1 year ago
1 month ago
4 months ago
10 months ago
1 year ago
1 month ago
1 month ago

Grafana for Garmin 仪表盘

一个 Docker 容器,用于从 Garmin 服务器获取数据并将数据存储在本地 InfluxDB 数据库中,以便通过 Grafana 实现美观的数据可视化。

Important

Garmin 是 Garmin Ltd. 或其子公司的注册商标。Grafana 是 Grafana Labs 的注册商标。本项目是一个独立的开源工具,与 Garmin Ltd. 或 Grafana Labs 无任何关联、背书、赞助或认可关系。

Note

本项目仓库动态镜像至 Codeberg 作为备份。另一个 Docker 镜像可在 codeberg.org/arpanghosh8453/garmin-grafana 获取。

Tip

如果您是 Fitbit 用户,请查看为 Fitbit 打造的 姊妹项目

目录

仪表板示例

Dashboard

力量训练仪表板

一个专门用于举重的独立仪表板,基于StrengthExerciseSetStrengthHRZones测量数据构建。它涵盖了每个练习的估计1RM(一次最大重量)进展、训练量、个人记录、练习平衡、组级别的训练日志以及力量训练期间的心率区间时间。

Strength Training Dashboard

功能特点

  • 从Garmin自动收集数据
  • 收集全面的健康指标,包括:
    • 心率数据
    • 每小时步数热力图
    • 每日步数统计
    • 睡眠数据和模式(血氧饱和度SpO2、呼吸频率、睡眠动作、心率变异性HRV)
    • 睡眠规律性热力图(可视化睡眠习惯)
    • 压力数据
    • 身体电量数据
    • 卡路里消耗
    • 睡眠得分
    • 活动分钟数和心率区间
    • 活动时间线( workouts)
    • 来自 workouts 的GPS数据(轨迹、配速、海拔、心率)
    • 以及更多...
  • 按固定间隔自动获取数据(设置后无需干预)
  • 历史数据回填

为什么使用本项目?

  • 免费且完全开源:100%透明开放的项目——您可以随意修改、分发、扩展和自行托管,无隐藏成本。只需注明作者并以您喜欢的方式支持本项目!
  • 本地数据所有权:保留您Garmin数据的完整、私密备份。脚本会在每次Garmin Connect上传后自动同步新数据——无需手动操作(“设置后便无需理会”)。
  • 完全的可视化自由:不受Garmin应用程序的限制。在单个面板上组合多个指标,放大特定时间窗口,查看数天或数周的原始(非平均)数据,并构建完全自定义的仪表板。
  • 更深入的洞察 - 全天指标:探索您的数据以发现模式、优化表现并跟踪长期趋势。可从Grafana导出数据用于高级分析(Python、Excel等),设置自定义警报,或创建新的个性化指标。本项目从您的Garmin手表获取几乎所有数据——不仅仅局限于其他大多数在线平台所提供的活动分析。
  • 无第三方数据共享:您可以避免将敏感的健康相关数据分享给任何第三方服务提供商,同时免费拥有一个出色的数据可视化平台!

使用辅助脚本自动安装(推荐给不太懂技术的用户)

Important

此脚本仅用于初始设置。如果您已经使用过此脚本或通过手动设置部署了此项目,在保存 garminconnect OAuth 令牌(首次成功获取数据)后,不应再次运行此脚本。请查看“更新到新版本”部分以升级容器。

Tip

如果遇到无法解决的错误,可以尝试求助万能的 ChatGPT,它通常对排查此项目和脚本的问题很有帮助。

此脚本需要 Linux 环境。如果您的 Linux/MacOS 系统上未安装 Docker,请按照说明在 Linux 上手动安装 Docker。也可以使用一行命令通过自动化 Docker 安装脚本进行安装:curl -fsSL https://get.docker.com -o get-docker.sh && sh get-docker.sh

如果您使用的是 Windows,建议使用 WSL 来搭建 Linux 子系统。

Windows 用户的详细步骤如下:

  • 安装 Docker Desktop
  • 从 Microsoft Store 安装 WSLUbuntu
  • 开始 -> 运行 -> 输入 WSL.exe,按照提示创建 Linux sudo(管理员)用户和密码。此密码在后续步骤中需要用到。
  • 打开 Docker Desktop 并同意最终用户许可协议
  • 重启计算机(重要)
  • 重启后,WSL 和 Docker 应已安装并链接在一起。
  • 开始 -> 运行 -> 输入 WSL.exe,然后在终端窗口中运行以下 bash 命令。

对于 Linux 或 MacOS 用户,只需在 Linux 命令行(终端)中运行以下 bash 命令。

Note

如果出现 git: command not found 错误,则需要安装 git。对于 Ubuntu/Debian/WSL(Windows)系统,使用命令 sudo apt install git。对于 Mac,使用 brew install git。如果您使用的是非 Debian 系 Linux 发行版,请使用适合您操作系统的包管理器替换 apt

使用以下命令将此仓库克隆到您的本地计算机

cd ~ && git clone https://github.com/arpanghosh8453/garmin-grafana.git garmin-grafana

使用以下命令通过简易安装脚本自动安装。如果因未安装 docker 而失败,请在安装 docker 后重试该命令。

cd garmin-grafana && sudo bash ./easy-install.sh

当系统提示时输入 Garmin Connect 凭据,您的系统就应该能正常运行了(如果您启用了双重认证,系统也会提示您输入 2FA 验证码)。一旦数据开始持续传入,您可以访问 http://localhost:3000(默认地址)打开 Grafana,使用默认用户名 admin 和密码 admin 完成初始设置。点击左侧边栏的“仪表盘”链接,您会看到在仪表盘部分自动配置了一个名为 Garmin-Stats 的仪表盘。在那里,您应该能看到已添加的数据。只要您的 Garmin Connect 账户同步了新数据,仪表盘就会自动更新

Note

首次运行时,系统只会自动获取过去 7 天的数据,并在未来持续拉取 Garmin Connect 新同步的数据。如果您想同步更早的数据,操作也非常简单。只需在终端(Windows 用户使用 WSL)中运行以下命令,将 YYYY-MM-DD 替换为合适的开始和结束日期(MANUAL_START_DATE 的值必须早于 MANUAL_END_DATE 的值)

cd ~/garmin-grafana && docker compose run --rm -e MANUAL_START_DATE=YYYY-MM-DD -e MANUAL_END_DATE=YYYY-MM-DD garmin-fetch-data

目前您需要了解的就是这些!只要您的设备处于开机状态,脚本就会在后台运行。重启设备后,如果您使用的是 Windows 系统,请确保 Docker Desktop 已打开(如果它没有自动启动),这样容器才能随之启动。对于 Linux 系统,重启后所有服务都应能可靠地自动重启。如果遇到问题,请确保 Docker 守护进程正在运行,并使用 docker ps 命令检查容器状态。

使用 Docker 手动安装(如果您了解 Linux 概念,建议使用此方法)

Important

如果您尚未安装 Docker,请先进行安装。Docker 支持所有主流平台/操作系统。请查看 Docker 安装指南。您可以通过 WSL 在 Windows 上安装,通过 Docker Compose 插件在 Unraid 上安装,通过 Docker-LXC 在 Proxmox 上安装,也可以在 Linux 和 Mac 上原生安装。

  1. 使用命令 git clone https://github.com/arpanghosh8453/garmin-grafana.git 克隆此仓库。使用 cd garmin-grafana 命令切换到工作目录。然后在当前文件夹(garmin-grafana)内使用 mkdir garminconnect-tokens 命令创建一个名为 garminconnect-tokens 的文件夹。运行 chown -R 1000:1000 garminconnect-tokens 更改 garminconnect-tokens 文件夹的所有权(以便 garmin-fetch-data 容器的内部用户可以使用该文件夹存储身份验证令牌)。如果在脚本执行过程中持续遇到 PermissionError,您也可以运行 chmod -R 777 garminconnect-tokens 使该文件夹对系统上的所有用户通用。克隆此仓库可以保持文件夹和文件结构,并允许您使用 Grafana 自配置数据库。
  2. 在当前 garmin-grafana 文件夹内创建一个空的 compose.yml 文件,内容与提供的 compose-example.yml 相同,或者直接使用 mv compose-example.yml compose.yml 命令将现有的 compose-example.yml 文件重命名为 compose.yml(根据说明修改其中的环境变量)

Tip

Docker 镜像除了 thisisarpanghosh/garmin-fetch-data:latest 外,还可以通过 ghcr.io/arpanghosh8453/garmin-fetch-data:latest 获取。

  1. 您可以使用两个额外的环境变量 GARMINCONNECT_EMAILGARMINCONNECT_BASE64_PASSWORD 直接添加登录信息。否则,您需要在初始设置阶段按提示输入这些信息。如果您不使用这些环境变量传递 Garmin Connect 登录信息,则必须将它们从 compose 文件中完全删除(删除包括变量名在内的整行,或在变量名前用 # 注释掉——示例中默认已注释)——保留占位符值或空值可能会导致登录尝试无效,并可能出现 401 Client Error。请注意,使用 GARMINCONNECT_BASE64_PASSWORD 环境变量时,密码必须通过 Base64 进行编码。这是为了确保您的 Garmin Connect 密码不会以明文形式出现在 compose 文件中。脚本会在需要时对其进行解码并使用。如果您设置了这两个环境变量,并且没有启用双重认证(通过短信或电子邮件),则可以直接跳至 步骤 5。如果您在中国大陆并使用 Garmin 中国账户,则需要设置 GARMINCONNECT_IS_CN=True。您还可以通过 compose 文件中的 FETCH_SELECTION 变量选择要获取的数据类型。

Note

如果您计划使用 Influxdb V3,则需要在 INFLUXDB_V3_ACCESS_TOKEN 中输入管理员访问令牌。要生成管理员令牌,您应该运行 docker exec influxdb influxdb3 create token --admin 命令。这将为您提供管理员令牌,您必须将其更新到 INFLUXDB_V3_ACCESS_TOKEN 环境变量中。此操作只能执行一次,且令牌一旦生成便无法再次查看或检索(Influxdb 仅在数据库中存储其哈希值用于比较)。因此,请妥善保管此令牌。

  1. 如果您未设置电子邮件和密码环境变量,或者启用了 2FA,则必须先运行以下命令以交互方式获取电子邮件、密码和 2FA 验证码提示:docker pull thisisarpanghosh/garmin-fetch-data:latest && docker compose run --rm garmin-fetch-data。输入电子邮件、密码(输入时字符会可见,以避免混淆,因此请确保环境私密。如果粘贴密码,请确保没有尾随空格或多余字符)以及 2FA 验证码(如果已启用)。看到身份验证成功的消息后,就可以继续操作了。脚本会自行退出,并提示您重新启动脚本(请按照下一步操作)。由于启动时使用了 --rm 标志,此孤立容器将被自动删除。您只需登录一次。脚本会将会话身份验证令牌保存在容器内部的 /home/appuser/.garminconnect 文件夹中,供未来使用。只要令牌有效,就可以用于所有未来的请求(预期会话令牌的有效期约为一年,因为 Garmin 似乎使用长期有效的访问令牌,而不是短期有效的 {访问令牌 + 刷新令牌} 对)。这有助于在容器启动时无需每次都登录,因为从同一 IP 地址重复尝试登录可能会导致 429 Client Error。如果在首次使用此脚本登录时遇到 429 Client Error,请参考下面的故障排除部分。

Tip

您可以取消 compose.yml 文件中 # user: root 这一行的注释,以 root(超级用户)身份运行容器——这将解决您在运行此初始设置时遇到的任何权限错误或读写问题。如果上述 chownchmod 命令对您不起作用,并且在运行初始设置时持续遇到 Permission Error,请使用此方法。如果这样做,您必须将 compose 卷挂载从 ./garminconnect-tokens:/home/appuser/.garminconnect 更改为 ./garminconnect-tokens:/root/.garminconnect,以便在使用 docker compose down 命令停止容器进行重启或重建时,令牌文件得以保留。

  1. 如果您使用此项目提供的 Grafana 自配置功能,则应将仪表盘 JSON 中的占位符变量名 ${DS_GARMIN_STATS}(用于支持外部导入)更新为静态值 garmin_influxdb,因为这是仪表盘自配置过程中设置的 UID。要执行此操作,请在 garmin-grafana 根目录中运行以下命令:

Linux

sed -i 's/\${DS_GARMIN_STATS}/garmin_influxdb/g' Grafana_Dashboard/Garmin-Grafana-Dashboard.json

苹果操作系统

sed -i '' 's/\${DS_GARMIN_STATS}/garmin_influxdb/g' Grafana_Dashboard/Garmin-Grafana-Dashboard.json
  1. 最后运行:docker compose up -d(以分离模式启动整个堆栈)。之后,您应使用 docker compose logs --follow 命令查看日志,以了解容器可能出现的任何错误。这将帮助您调试问题(尤其是读写权限问题)。如果您使用 docker 卷,这种情况发生的可能性很小,因为文件权限将由 docker 管理。对于绑定挂载,如果遇到权限问题,请查看故障排除部分。

  2. 现在,您可以访问 http://localhost:3000 以打开 Grafana(默认情况下),使用默认用户名 admin 和密码 admin 进行初始设置。如果您已按照步骤 1 中的说明克隆了存储库,并为 grafana 仪表板和数据库使用了自配置功能,那么您应该会在“仪表板”部分下自动设置一个名为 Garmin-Grafana 的仪表板,其中已填充数据!至此,您已完成所有设置!

  3. 如果您不使用自配置功能,则需要手动添加 influxdb 作为数据源,并继续按照以下说明操作。请注意,influxdb 的主机名设置为 influxdb,端口为 8086,因此在数据源设置过程中,您应使用 http://influxdb:8086 作为地址,而不是 http://localhost:8086,因为 influxdb 作为一个单独的容器运行,但属于同一 docker 网络和堆栈。此处的数据库名称应为 GarminStats,与 docker compose 中的 influxdb 数据库名称匹配。仪表板使用的查询语言是 influxql,InfluxDB 1.x 和 3.x 均支持该语言,因此请在设置过程中从语言下拉菜单中选择它。使用您为 influxdb 容器设置的相同用户名和密码(查看您的 docker compose 配置中的 influxdb 容器,在默认配置中我们使用 influxdb_userinfluxdb_secret_password)。测试连接以确保 influxdb 已启动且可访问(如果测试连接时能找到测量值,则说明一切正常)。

  4. 要手动导入并使用 Grafana 仪表板,请直接从 GitHub 下载 JSON 文件,或使用导入代码 23245 直接从 Grafana 仪表板云拉取。在 Grafana 仪表板中,热力图面板需要安装一个额外的插件。您可以像 compose-example.yml 文件中那样使用 GF_PLUGINS_PREINSTALL=marcusolsson-hourly-heatmap-panel 环境变量来安装,或者在容器创建后使用 docker 命令轻松安装。只需运行 docker exec -it grafana grafana cli plugins install marcusolsson-hourly-heatmap-panel,然后运行 docker restart grafana 以应用该插件更新。现在,您应该能够看到仪表板上的热力图面板成功加载。

  5. 如果您进行力量训练,还可以导入 力量训练仪表板。它仅使用核心 Grafana 面板(无需额外插件),并从仪表板下拉菜单中选择其 InfluxDB 数据源,因此不需要进行 sed 替换。它读取 StrengthExerciseSetStrengthHRZones 测量值,因此在您记录力量训练活动之前,它将保持为空。由于力量训练数据与每日指标相比更为稀疏,其默认时间范围为过去 6 个月。

Note

首次运行时,它只会自动获取最近 7 天的数据,并在后续持续拉取与 Garmin Connect 同步的新数据。要同步更早的数据,请使用以下命令,并将 YYYY-MM-DD 替换为适当的开始和结束日期(MANUAL_START_DATE 值必须早于 MANUAL_END_DATE 值)

docker compose run --rm -e MANUAL_START_DATE=YYYY-MM-DD -e MANUAL_END_DATE=YYYY-MM-DD garmin-fetch-data

如果您已完成上述所有步骤,一切应该都能正常工作。如果没有,请查看故障排除部分了解已知问题。如果一切正常,恭喜您! 享受您的仪表板并坚持锻炼!如果您喜欢这个仪表板以及我为此付出的努力,请为这个存储库点赞。如果您非常喜欢并想表达您的赞赏与我分享这份喜悦,欢迎 请我喝杯咖啡。维护这个项目占用了我大量的空闲时间,您的支持将激励我为社区开发更多功能,并在类似项目上投入更多时间。如果您遇到任何问题,欢迎在此处提出 issue,我会尽力帮助您!


此项目是为 InfluxDB 1.11 设计的,因为在某些情况下,InfluxDB 2.x 上的 Flux 查询在 Grafana 中使用可能会出现问题。事实上,InfluxQL 已在 InfluxDB 3.0 中重新引入,这反映了用户的反馈。Grafana 与 InfluxDB 1.11 的 InfluxQL 也具有更好的兼容性和稳定性。此外,有统计证据表明 Influxdb 1.11 的查询运行速度比 Influxdb 2.x 更快。由于 InfluxDB 2.x 对此项目没有明显优势,因此目前没有迁移计划。

Important

如果您已有现有的 InfluxDB v2.x 数据库,并希望将其与此项目集成,您可以按照 本指南 操作,尽管我们官方不支持将此项目与 InfluxDB v2.x 配合使用。我们直接支持 InfluxDB v3.x,但不积极鼓励人们使用它,因为它包含付费功能(InfluxDB v3.x OSS 将数据查询时间限制为 72 小时——长期查询仅在企业版和 InfluxData 云托管实例中可用),而这些功能对于长期数据可视化至关重要。由于我们关注的是长期数据趋势的可视化,此限制违背了项目的初衷。因此,我们强烈建议用户使用 InfluxDB 1.11.x(默认设置),除非它已停止生产支持。

其他配置和环境变量

✅ 上述 Compose 文件会创建一个开放读写权限且无身份验证的 InfluxDB 数据库。除非你直接将此数据库暴露在开放互联网上,否则不会构成任何威胁。如果你共享本地网络,并且希望增强安全性,可以按照 InfluxDB 指南,在设置过程中通过 INFLUXDB_ADMIN_ENABLEDINFLUXDB_ADMIN_USERINFLUXDB_ADMIN_PASSWORD 环境变量手动启用身份验证,并为 influxdb_user 授予对 GarminStats 数据库适当的读写权限。但为简洁起见,本文档不对此进行详细介绍。

✅ 你还可以在 Compose 文件中通过 FETCH_SELECTION 环境变量启用额外的高级训练数据获取功能(例如坡度评分、训练准备度、耐力评分、血压、水分摄入等)。请查看 讨论 #119 了解可用的额外选项。默认的 Grafana 仪表板上没有显示这些额外数据的面板。你必须创建自己的面板以在 Grafana 上可视化这些数据,或者使用 @brunothesatellite 提供的这个面板,其中包含更多面板。

✅ 默认情况下,为了节省导入期间的存储空间,不会将拉取的 FIT 文件保存为文件(而是使用内存 IO 缓冲区)。如果你希望保留导入期间下载的 FIT 文件,以便将来用于 Strava 或任何其他支持导入 FIT 文件的应用程序,可以在 Compose 文件的 garmin-fetch-data 环境变量下设置 KEEP_FIT_FILES=True。要从主机访问这些文件,你需要在 garmin-fetch-data 文件夹(即当前 Compose 文件所在的文件夹)内创建一个名为 fit_filestore 的文件夹(使用 mkdir fit_filestore 命令),并使用 chown 1000:1000 fit_filestore 命令更改其所有权,然后必须在 garmin-fetch-data 的 volumes 部分设置一个卷绑定挂载,如下所示:./fit_filestore:/home/appuser/fit_filestore。这会将容器内部的 /home/appuser/fit_filestore 文件夹映射到你创建的 fit_filestore 文件夹。一旦脚本开始运行,你将在这个 fit_filestore 文件夹中看到你的活动对应的 FIT 文件。

✅ 默认情况下,为了节省每个获取活动的资源和处理时间,不会处理缺少 GPS 数据的室内活动 FIT 文件(所有活动的活动摘要都会被处理,只是不处理 FIT 文件中包含的详细活动内心率、配速等数据,这些数据需要额外的处理能力)。如果你希望处理所有活动,无论该活动是否关联 GPS 数据,可以在 garmin-fetch-data 容器的环境变量部分设置 ALWAYS_PROCESS_FIT_FILES=True,这将确保无论活动是否有 GPS 数据,所有 FIT 文件都会被处理。

✅ 如果你遇到前几天截止午夜的数据缺失(这些数据在 Garmin Connect 上可用,但在仪表板上缺失),或者使用自动定期获取时出现同步问题,请考虑将容器更新到最新版本,并在 garmin-fetch-data 服务下使用 USER_TIMEZONE 环境变量。该值必须是有效的时区标识符,例如 Europe/Budapest。此变量是可选的,如果未设置此变量,脚本会尝试自动确定时区并获取 UTC 偏移量。如果你发现自动识别对你不起作用,可以使用此变量覆盖该行为,并确保脚本在所有数据获取相关活动中使用硬编码的时区。之前的 gaps 不会被填补(你需要使用历史批量更新方法来获取它们),但从现在开始,脚本将保持所有内容同步。

✅ 想要此仪表板使用英制单位而非公制单位?我无法同时维护两个单独的仪表板,但这里有一个出色的分步指南,教你如何在自己的仪表板上进行设置!此外,如果你更喜欢 24 小时制时间格式而非带 AM/PM 的 12 小时制,可以从 compose.yml 文件中删除 GF_DATE_FORMATS_* 环境变量。

定期收集手表电池电量

遗憾的是,Garmin Connect 不会同步设备电池电量(可能是由于被动同步间隔较长)。因此,无法通过此设置直接获取手表的电池数据。不过,我找到了一个替代方案,但这需要大量额外设置(超出了本项目的范围——不过我会提供简要说明)。

你需要一个自托管/云实例的 homeassistant 以及 Connect IQ 上的 GarminHomeAssistant(手表应用程序)。详细的安装说明可在 此处获取。该应用程序与本项目一样,也是免费开源的,并且维护者非常支持!

安装后,你需要在 Connect IQ 的应用程序设置中启用电池电量和其他统计数据的收集(后台运行)。之后,你将在 HomeAssistant 的实体面板上看到电池电量历史记录(显示为 sensor.garmin_device_battery_level)。如果你想将此数据集成到本项目现有的 InfluxDB 数据库和 Grafana 仪表盘中,需要在 HomeAssistant 安装的 configuration.yaml 文件中添加以下额外的 InfluxDB 插件配置。

influxdb:
  host: influxdb
  port: 8086
  database: GarminStats
  username: influxdb_user
  password: influxdb_secret_password
  ssl: false
  verify_ssl: false
  max_retries: 3
  include:
    entities:
      - sensor.garmin_device_battery_level
  tags:
    source: hass

仪表盘中有一个 Grafana 面板(随本项目提供),在数据可用时会显示此数据。如果您没有进行此设置,则应从仪表盘中移除该面板,因为否则无法从手表收集电池数据。

多用户实例设置

如果这个项目对您来说运行良好,您可能想为家人/配偶也设置一个。为此,您不应复制整个 compose 堆栈(虽然可以,但这样同一台主机上会运行两个 Grafana 和 InfluxDB 容器实例,这不是个明智的做法)。您可以按照本指南进行操作。目前没有自动设置脚本,您需要对 Docker 有一定了解并按照给出的说明操作。

更新到新版本

使用 Docker 进行更新非常简单。只需进入 compose.yml 所在的文件夹,运行 docker compose pull,然后运行 docker compose down && docker compose up -d。请通过 docker compose logs --follow 命令检查日志,以确认一切运行正常。

Caution

如果您运行 docker compose down -v,使用 -v 标志会清除 InfluxDB 的持久化 Docker 卷(如果您使用的是 Docker 卷 - 默认设置),这将删除 InfluxDB 容器中存储的所有数据和数据库。请谨慎执行此操作,但如果您想清除旧数据库和容器并重新开始,此操作会很有用。此操作无法撤销。

历史数据获取(批量更新)

Tip

请注意,此过程特意设置了 5 秒的速率限制,即在每天的更新之间等待 5 秒,以确保在使用批量更新时不会给 Garmin 服务器造成过多请求负担。您可以通过 garmin-fetch-data 容器中的 RATE_LIMIT_CALLS_SECONDS 环境变量修改此值,但不建议降低该值。

Note

请注意,如果多次重复此过程,在与 InfluxDB 一起使用时,不会在数据库中创建任何重复数据。InfluxDB 作为时序数据库,会结合使用时间戳和标签创建一个哈希值作为主键。因此,写入具有相同时间戳和标签的相同值实际上会覆盖之前的字段值。

步骤

  1. 请先运行上述基于 Docker 的安装步骤 1 到 4(如果尚未设置 Garmin Connect 登录会话令牌)。
  2. 如果容器已在运行,请使用 docker compose down 停止并移除正在运行的容器。
  3. 运行命令 docker compose run --rm -e MANUAL_START_DATE=YYYY-MM-DD -e MANUAL_END_DATE=YYYY-MM-DD garmin-fetch-data 来更新两个日期之间的数据。您需要将 YYYY-MM-DD 替换为实际的日期,例如 docker compose run --rm -e MANUAL_START_DATE=2025-04-12 -e MANUAL_END_DATE=2025-04-14 garmin-fetch-dataMANUAL_END_DATE 变量是可选的,如果未提供,脚本会将其默认为当前日期。MANUAL_END_DATE 必须晚于传入的 MANUAL_START_DATE 变量,如果两者相同,仍会拉取该特定日期的数据。

Tip

如果您在容器更新后多次运行此命令以更新旧数据,并且只想获取特定数据点而不是批量获取所有数据(以节省时间和资源),您可以将 FETCH_SELECTION 设置为您想要再次获取的测量值。您可以像这样覆盖 compose 中的值:docker compose run --rm -e MANUAL_START_DATE=YYYY-MM-DD -e MANUAL_END_DATE=YYYY-MM-DD -e FETCH_SELECTION=activity,sleep garmin-fetch-data,如果您只想更新/重新获取过去的活动和睡眠数据,而不是其他数据。查看 compose 文件的注释,了解此变量可用的值。

  1. 请注意,批量数据获取是按逆时间顺序进行的。因此,您会先获得最近的数据,然后不断回溯,直到达到 MANUAL_START_DATE。您可以让它在后台运行。如果它在一段时间后意外终止,您可以从容器的标准输出日志中查看最后一次成功更新的日期,并在再次运行批量更新时将其用作 MANUAL_END_DATE,因为它是按逆时间顺序进行的。
  2. 成功完成批量获取后,您将看到 Bulk update success 消息,容器将自动退出并移除自身。
  3. 现在您可以使用 docker compose up -d 运行常规的定期更新。

Important

Garmin 会将超过六个月日内历史数据放入冷存储(归档数据库),这些数据不再直接通过常规 API 端点提供。您可以从应用程序手动刷新某一天的数据,之后该数据仅在 7 天内可用,然后会再次回到冷存储。刷新请求有每日服务器端限制(估计每天约 20-40 次)——因此在导入时无法批量刷新数据。如果您使用此脚本批量获取超过 6 个月的历史数据,较旧日期的日内数据点(日内心率、日内睡眠阶段等)将会缺失——尽管每日平均数据点对于任何过去的日期(无论多旧)在 API 端点上仍然可用,因此不受影响。如果您想了解更多信息,请查看问题 #77。这不是本项目的限制,而是 Garmin API 设计所施加的。

从 Garmin Connect 导出文件导入数据

有关如何手动导入本地文件(例如 Garmin 批量导出文件或本地 .FIT 文件)的说明,请参见此处。请注意,此方法不会导入日内级数据,仅导入基本的每日平均统计数据以及来自 FIT 文件的活动或锻炼统计数据。若需日内级详细数据,请使用上文提供的批量导入选项。

将数据导出为 CSV 文件

本项目提供了额外工具,可将数据导出为 CSV 格式,以便进行外部分析或 AI 集成。导出后,您可以使用这些 CSV 文件输入到 ChatGPT(如果您不在欧盟,您的数据将用于训练),或通过 Openweb-UIanythingllm(原生支持基于 RAG 的文档摄入,并提供 Windows 应用程序版本)等任何本地托管的 LLM 聊天界面,从而从您的长期健康数据中获取洞察。如果开启聊天历史记录,随着时间推移,您或许能获得更具洞察力的建议。

有两种方法可将数据导出为 CSV 文件:

  1. 使用 Grafana 原生的 CSV 导出功能,您可以按照本指南将任何 Grafana 面板上显示的数据导出为 CSV。

  2. 如果上述方法较为繁琐,而您希望通过一条命令直接从本地 InfluxDB 数据库中获取所有详细测量数据并保存为 CSV 文件,本项目提供了一个便捷的导出脚本(包含在 Docker 容器内)。

    2.1 只需在终端中运行以下 Docker 命令 docker exec garmin-fetch-data python /app/garmin_grafana/influxdb_exporter.py 即可导出最近 30 天的数据。该脚本接受额外参数,如 last-n-daysstart-dateend-date,以便导出最近 n 天或特定日期范围内的数据。您应按如下方式运行命令:

    docker exec garmin-fetch-data python /app/garmin_grafana/influxdb_exporter.py --last-n-days=7
    

    docker exec garmin-fetch-data python /app/garmin_grafana/influxdb_exporter.py --start-date=2025-01-01 --end-date=2025-03-01
    

    2.2 导出完成后,您将看到一个输出文件路径,格式为 已将 N 个测量数据 CSV 导出至 /tmp/GarminStats_Export_XYZ.zip。zip 文件名会根据您运行命令的时间和选择的天数而有所不同。请记下完整的导出路径名称。

    2.3 现在,导出的 zip 文件已保存到容器内部,我们需要将其复制到主机。为此,运行 docker cp garmin-fetch-data:/tmp/GarminStats_Export_XYZ.zip ./,并将 /tmp/GarminStats_Export_XYZ.zip 部分替换为上一步命令输出中的 zip 文件名。此命令会将 zip 文件放置在您当前的工作目录中 — 如果您想将其放置在特定位置,可以将命令末尾的 ./ 替换为本地路径,如 ~/garmin-grafana/。复制完成后,您可以通过运行 docker exec garmin-fetch-data rm /tmp/GarminStats_Export_XYZ.zip 从容器中删除导出的 zip 文件以释放空间(可选操作)。

    2.4 现在解压您获得的 zip 文件,您将看到所有测量数据均以单独的 CSV 文件形式存在。您可以使用这些文件进行自定义分析,或直接将 CSV 文件输入 LLM 以获取洞察!

备份 InfluxDB 数据库

无论您使用的是绑定挂载还是 Docker 卷,为宝贵的健康数据创建可恢复的归档备份始终是明智之举。假设您将数据库命名为 GarminStats,且 InfluxDB 容器名称为 influxdb,您可以使用以下脚本为当时 InfluxDB 数据库中的数据创建静态归档备份。这些还原点可用于重新创建包含归档数据的 InfluxDB 数据库,而无需再次从 Garmin 的服务器请求数据,这不仅耗时,而且会占用大量资源。

#!/bin/bash
TIMESTAMP=$(date +%F_%H-%M)
BACKUP_DIR="./influxdb_backups/$TIMESTAMP"
mkdir -p "$BACKUP_DIR"
docker exec influxdb influxd backup -portable -db GarminStats /tmp/influxdb_backup
docker cp influxdb:/tmp/influxdb_backup "$BACKUP_DIR"
docker exec influxdb rm -r "/tmp/influxdb_backup"

上述 bash 脚本会在您当前的工作目录中创建一个名为 influxdb_backups 的文件夹,并在其中创建一个包含当前日期时间的子文件夹。然后,它将为 GarminStats 数据库创建备份,并将备份文件复制到该位置。

要从备份恢复数据,您首先需要将文件放入新的 influxdb Docker 容器中。您可以使用 docker cp 或卷绑定挂载来实现。一旦备份数据在容器内部可用,您只需运行 docker exec influxdb influxd restore -portable -db GarminStats /path/to/internal-backup-directory 即可恢复备份。

请从 influxDB 备份和恢复文档 中阅读有关此操作的详细指南。

故障排除

  • 发出的会话令牌显然仅在 1 年内有效或更短。因此,令牌过期后,自动获取将失败。如果您使用该程序超过一年,可能需要停止、删除并重新部署容器(按照初始设置的相同说明操作,系统会再次要求您输入用户名、密码以及 2FA 验证码)。如果您不使用 MFA/2FA(短信或电子邮件一次性验证码),可以在 compose 文件中使用 GARMINCONNECT_EMAILGARMINCONNECT_BASE64_PASSWORD(请记住,这是base64 编码的密码,不是明文)环境变量直接提供此信息,这样脚本就能在令牌过期后重新生成令牌。遗憾的是,如果您使用 MFA/2FA,则需要在每年令牌过期后重建容器时手动输入一次性验证码,以保持脚本运行(一旦会话令牌再次有效,脚本将自动补填您错过的数据)
  • 如果在初始设置期间经过几次登录尝试后收到 429 Client Error,这表明您的公网 IP 受到了速率限制。Garmin 对来自同一 IP 地址的重复登录尝试设置了限制,以保护您的账户。您可以等待几个小时或一天,或者切换到家庭外的其他 wifi 网络(会为您提供新的公网 IP),或者只需使用手机热点(也会为您提供新的公网 IP)进行初始登录尝试。相关行为在 python-garminconnect 问题跟踪器 中有所讨论。
  • 首次尝试登录时遇到 401 Client Error?请确保您使用的是账户的正确用户名和密码。如果您在运行时输入,应以明文形式输入;但如果您通过 docker compose 堆栈中的环境变量添加,则必须进行Base64 编码。如果您 100% 确定使用的是正确凭据,但仍然收到此错误,可能是由于您连接到了 VPN 网络,从而阻止了登录请求(参见问题 #20)。如果您没有使用 VPN,请尝试通过手机热点网络或 VPN 出口隧道运行容器(两者都会为您提供不同的公网 IP)——您需要以某种方式从不同的网络进行尝试。
  • 如果您想为 garmin-fetch-data 容器绑定挂载 docker 卷,请注意脚本以内置用户 appuser 运行,其 uid 和 gid 均设置为 1000。因此,请按照上述说明相应地更改绑定挂载文件夹的所有权。此外,grafana 容器要求绑定挂载文件夹归 472:472 所有,influxdb:1.11 容器要求绑定挂载文件夹归 1500:1500 所有。如果这些都无法解决您的 Permission Denied 问题,您可以使用 chmod -R 777 garminconnect-tokens 将绑定挂载文件夹权限更改为 777。另一个解决方案是在容器配置中添加 user: root,以 root 用户而不是默认的 appuser 运行容器(此选项存在安全考虑)
  • 如果仪表板上未显示活动详情(GPS、配速、心率、海拔),请确保选择仪表板左上角列出的活动(在“Activity with GPS”变量下拉菜单中)。如果您看到那里没有可用值,但在日志中看到活动已成功拉取,那么这是由于 Grafana 错误。转到仪表板变量设置,请确保为变量选择了正确的数据源,并且查询设置为 SHOW TAG VALUES FROM "ActivityGPS" WITH KEY = "ActivitySelector" WHERE $timeFilter。在仪表板导入后正确设置此选项后,值应在下拉菜单中正确显示,您将能够选择特定活动并在仪表板上查看其统计信息。
  • 仪表板上缺少电池电量数据?请查看标题为“Collecting periodic watch battery levels”的部分,了解如何进行设置。

致谢

本项目的实现离不开社区对 gofundme 的慷慨捐助,该众筹活动在 Reddit 的 r/garmin 社区的 这篇帖子 中进行了宣传。长期以来,我一直希望开发这个工具,但由于 Garmin 设备价格不菲,始终未能凑足购买设备的资金。正是凭借社区的捐赠,我才得以购买 Garmin Vivoactive 6 并开发出这个向所有人开放的工具。如果您正在使用本工具并觉得它很有用,请记住是什么让这一切成为可能!特别要感谢 r/garmin 社区的慷慨解囊、对我的信任以及对我想法的积极支持!

依赖项

贡献指南

贡献指南详见 此处

局限性

本项目依赖于 Garmin 云服务,并非直接从您的手表同步数据。您的数据首先同步至 Garmin 云,然后脚本会在设定的时间间隔内,使用本地存储的 Oauth 令牌定期从 Garmin 服务器获取数据。实现直接同步相当复杂,且可能会解除您当前设备的配对并接管同步活动。若发生任何脚本错误或用户操作失误,都可能导致永久性数据丢失。由于本项目不提供任何责任担保或保修服务,因此风险由使用本项目的用户自行承担。如果您希望从手表直接同步数据,本项目并不适用。您可以考虑 Gadgetbridge 项目,如果您准备好对自己的数据承担全部责任,该项目或许能满足您的需求。直接同步功能目前不在我们的开发计划中。

喜欢这个项目吗?

得知您正在使用此仪表板,我感到非常高兴!您的关注和参与对我而言意义重大!通过此设置,您可以查看和分析比 Garmin connect+ 订阅服务更详细的健康统计数据。

维护和改进这个项目占用了我大量的业余时间。您的支持将激励我继续添加新功能,并开发更多有益于社区的类似项目。

如果您觉得本项目对您有所帮助,欢迎考虑:

⭐ 为这个仓库点亮星标,以表示您的支持并帮助传播!

☕ 如果您愿意为项目的维护和未来发展提供支持,欢迎 请我喝杯咖啡

ko-fi

需要帮助?

如果您在运行本项目时遇到任何问题或有疑问,欢迎随时在本仓库中提交 issue。我会尽力为您提供帮助。

需要桌面应用?

自行托管只为查看 FIT 文件活动数据太复杂?那完全离线的桌面解决方案如何?可通过标准二进制文件安装。这是一个跨平台解决方案,敬请查看 fit-dashboard

individual_page

overview_page

星标历史

Star History Chart

Introduction

一个Python脚本,用于获取Garmin健康数据并将其填充至InfluxDB数据库中,以便使用Grafana进行长期健康趋势的可视化。【此简介由AI生成】

Customize your domain
303.46 K227Visit GitHub