Skip to main content

Garmin SSO auth + Connect client

Project description

Garth

CI codecov PyPI version PyPI - Downloads

Garmin SSO auth + Connect Python client

Garmin Connect MCP Server

garth-mcp-server is in early development. Contributions are greatly appreciated.

To generate your GARTH_TOKEN, use uvx garth login. For China, do uvx garth --domain garmin.cn login.

Google Colabs

Stress: 28-day rolling average

Stress levels from one day to another can vary by extremes, but there's always a general trend. Using a scatter plot with a rolling average shows both the individual days and the trend. The Colab retrieves up to three years of daily data. If there's less than three years of data, it retrieves whatever is available.

Stress: Garph of 28-day rolling average

Sleep analysis over 90 days

The Garmin Connect app only shows a maximum of seven days for sleep stages—making it hard to see trends. The Connect API supports retrieving daily sleep quality in 28-day pages, but that doesn't show details. Using SleedData.list() gives us the ability to retrieve an arbitrary number of day with enough detail to product a stacked bar graph of the daily sleep stages.

Sleep stages over 90 days

One specific graph that's useful but not available in the Connect app is sleep start and end times over an extended period. This provides context to the sleep hours and stages.

Sleep times over 90 days

ChatGPT analysis of Garmin stats

ChatGPT's Advanced Data Analysis took can provide incredible insight into the data in a way that's much simpler than using Pandas and Matplotlib.

Start by using the linked Colab to download a CSV of the last three years of your stats, and upload the CSV to ChatGPT.

Here's the outputs of the following prompts:

How do I sleep on different days of the week?

image

On what days do I exercise the most?

image

Magic!

Background

Garth is meant for personal use and follows the philosophy that your data is your data. You should be able to download it and analyze it in the way that you'd like. In my case, that means processing with Google Colab, Pandas, Matplotlib, etc.

There are already a few Garmin Connect libraries. Why write another?

Authentication and stability

The most important reasoning is to build a library with authentication that works on Google Colab and doesn't require tools like Cloudscraper. Garth, in comparison:

  1. Uses OAuth1 and OAuth2 token authentication after initial login
  2. OAuth1 token survives for a year
  3. Supports MFA
  4. Auto-refresh of OAuth2 token when expired
  5. Works on Google Colab
  6. Uses Pydantic dataclasses to validate and simplify use of data
  7. Full test coverage

JSON vs HTML

Using garth.connectapi() allows you to make requests to the Connect API and receive JSON vs needing to parse HTML. You can use the same endpoints the mobile app uses.

This also goes back to authentication. Garth manages the necessary Bearer Authentication (along with auto-refresh) necessary to make requests routed to the Connect API.

Instructions

Install

python -m pip install garth

Clone, setup environment and run tests

gh repo clone matin/garth
cd garth
make install
make

Use make help to see all the options.

Authenticate and save session

import garth
from getpass import getpass

email = input("Enter email address: ")
password = getpass("Enter password: ")
# If there's MFA, you'll be prompted during the login
garth.login(email, password)

garth.save("~/.garth")

Custom MFA handler

By default, MFA will prompt for the code in the terminal. You can provide your own handler:

garth.login(email, password, prompt_mfa=lambda: input("Enter MFA code: "))

For advanced use cases (like async handling), MFA can be handled separately:

result1, result2 = garth.login(email, password, return_on_mfa=True)
if result1 == "needs_mfa":  # MFA is required
    mfa_code = "123456"  # Get this from your custom MFA flow
    oauth1, oauth2 = garth.resume_login(result2, mfa_code)

Configure

Set domain for China

garth.configure(domain="garmin.cn")

Proxy through Charles

garth.configure(proxies={"https": "http://localhost:8888"}, ssl_verify=False)

Attempt to resume session

import garth
from garth.exc import GarthException

garth.resume("~/.garth")
try:
    garth.client.username
except GarthException:
    # Session is expired. You'll need to log in again

Connect API

Daily details

