Skip to content

rwlove/PUMP

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

251 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Publish Container Images Go Report Card

PUMP

Please Use More Protein — workout diary with daily set logging, body weight tracking, training stats, and a whole-body Health dashboard fed by your fitness tracker via Android Health Connect.

Overall Health Workout Stats: Exercise Distribution
Overall Health Workout Stats Exercise Distribution
Stats: Weight Moved Stats: Body Weight Config
Stats Weight Moved Stats Body Weight Config
Stats: Steps Stats: Heart Rate Stats: Sleep
Stats Steps Stats Heart Rate Stats Sleep
Stats: Cardio Stats: Muscle Balance
Stats Cardio Stats Muscle Balance

Architecture

Browser ──▶ pump  :8080  ──▶ PostgreSQL
            (UI + API)

The pump monolith serves both the web UI and the JSON API on a single port (default 8080). There is no separate API or frontend port — all traffic goes through :8080.

Path prefix Purpose
/ Web UI (HTML, CSS, JS)
/api/ JSON REST API (used by pump-cv and other in-cluster integrations)

Use image ghcr.io/rwlove/pump. Set POSTGRES_DSN. Front the deployment with an OIDC reverse proxy (e.g. oauth2-proxy) on the gateway — pump itself ships with no inbound auth.

Optional: pump-cv camera sidecar

A separate Python service under cv/ watches gym cameras, detects exercises/reps/sets, and writes them to PUMP via the per-set REST API. Disabled by default — enable on the config page (CVAutoLog) once cameras are installed and the sidecar is running. See docs/cv-autolog-plan.md for the full design and cv/README.md for runtime details.

Health dashboard & wearable metrics

The Health page (/health/) is a one-page, whole-body view that pulls from every source PUMP tracks — body weight, strength training, and wearable metrics — as summary tiles (latest value, trend delta, sparkline) that deep-link into the matching Stats tab.

Wearable data is ingested generically from Android Health Connect via the HC Webhook bridge app, which POSTs a Health Connect envelope to POST /api/health (gated by HEALTH_INGEST_KEY). Each datum is stored in the health_record table, deduped on (metric_type, start_time, end_time). The known types (steps, active calories, heart rate, resting heart rate, sleep, exercise) are charted on dedicated Stats tabs — Steps, Heart Rate, Sleep, Cardio — and every other Health Connect type is preserved generically, so no schema change is needed to ingest new metrics.

Notes on source coverage: sleep stages arrive as Health Connect numeric stage codes and are decoded into Deep/Light/REM/Awake minutes. When a source exports raw heart_rate but no resting_heart_rate, the day's minimum heart rate is used as a resting-HR estimate. The Cardio tab charts daily active calories (active_calories); per-session cardio also appears there once the bridge exports ExerciseSession records.

Cardio sessions can also be captured directly from the gym treadmill with no wearable involved. The treadmill's Z-Wave metering smart plug publishes its wattage to MQTT (via zwave-js-ui); when TREADMILL_MQTT_ENABLED is set, PUMP subscribes to that feed, detects a workout with a wattage threshold + off-debounce state machine, and writes each session as an exercise record (duration only — a plug can't measure distance). These land on the Cardio tab alongside wearable sessions and dedupe on (metric_type, start_time, end_time) like every other health record. See the TREADMILL_MQTT_* settings below.

Configuration

All configuration is via environment variables. No config file is required.

pump

