🙏 A Heartfelt Thank You
Before diving into the technical details, a huge and sincere thank you to @shuchirj for building and maintaining HCGateway. This project is the critical missing piece that bridges the gap between the local Android Health Connect API and any self-hosted backend. Without this open-source effort, automating health data ingestion from consumer wearables would require either vendor lock-in or significantly more complex solutions. The clean REST API design, Bearer token auth, and Docker-first deployment made integration a joy. Truly outstanding work. 🎉
Overview
This issue documents a fully automated health data pipeline that reads data from an Amazfit GTR 3 smartwatch and writes structured daily log notes into an Obsidian vault, orchestrated by an OpenClaw agent skill running on a self-hosted VPS.
No proprietary cloud subscriptions or third-party SaaS services are required beyond the existing Zepp app and Google Health Connect (built into Android 14+).
Goal
Automatically ingest Amazfit GTR 3 health metrics into Obsidian as structured daily Markdown notes, triggered daily at 06:00 via OpenClaw's cron system.
Architecture & Data Flow
Amazfit GTR 3
│ (Bluetooth)
▼
Zepp App (Android)
│ writes 26 health data types
▼
Google Health Connect (Android 14+ built-in)
│ local Android API — no cloud
▼
HCGateway Android App
│ reads Health Connect, POSTs every 2h
▼
HCGateway REST Server (Docker, self-hosted VPS)
│ Python/Flask + MongoDB, Bearer token auth
▼
OpenClaw Skill: amazfit-health-log
│ Python script fetches & aggregates previous day's data
▼
Obsidian Vault
└── Gesundheit/Logs/GTR3/YYYY-MM-DD.md
Components
1. HCGateway Server (Docker)
Stack: Python/Flask · MongoDB 7 · Docker Compose
docker-compose.yml:
services:
api:
image: ghcr.io/shuchirj/hcgateway:latest
container_name: hcgateway_api
restart: always
ports:
- "0.0.0.0:6644:6644"
env_file:
- ./api/.env
volumes:
- ./api/service-account.json:/app/service-account.json:ro
depends_on:
- db
networks:
- hcgateway_net
db:
image: mongo:7
container_name: hcgateway_db
restart: always
volumes:
- ./db:/data/db
environment:
MONGO_INITDB_ROOT_USERNAME: hcgateway
MONGO_INITDB_ROOT_PASSWORD: <STRONG_PASSWORD>
MONGO_INITDB_DATABASE: hcgateway
networks:
- hcgateway_net
networks:
hcgateway_net:
driver: bridge
api/.env:
APP_HOST=0.0.0.0
APP_PORT=6644
APP_DEBUG=False
SENTRY_DSN=
FCM_PROJECT_ID=
MONGO_URI=mongodb://hcgateway:<STRONG_PASSWORD>@hcgateway_db:27017/hcgateway?authSource=admin
Note: Firebase/FCM is optional. It is only required for pushing data to the device. For read-only health logging it can be left empty — service-account.json can be a placeholder {}.
Key API endpoints used:
| Method |
Endpoint |
Purpose |
POST |
/api/v2/login |
Obtain Bearer token (creates user on first call) |
POST |
/api/v2/refresh |
Refresh expired token |
POST |
/api/v2/fetch/<type> |
Read health data |
2. Zepp ↔ Health Connect Sync
The Zepp app writes 26 health data types to Health Connect. Relevant confirmed types for GTR 3:
| Type |
HCGateway endpoint |
Notes |
| Steps |
steps |
10-min intervals |
| Distance |
distance |
Nested unit object (inMeters) |
| Sleep sessions |
sleepSession |
Full stage data (see below) |
| Heart rate |
heartRate |
Samples array |
| Resting heart rate |
restingHeartRate |
Daily value |
| Blood oxygen |
oxygenSaturation |
percentage field |
Sleep stage encoding (from com.huami.watch.hmwatchmanager):
| Code |
Stage |
| 1 |
Awake |
| 4 |
Light |
| 5 |
Deep |
| 6 |
REM |
Setup path on Android: Zepp App → Profile → 3rd Party Account Linking → Health Connect
Historical data: Last 30 days on initial sync; forward-only thereafter.
3. OpenClaw Skill: amazfit-health-log
Location: ~/.openclaw/workspace/skills/amazfit-health-log/
amazfit-health-log/
├── SKILL.md ← OpenClaw skill descriptor
├── config.json ← HCGateway credentials & base URL
└── scripts/
└── fetch-health.py
config.json:
{
"base_url": "http://127.0.0.1:6644",
"username": "<USERNAME>",
"password": "<PASSWORD>"
}
fetch-health.py — core logic:
- Authenticates against HCGateway and obtains a Bearer token
- Fetches all relevant data types for a target date (default: yesterday)
- Aggregates steps (sum), distance (sum → km), sleep (total duration + stage breakdown in minutes), heart rate (avg / min / max), resting HR (daily value), SpO2 (avg)
- Handles the
distance field correctly — HCGateway returns it as a nested object with multiple units (inMeters, inKilometers, etc.) rather than a plain number
- Writes a structured Obsidian Markdown note with full YAML frontmatter
Usage:
# Yesterday (default)
python3 ~/.openclaw/workspace/skills/amazfit-health-log/scripts/fetch-health.py
# Specific date
python3 ~/.openclaw/workspace/skills/amazfit-health-log/scripts/fetch-health.py 2026-04-06
Requirements: Python 3.9+ (stdlib only — no pip dependencies)
📦 The complete amazfit-health-log OpenClaw skill is now published and available at clawhub.ai/sanwebgit/amazfit-health-log, directly installable for any OpenClaw user with a single command.
4. Generated Obsidian Note Format
Path: <VAULT_ROOT>/Gesundheit/Logs/GTR3/YYYY-MM-DD.md
The script generates a fully structured Markdown note with YAML frontmatter, an overview table, and dedicated sections for each health domain:
---
datum: 2026-04-06
wochentag: Monday
tags: [gesundheit, gtr3, log, automatisch]
quelle: HCGateway / Amazfit GTR3
erstellt: 2026-04-06T06:05
---
# 🏃 GTR3 Health Log — Monday, 06.04.2026
> [!info] Auto-generated
> This note was automatically created from Amazfit GTR3 data via HCGateway.
## 📊 Summary
| Metric | Value |
|--------|-------|
| 👟 Steps | 8432 |
| 📏 Distance | 6.2 km |
| 😴 Sleep Duration | 7h 15m |
| ❤️ Resting HR | 52 bpm |
| 🩸 SpO2 (avg) | 97.2 % |
### 😴 Sleep
- **Period:** 23:14 – 06:29
- **Duration:** 7h 15m
| Stage | Minutes |
|--------|---------|
| Deep | 82 min |
| REM | 74 min |
| Light | 259 min |
| Awake | 20 min |
### ❤️ Heart Rate
- **Avg** 68 bpm · Min 48 · Max 112 bpm
- **Resting HR:** 52 bpm
### 🩸 SpO2
- **Avg Blood Oxygen:** 97.2 %
Notes are linked to the previous and next day via Obsidian wikilinks for easy navigation.
5. OpenClaw Cron Job
Added to ~/.openclaw/cron/jobs.json — runs daily at 06:00 (Europe/Berlin), fetches the previous day's data, and sends a confirmation via messaging:
{
"id": "<uuid>",
"agentId": "main",
"name": "GTR3 Health Log",
"schedule": {
"kind": "cron",
"expr": "0 6 * * *",
"tz": "Europe/Berlin"
},
"sessionTarget": "isolated",
"payload": {
"kind": "agentTurn",
"message": "Run the GTR3 health log script and confirm the written values.",
"model": "<LLM_MODEL>"
},
"delivery": {
"mode": "announce",
"channel": "telegram",
"bestEffort": true
}
}
Device Compatibility
This integration was built and tested with an Amazfit GTR 3, but it should work with any Amazfit or Zepp-compatible device that:
- Syncs data to the Zepp app (not Zepp Life — though that may work too)
- Has Health Connect sync enabled in the Zepp app settings
- Supports the relevant health metrics (steps, sleep, heart rate, SpO2)
Likely compatible devices include other GTR / GTS series watches, the T-Rex series, Amazfit Balance, Bip series, and any device running Zepp OS with Health Connect write support. If you have tested this with a different device, please share your findings in the comments!
What Does NOT Work (EU Limitations)
- Blood pressure — The Amazfit GTR 3 hardware supports it, but the feature is blocked for EU users. Workaround: manual entry via a Telegram command parsed by OpenClaw.
- Google Health Cloud REST API — The new
googlehealth.activity_and_fitness.readonly OAuth scope exists and is real, but Zepp/Amazfit does not sync to Google's cloud — only to the local Health Connect. No cloud REST access is possible for Amazfit data via this route.
Prerequisites
- Android device (Android 14+ recommended) with Zepp app installed
- Amazfit GTR 3 (or compatible Zepp-based device) paired and syncing to Zepp
- Zepp → Health Connect sync enabled (Zepp → Profile → 3rd Party Account Linking)
- HCGateway Android app installed and pointing to your server
- Docker on VPS
- OpenClaw installed on VPS
- Python 3.9+ (stdlib only, no extra packages)
Known Issues / Future Work
🙏 A Heartfelt Thank You
Before diving into the technical details, a huge and sincere thank you to @shuchirj for building and maintaining HCGateway. This project is the critical missing piece that bridges the gap between the local Android Health Connect API and any self-hosted backend. Without this open-source effort, automating health data ingestion from consumer wearables would require either vendor lock-in or significantly more complex solutions. The clean REST API design, Bearer token auth, and Docker-first deployment made integration a joy. Truly outstanding work. 🎉
Overview
This issue documents a fully automated health data pipeline that reads data from an Amazfit GTR 3 smartwatch and writes structured daily log notes into an Obsidian vault, orchestrated by an OpenClaw agent skill running on a self-hosted VPS.
No proprietary cloud subscriptions or third-party SaaS services are required beyond the existing Zepp app and Google Health Connect (built into Android 14+).
Goal
Architecture & Data Flow
Components
1. HCGateway Server (Docker)
Stack: Python/Flask · MongoDB 7 · Docker Compose
docker-compose.yml:api/.env:Key API endpoints used:
POST/api/v2/loginPOST/api/v2/refreshPOST/api/v2/fetch/<type>2. Zepp ↔ Health Connect Sync
The Zepp app writes 26 health data types to Health Connect. Relevant confirmed types for GTR 3:
stepsdistanceinMeters)sleepSessionheartRaterestingHeartRateoxygenSaturationpercentagefieldSleep stage encoding (from
com.huami.watch.hmwatchmanager):Setup path on Android: Zepp App → Profile → 3rd Party Account Linking → Health Connect
Historical data: Last 30 days on initial sync; forward-only thereafter.
3. OpenClaw Skill:
amazfit-health-logLocation:
~/.openclaw/workspace/skills/amazfit-health-log/config.json:{ "base_url": "http://127.0.0.1:6644", "username": "<USERNAME>", "password": "<PASSWORD>" }fetch-health.py— core logic:distancefield correctly — HCGateway returns it as a nested object with multiple units (inMeters,inKilometers, etc.) rather than a plain numberUsage:
Requirements: Python 3.9+ (stdlib only — no pip dependencies)
4. Generated Obsidian Note Format
Path:
<VAULT_ROOT>/Gesundheit/Logs/GTR3/YYYY-MM-DD.mdThe script generates a fully structured Markdown note with YAML frontmatter, an overview table, and dedicated sections for each health domain:
Notes are linked to the previous and next day via Obsidian wikilinks for easy navigation.
5. OpenClaw Cron Job
Added to
~/.openclaw/cron/jobs.json— runs daily at 06:00 (Europe/Berlin), fetches the previous day's data, and sends a confirmation via messaging:{ "id": "<uuid>", "agentId": "main", "name": "GTR3 Health Log", "schedule": { "kind": "cron", "expr": "0 6 * * *", "tz": "Europe/Berlin" }, "sessionTarget": "isolated", "payload": { "kind": "agentTurn", "message": "Run the GTR3 health log script and confirm the written values.", "model": "<LLM_MODEL>" }, "delivery": { "mode": "announce", "channel": "telegram", "bestEffort": true } }Device Compatibility
This integration was built and tested with an Amazfit GTR 3, but it should work with any Amazfit or Zepp-compatible device that:
Likely compatible devices include other GTR / GTS series watches, the T-Rex series, Amazfit Balance, Bip series, and any device running Zepp OS with Health Connect write support. If you have tested this with a different device, please share your findings in the comments!
What Does NOT Work (EU Limitations)
googlehealth.activity_and_fitness.readonlyOAuth scope exists and is real, but Zepp/Amazfit does not sync to Google's cloud — only to the local Health Connect. No cloud REST access is possible for Amazfit data via this route.Prerequisites
Known Issues / Future Work
stressLevel,calories,heartRateVariabilityRmssdnot yet syncing from Zepp → Health Connect (zero records observed; may require explicit Health Connect permission grant in Zepp)