sleep = garth.connectapi(
    f"/wellness-service/wellness/dailySleepData/{garth.client.username}",
    params={"date": "2023-07-05", "nonSleepBufferMinutes": 60},
)
list(sleep.keys())
[
    "dailySleepDTO",
    "sleepMovement",
    "remSleepData",
    "sleepLevels",
    "sleepRestlessMoments",
    "restlessMomentsCount",
    "wellnessSpO2SleepSummaryDTO",
    "wellnessEpochSPO2DataDTOList",
    "wellnessEpochRespirationDataDTOList",
    "sleepStress"
]

Stats

stress = garth.connectapi("/usersummary-service/stats/stress/weekly/2023-07-05/52")
{
    "calendarDate": "2023-07-13",
    "values": {
        "highStressDuration": 2880,
        "lowStressDuration": 10140,
        "overallStressLevel": 33,
        "restStressDuration": 30960,
        "mediumStressDuration": 8760
    }
}

Upload

with open("12129115726_ACTIVITY.fit", "rb") as f:
    uploaded = garth.client.upload(f)

Note: Garmin doesn't accept uploads of structured FIT files as outlined in this conversation. FIT files generated from workouts are accepted without issues.

{
    'detailedImportResult': {
        'uploadId': 212157427938,
        'uploadUuid': {
            'uuid': '6e56051d-1dd4-4f2c-b8ba-00a1a7d82eb3'
        },
        'owner': 2591602,
        'fileSize': 5289,
        'processingTime': 36,
        'creationDate': '2023-09-29 01:58:19.113 GMT',
        'ipAddress': None,
        'fileName': '12129115726_ACTIVITY.fit',
        'report': None,
        'successes': [],
        'failures': []
    }
}

Stats resources

Stress

Daily stress levels

DailyStress.list("2023-07-23", 2)
[
    DailyStress(
        calendar_date=datetime.date(2023, 7, 22),
        overall_stress_level=31,
        rest_stress_duration=31980,
        low_stress_duration=23820,
        medium_stress_duration=7440,
        high_stress_duration=1500
    ),
    DailyStress(
        calendar_date=datetime.date(2023, 7, 23),
        overall_stress_level=26,
        rest_stress_duration=38220,
        low_stress_duration=22500,
        medium_stress_duration=2520,
        high_stress_duration=300
    )
]

Weekly stress levels

WeeklyStress.list("2023-07-23", 2)
[
    WeeklyStress(calendar_date=datetime.date(2023, 7, 10), value=33),
    WeeklyStress(calendar_date=datetime.date(2023, 7, 17), value=32)
]

Body Battery

Daily Body Battery and stress data

garth.DailyBodyBatteryStress.get("2023-07-20")
DailyBodyBatteryStress(
    user_profile_pk=2591602,
    calendar_date=datetime.date(2023, 7, 20),
    start_timestamp_gmt=datetime.datetime(2023, 7, 20, 6, 0),
    end_timestamp_gmt=datetime.datetime(2023, 7, 21, 5, 59, 59, 999000),
    start_timestamp_local=datetime.datetime(2023, 7, 19, 23, 0),
    end_timestamp_local=datetime.datetime(2023, 7, 20, 22, 59, 59, 999000),
    max_stress_level=85,
    avg_stress_level=25,
    stress_chart_value_offset=0,
    stress_chart_y_axis_origin=0,
    stress_values_array=[
        [1689811800000, 12], [1689812100000, 18], [1689812400000, 15],
        [1689815700000, 45], [1689819300000, 85], [1689822900000, 35],
        [1689826500000, 20], [1689830100000, 15], [1689833700000, 25],
        [1689837300000, 30]
    ],
    body_battery_values_array=[
        [1689811800000, 'charging', 45, 1.0], [1689812100000, 'charging', 48, 1.0],
        [1689812400000, 'charging', 52, 1.0], [1689815700000, 'charging', 65, 1.0],
        [1689819300000, 'draining', 85, 1.0], [1689822900000, 'draining', 75, 1.0],
        [1689826500000, 'draining', 65, 1.0], [1689830100000, 'draining', 55, 1.0],
        [1689833700000, 'draining', 45, 1.0], [1689837300000, 'draining', 35, 1.0],
        [1689840900000, 'draining', 25, 1.0]
    ]
)