Variable Description Default
PORT Listen port 8080
HOST Listen address 0.0.0.0
POSTGRES_DSN PostgreSQL connection string (required)
API_KEY Sent as X-Api-Key when proxying to pump-cv (server-to-server only — pump has no inbound auth) ""
WEIGHT_INGEST_KEY When set, POST /api/weight requires header X-Api-Key matching this value. Enables off-cluster ingest (e.g. a BLE-scale ESPHome device) via an oauth2-bypassing internal Route scoped to /api/weight. Unset preserves the legacy no-inbound-auth posture. ""
HEALTH_INGEST_KEY When set, POST /api/health requires header X-Api-Key matching this value. Enables off-cluster wearable-metrics ingest from Android Health Connect (via the HC Webhook bridge app) over a path-scoped internal Route. The endpoint accepts a Health Connect envelope (per-type arrays: steps, active_calories, heart_rate, sleep, exercise, …) and stores each datum in health_record, deduped on (metric_type, start_time, end_time). Unset preserves the no-inbound-auth posture. ""
LOG_LEVEL Log verbosity: debug, info, warn, error info
COLOR UI color mode: light or dark dark
PAGESTEP Rows per page on the body weight log 10
DISPLAY_DAYS Days of workout history shown on the main page (7/30/90/365) 30
FREQUENCY_DAYS Look-back window (days) for sorting exercises by usage frequency 30
AUTOFILL Pre-fill weight/reps from last performance when adding a set true
CVAUTOLOG Accept set writes from the pump-cv camera sidecar; toggleable in the UI false
PUSHOVER_USER_KEY Pushover user key for low-confidence set notifications; env-only, never in UI ""
PUSHOVER_APP_TOKEN Pushover app token for low-confidence set notifications; env-only, never in UI ""
PUSHOVER_API_URL Pushover API endpoint override (testing only) Pushover
PUBLIC_URL Externally-reachable PUMP base URL; used to build deep-links in notifications ""
PUMP_CV_URL Where to forward reference-clip uploads (e.g. http://pump-cv:8080); empty disables the in-browser recorder ""
NODE_PATH Path to local node_modules directory; empty = use CDN for Bootstrap/Chart.js ""
TREADMILL_MQTT_ENABLED Enable treadmill cardio auto-capture: subscribe to the smart-plug wattage feed zwave-js-ui publishes to MQTT, detect each workout, and log it as a cardio session (no Home Assistant in the path). false
TREADMILL_MQTT_BROKER MQTT broker URL, e.g. tcp://emqx-headless.home.svc.cluster.local:1883 ""
TREADMILL_MQTT_USERNAME MQTT broker username ""
TREADMILL_MQTT_PASSWORD MQTT broker password ""
TREADMILL_MQTT_TOPIC Topic carrying the plug's instantaneous wattage (Z-Wave Meter CC) zwave/Gym/Treadmill/50/0/value/66049
TREADMILL_WATTS_THRESHOLD Watts at/above which the treadmill counts as "in use" 50
TREADMILL_OFF_DEBOUNCE_SECONDS Sustained sub-threshold time before a session closes (ignores brief dips) 60
TREADMILL_MIN_SESSION_SECONDS Sessions shorter than this are discarded 120
TREADMILL_SESSION_TYPE Cardio type label stored with each session Treadmill
TZ Timezone ""

POSTGRES_DSN must be set or the server will not start:

POSTGRES_DSN=postgres://user:password@host:5432/pump

The schema is versioned and managed automatically on startup — no manual CREATE TABLE needed.

pump-cv (optional camera sidecar)

A separate Python service under cv/ that watches gym RTSP cameras, detects exercises/reps/sets, and writes them to PUMP via the per-set REST API. Disabled by default — set CVAUTOLOG=true (or flip the toggle in PUMP's settings) once cameras are installed and the sidecar is running.

Reads its configuration from a yaml file (mounted as a Kubernetes ConfigMap, default path /app/configs/default.yaml) plus a few env overrides. See cv/README.md for the full module breakdown.

Variable Description Default
PUMP_API_BASE_URL Override pump.base_url from the yaml yaml value
PUMP_API_KEY Sent as X-Api-Key on every PUMP request; secret, not in yaml ""
PUMP_CV_CONFIG Path to the yaml config configs/default.yaml
PUMP_CV_PROTOTYPE_DIR Where DTW exercise prototypes are stored prototypes
PUMP_CV_SNAPSHOT_DIR Where annotated debug snapshots are written per detected set snapshots
PUMP_CV_HEALTHD_PORT Listen port for /healthz, /readyz, /metrics, and POST /api/v1/reference 8080
CV_CONFIDENCE_THRESHOLD Override the cutoff for marking a CV-detected set pending yaml value
LOG_LEVEL debug / info / warn / error info

Architecture sketch

┌────────────────────────┐         ┌──────────────────────────┐
│ pump (Go) Deployment   │         │ pump-cv (Python)         │
│  ports: 8080           │         │  ports: 8080 (healthd)   │
│  env: POSTGRES_DSN     │ ──────▶ │  resources: nvidia.com/  │
│       PUMP_CV_URL      │  HTTP   │             gpu: 1       │
│       PUSHOVER_*       │ ◀────── │  env: PUMP_API_BASE_URL  │
│       CVAUTOLOG=true   │ /api/   │       PUMP_API_KEY (Sec) │
└────────────────────────┘  sets   │  vol: /data/pump-cv      │
            │                      │       (prototypes,       │
            ▼                      │        snapshots)        │
   PostgreSQL (Service)            │  config: ConfigMap →     │
                                   │          /app/configs/   │
                                   └──────────────────────────┘
                                              ▲
                                              │ RTSP
                                  ┌───────────┴───────────┐
                                  │     IP cameras        │
                                  └───────────────────────┘

The two services are independent Deployments, talk only over HTTP+JSON, and either can be restarted without touching the other. pump-cv only needs egress to PUMP and ingress from RTSP cameras — no public-internet egress (Pushover credentials live on the PUMP side, not the sidecar).

A persistent volume holding prototypes/ and snapshots/ is recommended; both directories are write-only from pump-cv and survive Pod restarts. Exercise prototypes are loaded once at sidecar startup, so a rolling restart is needed to pick up new prototypes (UI uploads work via the live POST /api/v1/reference endpoint without restart, but the next pipeline restart will then see them).

About

The official Please Use More Protein repository!

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors