import os import datetime from dotenv import load_dotenv # Load env vars first load_dotenv() from src.services.postgresql_manager import PostgreSQLManager from src.services.fitbit_client import FitbitClient from src.models.api_token import APIToken from src.models.weight_record import WeightRecord # Set DB URL if not os.environ.get('DATABASE_URL'): os.environ['DATABASE_URL'] = 'postgresql://postgres:password@localhost:5433/fitbit_garmin_sync' def main(): print("Connecting to DB...") db = PostgreSQLManager() with db.get_db_session() as session: # Get a date with NULL BMI null_record = session.query(WeightRecord).filter(WeightRecord.bmi == None).first() if not null_record: print("No NULL BMI records found.") return date_str = null_record.date.strftime('%Y-%m-%d') print(f"Checking Fitbit API for date: {date_str} (Existing BMI: {null_record.bmi})") # Init Client token_record = session.query(APIToken).filter_by(token_type='fitbit').first() if not token_record: print("No Fitbit token found.") return token_dict = { 'access_token': token_record.access_token, 'refresh_token': token_record.refresh_token, 'expires_at': token_record.expires_at.timestamp() if token_record.expires_at else None, 'scope': token_record.scopes } from src.utils.config import config from src.models.config import Configuration client_id = config.FITBIT_CLIENT_ID client_secret = config.FITBIT_CLIENT_SECRET # Fallback to DB if not client_id or not client_secret: print("Config missing credentials, checking DB...") db_config = session.query(Configuration).first() if db_config: client_id = db_config.fitbit_client_id client_secret = db_config.fitbit_client_secret print("Loaded credentials from DB Configuration.") if not client_id or not client_secret: print("ERROR: Could not find Fitbit credentials in Config or DB.") return def refresh_cb(token): print("DEBUG: Token refreshed!", flush=True) # In real app we would save to DB here # Update the client with new token just in case pass client = FitbitClient( client_id=client_id, client_secret=client_secret, redirect_uri=os.environ.get('FITBIT_REDIRECT_URI', 'http://localhost:8000/api/setup/fitbit/callback'), access_token=token_record.access_token, refresh_token=token_record.refresh_token, refresh_cb=refresh_cb ) # Force refresh validation? # fitbit library calculates expiry. If expired, it refreshes ON REQUEST. # So making the request should trigger it. try: logs = client.get_weight_logs(date_str, date_str) print(f"Fetched {len(logs)} logs for {date_str}") if logs: print("First log payload:", logs[0]) if 'bmi' in logs[0]: print(f"BMI in response: {logs[0]['bmi']}") else: print("BMI NOT found in response.") except Exception as e: print(f"Error fetching logs: {e}") # Try manual refresh if library didn't auto-refresh try: print("Attempting manual refresh...") # python-fitbit usually exposes client.fitbit.client.refresh_token # Token URL: https://api.fitbit.com/oauth2/token new_token = client.fitbit.client.refresh_token( 'https://api.fitbit.com/oauth2/token', refresh_token=token_record.refresh_token, auth=((client_id, client_secret)) ) print("Manual refresh success:", new_token.keys()) # Retry request client.fitbit.client.token = new_token logs = client.get_weight_logs(date_str) if logs: print("Retry Payload:", logs[0]) except Exception as re: print(f"Manual refresh failed: {re}") # Need to refresh likely # But let's assume valid or client handles it? # Actually client usually needs active session or refresh. # The client.get_weight_logs wraps request. try: logs = client.get_weight_logs(date_str) print(f"Fetched {len(logs)} logs for {date_str}") if logs: print("First log payload:", logs[0]) if 'bmi' in logs[0]: print(f"BMI in response: {logs[0]['bmi']}") else: print("BMI NOT found in response.") except Exception as e: print(f"Error fetching logs: {e}") if __name__ == "__main__": main()