# Access derived properties
daily_bb = garth.DailyBodyBatteryStress.get("2023-07-20")
daily_bb.current_body_battery  # 25 (last reading)
daily_bb.max_body_battery      # 85
daily_bb.min_body_battery      # 25
daily_bb.body_battery_change   # -20 (45 -> 25)

# Access structured readings
for reading in daily_bb.body_battery_readings:
    print(f"Level: {reading.level}, Status: {reading.status}")
    # Level: 45, Status: charging
    # Level: 48, Status: charging
    # ... etc

for reading in daily_bb.stress_readings:
    print(f"Stress: {reading.stress_level}")
    # Stress: 12
    # Stress: 18
    # ... etc

Body Battery events (sleep events)

garth.BodyBatteryData.get("2023-07-20")
[
    BodyBatteryData(
        event=BodyBatteryEvent(
            event_type='sleep',
            event_start_time_gmt=datetime.datetime(2023, 7, 19, 21, 30),
            timezone_offset=-25200000,
            duration_in_milliseconds=28800000,
            body_battery_impact=35,
            feedback_type='good_sleep',
            short_feedback='Good sleep restored your Body Battery'
        ),
        activity_name=None,
        activity_type=None,
        activity_id=None,
        average_stress=15.5,
        stress_values_array=[
            [1689811800000, 12], [1689812100000, 18], [1689812400000, 15]
        ],
        body_battery_values_array=[
            [1689811800000, 'charging', 45, 1.0],
            [1689812100000, 'charging', 48, 1.0],
            [1689812400000, 'charging', 52, 1.0],
            [1689840600000, 'draining', 85, 1.0]
        ]
    )
]

# Access convenience properties on each event
events = garth.BodyBatteryData.get("2023-07-20")
event = events[0]
event.current_level    # 85 (last reading)
event.max_level        # 85
event.min_level        # 45

Hydration

Daily hydration data

garth.DailyHydration.list(period=2)
[
    DailyHydration(
        calendar_date=datetime.date(2024, 6, 29),
        value_in_ml=1750.0,
        goal_in_ml=2800.0
    )
]

Steps

Daily steps

garth.DailySteps.list(period=2)
[
    DailySteps(
        calendar_date=datetime.date(2023, 7, 28),
        total_steps=6510,
        total_distance=5552,
        step_goal=8090
    ),
    DailySteps(
        calendar_date=datetime.date(2023, 7, 29),
        total_steps=7218,
        total_distance=6002,
        step_goal=7940
    )
]

Weekly steps

garth.WeeklySteps.list(period=2)
[
    WeeklySteps(
        calendar_date=datetime.date(2023, 7, 16),
        total_steps=42339,
        average_steps=6048.428571428572,
        average_distance=5039.285714285715,
        total_distance=35275.0,
        wellness_data_days_count=7
    ),
    WeeklySteps(
        calendar_date=datetime.date(2023, 7, 23),
        total_steps=56420,
        average_steps=8060.0,
        average_distance=7198.142857142857,
        total_distance=50387.0,
        wellness_data_days_count=7
    )
]

Intensity Minutes

Daily intensity minutes

garth.DailyIntensityMinutes.list(period=2)
[
    DailyIntensityMinutes(
        calendar_date=datetime.date(2023, 7, 28),
        weekly_goal=150,
        moderate_value=0,
        vigorous_value=0
    ),
    DailyIntensityMinutes(
        calendar_date=datetime.date(2023, 7, 29),
        weekly_goal=150,
        moderate_value=0,
        vigorous_value=0
    )
]

Weekly intensity minutes

