mirror of
https://github.com/sstent/GarminSync.git
synced 2026-01-26 09:02:51 +00:00
9.1 KiB
9.1 KiB
Of course. The design has been updated to use the python-garminconnect library and now includes a dedicated documentation section with links to all key upstream libraries.
GarminSync Application Design (Python Version)
Basic Info
App Name: GarminSync
What it does: A CLI application that downloads .fit files for every activity in Garmin Connect.
Core Features
- List all activities (
garminsync list --all) - List activities that have not been downloaded (
garminsync list --missing) - List activities that have been downloaded (
garminsync list --downloaded) - Download all missing activities (
garminsync download --missing)
Tech Stack 🐍
- Frontend: CLI (Python)
- Backend: Python
- Database: SQLite (
garmin.db) - Hosting: Docker container
- Key Libraries:
python-garminconnect: The library for Garmin Connect API communication.typer: A modern and easy-to-use CLI framework (built onclick).python-dotenv: For loading credentials from a.envfile.sqlalchemy: A robust ORM for database interaction and schema management (using Alembic for migrations). The built-insqlite3module can be used for simpler needs.tqdm: For creating user-friendly progress bars.
Data Structure
The core database schema remains the same. It can be defined using raw SQL with the sqlite3 module or, more robustly, with an SQLAlchemy model.
SQLAlchemy Model Example (models.py):
from sqlalchemy import create_engine, Column, Integer, String, Boolean
from sqlalchemy.orm import declarative_base
Base = declarative_base()
class Activity(Base):
__tablename__ = 'activities'
activity_id = Column(Integer, primary_key=True)
start_time = Column(String, nullable=False)
filename = Column(String, unique=True, nullable=True)
downloaded = Column(Boolean, default=False, nullable=False)
User Flow
- User launches the container with their credentials:
docker run -it --env-file .env -v $(pwd)/data:/app/data garminsync - The application presents a help menu generated by
Typer. - User runs a command, e.g.,
garminsync download --missing. - The application executes the task, showing progress indicators for API calls and downloads.
- Upon completion, the application displays a summary of actions taken.
File Structure
A standard Python project structure is recommended.
/garminsync
├── garminsync/ # Main application package
│ ├── __init__.py
│ ├── cli.py # Typer CLI commands and entrypoint
│ ├── config.py # Configuration loading (dotenv)
│ ├── database.py # SQLAlchemy models and sync logic
│ └── garmin.py # Wrapper for the python-garminconnect client
├── data/ # Directory for downloaded .fit files and DB
├── tests/ # Unit and integration tests
├── .env # Stores GARMIN_EMAIL/GARMIN_PASSWORD
├── .gitignore
├── Dockerfile
├── README.md
└── requirements.txt # Pinned Python dependencies
Technical Implementation Notes
- Architecture: A Python application using
Typerfor the CLI. Logic is separated into modules for configuration, database interaction, and Garmin communication. - Authentication: Credentials from
GARMIN_EMAILandGARMIN_PASSWORDenvironment variables are loaded viapython-dotenvand passed topython-garminconnect. - File Naming: Files will be named using Python's f-strings:
f"activity_{activity_id}_{timestamp}.fit". - Rate Limiting: A simple
time.sleep(2)will be inserted between API requests to avoid overloading Garmin's servers. - Database: The schema will be managed by
SQLAlchemy. Versioned migrations can be handled by Alembic, which integrates with SQLAlchemy. - Database Sync: Before any operation, a sync function will use
python-garminconnectto fetch the latest activities and reconcile them with the local SQLite database. - Package Management: Dependencies and their versions will be pinned in
requirements.txtfor reproducible builds (pip freeze > requirements.txt). - Session Management:
python-garminconnecthandles authentication and session management. - Docker Permissions: Mounting a local
./datadirectory into the container allows downloaded files and the database to persist. Thesudoprefix is generally not required if the user is part of thedockergroup.
Development Phases (Proposed for Python)
Phase 1: Core Infrastructure
Dockerfilecreation for a Python environment.- Uses Python 3.10 slim base image
- Sets PYTHONDONTWRITEBYTECODE and PYTHONUNBUFFERED
- Installs build dependencies
- Copies requirements first for layer caching
- Sets ENV_FILE for configuration
- Entrypoint runs application via
python -m garminsync
- Setup
python-dotenvfor environment variable handling.- Added
python-dotenvto requirements.txt - Implemented environment loading in config.py:
from dotenv import load_dotenv load_dotenv() # Load .env file - Updated Dockerfile to copy .env file during build
- Added documentation for environment variable setup
- Added
- Initialize the
TyperCLI framework incli.py.- Created basic Typer app structure
- Implemented skeleton commands for
listanddownload - Added proper type hints and docstrings
- Integrated with config.py for environment variable loading
- Implement the
python-garminconnectclient wrapper (garmin.py).- Created GarminClient class with authentication
- Implemented get_activities() with rate limiting
- Implemented download_activity_fit() method
- Added error handling for missing credentials
Phase 2: Activity Listing
- Implement the
SQLAlchemyschema and database connection.- Created database.py with Activity model
- Implemented init_db() for database initialization
- Added get_session() for session management
- Implemented sync_database() to fetch activities from Garmin and update database
- Create the
listcommands (--all,--missing,--downloaded).- Implemented command logic in cli.py
- Added database synchronization before listing
- Added input validation for filter options
- Used tqdm for progress display
Phase 3: Download Pipeline
- Implement the
.fitfile download function usingpython-garminconnect.- Added download logic to cli.py
- Used GarminClient to download FIT files
- Created filename-safe timestamps
- Saved files to data directory
- Ensure downloads are idempotent (don't re-download existing files).
- Database tracks downloaded status
- Only missing activities are downloaded
- Update the database record to
downloaded=Trueon success.- Updated activity record after successful download
- Set filename path in database
Phase 4: Polish ✨
- Add
tqdmprogress bars for the download command.- Implemented in both list and download commands
- Update Dockerfile to:
- Use multi-stage builds for smaller image size
- Add health checks
- Set non-root user for security
- Implement robust error handling (e.g., API errors, network issues).
- Basic error handling implemented but needs improvement
- Write comprehensive
README.mddocumentation. - Add unit tests for database and utility functions.
Current Issues
-
Docker Build Warnings
- Legacy ENV format warnings during build
- Solution: Update Dockerfile to use
ENV key=valueformat
-
Typer Command Parameters
- Occasional
Parameter.make_metavar()errors - Resolved by renaming reserved keywords and fixing decorators
- Occasional
-
Configuration Loading
- Initial import issues between modules
- Resolved by restructuring config loading
Documentation 📚
Here are links to the official documentation for the key libraries used in this design.
- Garmin API:
python-garminconnect - CLI Framework:
Typer - Environment Variables:
python-dotenv - Database ORM:
SQLAlchemy - Database Migrations:
Alembic - Progress Bars:
tqdm