Overview
Containerize the Garmin report scripts so they run cleanly on a Raspberry Pi 2 without installing Python, pip, or any dependencies on the host. The container spins up, runs the script, and exits — no resources wasted.
Prerequisites
- Raspberry Pi with Docker and Docker Compose installed
- The garminconnector repository cloned on the Pi
config.pywith Garmin credentials on the Pi
Step 1: Dockerfile
The Dockerfile uses python:3.11-slim as the base image with only the garth dependency:
FROM python:3.11-slim
WORKDIR /app
# Install dependencies
RUN pip install --no-cache-dir "garth>=0.5.17,<0.6.0"
# Copy project files
COPY garminconnect/ ./garminconnect/
COPY custom_scripts/ ./custom_scripts/
# Default script (override with any script at runtime)
CMD ["python3", "custom_scripts/daily_report.py"]
Key design decisions:
python:3.11-slim— Small image, has everything needed- Only
garthdependency — The garminconnect library is copied directly CMDsets the default script, but can be overridden at runtime
Step 2: Docker Compose
services:
garmin-report:
build: .
volumes:
- ./config.py:/app/config.py:ro
- garth-tokens:/root/.garth
environment:
- TZ=Australia/Sydney
volumes:
garth-tokens:
Key details:
config.pyis mounted read-only (:ro) — credentials stay on the host, not baked into the imagegarth-tokensis a named volume — OAuth tokens persist between container runsTZ=Australia/Sydney— Ensures correct timezone for report dates
Step 3: Build & Test on the Pi
SSH into the Pi and run:
cd ~/garminconnector
git pull
docker compose build
Create config.py if it doesn’t exist:
cp config.example.py config.py
nano config.py
# Fill in your Garmin email and password
Test the daily report:
docker compose run --rm garmin-report
Success: You should see the full daily health report output in your terminal.
Running Different Scripts
The Docker image contains all scripts from custom_scripts/. Override the default command to run any of them:
# Daily report (default)
docker compose run --rm garmin-report
# Weekly report
docker compose run --rm garmin-report python3 custom_scripts/weekly_report.py
# Trainer report
docker compose run --rm garmin-report python3 custom_scripts/trainer_report.py
# Heart rate analysis
docker compose run --rm garmin-report python3 custom_scripts/heart_rate_analysis.py
One Docker image, any script.
How It Works
docker compose run --rm garmin-report
│
▼
┌─────────────────────┐
│ Spin up container │
│ python:3.11-slim │
├─────────────────────┤
│ Mount config.py │ ← credentials from host
│ Mount garth-tokens │ ← persisted OAuth tokens
├─────────────────────┤
│ Run daily_report │ ← fetches Garmin API data
│ Print output │ ← captured by caller
├─────────────────────┤
│ Container exits │
│ --rm removes it │ ← clean, no leftover containers
└─────────────────────┘
Updating
When you update scripts on your Mac and push to git:
# On the Pi
cd ~/garminconnector
git pull
docker compose build
The image rebuilds with the latest scripts.