garth.WeeklyIntensityMinutes.list(period=2)
[
    WeeklyIntensityMinutes(
        calendar_date=datetime.date(2023, 7, 17),
        weekly_goal=150,
        moderate_value=103,
        vigorous_value=9
    ),
    WeeklyIntensityMinutes(
        calendar_date=datetime.date(2023, 7, 24),
        weekly_goal=150,
        moderate_value=101,
        vigorous_value=105
    )
]

HRV

Daily HRV

garth.DailyHRV.list(period=2)
[
    DailyHRV(
        calendar_date=datetime.date(2023, 7, 28),
        weekly_avg=39,
        last_night_avg=36,
        last_night_5_min_high=52,
        baseline=HRVBaseline(
            low_upper=36,
            balanced_low=39,
            balanced_upper=51,
            marker_value=0.25
        ),
        status='BALANCED',
        feedback_phrase='HRV_BALANCED_2',
        create_time_stamp=datetime.datetime(2023, 7, 28, 12, 40, 16, 785000)
    ),
    DailyHRV(
        calendar_date=datetime.date(2023, 7, 29),
        weekly_avg=40,
        last_night_avg=41,
        last_night_5_min_high=76,
        baseline=HRVBaseline(
            low_upper=36,
            balanced_low=39,
            balanced_upper=51,
            marker_value=0.2916565
        ),
        status='BALANCED',
        feedback_phrase='HRV_BALANCED_8',
        create_time_stamp=datetime.datetime(2023, 7, 29, 13, 45, 23, 479000)
    )
]

Detailed HRV data

garth.HRVData.get("2023-07-20")
HRVData(
    user_profile_pk=2591602,
    hrv_summary=HRVSummary(
        calendar_date=datetime.date(2023, 7, 20),
        weekly_avg=39,
        last_night_avg=42,
        last_night_5_min_high=66,
        baseline=Baseline(
            low_upper=36,
            balanced_low=39,
            balanced_upper=52,
            marker_value=0.25
        ),
        status='BALANCED',
        feedback_phrase='HRV_BALANCED_7',
        create_time_stamp=datetime.datetime(2023, 7, 20, 12, 14, 11, 898000)
    ),
    hrv_readings=[
        HRVReading(
            hrv_value=54,
            reading_time_gmt=datetime.datetime(2023, 7, 20, 5, 29, 48),
            reading_time_local=datetime.datetime(2023, 7, 19, 23, 29, 48)
        ),
        HRVReading(
            hrv_value=56,
            reading_time_gmt=datetime.datetime(2023, 7, 20, 5, 34, 48),
            reading_time_local=datetime.datetime(2023, 7, 19, 23, 34, 48)
        ),
        # ... truncated for brevity
        HRVReading(
            hrv_value=38,
            reading_time_gmt=datetime.datetime(2023, 7, 20, 12, 9, 48),
            reading_time_local=datetime.datetime(2023, 7, 20, 6, 9, 48)
        )
    ],
    start_timestamp_gmt=datetime.datetime(2023, 7, 20, 5, 25),
    end_timestamp_gmt=datetime.datetime(2023, 7, 20, 12, 9, 48),
    start_timestamp_local=datetime.datetime(2023, 7, 19, 23, 25),
    end_timestamp_local=datetime.datetime(2023, 7, 20, 6, 9, 48),
    sleep_start_timestamp_gmt=datetime.datetime(2023, 7, 20, 5, 25),
    sleep_end_timestamp_gmt=datetime.datetime(2023, 7, 20, 12, 11),
    sleep_start_timestamp_local=datetime.datetime(2023, 7, 19, 23, 25),
    sleep_end_timestamp_local=datetime.datetime(2023, 7, 20, 6, 11)
)

Sleep

Daily sleep quality

garth.DailySleep.list("2023-07-23", 2)
[
    DailySleep(calendar_date=datetime.date(2023, 7, 22), value=69),
    DailySleep(calendar_date=datetime.date(2023, 7, 23), value=73)
]

Detailed sleep data

