Files
fitbit_garmin_sync/fitsync_garthtest.py
2025-10-04 16:08:55 -07:00

110 lines
4.7 KiB
Python
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import json
import sys
import time
import garth
from datetime import datetime
def main():
try:
# Load configuration
with open('config.json') as f:
config = json.load(f)
garmin_config = config.get('garmin', {})
username = garmin_config.get('username')
password = garmin_config.get('password')
is_china = garmin_config.get('is_china', False)
session_file = garmin_config.get('session_data_file', 'garmin_session.json')
if not username or not password:
print("❌ Missing Garmin credentials in config.json")
return 1
# Set domain based on region
domain = "garmin.cn" if is_china else "garmin.com"
garth.configure(domain=domain)
try:
# Authentication attempt
start_time = time.time()
garth.login(username, password)
end_time = time.time()
print("✅ Authentication successful!")
print(f"⏱️ Authentication time: {end_time - start_time:.2f} seconds")
garth.save(session_file)
return 0
except garth.exc.GarthHTTPError as e:
end_time = time.time() # Capture time when error occurred
# Extract information from the exception message
error_msg = str(e)
print(f"\n⚠️ Garth HTTP Error: {error_msg}")
# Check if it's a 429 error by parsing the message
if "429" in error_msg:
print("=" * 50)
print("Rate Limit Exceeded (429)")
print(f"Response Time: {end_time - start_time:.2f} seconds")
# Try to extract URL from error message
url_start = error_msg.find("url: ")
if url_start != -1:
url = error_msg[url_start + 5:]
print(f"URL: {url}")
# Try to access response headers if available
if hasattr(e, 'response') and e.response is not None:
headers = e.response.headers
retry_after = headers.get('Retry-After')
reset_timestamp = headers.get('X-RateLimit-Reset')
remaining = headers.get('X-RateLimit-Remaining')
limit = headers.get('X-RateLimit-Limit')
print("\n📊 Rate Limit Headers Found:")
if retry_after:
print(f"⏳ Retry-After: {retry_after} seconds")
wait_time = int(retry_after)
reset_time = datetime.utcfromtimestamp(time.time() + wait_time)
print(f"⏰ Estimated reset time: {reset_time} UTC")
if reset_timestamp:
try:
reset_time = datetime.utcfromtimestamp(float(reset_timestamp))
print(f"⏰ Rate limit resets at: {reset_time} UTC")
except ValueError:
print(f"⚠️ Invalid reset timestamp: {reset_timestamp}")
if remaining:
print(f"🔄 Requests remaining: {remaining}")
if limit:
print(f"📈 Rate limit: {limit} requests per window")
if not any([retry_after, reset_timestamp, remaining, limit]):
print(" No rate limit headers found in response")
else:
print("\n⚠️ Response headers not accessible directly from GarthHTTPError")
print("Common rate limit headers to look for:")
print(" - Retry-After: Seconds to wait before retrying")
print(" - X-RateLimit-Limit: Maximum requests per time window")
print(" - X-RateLimit-Remaining: Remaining requests in current window")
print(" - X-RateLimit-Reset: Time when rate limit resets")
print(f"\nRecommend waiting at least 60 seconds before retrying.")
return 429
# Handle other HTTP errors
print(f"❌ HTTP Error detected: {error_msg}")
return 1
except Exception as e:
print(f"❌ Authentication failed: {str(e)}")
return 1
except FileNotFoundError:
print("❌ config.json file not found")
return 1
except json.JSONDecodeError:
print("❌ Error parsing config.json")
return 1
if __name__ == "__main__":
sys.exit(main())