Skip to content

Commit d8fb7ab

Browse files
committed
Initial README - public-facing planning doc
0 parents  commit d8fb7ab

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

README.md

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
# polar-flow-server
2+
3+
Self-hosted health analytics server for Polar devices. Own your data, analyze it yourself.
4+
5+
## What This Does
6+
7+
Polar devices (watches, fitness trackers) collect health data: sleep, HRV, activity, exercises. The Polar API gives you access to this data, but only for the last 28-30 days. No long-term trends, no baselines, no recovery analysis.
8+
9+
This server fixes that. It:
10+
11+
1. **Syncs** your data from the Polar API automatically
12+
2. **Stores** everything in a local database (your data, your disk)
13+
3. **Analyzes** the data (HRV baselines, recovery scores, sleep debt, training load)
14+
4. **Exposes** a REST API so you can build dashboards, apps, or integrations
15+
16+
Think of it as your personal health data warehouse with built-in analytics.
17+
18+
## Why Self-Host
19+
20+
- **Own your data** - Not locked into Polar's 28-day window
21+
- **Deep analysis** - HRV baselines over months/years, not days
22+
- **Privacy** - Your health data stays on your server
23+
- **Extensible** - Build your own dashboards, connect to other tools
24+
- **Free** - No subscription, no limits
25+
26+
## Architecture
27+
28+
```
29+
Polar API → polar-flow SDK → Scheduler → Database → Analytics Engine → REST API
30+
31+
Your Dashboard/App
32+
```
33+
34+
**Components:**
35+
36+
- **Scheduler** - Fetches new data every hour using [polar-flow](https://github.com/StuMason/polar-flow)
37+
- **Database** - DuckDB (embedded) or TimescaleDB (production)
38+
- **Analytics** - HRV baselines, recovery scores, sleep debt calculations
39+
- **API** - FastAPI endpoints for querying your data
40+
- **MCP Server** (optional) - Claude Desktop integration for AI health insights
41+
42+
## What You Get
43+
44+
**Data Storage:**
45+
- Sleep data (scores, stages, HRV, breathing rate)
46+
- Nightly Recharge (ANS charge, recovery metrics)
47+
- Activities (steps, calories, distance, zones)
48+
- Exercises (workouts with heart rate, pace, samples)
49+
50+
**Computed Metrics:**
51+
- HRV baselines (7-day, 30-day rolling averages)
52+
- HRV deviation from baseline (%)
53+
- Recovery status (recovered, recovering, strained)
54+
- Sleep debt tracking
55+
- Training load and readiness scores
56+
57+
**API Endpoints:**
58+
- `/recovery/today` - Current recovery status
59+
- `/sleep/history` - Historical sleep data with computed metrics
60+
- `/activity/list` - Activity summaries
61+
- `/hrv/trends` - HRV trends and baselines
62+
- `/sync/trigger` - Manual sync endpoint
63+
64+
## Prerequisites
65+
66+
- A Polar device (watch, fitness tracker)
67+
- Polar AccessLink API credentials ([get them here](https://admin.polaraccesslink.com))
68+
- Docker (easiest) or Python 3.11+
69+
- 100MB disk space (grows with your data)
70+
71+
## Quick Start
72+
73+
### 1. Get Polar API Credentials
74+
75+
1. Go to [admin.polaraccesslink.com](https://admin.polaraccesslink.com)
76+
2. Create a new client
77+
3. Set redirect URI to `http://localhost:8888/callback`
78+
4. Note your `CLIENT_ID` and `CLIENT_SECRET`
79+
80+
### 2. Authenticate
81+
82+
```bash
83+
docker run -it --rm \
84+
-e CLIENT_ID=your_client_id \
85+
-e CLIENT_SECRET=your_client_secret \
86+
-v ~/.polar-flow:/root/.polar-flow \
87+
stumason/polar-flow-server \
88+
polar-flow auth
89+
```
90+
91+
This opens your browser, handles OAuth, and saves the token.
92+
93+
### 3. Run the Server
94+
95+
```bash
96+
docker run -d \
97+
-p 8000:8000 \
98+
-v ~/.polar-flow:/root/.polar-flow \
99+
-v polar-data:/data \
100+
--name polar-flow-server \
101+
stumason/polar-flow-server
102+
```
103+
104+
That's it. The server starts syncing your data every hour.
105+
106+
### 4. Check Your Data
107+
108+
```bash
109+
curl http://localhost:8000/recovery/today
110+
```
111+
112+
## Installation
113+
114+
### Docker (Recommended)
115+
116+
See Quick Start above.
117+
118+
### Docker Compose
119+
120+
```yaml
121+
version: "3.8"
122+
123+
services:
124+
polar-flow-server:
125+
image: stumason/polar-flow-server:latest
126+
ports:
127+
- "8000:8000"
128+
volumes:
129+
- ~/.polar-flow:/root/.polar-flow
130+
- polar-data:/data
131+
environment:
132+
- SYNC_INTERVAL_HOURS=1
133+
restart: unless-stopped
134+
135+
volumes:
136+
polar-data:
137+
```
138+
139+
### From Source
140+
141+
```bash
142+
git clone https://github.com/StuMason/polar-flow-server.git
143+
cd polar-flow-server
144+
145+
# Install dependencies
146+
uv sync
147+
148+
# Authenticate
149+
uv run polar-flow auth
150+
151+
# Run server
152+
uv run python -m polar_flow_server
153+
```
154+
155+
## Configuration
156+
157+
Environment variables:
158+
159+
- `DATABASE_PATH` - Path to DuckDB file (default: `/data/polar.db`)
160+
- `SYNC_INTERVAL_HOURS` - How often to sync (default: `1`)
161+
- `SYNC_ON_STARTUP` - Sync immediately on start (default: `true`)
162+
- `API_HOST` - API host (default: `0.0.0.0`)
163+
- `API_PORT` - API port (default: `8000`)
164+
165+
## API Documentation
166+
167+
Once running, visit `http://localhost:8000/docs` for interactive API documentation.
168+
169+
Key endpoints:
170+
171+
**Recovery:**
172+
- `GET /recovery/today` - Current recovery status with score and recommendation
173+
- `GET /recovery/history?days=7` - Recovery history
174+
175+
**Sleep:**
176+
- `GET /sleep/history?days=30` - Sleep data with computed metrics
177+
- `GET /sleep/debt` - Current sleep debt
178+
179+
**Activity:**
180+
- `GET /activity/list` - Recent activities
181+
- `GET /activity/trends` - Activity trends
182+
183+
**HRV:**
184+
- `GET /hrv/trends?days=90` - HRV baselines and trends
185+
186+
**Sync:**
187+
- `POST /sync/trigger` - Manually trigger data sync
188+
- `GET /sync/status` - Check sync status
189+
190+
## Analytics Explained
191+
192+
### HRV Baseline
193+
194+
Calculates rolling median HRV over 7 and 30 days. Median is used instead of mean to reduce impact of outliers (bad sleep, alcohol, etc.).
195+
196+
**Why it matters:** HRV below your baseline indicates stress, fatigue, or illness. HRV above baseline indicates good recovery.
197+
198+
### Recovery Score
199+
200+
Weighted combination of:
201+
- HRV deviation (40%)
202+
- Sleep score (30%)
203+
- ANS charge (20%)
204+
- Sleep duration (10%)
205+
206+
**Scale:** 0-100
207+
- 70+ = Recovered (ready for intense training)
208+
- 50-70 = Recovering (moderate training ok)
209+
- <50 = Strained (prioritize rest)
210+
211+
### Sleep Debt
212+
213+
Cumulative sleep deficit relative to your target (default 8 hours). Includes decay factor - old debt gradually diminishes.
214+
215+
**Why it matters:** Sleep debt accumulates and impacts recovery, performance, and health.
216+
217+
## MCP Server (Claude Integration)
218+
219+
Optional feature for Claude Desktop users. Enables natural language queries:
220+
221+
- "What's my recovery status?"
222+
- "Should I train hard today?"
223+
- "Show my HRV trends this month"
224+
- "Am I getting enough sleep?"
225+
226+
Enable by setting `ENABLE_MCP=true`.
227+
228+
## Development
229+
230+
```bash
231+
# Run tests
232+
uv run pytest
233+
234+
# Run with hot reload
235+
uv run uvicorn polar_flow_server.main:app --reload
236+
237+
# Run sync manually
238+
uv run python -m polar_flow_server.sync
239+
```
240+
241+
## Contributing
242+
243+
Contributions welcome! This is a personal project but PRs for bug fixes, new analytics, or features are appreciated.
244+
245+
## License
246+
247+
MIT
248+
249+
## Acknowledgments
250+
251+
Built on [polar-flow](https://github.com/StuMason/polar-flow), a modern Python SDK for the Polar AccessLink API.
252+
253+
## Support
254+
255+
This is a self-hosted tool. No support provided, but feel free to open issues for bugs or feature requests.
256+
257+
If you want a managed version with dashboards, mobile apps, and support, check out [stumason.dev](https://stumason.dev).

0 commit comments

Comments
 (0)