garth.SleepData.get("2023-07-20")
SleepData(
    daily_sleep_dto=DailySleepDTO(
        id=1689830700000,
        user_profile_pk=2591602,
        calendar_date=datetime.date(2023, 7, 20),
        sleep_time_seconds=23700,
        nap_time_seconds=0,
        sleep_window_confirmed=True,
        sleep_window_confirmation_type='enhanced_confirmed_final',
        sleep_start_timestamp_gmt=datetime.datetime(2023, 7, 20, 5, 25, tzinfo=TzInfo(UTC)),
        sleep_end_timestamp_gmt=datetime.datetime(2023, 7, 20, 12, 11, tzinfo=TzInfo(UTC)),
        sleep_start_timestamp_local=datetime.datetime(2023, 7, 19, 23, 25, tzinfo=TzInfo(UTC)),
        sleep_end_timestamp_local=datetime.datetime(2023, 7, 20, 6, 11, tzinfo=TzInfo(UTC)),
        unmeasurable_sleep_seconds=0,
        deep_sleep_seconds=9660,
        light_sleep_seconds=12600,
        rem_sleep_seconds=1440,
        awake_sleep_seconds=660,
        device_rem_capable=True,
        retro=False,
        sleep_from_device=True,
        sleep_version=2,
        awake_count=1,
        sleep_scores=SleepScores(
            total_duration=Score(
                qualifier_key='FAIR',
                optimal_start=28800.0,
                optimal_end=28800.0,
                value=None,
                ideal_start_in_seconds=None,
                deal_end_in_seconds=None
            ),
            stress=Score(
                qualifier_key='FAIR',
                optimal_start=0.0,
                optimal_end=15.0,
                value=None,
                ideal_start_in_seconds=None,
                ideal_end_in_seconds=None
            ),
            awake_count=Score(
                qualifier_key='GOOD',
                optimal_start=0.0,
                optimal_end=1.0,
                value=None,
                ideal_start_in_seconds=None,
                ideal_end_in_seconds=None
            ),
            overall=Score(
                qualifier_key='FAIR',
                optimal_start=None,
                optimal_end=None,
                value=68,
                ideal_start_in_seconds=None,
                ideal_end_in_seconds=None
            ),
            rem_percentage=Score(
                qualifier_key='POOR',
                optimal_start=21.0,
                optimal_end=31.0,
                value=6,
                ideal_start_in_seconds=4977.0,
                ideal_end_in_seconds=7347.0
            ),
            restlessness=Score(
                qualifier_key='EXCELLENT',
                optimal_start=0.0,
                optimal_end=5.0,
                value=None,
                ideal_start_in_seconds=None,
                ideal_end_in_seconds=None
            ),
            light_percentage=Score(
                qualifier_key='EXCELLENT',
                optimal_start=30.0,
                optimal_end=64.0,
                value=53,
                ideal_start_in_seconds=7110.0,
                ideal_end_in_seconds=15168.0
            ),
            deep_percentage=Score(
                qualifier_key='EXCELLENT',
                optimal_start=16.0,
                optimal_end=33.0,
                value=41,
                ideal_start_in_seconds=3792.0,
                ideal_end_in_seconds=7821.0
            )
        ),
        auto_sleep_start_timestamp_gmt=None,
        auto_sleep_end_timestamp_gmt=None,
        sleep_quality_type_pk=None,
        sleep_result_type_pk=None,
        average_sp_o2_value=92.0,
        lowest_sp_o2_value=87,
        highest_sp_o2_value=100,
        average_sp_o2_hr_sleep=53.0,
        average_respiration_value=14.0,
        lowest_respiration_value=12.0,
        highest_respiration_value=16.0,
        avg_sleep_stress=17.0,
        age_group='ADULT',
        sleep_score_feedback='NEGATIVE_NOT_ENOUGH_REM',
        sleep_score_insight='NONE'
    ),
    sleep_movement=[
        SleepMovement(
            start_gmt=datetime.datetime(2023, 7, 20, 4, 25),
            end_gmt=datetime.datetime(2023, 7, 20, 4, 26),
            activity_level=5.688743692980419
        ),
        SleepMovement(
            start_gmt=datetime.datetime(2023, 7, 20, 4, 26),
            end_gmt=datetime.datetime(2023, 7, 20, 4, 27),
            activity_level=5.318763075304898
        ),
        # ... truncated for brevity
        SleepMovement(
            start_gmt=datetime.datetime(2023, 7, 20, 13, 10),
            end_gmt=datetime.datetime(2023, 7, 20, 13, 11),
            activity_level=7.088729101943337
        )
    ]
)

