moved to python for garmin api and golang for everything else

This commit is contained in:
2025-08-26 10:29:42 -07:00
parent 8558ac3d41
commit 0a5076f7bb
7 changed files with 289 additions and 368 deletions

View File

@@ -0,0 +1,25 @@
# Builder stage
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Final stage
FROM python:3.12-slim
WORKDIR /app
# Copy dependencies from builder stage
COPY --from=builder /usr/local/lib/python3.12/site-packages /usr/local/lib/python3.12/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
# Copy application code
COPY app.py .
# Add user for security
RUN groupadd -r appuser && \
useradd -r -g appuser appuser && \
chown -R appuser:appuser /app
USER appuser
EXPOSE 8081
CMD ["python", "app.py"]

86
garmin-api-wrapper/app.py Normal file
View File

@@ -0,0 +1,86 @@
import os
import json
from flask import Flask, request, jsonify
from garminconnect import Garmin
import logging
app = Flask(__name__)
# Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
# Environment variables
GARMIN_EMAIL = os.getenv("GARMIN_EMAIL")
GARMIN_PASSWORD = os.getenv("GARMIN_PASSWORD")
def init_api():
"""Initializes the Garmin API client."""
try:
api = Garmin(GARMIN_EMAIL, GARMIN_PASSWORD)
api.login()
logger.info("Successfully authenticated with Garmin API")
return api
except Exception as e:
logger.error(f"Error initializing Garmin API: {e}")
return None
@app.route('/stats', methods=['GET'])
def get_stats():
"""Endpoint to get user stats."""
stats_date = request.args.get('date')
if not stats_date:
return jsonify({"error": "A 'date' query parameter is required in YYYY-MM-DD format."}), 400
api = init_api()
if not api:
return jsonify({"error": "Failed to connect to Garmin API"}), 500
try:
logger.info(f"Fetching stats for date: {stats_date}")
user_stats = api.get_stats(stats_date)
return jsonify(user_stats)
except Exception as e:
logger.error(f"Error fetching stats: {str(e)}")
return jsonify({"error": str(e)}), 500
@app.route('/activities', methods=['GET'])
def get_activities():
"""Endpoint to get activities list."""
start = request.args.get('start', default=0, type=int)
limit = request.args.get('limit', default=10, type=int)
api = init_api()
if not api:
return jsonify({"error": "Failed to connect to Garmin API"}), 500
try:
logger.info(f"Fetching activities from {start} with limit {limit}")
activities = api.get_activities(start, limit)
return jsonify(activities)
except Exception as e:
logger.error(f"Error fetching activities: {str(e)}")
return jsonify({"error": str(e)}), 500
@app.route('/activities/<activity_id>', methods=['GET'])
def get_activity_details(activity_id):
"""Endpoint to get activity details."""
api = init_api()
if not api:
return jsonify({"error": "Failed to connect to Garmin API"}), 500
try:
logger.info(f"Fetching activity details for {activity_id}")
activity = api.get_activity(activity_id)
return jsonify(activity)
except Exception as e:
logger.error(f"Error fetching activity details: {str(e)}")
return jsonify({"error": str(e)}), 500
@app.route('/health', methods=['GET'])
def health_check():
"""Health check endpoint."""
return jsonify({"status": "healthy", "service": "garmin-api"})
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8081)

View File

@@ -0,0 +1,3 @@
garminconnect==0.2.28
garth
Flask

View File

@@ -0,0 +1,69 @@
import os
import json
from garminconnect import Garmin
import logging
from datetime import datetime
def main():
# Setup logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s')
logger = logging.getLogger(__name__)
print("=== Starting Garmin API Tests ===")
# Load credentials from environment
email = os.getenv("GARMIN_EMAIL")
password = os.getenv("GARMIN_PASSWORD")
if not email or not password:
logger.error("GARMIN_EMAIL or GARMIN_PASSWORD environment variables not set")
return
try:
# 1. Test Authentication
logger.info("Testing authentication...")
api = Garmin(email, password)
api.login()
logger.info("✅ Authentication successful")
# 2. Test Activity Listing
logger.info("Testing activity listing...")
activities = api.get_activities(0, 1) # Get 1 most recent activity
if not activities:
logger.error("❌ No activities found")
else:
logger.info(f"✅ Found {len(activities)} activities")
print("Sample activity:")
print(json.dumps(activities[0], indent=2)[:1000]) # Print first 1000 chars
# 3. Test Activity Download (if we got any activities)
if activities:
logger.info("Testing activity download...")
activity_id = activities[0]["activityId"]
details = api.get_activity(activity_id)
if details:
logger.info(f"✅ Activity {activity_id} details retrieved")
print("Sample details:")
print(json.dumps(details, indent=2)[:1000]) # Print first 1000 chars
else:
logger.error("❌ Failed to get activity details")
# 4. Test Stats Retrieval
logger.info("Testing stats retrieval...")
stats = api.get_stats(datetime.now().strftime("%Y-%m-%d"))
if stats:
logger.info("✅ Stats retrieved")
print(json.dumps(stats, indent=2)[:1000])
else:
logger.error("❌ Failed to get stats")
except Exception as e:
logger.error(f"❌ Test failed: {str(e)}")
# Print detailed exception info
import traceback
traceback.print_exc()
print("\n=== Test Complete ===")
if __name__ == "__main__":
main()