- Rust 58.1%
- HTML 31.6%
- CSS 6.5%
- JavaScript 3.5%
- Just 0.3%
The stat cards are now a table, easier to scan than the grid. The detail page also plots per-minute heart rate for the activity's time range with uPlot, reusing the existing /api/activity endpoint. An elevation graph was considered but dropped: this export has no per-timestamp altitude series anywhere in the DB (every altitude- bearing table is empty), only the aggregate gain/loss/min/max already in SUMMARY_DATA and shown in the stats table. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> |
||
|---|---|---|
| src | ||
| static | ||
| templates | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| DB-FORMAT.md | ||
| DB-INVESTIGATION.md | ||
| Justfile | ||
| README.md | ||
gadgetbridge-graph
A project to create graphs from a Gadgetbridge database — the SQLite export produced by the Gadgetbridge Android app, which stores activity, sleep, heart rate, and other data synced from Bluetooth wearables.
See DB-FORMAT.md for general Gadgetbridge database schema documentation and DB-INVESTIGATION.md for findings specific to the sample database used during development.
Running
The server reads Gadgetbridge.db in the working directory (override with GADGETBRIDGE_DB_PATH) and serves the API plus the static frontend on port 3000 (override with PORT):
just
This builds, runs, and opens http://localhost:3000/ in your browser. cargo run works too if you don't want the browser opened for you.
API
GET /api/activity?from=<unix_seconds>&to=<unix_seconds>— per-minute steps/heart rate/intensity samples fromGARMIN_ACTIVITY_SAMPLE.GET /api/body-battery?from=<unix_seconds>&to=<unix_seconds>— Body Battery (0–100) fromGARMIN_BODY_ENERGY_SAMPLE.GET /api/stress?from=<unix_seconds>&to=<unix_seconds>— stress score (0–100) fromGARMIN_STRESS_SAMPLE.GET /api/spo2?from=<unix_seconds>&to=<unix_seconds>— blood oxygen % fromGARMIN_SPO2_SAMPLE.GET /api/respiratory-rate?from=<unix_seconds>&to=<unix_seconds>— breathing rate fromGARMIN_RESPIRATORY_RATE_SAMPLE.GET /api/sleep-stages?from=<unix_seconds>&to=<unix_seconds>— sleep-stage transitions fromGARMIN_SLEEP_STAGE_SAMPLE(event-based, not fixed-interval).GET /api/sleep-nights?from=<unix_seconds>&to=<unix_seconds>— one row per night (sleep score, restless-moment count, HRV last-night average) joined fromGARMIN_SLEEP_STATS_SAMPLE,GARMIN_SLEEP_RESTLESS_MOMENTS_SAMPLE, andGARMIN_HRV_SUMMARY_SAMPLE.GET /api/charging-sessions— every charge-up derived fromBATTERY_LEVEL(a maximal run of non-decreasing samples), as{start_timestamp, start_level, end_timestamp, end_level}.GET /api/daily-steps— total steps per local calendar day, as{date, steps}(dateisYYYY-MM-DD), for every day with data.GET /api/activities— every logged workout fromBASE_ACTIVITY_SUMMARY, most recent first.GET /api/activities/<id>— full detail (curated stats parsed out ofSUMMARY_DATA) for one activity, or 404.
More query endpoints will be added as new graphs/facts are needed.
Pages
/— heart rate, Body Battery, stress, SpO2, and respiratory rate over a selectable time range./activities— logged workouts (walks, rides, hikes, ...) from most recent to oldest./activities/<id>— detail page for one activity: distance, duration, heart rate, training effect, and other stats found in itsSUMMARY_DATA./calendar.html— a month calendar with a per-day step gauge, sized against the highest daily step count ever recorded and colored on a red-yellow-green gradient by progress toward a configurable daily target (green at or above it, red at or below half of it)./sleep.html— a per-night sleep-stage hypnogram, plus nightly trends for sleep score, restless moments, and HRV./fun-facts.html— charging frequency and the weekday you usually charge on.
Pages are rendered server-side with Askama templates in templates/. templates/layout.html holds the shared nav and page shell; each page template extends it and only fills in its own content block, so the header/footer stay consistent automatically. Shared styling lives in static/style.css, themed with the Solarized palette (dark by default, light via prefers-color-scheme). Charts are rendered with uPlot (vendored under static/vendor/uplot/, no CDN dependency) instead of hand-rolled canvas drawing; the shared setup for a time-series line chart lives in static/charts.js (createLineChart), used by both / and /sleep.html.
Development
just test
just lint