List sleep data over several nights.

garth.SleepData.list("2023-07-20", 30)

Weight

Retrieve the latest weight measurement and body composition data for a given date.

Note: Weight, weight delta, bone mass, and muscle mass values are measured in grams

garth.WeightData.get("2025-06-01")
WeightData(
    sample_pk=1749996902851,
    calendar_date=datetime.date(2025, 6, 15),
    weight=59720,
    source_type='INDEX_SCALE',
    weight_delta=200.00000000000284,
    timestamp_gmt=1749996876000,
    datetime_utc=datetime.datetime(2025, 6, 15, 14, 14, 36, tzinfo=TzInfo(UTC)),
    datetime_local=datetime.datetime(
        2025, 6, 15, 8, 14, 36,
        tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=64800))
    ),
    bmi=22.799999237060547,
    body_fat=19.3,
    body_water=58.9,
    bone_mass=3539,
    muscle_mass=26979,
    physique_rating=None,
    visceral_fat=None,
    metabolic_age=None
)

Get weight entries for a date range.

garth.WeightData.list("2025-06-01", 30)
[
    WeightData(
        sample_pk=1749307692871,
        calendar_date=datetime.date(2025, 6, 7),
        weight=59189,
        source_type='INDEX_SCALE',
        weight_delta=500.0,
        timestamp_gmt=1749307658000,
        datetime_utc=datetime.datetime(2025, 6, 7, 14, 47, 38, tzinfo=TzInfo(UTC)),
        datetime_local=datetime.datetime(
            2025, 6, 7, 8, 47, 38,
            tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=64800))
        ),
        bmi=22.600000381469727,
        body_fat=20.0,
        body_water=58.4,
        bone_mass=3450,
        muscle_mass=26850,
        physique_rating=None,
        visceral_fat=None,
        metabolic_age=None
    ),
    WeightData(
        sample_pk=1749909217098,
        calendar_date=datetime.date(2025, 6, 14),
        weight=59130,
        source_type='INDEX_SCALE',
        weight_delta=-100.00000000000142,
        timestamp_gmt=1749909180000,
        datetime_utc=datetime.datetime(2025, 6, 14, 13, 53, tzinfo=TzInfo(UTC)),
        datetime_local=datetime.datetime(
            2025, 6, 14, 7, 53,
            tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=64800))
        ),
        bmi=22.5,
        body_fat=20.3,
        body_water=58.2,
        bone_mass=3430,
        muscle_mass=26840,
        physique_rating=None,
        visceral_fat=None,
        metabolic_age=None
    ),
    WeightData(
        sample_pk=1749948744411,
        calendar_date=datetime.date(2025, 6, 14),
        weight=59500,
        source_type='MANUAL',
        weight_delta=399.9999999999986,
        timestamp_gmt=1749948725175,
        datetime_utc=datetime.datetime(
            2025, 6, 15, 0, 52, 5, 175000, tzinfo=TzInfo(UTC)
        ),
        datetime_local=datetime.datetime(
            2025, 6, 14, 18, 52, 5, 175000,
            tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=64800))
        ),
        bmi=None,
        body_fat=None,
        body_water=None,
        bone_mass=None,
        muscle_mass=None,
        physique_rating=None,
        visceral_fat=None,
        metabolic_age=None
    ),
    WeightData(
        sample_pk=1749996902851,
        calendar_date=datetime.date(2025, 6, 15),
        weight=59720,
        source_type='INDEX_SCALE',
        weight_delta=200.00000000000284,
        timestamp_gmt=1749996876000,
        datetime_utc=datetime.datetime(2025, 6, 15, 14, 14, 36, tzinfo=TzInfo(UTC)),
        datetime_local=datetime.datetime(
            2025, 6, 15, 8, 14, 36,
            tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=64800))
        ),
        bmi=22.799999237060547,
        body_fat=19.3,
        body_water=58.9,
        bone_mass=3539,
        muscle_mass=26979,
        physique_rating=None,
        visceral_fat=None,
        metabolic_age=None
    )
]

