-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathgarmin_client.py
More file actions
90 lines (71 loc) · 2.86 KB
/
garmin_client.py
File metadata and controls
90 lines (71 loc) · 2.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
"""Simplified Garmin client using .env configuration."""
import io
import logging
import os
import garth
logger = logging.getLogger(__name__)
class GarminException(Exception):
"""Exception for Garmin API errors."""
pass
class GarminClient:
"""Simplified Garmin client using .env configuration."""
def __init__(self):
# Load configuration from environment variables
self.username = os.getenv("GARMIN_USERNAME")
self.password = os.getenv("GARMIN_PASSWORD")
if not self.username or not self.password:
raise GarminException(
"Missing required environment variables:"
" GARMIN_USERNAME, GARMIN_PASSWORD"
)
# Session file location - store in project directory
self.session_file = ".garmin_session"
# Initialize Garth client
# Temporary fix for Garth user agent
garth.http.USER_AGENT = {"User-Agent": "GCM-iOS-5.7.2.1"}
self.client = garth.Client()
# Authenticate
self._authenticate()
def _authenticate(self):
"""Authenticate with Garmin Connect."""
# Try to load existing session
if os.path.exists(self.session_file):
try:
self.client.load(self.session_file)
if hasattr(self.client, "username"):
logger.info("Loaded existing Garmin session")
return
except Exception as e:
logger.warning(f"Failed to load existing session: {e}")
# Login with credentials
try:
logger.info("Logging into Garmin Connect...")
self.client.login(self.username, self.password)
self.client.dump(self.session_file)
logger.info("Successfully authenticated with Garmin Connect")
except Exception as e:
raise GarminException(f"Garmin authentication failed: {e}")
def upload_file(
self, file_data: bytes, filename: str = "withings_sync.fit"
) -> bool:
"""Upload FIT file to Garmin Connect."""
try:
fit_file = io.BytesIO(file_data)
fit_file.name = filename
self.client.upload(fit_file)
logger.info(f"Successfully uploaded {filename} to Garmin Connect")
return True
except Exception as e:
logger.error(f"Failed to upload file to Garmin Connect: {e}")
return False
def test_connection(self) -> bool:
"""Test connection to Garmin Connect."""
try:
# Simple test to see if we can access the API
if hasattr(self.client, "username"):
logger.info(f"Connected to Garmin Connect as: {self.client.username}")
return True
return False
except Exception as e:
logger.error(f"Garmin connection test failed: {e}")
return False