mirror of
https://github.com/sstent/garminsync-go.git
synced 2026-01-27 01:21:57 +00:00
moved to python for garmin api and golang for everything else
This commit is contained in:
25
garmin-api-wrapper/Dockerfile
Normal file
25
garmin-api-wrapper/Dockerfile
Normal 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
86
garmin-api-wrapper/app.py
Normal 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)
|
||||
3
garmin-api-wrapper/requirements.txt
Normal file
3
garmin-api-wrapper/requirements.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
garminconnect==0.2.28
|
||||
garth
|
||||
Flask
|
||||
69
garmin-api-wrapper/test_api.py
Normal file
69
garmin-api-wrapper/test_api.py
Normal 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()
|
||||
Reference in New Issue
Block a user