User

UserProfile

garth.UserProfile.get()
UserProfile(
    id=3154645,
    profile_id=2591602,
    garmin_guid="0690cc1d-d23d-4412-b027-80fd4ed1c0f6",
    display_name="mtamizi",
    full_name="Matin Tamizi",
    user_name="mtamizi",
    profile_image_uuid="73240e81-6e4d-43fc-8af8-c8f6c51b3b8f",
    profile_image_url_large=(
        "https://s3.amazonaws.com/garmin-connect-prod/profile_images/"
        "73240e81-6e4d-43fc-8af8-c8f6c51b3b8f-2591602.png"
    ),
    profile_image_url_medium=(
        "https://s3.amazonaws.com/garmin-connect-prod/profile_images/"
        "685a19e9-a7be-4a11-9bf9-faca0c5d1f1a-2591602.png"
    ),
    profile_image_url_small=(
        "https://s3.amazonaws.com/garmin-connect-prod/profile_images/"
        "6302f021-0ec7-4dc9-b0c3-d5a19bc5a08c-2591602.png"
    ),
    location="Ciudad de México, CDMX",
    facebook_url=None,
    twitter_url=None,
    personal_website=None,
    motivation=None,
    bio=None,
    primary_activity=None,
    favorite_activity_types=[],
    running_training_speed=0.0,
    cycling_training_speed=0.0,
    favorite_cycling_activity_types=[],
    cycling_classification=None,
    cycling_max_avg_power=0.0,
    swimming_training_speed=0.0,
    profile_visibility="private",
    activity_start_visibility="private",
    activity_map_visibility="public",
    course_visibility="public",
    activity_heart_rate_visibility="public",
    activity_power_visibility="public",
    badge_visibility="private",
    show_age=False,
    show_weight=False,
    show_height=False,
    show_weight_class=False,
    show_age_range=False,
    show_gender=False,
    show_activity_class=False,
    show_vo_2_max=False,
    show_personal_records=False,
    show_last_12_months=False,
    show_lifetime_totals=False,
    show_upcoming_events=False,
    show_recent_favorites=False,
    show_recent_device=False,
    show_recent_gear=False,
    show_badges=True,
    other_activity=None,
    other_primary_activity=None,
    other_motivation=None,
    user_roles=[
        "SCOPE_ATP_READ",
        "SCOPE_ATP_WRITE",
        "SCOPE_COMMUNITY_COURSE_READ",
        "SCOPE_COMMUNITY_COURSE_WRITE",
        "SCOPE_CONNECT_READ",
        "SCOPE_CONNECT_WRITE",
        "SCOPE_DT_CLIENT_ANALYTICS_WRITE",
        "SCOPE_GARMINPAY_READ",
        "SCOPE_GARMINPAY_WRITE",
        "SCOPE_GCOFFER_READ",
        "SCOPE_GCOFFER_WRITE",
        "SCOPE_GHS_SAMD",
        "SCOPE_GHS_UPLOAD",
        "SCOPE_GOLF_API_READ",
        "SCOPE_GOLF_API_WRITE",
        "SCOPE_INSIGHTS_READ",
        "SCOPE_INSIGHTS_WRITE",
        "SCOPE_PRODUCT_SEARCH_READ",
        "ROLE_CONNECTUSER",
        "ROLE_FITNESS_USER",
        "ROLE_WELLNESS_USER",
        "ROLE_OUTDOOR_USER",
        "ROLE_CONNECT_2_USER",
        "ROLE_TACX_APP_USER",
    ],
    name_approved=True,
    user_profile_full_name="Matin Tamizi",
    make_golf_scorecards_private=True,
    allow_golf_live_scoring=False,
    allow_golf_scoring_by_connections=True,
    user_level=3,
    user_point=118,
    level_update_date="2020-12-12T15:20:38.0",
    level_is_viewed=False,
    level_point_threshold=140,
    user_point_offset=0,
    user_pro=False,
)

UserSettings

garth.UserSettings.get()
UserSettings(
    id=2591602,
    user_data=UserData(
        gender="MALE",
        weight=83000.0,
        height=182.0,
        time_format="time_twenty_four_hr",
        birth_date=datetime.date(1984, 10, 17),
        measurement_system="metric",
        activity_level=None,
        handedness="RIGHT",
        power_format=PowerFormat(
            format_id=30,
            format_key="watt",
            min_fraction=0,
            max_fraction=0,
            grouping_used=True,
            display_format=None,
        ),
        heart_rate_format=PowerFormat(
            format_id=21,
            format_key="bpm",
            min_fraction=0,
            max_fraction=0,
            grouping_used=False,
            display_format=None,
        ),
        first_day_of_week=FirstDayOfWeek(
            day_id=2,
            day_name="sunday",
            sort_order=2,
            is_possible_first_day=True,
        ),
        vo_2_max_running=45.0,
        vo_2_max_cycling=None,
        lactate_threshold_speed=0.34722125000000004,
        lactate_threshold_heart_rate=None,
        dive_number=None,
        intensity_minutes_calc_method="AUTO",
        moderate_intensity_minutes_hr_zone=3,
        vigorous_intensity_minutes_hr_zone=4,
        hydration_measurement_unit="milliliter",
        hydration_containers=[],
        hydration_auto_goal_enabled=True,
        firstbeat_max_stress_score=None,
        firstbeat_cycling_lt_timestamp=None,
        firstbeat_running_lt_timestamp=1044719868,
        threshold_heart_rate_auto_detected=True,
        ftp_auto_detected=None,
        training_status_paused_date=None,
        weather_location=None,
        golf_distance_unit="statute_us",
        golf_elevation_unit=None,
        golf_speed_unit=None,
        external_bottom_time=None,
    ),
    user_sleep=UserSleep(
        sleep_time=80400,
        default_sleep_time=False,
        wake_time=24000,
        default_wake_time=False,
    ),
    connect_date=None,
    source_type=None,
)

Star History

Star History Chart

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

garth-0.5.17.tar.gz (1.8 MB view details)

Uploaded Source

Built Distribution

garth-0.5.17-py3-none-any.whl (33.0 kB view details)

Uploaded Python 3

File details

Details for the file garth-0.5.17.tar.gz.

File metadata

  • Download URL: garth-0.5.17.tar.gz
  • Upload date:
  • Size: 1.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for garth-0.5.17.tar.gz
Algorithm Hash digest
SHA256 48ede938c38b2fd70777e55c7025538775d93c1047f43cc7c4481f2a04b109cb
MD5 1013783e182a81c767548025408247d0
BLAKE2b-256 37ca6a2b9dc95fd36bb098ec6318c21fd8e2419e5b770bd8c618b9d2d1077362

See more details on using hashes here.

Provenance

The following attestation bundles were made for garth-0.5.17.tar.gz:

Publisher: publish.yml on matin/garth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file garth-0.5.17-py3-none-any.whl.

File metadata

  • Download URL: garth-0.5.17-py3-none-any.whl
  • Upload date:
  • Size: 33.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for garth-0.5.17-py3-none-any.whl
Algorithm Hash digest
SHA256 4b109140dfacea6d96060bad8dead8da36699a0729cb0c4ca3b31fa49f860e88
MD5 65106b23720d6b2c2c16bf0aedd2a49c
BLAKE2b-256 eda57b22d90cc735abda0526aa708f54a729a966e50f7acef7d0b57dd48d0823

See more details on using hashes here.

Provenance

The following attestation bundles were made for garth-0.5.17-py3-none-any.whl:

Publisher: publish.yml on matin/garth

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page