Ë
    €ºßh]K ã                   óÆ  — d Z ddlZddlZddlZddlZddlmZ ddlmZmZm	Z	 ddl
mZmZ ddlmZ ddlmZ ddlZddlZddlmZmZ dd	lmZ d
dlmZ  ej2                  e«      ZdZdZdZdZddhZ d&de!de!de!fd„Z"	 d'de#e$z  de!de#e$z  fd„Z%d'de#de!de#fd„Z&d'de#de!de#fd„Z'dede!fd„Z( G d„ d«      Z) G d„ de*«      Z+ G d „ d!e*«      Z, G d"„ d#e*«      Z- G d$„ d%e*«      Z.y)(z(Python 3 API wrapper for Garmin Connect.é    N)ÚCallable)ÚdateÚdatetimeÚtimezone)ÚEnumÚauto)ÚPath)ÚAny)ÚGarthExceptionÚGarthHTTPError)Ú	HTTPErroré   )ÚFitEncoderWeightéè  i'  z^\d{4}-\d{2}-\d{2}$z%Y-%m-%dÚkgÚlbsÚdate_strÚ
param_nameÚreturnc                 ó2  — t        | t        «      st        |› d�«      ‚| j                  «       } t	        j
                  t        | «      st        |› d| › �«      ‚	 t        j                  | t        «       | S # t        $ r}t        d|› d|› �«      |‚d}~ww xY w)z'Validate date string format YYYY-MM-DD.z must be a stringz& must be in format 'YYYY-MM-DD', got: zinvalid ú: N)
Ú
isinstanceÚstrÚ
ValueErrorÚstripÚreÚ	fullmatchÚDATE_FORMAT_REGEXr   ÚstrptimeÚDATE_FORMAT_STR)r   r   Úes      úQ/var/www/html/python/myenv/lib/python3.12/site-packages/garminconnect/__init__.pyÚ_validate_date_formatr#      s    € ä�h¤Ô$Ü˜J˜<Ð'8Ð9Ó:Ð:ð �~‰~Ó€Hä�<‰<Ô)¨8Ô4ÜØˆlÐ@ÀÀ
ÐKó
ð 	
ð>ä×Ñ˜(¤OÔ4ð €Oøô ò >Ü˜8 J <¨r°!°Ð5Ó6¸AÐ=ûð>ús   ÁA6 Á6	BÁ?BÂBÚvaluec                 ó¼   — t        | t        j                  «      st        |› d�«      ‚t        | t        «      rt        |› d�«      ‚| dk  rt        |› d| › �«      ‚| S )z#Validate that a number is positive.z must be a numberz must be a number, not boolr   z must be positive, got: )r   ÚnumbersÚRealr   Úbool©r$   r   s     r"   Ú_validate_positive_numberr*   5   se   € ô �eœWŸ\™\Ô*Ü˜J˜<Ð'8Ð9Ó:Ð:ä�%œÔÜ˜J˜<Ð'BÐCÓDÐDà�‚zÜ˜J˜<Ð'?À¸wÐGÓHÐHà€Ló    c                 óŒ   — t        | t        «      rt        | t        «      rt        |› d�«      ‚| dk  rt        |› d| › �«      ‚| S )z0Validate that a value is a non-negative integer.ú must be an integerr   z must be non-negative, got: ©r   Úintr(   r   r)   s     r"   Ú_validate_non_negative_integerr0   E   sK   € ä�eœSÔ!¤Z°´tÔ%<Ü˜J˜<Ð':Ð;Ó<Ð<àˆq‚yÜ˜J˜<Ð'CÀEÀ7ÐKÓLÐLà€Lr+   c                 óŒ   — t        | t        «      rt        | t        «      rt        |› d�«      ‚| dk  rt        |› d| › �«      ‚| S )z,Validate that a value is a positive integer.r-   r   z" must be a positive integer, got: r.   r)   s     r"   Ú_validate_positive_integerr2   P   sK   € ä�eœSÔ!¤Z°´tÔ%<Ü˜J˜<Ð':Ð;Ó<Ð<Ø�‚zÜ˜J˜<Ð'IÈ%ÈÐQÓRÐRØ€Lr+   Údtc                 óJ   — | j                  d ¬«      j                  d«      d d S )N©Útzinfoz%Y-%m-%dT%H:%M:%S.%féýÿÿÿ)ÚreplaceÚstrftime)r3   s    r"   Ú_fmt_tsr:   Y   s&   € à�:‰:˜Tˆ:Ó"×+Ñ+Ð,BÓCÀCÀRÐHÐHr+   c                   ó,  — e Zd ZdZ	 	 	 	 	 dºdedz  dedz  dedeg ef   dz  deddfd	„Zd
ededefd„Z	d
ededefd„Z
d»dedz  deedz  edz  f   fd„Zdeeef   dedeeef   fd„Zdedz  fd„Zdedz  fd„Zdedeeef   fd„Zdedeeef   fd„Zdedeeeef      fd„Zdedeeef   fd„Zdededeeeef      fd„Zdedeeef   fd„Zdedeeef   fd„Z	 d»ded edz  deeef   fd!„Z	 	 	 	 	 	 	 	 	 	 	 d¼d"edz  d#ed$edz  d%edz  d&edz  d'edz  d(edz  d)edz  d*edz  d+edz  d,edz  d-edz  d.edz  deeef   fd/„Z	 d½d#eez  d0ed"edeeef   fd1„Z	 	 	 d¾d#eez  d0ed2ed3edeeef   f
d4„Zded edeeef   fd5„Zdedeeef   fd6„Z d7ededefd8„Z!d¿ded9ededz  fd:„Z"	 d»ded edz  deeeef      fd;„Z#dedeeeef      fd<„Z$	 	 dÀd=ed>ed?ed"ed@edeeef   fdA„Z%	 d»ded edz  deeef   fdB„Z&dCededeeef   fdD„Z'dedeeef   fdE„Z(dFdddGdHœdIedJee)z  dz  dKee)z  dz  dLedeeef   f
dM„Z*	 	 dÁdNed"edz  dedz  deeef   fdO„Z+dedeeef   fdP„Z,dedeeef   fdQ„Z-dedeeef   fdR„Z.dedeeef   fdS„Z/dedeeef   fdT„Z0dedeeef   fdU„Z1deeef   fdV„Z2deeeef      fdW„Z3deeeef      fdX„Z4deeeef      fdY„Z5dedZedeeef   fd[„Z6dedZedeeef   fd\„Z7dedZedeeef   fd]„Z8dedZedeeef   fd^„Z9dedZedeeef   fd_„Z:dedeeef   fd`„Z;dedeeef   fda„Z<dedeeef   fdb„Z=dedeeef   dz  fdc„Z>dedeeef   fdd„Z?	 d»ded edz  deeef   fde„Z@	 	 	 dÂdedz  d edz  dfedz  deeef   fdg„ZAdedeeef   fdh„ZBdedeeef   fdi„ZC	 d»ded edz  deeef   fdj„ZDdeeeef      fdk„ZEdledeeef   fdm„ZFdeeef   fdn„ZG	 d»dleded edz  deeeef      fdo„ZHdee   fdp„ZIdeeef   fdq„ZJ	 	 	 dÃdedZedredz  deeef   ee   z  fds„ZKdtedeeef   fdu„ZLdvedwedefdx„ZMdvedyedzed{edef
d|„ZNd}eeef   defd~„ZOded€edzed�ed‚edƒedefd„„ZPdeeef   dz  fd…„ZQd†edefd‡„ZRdvedefdˆ„ZS	 	 	 dÂded edz  dredz  d‰edz  deeeef      f
dŠ„ZT	 	 dÄded ed‹edŒedeeef   f
d�„ZUdeeef   fdŽ„ZV	 dÅd�ededZedeeeef      fd�„ZWd‘edeeef   fd’„ZXd“edeeef   fd”„ZYd‘edeeef   fd•„ZZ	 dÆd–ed“ed—edefd˜„Z[ G d™„ dše\«      Z] G d›„ dœe\«      Z^e]j¾                  fdved�e]de`fdž„Zadvedeeef   fdŸ„Zbdvedeeef   fd „Zcdvedeeef   fd¡„Zddvedeeef   fd¢„Zedvedeeef   fd£„Zfdvedeeef   fd¤„Zg	 dÇdved¥ed¦edeeef   fd§„Zhdveez  deeef   fd¨„Zidveez  deeef   fd©„Zj	 dÈd“edZedeeeef      fdª„Zkdeeef   fd«„Zldeeef   fd¬„Zmdedeeef   fd­„ZndÉdedZedeeef   fd®„Zod¯eez  deeef   fd°„Zpd¯eez  de`fd±„Zqd²eeef   ee   z  ez  deeef   fd³„Zrdtedeeef   fd´„Zsded edeeef   fdµ„Ztdeeef   fd¶„Zud·eeef   deeef   fd¸„ZvdÊd¹„Zwy)ËÚGarminz,Class for fetching data from Garmin Connect.NÚemailÚpasswordÚis_cnÚ
prompt_mfaÚreturn_on_mfar   c                 ó$  — |�t        |t        «      st        d«      ‚|�t        |t        «      st        d«      ‚t        |t        «      st        d«      ‚t        |t        «      st        d«      ‚|| _        || _        || _        || _        || _        d| _	        d| _
        d| _        d	| _        d
| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _        d| _         d| _!        d| _"        d | _#        d!| _$        d"| _%        d#| _&        d$| _'        d%| _(        d&| _)        d'| _*        d(| _+        d)| _,        d*| _-        d+| _.        d,| _/        d-| _0        d.| _1        d/| _2        d0| _3        d1| _4        d2| _5        d3| _6        d4| _7        d5| _8        d6| _9        d7| _:        d8| _;        d9| _<        d:| _=        d;| _>        d<| _?        d=| _@        d>| _A        d?| _B        d@| _C        dA| _D        dB| _E        dC| _F        dD| _G        d6| _H        dE| _I        t•        j–                  |rdFndGdHdH¬I«      | _J        d| _L        d| _M        d| _N        y)JzCreate a new class instance.Nzemail must be a string or Nonez!password must be a string or Nonezis_cn must be a booleanzreturn_on_mfa must be a booleanz./userprofile-service/userprofile/user-settingsz)/userprofile-service/userprofile/settingsz*/device-service/deviceregistration/devicesz/device-service/deviceservicez0/web-gateway/device-info/primary-training-devicez/web-gateway/solarz/weight-servicez&/usersummary-service/usersummary/dailyz%/metrics-service/metrics/maxmet/dailyz/biometric-service/biometricz/biometric-service/statsz0/usersummary-service/usersummary/hydration/dailyz./usersummary-service/usersummary/hydration/logz&/usersummary-service/stats/steps/dailyz*/personalrecord-service/personalrecord/prsz/badge-service/badge/earnedz/badge-service/badge/availablez1/adhocchallenge-service/adHocChallenge/historicalz0/badgechallenge-service/badgeChallenge/completedz0/badgechallenge-service/badgeChallenge/availablez4/badgechallenge-service/badgeChallenge/non-completedz3/badgechallenge-service/virtualChallenge/inProgressz)/wellness-service/wellness/dailySleepDataz&/wellness-service/wellness/dailyStressz"/metrics-service/metrics/hillscorez4/wellness-service/wellness/bodyBattery/reports/dailyz-/wellness-service/wellness/bodyBattery/eventsz*/bloodpressure-service/bloodpressure/rangez$/bloodpressure-service/bloodpressurez'/metrics-service/metrics/endurancescorez//periodichealth-service/menstrualcycle/calendarz./periodichealth-service/menstrualcycle/dayviewz8/periodichealth-service/menstrualcycle/pregnancysnapshotz/goal-service/goal/goalsz!/userstats-service/wellness/dailyz/hrv-service/hrvz*/metrics-service/metrics/trainingreadinessz(/metrics-service/metrics/racepredictionsz2/metrics-service/metrics/trainingstatus/aggregatedz,/wellness-service/wellness/dailySummaryChartz0/wellness-service/wellness/floorsChartData/dailyz)/wellness-service/wellness/dailyHeartRatez,/wellness-service/wellness/daily/respirationz%/wellness-service/wellness/daily/spo2z#/wellness-service/wellness/daily/imz&/wellness-service/wellness/dailyEventsz2/activitylist-service/activities/search/activitiesz!/activitylist-service/activities/z/activity-service/activityz(/activity-service/activity/activityTypesz!/mobile-gateway/heartRate/forDatez/fitnessstats-service/activityz/fitnessage-service/fitnessagez /download-service/files/activityz%/download-service/export/tcx/activityz%/download-service/export/gpx/activityz%/download-service/export/kml/activityz%/download-service/export/csv/activityz/upload-service/uploadz/gear-service/gear/filterGearz/gear-service/gear/z(/wellness-service/wellness/epoch/requestz/workout-servicezgraphql-gateway/graphqlz	garmin.cnz
garmin.comé   )ÚdomainÚpool_connectionsÚpool_maxsize)Or   r   r   r(   Úusernamer>   r?   r@   rA   Ú garmin_connect_user_settings_urlÚ'garmin_connect_userprofile_settings_urlÚgarmin_connect_devices_urlÚgarmin_connect_device_urlÚ!garmin_connect_primary_device_urlÚgarmin_connect_solar_urlÚgarmin_connect_weight_urlÚ garmin_connect_daily_summary_urlÚgarmin_connect_metrics_urlÚgarmin_connect_biometric_urlÚ"garmin_connect_biometric_stats_urlÚ"garmin_connect_daily_hydration_urlÚ garmin_connect_set_hydration_urlÚ$garmin_connect_daily_stats_steps_urlÚ"garmin_connect_personal_record_urlÚ garmin_connect_earned_badges_urlÚ#garmin_connect_available_badges_urlÚ#garmin_connect_adhoc_challenges_urlÚ#garmin_connect_badge_challenges_urlÚ-garmin_connect_available_badge_challenges_urlÚ1garmin_connect_non_completed_badge_challenges_urlÚ0garmin_connect_inprogress_virtual_challenges_urlÚgarmin_connect_daily_sleep_urlÚgarmin_connect_daily_stress_urlÚgarmin_connect_hill_score_urlÚ%garmin_connect_daily_body_battery_urlÚ&garmin_connect_body_battery_events_urlÚ&garmin_connect_blood_pressure_endpointÚ*garmin_connect_set_blood_pressure_endpointÚ"garmin_connect_endurance_score_urlÚ%garmin_connect_menstrual_calendar_urlÚ$garmin_connect_menstrual_dayview_urlÚ%garmin_connect_pregnancy_snapshot_urlÚgarmin_connect_goals_urlÚgarmin_connect_rhr_urlÚgarmin_connect_hrv_urlÚ%garmin_connect_training_readiness_urlÚ!garmin_connect_race_predictor_urlÚ"garmin_connect_training_status_urlÚ!garmin_connect_user_summary_chartÚ%garmin_connect_floors_chart_daily_urlÚ#garmin_connect_heartrates_daily_urlÚ$garmin_connect_daily_respiration_urlÚgarmin_connect_daily_spo2_urlÚ&garmin_connect_daily_intensity_minutesÚgarmin_daily_events_urlÚgarmin_connect_activitiesÚ!garmin_connect_activities_baseurlÚgarmin_connect_activityÚgarmin_connect_activity_typesÚgarmin_connect_activity_fordateÚgarmin_connect_fitnessstatsÚgarmin_connect_fitnessageÚgarmin_connect_fit_downloadÚgarmin_connect_tcx_downloadÚgarmin_connect_gpx_downloadÚgarmin_connect_kml_downloadÚgarmin_connect_csv_downloadÚgarmin_connect_uploadÚgarmin_connect_gearÚgarmin_connect_gear_baseurlÚgarmin_request_reload_urlÚgarmin_workoutsÚ"garmin_connect_delete_activity_urlÚgarmin_graphql_endpointÚgarthÚClientÚdisplay_nameÚ	full_nameÚunit_system)Úselfr=   r>   r?   r@   rA   s         r"   Ú__init__zGarmin.__init__a   sr  € ð Ð¤Z°´sÔ%;ÜÐ=Ó>Ð>ØÐ¬
°8¼SÔ(AÜÐ@ÓAÐAÜ˜%¤Ô&ÜÐ6Ó7Ð7Ü˜-¬Ô.ÜÐ>Ó?Ð?àˆŒØ ˆŒØˆŒ
Ø$ˆŒØ*ˆÔð =ð 	Ô-ð 8ð 	Ô4ð +WˆÔ'Ø)HˆÔ&ð ?ð 	Ô.ð )=ˆÔ%Ø):ˆÔ&Ø0XˆÔ-Ø*QˆÔ'Ø,JˆÔ)à2LˆÔ/à>ð 	Ô/ð =ð 	Ô-ð 5ð 	Ô1ð 9ð 	Ô/ð 1NˆÔ-Ø3SˆÔ0à?ð 	Ô0ð ?ð 	Ô0ð ?ð 	Ô:ð Cð 	Ô>ð Bð 	Ô=ð 8ð 	Ô+ð 0XˆÔ,Ø-QˆÔ*ð Cð 	Ô2ð
 <ð 	Ô3ð
 9ð 	Ô3ð
 3ð 	Ô7ð
 6ð 	Ô/ð >ð 	Ô2ð
 =ð 	Ô1ð Gð 	Ô2ð )CˆÔ%à&IˆÔ#à&8ˆÔ#ð 9ð 	Ô2ð
 7ð 	Ô.ð Að 	Ô/ð ;ð 	Ô.ð ?ð 	Ô2ð 8ð 	Ô0ð ;ð 	Ô1ð .UˆÔ*à1ð 	Ô3ð (PˆÔ$à@ð 	Ô&ð 2UˆÔ.Ø'CˆÔ$Ø-WˆÔ*Ø/RˆÔ,Ø+KˆÔ(Ø)IˆÔ&à+MˆÔ(Ø+RˆÔ(Ø+RˆÔ(Ø+RˆÔ(Ø+RˆÔ(à%=ˆÔ"à#BˆÔ Ø+@ˆÔ(à)SˆÔ&à1ˆÔà2NˆÔ/à'@ˆÔ$ä—\‘\Ù"'‘;¨\ØØô
ˆŒ
ð !ˆÔØˆŒØˆÕr+   ÚpathÚkwargsc                 óF  — 	  | j                   j                  |fi |¤ŽS # t        t        f$ rÁ}t	        |t        «      r#t        t        |j                  dd«      dd«      }nt        t        |dd«      dd«      }t        j                  d|||«       |dk(  rt        d|› �«      |‚|dk(  rt        d|› �«      |‚|r d	|cxk  rd
k  rn nt        d|› d|› �«      |‚t        d|› �«      |‚d}~wt        $ r*}t        j                  d|«       t        d|› �«      |‚d}~ww xY w)z1Wrapper for garth connectapi with error handling.ÚresponseNÚstatus_codez-API call failed for path '%s': %s (status=%s)é‘  úAuthentication failed: é­  úRate limit exceeded: é�  éô  zAPI client error (ú): zHTTP error: z*Connection error during connectapi path=%szConnection error: )r‰   Ú
connectapir   r   r   ÚgetattrÚerrorÚloggerÚ GarminConnectAuthenticationErrorÚ!GarminConnectTooManyRequestsErrorÚGarminConnectConnectionErrorÚ	ExceptionÚ	exception©rŽ   r�   r‘   r!   Ústatuss        r"   rœ   zGarmin.connectapi  sN  € ð	PØ(�4—:‘:×(Ñ(¨Ñ8°Ñ8Ð8øÜœ>Ð*ò 	Nä˜!œ^Ô,Ü Ü˜AŸG™G Z°Ó6¸Àtó‘ô !¤¨¨J¸Ó!=¸}ÈdÓS�ä�L‰LØ?ÀÀqÈ&ôð ˜Š}Ü6Ø-¨a¨SÐ1óàðð ˜3’Ü7Ø+¨A¨3Ð/óàðñ ˜C 6Ô/¨CÕ/ä2Ø(¨¨°°A°3Ð7óàðô 3°\À!ÀÐ3EÓFÈAÐMûÜò 	PÜ×ÑÐIÈ4ÔPÜ.Ð1CÀAÀ3Ð/GÓHÈaÐOûð	Pús!   ‚ ŸD ®B<C*Ã*D Ã6%DÄD c                 óD  — 	  | j                   j                  |fi |¤ŽS # t        t        f$ rÀ}t	        |t        «      r#t        t        |j                  dd«      dd«      }nt        t        |dd«      dd«      }t        j                  d||«       |dk(  rt        d|› �«      |‚|dk(  rt        d|› �«      |‚|r d|cxk  rd	k  rn nt        d
|› d|› �«      |‚t        d|› �«      |‚d}~wt        $ r*}t        j                  d|«       t        d|› �«      |‚d}~ww xY w)z/Wrapper for garth download with error handling.r“   Nr”   z)Download failed for path '%s' (status=%s)r•   zDownload error: r—   r™   rš   zDownload client error (r›   zDownload failed for path '%s')r‰   Údownloadr   r   r   r�   rž   rŸ   r¤   r    r¡   r¢   r£   r¥   s        r"   r¨   zGarmin.download:  sA  € ð	NØ&�4—:‘:×&Ñ& tÑ6¨vÑ6Ð6øÜœ>Ð*ò 	Rä˜!œ^Ô,Ü Ü˜AŸG™G Z°Ó6¸Àtó‘ô !¤¨¨J¸Ó!=¸}ÈdÓS�ä×ÑÐHÈ$ÐPVÔWØ˜Š}Ü6Ð9IÈ!ÈÐ7MÓNÐTUÐUØ˜3’Ü7Ð:JÈ1È#Ð8NÓOÐUVÐVÙ˜C 6Ô/¨CÕ/ä2Ø-¨f¨X°S¸¸Ð<óàðô 3Ð5EÀaÀSÐ3IÓJÐPQÐQûÜò 	NÜ×ÑÐ<¸dÔCÜ.Ð1AÀ!ÀÐ/EÓFÈAÐMûð	Nús!   ‚ ŸD®B;C)Ã)DÃ5%DÄDÚ
tokenstorec                óØ  ‡
— |xs t        j                  d«      }	 d}d}|rFt        |«      dkD  r| j                  j	                  |«       nþ| j                  j                  |«       nâ| j                  r| j                  st        d«      ‚| j                  s%| j                  rd| j                  vrt        d«      ‚| j                  rC| j                  j                  | j                  | j                  | j                  ¬«      \  }}||fS | j                  j                  | j                  | j                  | j                  ¬«      \  }}t        | j                  d	d«      sZ	 | j                  j                  d
«      }|rd|vrt        d«      ‚|j!                  d«      | _        |j!                  d«      | _        nT| j                  j&                  j!                  d«      | _        | j                  j&                  j!                  d«      | _        | j                  j                  | j(                  «      }|st        d«      ‚d|vrt        d«      ‚|d   j!                  d«      | _        ||fS # t        $ r}t        d«      |‚d}~ww xY w# t,        t.        j0                  j,                  t2        f$ r«}t        t        |dd«      dd«      }t4        j7                  d||«       |dk(  rt        d|› �«      |‚|dk(  rt9        d|› �«      |‚t;        |«      j=                  «       Š
g d¢}t?        ˆ
fd„|D «       «      rt        d|› �«      |‚tA        d|› �«      |‚d}~wtB        $ r ‚ t        $ r|}tE        |t        «      r‚ t;        |«      j=                  «       Š
g d¢}t?        ˆ
fd„|D «       «      }	|	rt        d|› �«      |‚t4        jG                  d«       tA        d|› �«      |‚d}~ww xY w) zÓ
        Log in using Garth.

        Returns:
            Tuple[str | None, str | None]: (access_token, refresh_token) when using credential flow;
            (None, None) when loading from tokenstore.
        ÚGARMINTOKENSNi   z"Username and password are requiredú@zEmail must contain '@' symbol)rA   )r@   Úprofilez(/userprofile-service/userprofile/profilezFailed to retrieve profileÚdisplayNamezInvalid profile data foundÚfullNamez Failed to retrieve user settingsÚuserDatazInvalid user settings foundÚmeasurementSystemr“   r”   zLogin failed: %s (status=%s)r•   r–   r—   r˜   )Ú401Úunauthorizedzauthentication failedc              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­w©N© ©Ú.0Ú	indicatorÚ	error_strs     €r"   ú	<genexpr>zGarmin.login.<locals>.<genexpr>¹  s   øè ø€ ÒK¨i�9 	Ô)ÑKùó   ƒzLogin failed: )r²   r³   Úauthenticationzlogin failedc              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wrµ   r¶   r·   s     €r"   r»   zGarmin.login.<locals>.<genexpr>Ë  s   øè ø€ ÒX¸9 	¨YÔ 6ÑXùr¼   zLogin failed)$ÚosÚgetenvÚlenr‰   ÚloadsÚloadrG   r>   r    r?   rA   Úloginr@   r�   rœ   r£   Úgetr‹   rŒ   r­   rH   r�   r   ÚrequestsÚ
exceptionsr   rŸ   rž   r¡   r   ÚlowerÚanyr¢   ÚFileNotFoundErrorr   r¤   )rŽ   r©   Útoken1Útoken2Úprofr!   Úsettingsr¦   Úauth_indicatorsÚis_auth_errorrº   s             @r"   rÄ   zGarmin.loginW  sÆ  ø€ ð  Ò<¤2§9¡9¨^Ó#<ˆ
ðq	LØˆFØˆFáÜ�z“? SÒ(Ø—J‘J×$Ñ$ ZÕ0à—J‘J—O‘O JÕ/ð —}’}¨D¯MªMÜ:Ø<óð ð
 —z’z d§m¢m¸À4Ç=Á=Ñ8PÜ:Ø7óð ð ×%Ò%Ø%)§Z¡Z×%5Ñ%5ØŸ™ØŸ™Ø&*×&8Ñ&8ð &6ó &‘N�F˜Fð " 6˜>Ð)à%)§Z¡Z×%5Ñ%5ØŸ™ØŸ™Ø#'§?¡?ð &6ó &‘N�F˜Fô ˜4Ÿ:™: y°$Ô7ðØŸ:™:×0Ñ0ØBó�Dñ ˜}°DÑ8Ü:Ð;WÓXÐXà$(§H¡H¨]Ó$;�Ô!Ø!%§¡¨*Ó!5�•à$(§J¡J×$6Ñ$6×$:Ñ$:¸=Ó$I�Ô!Ø!%§¡×!3Ñ!3×!7Ñ!7¸
Ó!C�”à—z‘z×,Ñ,¨T×-RÑ-RÓSˆHáÜ6Ø6óð ð  Ñ)Ü6Ð7TÓUÐUà'¨
Ñ3×7Ñ7Ð8KÓLˆDÔà˜6�>Ð!øô3 !ò Ü:Ø4óàðûðûô6 œ8×.Ñ.×8Ñ8¼.ÐIò 	LÜœW Q¨
°DÓ9¸=È$ÓOˆFÜ�L‰LÐ7¸¸FÔCð ˜Š}Ü6Ø-¨a¨SÐ1óàðð ˜3’Ü7Ø+¨A¨3Ð/óàðô
 ˜A›Ÿ™›ˆIÚNˆOÜÓK¸?ÔKÔKÜ6Ø-¨a¨SÐ1óàðô
 /°À¸sÐ/CÓDÈ!ÐKûÜ ò 	àÜò 	LÜ˜!Ô=Ô>ØäØóç‰e‹gð ò XˆOÜÓXÈÔXÓXˆMáÜ6Ø-¨a¨SÐ1óàðô ×Ñ˜^Ô,Ü.°À¸sÐ/CÓDÈ!ÐKûð	LúsR   œC.J
 ÄAJ
 Å"I- Å=C/J
 É-	JÉ6JÊJÊJ
 Ê
(O)Ê2B&MÍO)Í-A7O$Ï$O)Úclient_stateÚmfa_codec                 ó\  — | j                   j                  ||«      \  }}| j                   j                  r<| j                   j                  d   | _        | j                   j                  d   | _        | j                   j                  | j                  «      }|rd|v r|d   d   | _        ||fS )zResume login using Garth.r®   r¯   r°   r±   )r‰   Úresume_loginr­   r‹   rŒ   rœ   rH   r�   )rŽ   rÑ   rÒ   Úresult1Úresult2rÎ   s         r"   rÔ   zGarmin.resume_loginÔ  s›   € ð  Ÿ:™:×2Ñ2°<ÀÓJÑˆ�à�:‰:×ÒØ $§
¡
× 2Ñ 2°=Ñ AˆDÔØ!ŸZ™Z×/Ñ/°
Ñ;ˆDŒNà—:‘:×(Ñ(¨×)NÑ)NÓOˆÙ˜
 hÑ.Ø'¨
Ñ3Ð4GÑHˆDÔà˜ÐÐr+   c                 ó   — | j                   S )zReturn full name.)rŒ   ©rŽ   s    r"   Úget_full_namezGarmin.get_full_nameä  s   € ð �~‰~Ðr+   c                 ó   — | j                   S )zReturn unit system.)r�   rØ   s    r"   Úget_unit_systemzGarmin.get_unit_systemé  s   € ð ×ÑÐr+   Úcdatec                 ó$   — | j                  |«      S )zr
        Return user activity summary for 'cdate' format 'YYYY-MM-DD'
        (compat for garminconnect).
        )Úget_user_summary)rŽ   rÜ   s     r"   Ú	get_statszGarmin.get_statsî  s   € ð ×$Ñ$ UÓ+Ð+r+   c                 ó  — t        |d«      }| j                  › d| j                  › �}d|i}t        j	                  d«       | j                  ||¬«      }|st        d«      ‚|j                  d«      du rt        d	«      ‚|S )
z=Return user activity summary for 'cdate' format 'YYYY-MM-DD'.rÜ   ú/ÚcalendarDatezRequesting user summary©ÚparamszNo data received from serverÚprivacyProtectedTzAuthentication error)	r#   rO   r‹   rŸ   Údebugrœ   r¢   rÅ   r    ©rŽ   rÜ   Úurlrä   r“   s        r"   rÞ   zGarmin.get_user_summaryö  s‰   € ô & e¨WÓ5ˆà×6Ñ6Ð7°q¸×9JÑ9JÐ8KÐLˆØ  %Ð(ˆÜ�‰Ð.Ô/à—?‘? 3¨v�?Ó6ˆáÜ.Ð/MÓNÐNà�<‰<Ð*Ó+¨tÑ3Ü2Ð3IÓJÐJàˆr+   c                 óÞ   — t        |d«      }| j                  › d| j                  › �}d|i}t        j	                  d«       | j                  ||¬«      }|€t        j                  d«       g S |S )z7Fetch available steps data 'cDate' format 'YYYY-MM-DD'.rÜ   rá   r   zRequesting steps datarã   zNo steps data received)r#   ro   r‹   rŸ   ræ   rœ   Úwarningrç   s        r"   Úget_steps_datazGarmin.get_steps_data
  ss   € ô & e¨WÓ5ˆà×7Ñ7Ð8¸¸$×:KÑ:KÐ9LÐMˆØ˜%�ˆÜ�‰Ð,Ô-à—?‘? 3¨v�?Ó6ˆàÐÜ�N‰NÐ3Ô4ØˆIàˆr+   c                 ó¦   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      }|€t        d«      ‚|S )z8Fetch available floors data 'cDate' format 'YYYY-MM-DD'.rÜ   rá   zRequesting floors datazNo floors data received)r#   rp   rŸ   ræ   rœ   r¢   )rŽ   rÜ   rè   r“   s       r"   Ú
get_floorszGarmin.get_floors  sY   € ô & e¨WÓ5ˆà×;Ñ;Ð<¸A¸e¸WÐEˆÜ�‰Ð-Ô.à—?‘? 3Ó'ˆàÐÜ.Ð/HÓIÐIàˆr+   ÚstartÚendc                 óf  — t        |d«      }t        |d«      }t        j                  |t        «      j	                  «       }t        j                  |t        «      j	                  «       }||kD  rt        d«      ‚| j                  › d|› d|› �}t        j                  d«       | j                  |«      S )zAFetch available steps data 'start' and 'end' format 'YYYY-MM-DD'.rî   rï   z#start date cannot be after end daterá   zRequesting daily steps data)
r#   r   r   r    r   r   rU   rŸ   ræ   rœ   )rŽ   rî   rï   Ú
start_dateÚend_daterè   s         r"   Úget_daily_stepszGarmin.get_daily_steps,  s¡   € ô & e¨WÓ5ˆÜ# C¨Ó/ˆô ×&Ñ& u¬oÓ>×CÑCÓEˆ
Ü×$Ñ$ S¬/Ó:×?Ñ?ÓAˆà˜Ò ÜÐBÓCÐCà×:Ñ:Ð;¸1¸U¸GÀ1ÀSÀEÐJˆÜ�‰Ð2Ô3à�‰˜sÓ#Ð#r+   c                 óÆ   — t        |d«      }| j                  › d| j                  › �}d|i}t        j	                  d«       | j                  ||¬«      }|€t        d«      ‚|S )a®  Fetch available heart rates data 'cDate' format 'YYYY-MM-DD'.

        Args:
            cdate: Date string in format 'YYYY-MM-DD'

        Returns:
            Dictionary containing heart rate data for the specified date

        Raises:
            ValueError: If cdate format is invalid
            GarminConnectConnectionError: If no data received
            GarminConnectAuthenticationError: If authentication fails
        rÜ   rá   r   zRequesting heart ratesrã   zNo heart rate data received)r#   rq   r‹   rŸ   ræ   rœ   r¢   rç   s        r"   Úget_heart_rateszGarmin.get_heart_rates?  sm   € ô  & e¨WÓ5ˆà×9Ñ9Ð:¸!¸D×<MÑ<MÐ;NÐOˆØ˜%�ˆÜ�‰Ð-Ô.à—?‘? 3¨v�?Ó6ˆàÐÜ.Ð/LÓMÐMàˆr+   c                 ó    — | j                  |«      }| j                  |«      }|j                  d«      xs i }t        |t        «      si }i |¥|¥S )zEReturn activity data and body composition (compat for garminconnect).ÚtotalAverage)rß   Úget_body_compositionrÅ   r   Údict)rŽ   rÜ   ÚstatsÚbodyÚbody_avgs        r"   Úget_stats_and_bodyzGarmin.get_stats_and_body\  sT   € ð —‘˜uÓ%ˆØ×(Ñ(¨Ó/ˆØ—8‘8˜NÓ+Ò1¨rˆÜ˜(¤DÔ)ØˆHØ$�%Ð$˜8Ð$Ð$r+   Ú	startdateÚenddatec                 óŽ  — t        |d«      }|€|nt        |d«      }t        j                  |t        «      j	                  «       t        j                  |t        «      j	                  «       kD  rt        d«      ‚| j                  › d�}t        |«      t        |«      dœ}t        j                  d«       | j                  ||¬«      S )z‚
        Return available body composition data for 'startdate' format
        'YYYY-MM-DD' through enddate 'YYYY-MM-DD'.
        rþ   rÿ   z!startdate cannot be after enddatez/weight/dateRange©Ú	startDateÚendDatezRequesting body compositionrã   )r#   r   r   r    r   r   rN   r   rŸ   ræ   rœ   ©rŽ   rþ   rÿ   rè   rä   s        r"   rø   zGarmin.get_body_compositionf  s´   € ô *¨)°[ÓAˆ	à ˜‰IÔ.CÀGÈYÓ.Wð 	ô ×Ñ˜i¬Ó9×>Ñ>Ó@Ü×Ñ ¬Ó9×>Ñ>Ó@òAô Ð@ÓAÐAØ×/Ñ/Ð0Ð0AÐBˆÜ" 9›~¼#¸g»,ÑGˆÜ�‰Ð2Ô3à�‰˜s¨6ˆÓ2Ð2r+   Ú	timestampÚweightÚpercent_fatÚpercent_hydrationÚvisceral_fat_massÚ	bone_massÚmuscle_massÚ	basal_metÚ
active_metÚphysique_ratingÚmetabolic_ageÚvisceral_fat_ratingÚbmic                 óÜ  — t        |d«      }|rt        j                  |«      nt        j                  «       }t	        «       }|j                  «        |j                  «        |j                  |«       |j                  |||||||||	|
|||¬«       |j                  «        | j                  }dd|j                  «       fi}| j                  j                  d||d¬«      j                  «       S )Nr  )r  r  r  r	  r
  r  r  r  r  r  r  r  Úfilezbody_composition.fitrœ   T©ÚfilesÚapi)r*   r   ÚfromisoformatÚnowr   Úwrite_file_infoÚwrite_file_creatorÚwrite_device_infoÚwrite_weight_scaleÚfinishr‚   Úgetvaluer‰   ÚpostÚjson)rŽ   r  r  r  r  r	  r
  r  r  r  r  r  r  r  r3   Ú
fitEncoderrè   r  s                     r"   Úadd_body_compositionzGarmin.add_body_composition}  sì   € ô  +¨6°8Ó<ˆÙ2;ŒX×#Ñ# IÔ.ÄÇÁÃˆÜ%Ó'ˆ
Ø×"Ñ"Ô$Ø×%Ñ%Ô'Ø×$Ñ$ RÔ(Ø×%Ñ%ØØØ#Ø/Ø/ØØ#ØØ!Ø+Ø'Ø 3Øð 	&ô 	
ð 	×ÑÔà×(Ñ(ˆàÐ+¨Z×-@Ñ-@Ó-BÐCð
ˆð �z‰z�‰˜|¨S¸À4ˆÓH×MÑMÓOÐOr+   ÚunitKeyc                 óø  — t        |d«      }|t        vrt        dt        › �«      ‚| j                  › d�}	 |rt	        j
                  |«      nt	        j                  «       }|j                  t        j                  «      }t        |«      t        |«      |d|dœ}t        j                  d«       | j                  j                  d	||¬
«      j                  «       S # t        $ r}t        d|› �«      |‚d}~ww xY w)zAdd a weigh-in (default to kg)r  úunitKey must be one of ú/user-weightzinvalid timestamp format: NÚMANUAL©ÚdateTimestampÚgmtTimestampr#  Ú
sourceTyper$   zAdding weigh-inrœ   ©r   )r*   ÚVALID_WEIGHT_UNITSr   rN   r   r  r  Ú
astimezoner   Úutcr:   rŸ   ræ   r‰   r  r   )	rŽ   r  r#  r  rè   r3   r!   ÚdtGMTÚpayloads	            r"   Úadd_weigh_inzGarmin.add_weigh_inª  sí   € ô +¨6°8Ó<ˆàÔ,Ñ,ÜÐ6Ô7IÐ6JÐKÓLÐLà×/Ñ/Ð0°Ð=ˆð	FÙ6?”×'Ñ'¨	Ô2ÄXÇ\Á\Ã^ˆBð
 —‘œhŸl™lÓ+ˆä$ R›[Ü# E›NØØ"Øñ
ˆô 	�‰Ð&Ô'à�z‰z�‰˜|¨S°wˆÓ?×DÑDÓFÐFøô ò 	FÜÐ9¸!¸Ð=Ó>ÀAÐEûð	Fús   ·+C Ã	C9Ã%C4Ã4C9r)  r*  c                 ó¶  — | j                   › d�}|t        vrt        dt        › �«      ‚|r#t        j                  |«      j                  «       n!t        j                  «       j                  «       }|rat        j                  |«      }|j                  € |j                  t        j                  ¬«      }|j                  t        j                  «      }n|j                  t        j                  «      }t        |d«      }t        |«      t        |«      |d|dœ}	t        j                  d|	«       | j                  j!                  d||	¬	«      j#                  «       S )
z7Add a weigh-in with explicit timestamps (default to kg)r&  r%  r5   r  r'  r(  z,Adding weigh-in with explicit timestamps: %srœ   r,  )rN   r-  r   r   r  r.  r  r6   r8   r   r/  r*   r:   rŸ   ræ   r‰   r  r   )
rŽ   r  r#  r)  r*  rè   r3   Úgr0  r1  s
             r"   Úadd_weigh_in_with_timestampsz#Garmin.add_weigh_in_with_timestampsÉ  s$  € ð ×/Ñ/Ð0°Ð=ˆàÔ,Ñ,ÜÐ6Ô7IÐ6JÐKÓLÐLñ ô ×"Ñ" =Ó1×<Ñ<Ô>ä—‘“×*Ñ*Ó,ð 	ñ
 Ü×&Ñ& |Ó4ˆAà�x‰xÐØ—I‘I¤X§\¡\�IÓ2�Ø—L‘L¤§¡Ó.‰Eà—M‘M¤(§,¡,Ó/ˆEô +¨6°8Ó<ˆô % R›[Ü# E›NØØ"Øñ
ˆô 	�‰ÐCÀWÔMð �z‰z�‰˜|¨S°wˆÓ?×DÑDÓFÐFr+   c                 ó²   — t        |d«      }t        |d«      }| j                  › d|› d|› �}ddi}t        j                  d«       | j	                  ||¬«      S )	zFGet weigh-ins between startdate and enddate using format 'YYYY-MM-DD'.rþ   rÿ   z/weight/range/rá   Ú
includeAllTúRequesting weigh-insrã   ©r#   rN   rŸ   ræ   rœ   r  s        r"   Úget_weigh_inszGarmin.get_weigh_insö  sc   € ô *¨)°[ÓAˆ	Ü'¨°Ó;ˆØ×/Ñ/Ð0°¸y¸kÈÈ7È)ÐTˆØ Ð%ˆÜ�‰Ð+Ô,à�‰˜s¨6ˆÓ2Ð2r+   c                 ó”   — t        |d«      }| j                  › d|› �}ddi}t        j                  d«       | j	                  ||¬«      S )z.Get weigh-ins for 'cdate' format 'YYYY-MM-DD'.rÜ   z/weight/dayview/r7  Tr8  rã   r9  ©rŽ   rÜ   rè   rä   s       r"   Úget_daily_weigh_inszGarmin.get_daily_weigh_ins  sR   € ô & e¨WÓ5ˆØ×/Ñ/Ð0Ð0@ÀÀÐHˆØ Ð%ˆÜ�‰Ð+Ô,à�‰˜s¨6ˆÓ2Ð2r+   Ú	weight_pkc                 óª   — t        |d«      }| j                  › d|› d|› �}t        j                  d«       | j                  j                  dd|d¬«      S )	zDelete specific weigh-in.rÜ   z/weight/z/byversion/zDeleting weigh-inÚDELETErœ   T©r  )r#   rN   rŸ   ræ   r‰   Úrequest)rŽ   r>  rÜ   rè   s       r"   Údelete_weigh_inzGarmin.delete_weigh_in  s`   € ä% e¨WÓ5ˆØ×/Ñ/Ð0°¸¸¸{È9È+ÐVˆÜ�‰Ð(Ô)à�z‰z×!Ñ!ØØØØð	 "ó 
ð 	
r+   Ú
delete_allc                 ó~  — | j                  |«      }|j                  dg «      }|rt        |«      dk(  rt        j	                  d|› �«       yt        |«      dkD  r=t        j	                  d|› �«       |s#t        j	                  dt        |«      › d�«       y|D ]  }| j                  |d	   |«       Œ t        |«      S )
z�
        Delete weigh-in for 'cdate' format 'YYYY-MM-DD'.
        Includes option to delete all weigh-ins for that date.
        ÚdateWeightListr   zNo weigh-ins found on Nr   zMultiple weigh-ins found for z%Set delete_all to True to delete all z
 weigh-insÚsamplePk)r=  rÅ   rÁ   rŸ   rê   rC  )rŽ   rÜ   rD  Údaily_weigh_insÚ	weigh_insÚws         r"   Údelete_weigh_inszGarmin.delete_weigh_ins  sÀ   € ð ×2Ñ2°5Ó9ˆØ#×'Ñ'Ð(8¸"Ó=ˆ	ÙœC 	›N¨aÒ/Ü�N‰NÐ3°E°7Ð;Ô<ØÜ�‹^˜aÒÜ�N‰NÐ:¸5¸'ÐBÔCÙÜ—‘Ø;¼CÀ	»NÐ;KÈ:ÐVôð àò 	7ˆAØ× Ñ   :¡°Õ6ð	7ô �9‹~Ðr+   c                 óÒ   — t        |d«      }|€|}nt        |d«      }| j                  }t        |«      t        |«      dœ}t        j	                  d«       | j                  ||¬«      S )z|
        Return body battery values by day for 'startdate' format
        'YYYY-MM-DD' through enddate 'YYYY-MM-DD'
        rþ   rÿ   r  zRequesting body battery datarã   )r#   ra   r   rŸ   ræ   rœ   r  s        r"   Úget_body_batteryzGarmin.get_body_battery0  sc   € ô *¨)°[ÓAˆ	Øˆ?Ø‰Gä+¨G°YÓ?ˆGØ×8Ñ8ˆÜ" 9›~¼#¸g»,ÑGˆÜ�‰Ð3Ô4à�‰˜s¨6ˆÓ2Ð2r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )a   
        Return body battery events for date 'cdate' format 'YYYY-MM-DD'.
        The return value is a list of dictionaries, where each dictionary contains event data for a specific event.
        Events can include sleep, recorded activities, auto-detected activities, and naps
        rÜ   rá   z"Requesting body battery event data)r#   rb   rŸ   ræ   rœ   ©rŽ   rÜ   rè   s      r"   Úget_body_battery_eventszGarmin.get_body_battery_eventsC  sC   € ô & e¨WÓ5ˆØ×<Ñ<Ð=¸Q¸u¸gÐFˆÜ�‰Ð9Ô:à�‰˜sÓ#Ð#r+   ÚsystolicÚ	diastolicÚpulseÚnotesc           	      ó  — | j                   › }|rt        j                  |«      nt        j                  «       }|j	                  t
        j                  «      }t        |«      t        |«      |||d|dœ}	d|ddfd|ddfd	|d
dffD ]8  \  }
}}}t        |t        «      r||cxk  r|k  rŒ$n t        |
› d|› d|› d�«      ‚ t        j                  d«       | j                  j                  d||	¬«      j                  «       S )z0
        Add blood pressure measurement
        r'  )ÚmeasurementTimestampLocalÚmeasurementTimestampGMTrQ  rR  rS  r+  rT  rQ  éF   i  rR  é(   é–   rS  rC   éú   z must be an int in [ú, ú]zAdding blood pressurerœ   r,  )rd   r   r  r  r.  r   r/  r:   r   r/   r   rŸ   ræ   r‰   r  r   )rŽ   rQ  rR  rS  r  rT  rè   r3   r0  r1  ÚnameÚvalÚloÚhis                 r"   Úset_blood_pressurezGarmin.set_blood_pressureP  s
  € ð ×@Ñ@ÐAˆÙ2;ŒX×#Ñ# IÔ.ÄÇÁÃˆà—‘œhŸl™lÓ+ˆä)0°«Ü'.¨u£~Ø Ø"ØØ"Øñ
ˆð ˜ 2 sÐ+Ø˜) R¨Ð-Ø�e˜R Ð%ð"
ò 	KÑˆD�#�r˜2ô
 ˜c¤3Ô'°°c´¸RµÜ  D 6Ð)=¸b¸TÀÀBÀ4ÀqÐ!IÓJÐJð	Kô 	�‰Ð,Ô-à�z‰z�‰˜|¨S°wˆÓ?×DÑDÓFÐFr+   c                 ó¼   — t        |d«      }|€|}nt        |d«      }| j                  › d|› d|› �}ddi}t        j                  d«       | j	                  ||¬«      S )zx
        Returns blood pressure by day for 'startdate' format
        'YYYY-MM-DD' through enddate 'YYYY-MM-DD'
        rþ   rÿ   rá   r7  TzRequesting blood pressure datarã   )r#   rc   rŸ   ræ   rœ   r  s        r"   Úget_blood_pressurezGarmin.get_blood_pressuret  sm   € ô *¨)°[ÓAˆ	Øˆ?Ø‰Gä+¨G°YÓ?ˆGØ×<Ñ<Ð=¸Q¸y¸kÈÈ7È)ÐTˆØ Ð%ˆÜ�‰Ð5Ô6à�‰˜s¨6ˆÓ2Ð2r+   Úversionc                 ó®   — | j                   › d|› d|› �}t        j                  d«       | j                  j	                  dd|d¬«      j                  «       S )z+Delete specific blood pressure measurement.rá   z#Deleting blood pressure measurementr@  rœ   TrA  )rd   rŸ   ræ   r‰   rB  r   )rŽ   re  rÜ   rè   s       r"   Údelete_blood_pressurezGarmin.delete_blood_pressure‡  s]   € à×@Ñ@ÐAÀÀ5À'ÈÈ7È)ÐTˆÜ�‰Ð:Ô;à�z‰z×!Ñ!ØØØØð	 "ó 
÷
 ‰$‹&ð	r+   c                 óŽ   — t        |d«      }| j                  › d|› d|› �}t        j                  d«       | j	                  |«      S )zAReturn available max metric data for 'cdate' format 'YYYY-MM-DD'.rÜ   rá   zRequesting max metrics)r#   rP   rŸ   ræ   rœ   rO  s      r"   Úget_max_metricszGarmin.get_max_metrics“  sI   € ô & e¨WÓ5ˆØ×0Ñ0Ð1°°5°'¸¸5¸'ÐBˆÜ�‰Ð-Ô.à�‰˜sÓ#Ð#r+   TÚdaily)Úlatestrñ   rò   Úaggregationrk  rñ   rò   rl  c                ót  — |�r| j                   › d�}| j                   › dt        j                  «       › d�}| j                  |«      }t	        |t
        «      r|r|d   }nt	        |t        «      r|}ni }| j                  |«      }	ddddddddœ}
|	D ]~  }|j                  d«      }|�%|d   |
d<   |d	   |
d	<   |d
   |
d
<   |d   |
d<   ||
d<   |j                  d«      xs |j                  d«      }|�||
d<   |j                  d«      }|€Œz||
d<   Œ€ |
|dœS |€t        d«      ‚|€"t        j                  «       j                  «       }t	        |t        «      r|j                  «       }nt        |d«      }t	        |t        «      r|j                  «       }nt        |d«      }h d£}||vrt        d|› �«      ‚| j                  › d|› d|› d|› d�}| j                  › d|› d|› d|› d�}| j                  › d|› d|› d|› d�}| j                  |«      }| j                  |«      }| j                  |«      }|||dœS )a®  
        Returns Running Lactate Threshold information, including heart rate, power, and speed

        :param bool (Required) - latest: Whether to query for the latest Lactate Threshold info or a range.  False if querying a range
        :param date (Optional) - start_date: The first date in the range to query, format 'YYYY-MM-DD'.  Required if `latest` is False.  Ignored if `latest` is True
        :param date (Optional) - end_date: The last date in the range to query, format 'YYYY-MM-DD'. Defaults to current data. Ignored if `latest` is True
        :param str (Optional) - aggregation: How to aggregate the data. Must be one of `daily`, `weekly`, `monthly`, `yearly`.
        z/latestLactateThresholdz/powerToWeight/latest/z?sport=Runningr   N)ÚuserProfilePKre  râ   ÚsequenceÚspeedÚ	heartRateÚheartRateCyclingrp  rn  re  râ   ro  rq  ÚhearRaterr  )Úspeed_and_heart_rateÚpowerz5you must either specify 'latest=True' or a start_daterñ   rò   >   rj  ÚweeklyÚyearlyÚmonthlyzaggregation must be one of z/lactateThresholdSpeed/range/rá   z?sport=RUNNING&aggregation=z&aggregationStrategy=LATESTz!/lactateThresholdHeartRate/range/z /functionalThresholdPower/range/)rp  Ú
heart_rateru  )rQ   r   Útodayrœ   r   Úlistrù   rÅ   r   Ú	isoformatr#   rR   )rŽ   rk  rñ   rò   rl  Úspeed_and_heart_rate_urlÚ	power_urlru  Ú
power_dictrt  Úspeed_and_heart_rate_dictÚentryrp  ÚhrÚhrcÚ_valid_aggregationsÚ	speed_urlÚheart_rate_urlry  s                      r"   Úget_lactate_thresholdzGarmin.get_lactate_thresholdœ  s  € ò" à×4Ñ4Ð5Ð5LÐMð %ð  ×<Ñ<Ð=Ð=SÔTX×T^ÑT^ÓT`ÐSaÐaoÐpˆIà—O‘O IÓ.ˆEÜ˜%¤Ô&©5Ø" 1™X‘
Ü˜E¤4Ô(Ø"‘
à�
à#'§?¡?Ð3KÓ#LÐ ð "&ØØ $Ø ØØ!Ø$(ñ)Ð%ð .ò H�ØŸ	™	 'Ó*�ØÐ$ØAFÀÑAWÐ-¨oÑ>Ø;@ÀÑ;KÐ-¨iÑ8Ø@EÀnÑ@UÐ-¨nÑ=Ø<AÀ*Ñ<MÐ-¨jÑ9Ø9>Ð-¨gÑ6ð —Y‘Y˜{Ó+ÒD¨u¯y©y¸Ó/D�Ø�>Ø=?Ð-¨kÑ:ð —i‘iÐ 2Ó3�Ø‘?ØDGÐ-Ð.@ÒAð#Hð& )BØ#ñð ð
 ÐÜÐTÓUÐUàÐÜ—z‘z“|×-Ñ-Ó/ˆHô �j¤$Ô'Ø#×-Ñ-Ó/‰Jä.¨z¸<ÓHˆJÜ�h¤Ô%Ø×)Ñ)Ó+‰Hä,¨X°zÓBˆHâFÐØÐ1Ñ1ÜÐ:Ð;NÐ:OÐPÓQÐQà×>Ñ>Ð?Ð?\Ð]gÐ\hÐhiÐjrÐisð  tOð  P[ð  O\ð  \wð  xˆ	à ×CÑCÐDÐDeÐfpÐeqÐqrÐs{Ðr|ð  }Xð  Ydð  Xeð  e@ð  Aˆà×>Ñ>Ð?Ð?_Ð`jÐ_kÐklÐmuÐlvð  wRð  S^ð  R_ð  _zð  {ˆ	à—‘ 	Ó*ˆØ—_‘_ ^Ó4ˆ
Ø—‘ 	Ó*ˆà¨jÀ5ÑIÐIr+   Úvalue_in_mlc                 óØ  — t        |t        j                  «      st        d«      ‚t	        |«      t
        kD  rt        dt
        › d�«      ‚| j                  }|€B|€@t        j                  «       }t        |«      }t        j                  «       }t        |«      }�n|�4|€2t        |d«      }t        j                  |t        «      }t        |«      }nÞ|€^|�\t        |t        «      st        d«      ‚	 	 t        j                   |«      }|j                  «       j#                  «       }t        |«      }n~t        |d«      }t        |t        «      st        d«      ‚	 	 t        j                   |«      }|j                  «       j#                  «       }||k7  rt        d	|› d
|› d�«      ‚t        |«      }|||dœ}	t$        j'                  d«       | j(                  j+                  d||	¬«      j-                  «       S # t        $ r t        j                  |d«      }Y �Œw xY w# t        $ r}t        d«      |‚d}~ww xY w# t        $ r t        j                  |d«      }Y Œëw xY w# t        $ r ‚ w xY w)aÛ  Add hydration data in ml.  Defaults to current date and current timestamp if left empty
        :param float required - value_in_ml: The number of ml of water you wish to add (positive) or subtract (negative)
        :param timestamp optional - timestamp: The timestamp of the hydration update, format 'YYYY-MM-DDThh:mm:ss.ms' Defaults to current timestamp
        :param date optional - cdate: The date of the weigh in, format 'YYYY-MM-DD'. Defaults to current date
        zvalue_in_ml must be a numberz&value_in_ml seems unreasonably high (>zml)NrÜ   ztimestamp must be a stringz%Y-%m-%dT%H:%M:%Sz,Invalid timestamp format (expected ISO 8601)ztimestamp date (z) doesn't match cdate (ú))râ   ÚtimestampLocalÚ	valueInMLzAdding hydration datarœ   r,  )r   r&   r'   r   ÚabsÚMAX_HYDRATION_MLrT   r   rz  r   r   r  r:   r#   r   r    r  r|  rŸ   ræ   r‰   Úputr   )
rŽ   rˆ  r  rÜ   rè   Úraw_dateÚraw_tsr!   Úts_dater1  s
             r"   Úadd_hydration_datazGarmin.add_hydration_data  sb  € ô ˜+¤w§|¡|Ô4ÜÐ;Ó<Ð<ô ˆ{ÓÔ.Ò.ÜØ8Ô9IÐ8JÈ#ÐNóð ð ×3Ñ3ˆàÐ  ä—z‘z“|ˆHÜ˜“MˆEä—\‘\“^ˆFÜ ›ŠIàÐ 9Ð#4ä)¨%°Ó9ˆEÜ×&Ñ& u¬oÓ>ˆFÜ ›‰Iàˆ]˜yÐ4ä˜i¬Ô-Ü Ð!=Ó>Ð>ðXðOÜ%×3Ñ3°IÓ>�Fð Ÿ™›×/Ñ/Ó1�Ü# F›O‘	ô
 *¨%°Ó9ˆEÜ˜i¬Ô-Ü Ð!=Ó>Ð>ððOÜ%×3Ñ3°IÓ>�Fð !Ÿ+™+›-×1Ñ1Ó3�Ø˜eÒ#Ü$Ø*¨7¨)Ð3JÈ5È'ÐQRÐSóð ô $ F›O�	ð
 "Ø'Ø$ñ
ˆô 	�‰Ð,Ô-Ø�z‰z�~‰~˜l¨C°gˆ~Ó>×CÑCÓEÐEøôA "ò OÜ%×.Ñ.¨yÐ:MÓN“FðOûô ò XÜ Ð!OÓPÐVWÐWûðXûô "ò OÜ%×.Ñ.¨yÐ:MÓN’FðOûô ò Øðúsa   Ã2G6 Ä)H ÅH9 Å/A I Ç6HÈH ÈHÈH È	H6È%H1È1H6È9IÉI ÉIÉI ÉI)c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z<Return available hydration data 'cdate' format 'YYYY-MM-DD'.rÜ   rá   zRequesting hydration data)r#   rS   rŸ   ræ   rœ   rO  s      r"   Úget_hydration_datazGarmin.get_hydration_dataP  sC   € ô & e¨WÓ5ˆØ×8Ñ8Ð9¸¸5¸'ÐBˆÜ�‰Ð0Ô1à�‰˜sÓ#Ð#r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z>Return available respiration data 'cdate' format 'YYYY-MM-DD'.rÜ   rá   zRequesting respiration data)r#   rr   rŸ   ræ   rœ   rO  s      r"   Úget_respiration_datazGarmin.get_respiration_dataY  sC   € ô & e¨WÓ5ˆØ×:Ñ:Ð;¸1¸U¸GÐDˆÜ�‰Ð2Ô3à�‰˜sÓ#Ð#r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z7Return available SpO2 data 'cdate' format 'YYYY-MM-DD'.rÜ   rá   zRequesting SpO2 data)r#   rs   rŸ   ræ   rœ   rO  s      r"   Úget_spo2_datazGarmin.get_spo2_datab  sC   € ô & e¨WÓ5ˆØ×3Ñ3Ð4°A°e°WÐ=ˆÜ�‰Ð+Ô,à�‰˜sÓ#Ð#r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )zDReturn available Intensity Minutes data 'cdate' format 'YYYY-MM-DD'.rÜ   rá   z!Requesting Intensity Minutes data)r#   rt   rŸ   ræ   rœ   rO  s      r"   Úget_intensity_minutes_dataz!Garmin.get_intensity_minutes_datak  sC   € ô & e¨WÓ5ˆØ×<Ñ<Ð=¸Q¸u¸gÐFˆÜ�‰Ð8Ô9à�‰˜sÓ#Ð#r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )zAReturn available all day stress data 'cdate' format 'YYYY-MM-DD'.rÜ   rá   zRequesting all day stress data©r#   r_   rŸ   ræ   rœ   rO  s      r"   Úget_all_day_stresszGarmin.get_all_day_stresst  sC   € ô & e¨WÓ5ˆØ×5Ñ5Ð6°a¸°wÐ?ˆÜ�‰Ð5Ô6à�‰˜sÓ#Ð#r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z�
        Return available daily events data 'cdate' format 'YYYY-MM-DD'.
        Includes autodetected activities, even if not recorded on the watch
        rÜ   z?calendarDate=zRequesting all day events data)r#   ru   rŸ   ræ   rœ   rO  s      r"   Úget_all_day_eventszGarmin.get_all_day_events}  sC   € ô & e¨WÓ5ˆØ×-Ñ-Ð.¨n¸U¸GÐDˆÜ�‰Ð5Ô6à�‰˜sÓ#Ð#r+   c                 ó„   — | j                   › d| j                  › �}t        j                  d«       | j	                  |«      S )z)Return personal records for current user.rá   z$Requesting personal records for user)rV   r‹   rŸ   ræ   rœ   ©rŽ   rè   s     r"   Úget_personal_recordzGarmin.get_personal_record‰  s>   € ð ×8Ñ8Ð9¸¸4×;LÑ;LÐ:MÐNˆÜ�‰Ð;Ô<à�‰˜sÓ#Ð#r+   c                 óf   — | j                   }t        j                  d«       | j                  |«      S )z&Return earned badges for current user.z!Requesting earned badges for user)rW   rŸ   ræ   rœ   r¢  s     r"   Úget_earned_badgeszGarmin.get_earned_badges‘  s+   € ð ×3Ñ3ˆÜ�‰Ð8Ô9à�‰˜sÓ#Ð#r+   c                 ón   — | j                   }t        j                  d«       | j                  |ddi¬«      S )z)Return available badges for current user.z$Requesting available badges for userÚshowExclusiveBadgeÚtruerã   )rX   rŸ   ræ   rœ   r¢  s     r"   Úget_available_badgeszGarmin.get_available_badges™  s5   € ð ×6Ñ6ˆÜ�‰Ð;Ô<à�‰˜sÐ,@À&Ð+IˆÓJÐJr+   c                 ó’  — t         j                  d«       | j                  «       }| j                  «       }dt        dt
        fd„}t        t        ||«      «      }t        t        ||«      «      }|D �ci c]  }|d   |“Œ
 }}|j                  |D �ci c]  }|d   |“Œ
 c}«       t        |j                  «       «      S c c}w c c}w )z+Return in progress badges for current user.z&Requesting in progress badges for userÚbadger   c                 ó¸   — | j                  d«      }|sy|dk(  ry| j                  d«      }||k(  r*| j                  d«      €y| j                  dd«      | d   k  S y)z(Return True if the badge is in progress.ÚbadgeProgressValueFr   ÚbadgeTargetValueÚbadgeLimitCountÚbadgeEarnedNumberT)rÅ   )r«  ÚprogressÚtargets      r"   Úis_badge_in_progressz;Garmin.get_in_progress_badges.<locals>.is_badge_in_progressª  sk   € à—y‘yÐ!5Ó6ˆHÙØØ˜1Š}ØØ—Y‘YÐ1Ó2ˆFØ˜6Ò!Ø—9‘9Ð.Ó/Ð7Ø Ø—y‘yÐ!4°aÓ8¸5ÐARÑ;SÑSÐSØr+   ÚbadgeId)
rŸ   ræ   r¥  r©  rù   r(   r{  ÚfilterÚupdateÚvalues)rŽ   Úearned_badgesÚavailable_badgesr³  Úearned_in_progress_badgesÚavailable_in_progress_badgesÚbÚcombineds           r"   Úget_in_progress_badgeszGarmin.get_in_progress_badges¡  sÆ   € ô 	�‰Ð=Ô>à×.Ñ.Ó0ˆØ×4Ñ4Ó6Ðð	¬ð 	´ó 	ô %)¬Ð0DÀmÓ)TÓ$UÐ!Ü'+ÜÐ'Ð)9Ó:ó(
Ð$ð .GÖG¨�A�i‘L !‘OÐGˆÐGØ�‰Ð2NÖO¨Q˜˜9™ q™ÒOÔPÜ�H—O‘OÓ%Ó&Ð&ùò HùÚOs   Á4B?ÂCÚlimitc                 óÈ   — t        |d«      }t        |d«      }| j                  }t        |«      t        |«      dœ}t        j                  d«       | j                  ||¬«      S )z)Return adhoc challenges for current user.rî   r¿  ©rî   r¿  z$Requesting adhoc challenges for userrã   )r0   r2   rY   r   rŸ   ræ   rœ   ©rŽ   rî   r¿  rè   rä   s        r"   Úget_adhoc_challengeszGarmin.get_adhoc_challengesÁ  óY   € ô /¨u°gÓ>ˆÜ*¨5°'Ó:ˆØ×6Ñ6ˆÜ˜u›:´°E³
Ñ;ˆÜ�‰Ð;Ô<à�‰˜s¨6ˆÓ2Ð2r+   c                 óÈ   — t        |d«      }t        |d«      }| j                  }t        |«      t        |«      dœ}t        j                  d«       | j                  ||¬«      S )z)Return badge challenges for current user.rî   r¿  rÁ  ú$Requesting badge challenges for userrã   )r0   r2   rZ   r   rŸ   ræ   rœ   rÂ  s        r"   Úget_badge_challengeszGarmin.get_badge_challengesÌ  rÄ  r+   c                 óÈ   — t        |d«      }t        |d«      }| j                  }t        |«      t        |«      dœ}t        j                  d«       | j                  ||¬«      S )z"Return available badge challenges.rî   r¿  rÁ  z%Requesting available badge challengesrã   )r0   r2   r[   r   rŸ   ræ   rœ   rÂ  s        r"   Úget_available_badge_challengesz%Garmin.get_available_badge_challenges×  sY   € ô /¨u°gÓ>ˆÜ*¨5°'Ó:ˆØ×@Ñ@ˆÜ˜u›:´°E³
Ñ;ˆÜ�‰Ð<Ô=à�‰˜s¨6ˆÓ2Ð2r+   c                 óÈ   — t        |d«      }t        |d«      }| j                  }t        |«      t        |«      dœ}t        j                  d«       | j                  ||¬«      S )z7Return badge non-completed challenges for current user.rî   r¿  rÁ  rÆ  rã   )r0   r2   r\   r   rŸ   ræ   rœ   rÂ  s        r"   Ú"get_non_completed_badge_challengesz)Garmin.get_non_completed_badge_challengesâ  sY   € ô
 /¨u°gÓ>ˆÜ*¨5°'Ó:ˆØ×DÑDˆÜ˜u›:´°E³
Ñ;ˆÜ�‰Ð;Ô<à�‰˜s¨6ˆÓ2Ð2r+   c                 óÈ   — t        |d«      }t        |d«      }| j                  }t        |«      t        |«      dœ}t        j                  d«       | j                  ||¬«      S )z7Return in-progress virtual challenges for current user.rî   r¿  rÁ  z2Requesting in-progress virtual challenges for userrã   )r0   r2   r]   r   rŸ   ræ   rœ   rÂ  s        r"   Ú!get_inprogress_virtual_challengesz(Garmin.get_inprogress_virtual_challengesï  sY   € ô
 /¨u°gÓ>ˆÜ*¨5°'Ó:ˆØ×CÑCˆÜ˜u›:´°E³
Ñ;ˆÜ�‰ÐIÔJà�‰˜s¨6ˆÓ2Ð2r+   c                 óª   — t        |d«      }| j                  › d| j                  › �}|ddœ}t        j	                  d«       | j                  ||¬«      S )z#Return sleep data for current user.rÜ   rá   é<   )r   ÚnonSleepBufferMinuteszRequesting sleep datarã   )r#   r^   r‹   rŸ   ræ   rœ   r<  s       r"   Úget_sleep_datazGarmin.get_sleep_dataü  sX   € ô & e¨WÓ5ˆØ×4Ñ4Ð5°Q°t×7HÑ7HÐ6IÐJˆØ¸"Ñ=ˆÜ�‰Ð,Ô-à�‰˜s¨6ˆÓ2Ð2r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z$Return stress data for current user.rÜ   rá   zRequesting stress datar�  rO  s      r"   Úget_stress_datazGarmin.get_stress_data  sC   € ô & e¨WÓ5ˆØ×5Ñ5Ð6°a¸°wÐ?ˆÜ�‰Ð-Ô.à�‰˜sÓ#Ð#r+   c                 ó¬   — t        |d«      }| j                  › d| j                  › �}||ddœ}t        j	                  d«       | j                  ||¬«      S )z/Return resting heartrate data for current user.rÜ   rá   rÏ  )ÚfromDateÚ	untilDateÚmetricIdz!Requesting resting heartrate datarã   )r#   rj   r‹   rŸ   ræ   rœ   r<  s       r"   Úget_rhr_dayzGarmin.get_rhr_day  s`   € ô & e¨WÓ5ˆØ×,Ñ,Ð-¨Q¨t×/@Ñ/@Ð.AÐBˆàØØñ
ˆô
 	�‰Ð8Ô9à�‰˜s¨6ˆÓ2Ð2r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z:Return Heart Rate Variability (hrv) data for current user.rÜ   rá   z,Requesting Heart Rate Variability (hrv) data)r#   rk   rŸ   ræ   rœ   rO  s      r"   Úget_hrv_datazGarmin.get_hrv_data  sC   € ô & e¨WÓ5ˆØ×,Ñ,Ð-¨Q¨u¨gÐ6ˆÜ�‰ÐCÔDà�‰˜sÓ#Ð#r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z0Return training readiness data for current user.rÜ   rá   z"Requesting training readiness data)r#   rl   rŸ   ræ   rœ   rO  s      r"   Úget_training_readinesszGarmin.get_training_readiness&  sC   € ô & e¨WÓ5ˆØ×;Ñ;Ð<¸A¸e¸WÐEˆÜ�‰Ð9Ô:à�‰˜sÓ#Ð#r+   c                 óV  — t        |d«      }|€A| j                  }dt        |«      i}t        j	                  d«       | j                  ||¬«      S | j                  › d�}t        |d«      }t        |«      t        |«      ddœ}t        j	                  d	«       | j                  ||¬«      S )
a  
        Return endurance score by day for 'startdate' format 'YYYY-MM-DD'
        through enddate 'YYYY-MM-DD'.
        Using a single day returns the precise values for that day.
        Using a range returns the aggregated weekly values for that week.
        rþ   râ   z0Requesting endurance score data for a single dayrã   ú/statsrÿ   rv  ©r  r  rl  z3Requesting endurance score data for a range of days)r#   re   r   rŸ   ræ   rœ   r  s        r"   Úget_endurance_scorezGarmin.get_endurance_score/  s§   € ô *¨)°[ÓAˆ	Øˆ?Ø×9Ñ9ˆCØ$¤c¨)£nÐ5ˆFÜ�L‰LÐKÔLà—?‘? 3¨v�?Ó6Ð6à×<Ñ<Ð=¸VÐDˆCÜ+¨G°YÓ?ˆGä  ›^Ü˜w›<Ø'ñˆFô
 �L‰LÐNÔOà—?‘? 3¨v�?Ó6Ð6r+   Ú_typec                 ó(  — h d£}||vrt        d|›d�«      ‚|€1|€/|€-| j                  d| j                  › �z   }| j                  |«      S |�¼|�º|�¸t	        |d«      }t	        |d«      }t        j                  |t        «      j                  «       t        j                  |t        «      j                  «       z
  j                  dkD  rt        d«      ‚| j                  d	|› d	| j                  › �z   }||d
œ}| j                  ||¬«      S t        d«      ‚)a›  
        Return race predictions for the 5k, 10k, half marathon and marathon.
        Accepts either 0 parameters or all three:
        If all parameters are empty, returns the race predictions for the current date
        Or returns the race predictions for each day or month in the range provided

        Keyword Arguments:
        'startdate' the date of the earliest race predictions
        Cannot be more than one year before 'enddate'
        'enddate' the date of the last race predictions
        '_type' either 'daily' (the predictions for each day in the range) or
        'monthly' (the aggregated monthly prediction for each month in the range)
        >   Nrj  rx  zresults: _type must be one of ú.z/latest/rþ   rÿ   in  z5Startdate cannot be more than one year before enddaterá   )ÚfromCalendarDateÚtoCalendarDaterã   z7you must either provide all parameters or no parameters)
r   rm   r‹   rœ   r#   r   r   r    r   Údays)rŽ   rþ   rÿ   rá  Úvalidrè   rä   s          r"   Úget_race_predictionszGarmin.get_race_predictionsL  s:  € ò( +ˆØ˜ÑÜÐ=¸e¸YÀaÐHÓIÐIàˆ=˜YÐ.°7°?à×6Ñ6¸8ÀD×DUÑDUÐCVÐ9WÑWð ð —?‘? 3Ó'Ð'àÐ 9Ð#8¸WÐ=PÜ-¨i¸ÓEˆIÜ+¨G°YÓ?ˆGä×!Ñ! '¬?Ó;×@Ñ@ÓBÜ×#Ñ# I¬Ó?×DÑDÓFñGç‰d�Sòô !ØKóð ð ×6Ñ6¸1¸U¸GÀ1ÀT×EVÑEVÐDWÐ9XÑXð ð +4ÀwÑOˆFØ—?‘? 3¨v�?Ó6Ð6ô ÐVÓWÐWr+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z-Return training status data for current user.rÜ   rá   zRequesting training status data)r#   rn   rŸ   ræ   rœ   rO  s      r"   Úget_training_statuszGarmin.get_training_status}  sC   € ô & e¨WÓ5ˆØ×8Ñ8Ð9¸¸5¸'ÐBˆÜ�‰Ð6Ô7à�‰˜sÓ#Ð#r+   c                 óˆ   — t        |d«      }| j                  › d|› �}t        j                  d«       | j	                  |«      S )z)Return Fitness Age data for current user.rÜ   rá   zRequesting Fitness Age data)r#   r|   rŸ   ræ   rœ   rO  s      r"   Úget_fitnessage_datazGarmin.get_fitnessage_data†  sC   € ô & e¨WÓ5ˆØ×/Ñ/Ð0°°%°Ð9ˆÜ�‰Ð2Ô3à�‰˜sÓ#Ð#r+   c                 ón  — |€M| j                   }t        |d«      }dt        |«      i}t        j	                  d«       | j                  ||¬«      S | j                   › d�}t        |d«      }t        |d«      }t        |«      t        |«      ddœ}t        j	                  d	«       | j                  ||¬«      S )
zo
        Return hill score by day from 'startdate' format 'YYYY-MM-DD'
        to enddate 'YYYY-MM-DD'
        rþ   râ   z+Requesting hill score data for a single dayrã   rÞ  rÿ   rj  rß  z.Requesting hill score data for a range of days)r`   r#   r   rŸ   ræ   rœ   r  s        r"   Úget_hill_scorezGarmin.get_hill_score�  sµ   € ð ˆ?Ø×4Ñ4ˆCÜ-¨i¸ÓEˆIØ$¤c¨)£nÐ5ˆFÜ�L‰LÐFÔGà—?‘? 3¨v�?Ó6Ð6ð ×7Ñ7Ð8¸Ð?ˆCÜ-¨i¸ÓEˆIÜ+¨G°YÓ?ˆGä  ›^Ü˜w›<Ø&ñˆFô
 �L‰LÐIÔJà—?‘? 3¨v�?Ó6Ð6r+   c                 óf   — | j                   }t        j                  d«       | j                  |«      S )z6Return available devices for the current user account.zRequesting devices)rJ   rŸ   ræ   rœ   r¢  s     r"   Úget_deviceszGarmin.get_devices¬  s+   € ð ×-Ñ-ˆÜ�‰Ð)Ô*à�‰˜sÓ#Ð#r+   Ú	device_idc                 óp   — | j                   › d|› �}t        j                  d«       | j                  |«      S )z3Return device settings for device with 'device_id'.z/device-info/settings/zRequesting device settings©rK   rŸ   ræ   rœ   )rŽ   rñ  rè   s      r"   Úget_device_settingszGarmin.get_device_settings´  s8   € ð ×/Ñ/Ð0Ð0FÀyÀkÐRˆÜ�‰Ð1Ô2à�‰˜sÓ#Ð#r+   c                 óf   — | j                   }t        j                  d«       | j                  |«      S )zŒReturn detailed information around primary training devices, included the specified device and the
        priority of all devices.
        z.Requesting primary training device information)rL   rŸ   ræ   rœ   r¢  s     r"   Úget_primary_training_devicez"Garmin.get_primary_training_device¼  s+   € ð
 ×4Ñ4ˆÜ�‰ÐEÔFà�‰˜sÓ#Ð#r+   c                 óÌ   — |€|}d}nd}t        |d«      }t        |d«      }d|i}| j                  › d|› d|› d|› �}| j                  ||¬«      }|rd|vrt        d	«      ‚|d   S )
z8Return solar data for compatible device with 'device_id'TFrþ   rÿ   ÚsingleDayViewrá   rã   ÚdeviceSolarInputz#No device solar input data received)r#   rM   rœ   r¢   )rŽ   rñ  rþ   rÿ   Ú
single_dayrä   rè   Úresps           r"   Úget_device_solar_datazGarmin.get_device_solar_dataÆ  s’   € ð ˆ?ØˆGØ‰JàˆJä)¨)°[ÓAˆ	Ü'¨°Ó;ˆØ! :Ð.ˆà×.Ñ.Ð/¨q°°¸1¸Y¸KÀqÈÈ	ÐRˆà�‰˜s¨6ˆÓ2ˆÙÐ)°Ñ5Ü.Ð/TÓUÐUØÐ&Ñ'Ð'r+   c                 ó¼   — t         j                  d«       g }| j                  «       }|D ]/  }| j                  |d   «      }|j	                  d«      }|€Œ+||z  }Œ1 |S )z+Get list of active alarms from all devices.zRequesting device alarmsÚdeviceIdÚalarms)rŸ   ræ   rð  rô  rÅ   )rŽ   rÿ  ÚdevicesÚdeviceÚdevice_settingsÚdevice_alarmss         r"   Úget_device_alarmszGarmin.get_device_alarmsÛ  so   € ô 	�‰Ð/Ô0àˆØ×"Ñ"Ó$ˆØò 	(ˆFØ"×6Ñ6°v¸jÑ7IÓJˆOØ+×/Ñ/°Ó9ˆMØÑ(Ø˜-Ñ'‘ð		(ð
 ˆr+   c                 ól   — | j                   › d�}t        j                  d«       | j                  |«      S )zReturn device last used.z/mylastusedzRequesting device last usedró  r¢  s     r"   Úget_device_last_usedzGarmin.get_device_last_usedé  s3   € ð ×/Ñ/Ð0°Ð<ˆÜ�‰Ð2Ô3à�‰˜sÓ#Ð#r+   Úactivitytypec                 óX  — t        |d«      }t        |d«      }|t        kD  rt        dt        › �«      ‚| j                  }t        |«      t        |«      dœ}|rt        |«      |d<   t        j                  d||«       | j                  ||¬«      }|€t        j                  d«       g S |S )	a,  
        Return available activities.
        :param start: Starting activity offset, where 0 means the most recent activity
        :param limit: Number of activities to return
        :param activitytype: (Optional) Filter activities by type
        :return: List of activities from Garmin
        rî   r¿  zlimit cannot exceed rÁ  ÚactivityTypez+Requesting activities from %d with limit %drã   zNo activities data received)
r0   r2   ÚMAX_ACTIVITY_LIMITr   rv   r   rŸ   ræ   rœ   rê   )rŽ   rî   r¿  r  rè   rä   Ú
activitiess          r"   Úget_activitieszGarmin.get_activitiesñ  sª   € ô /¨u°gÓ>ˆÜ*¨5°'Ó:ˆàÔ%Ò%ÜÐ3Ô4FÐ3GÐHÓIÐIà×,Ñ,ˆÜ˜u›:´°E³
Ñ;ˆÙÜ%(¨Ó%6ˆF�>Ñ"ä�‰ÐBÀEÈ5ÔQà—_‘_ S°�_Ó8ˆ
àÐÜ�N‰NÐ8Ô9ØˆIàÐr+   Úfordatec                 óŠ   — t        |d«      }| j                  › d|› �}t        j                  d|«       | j	                  |«      S )z%Return available activities for date.r  rá   z!Requesting activities for date %s)r#   rz   rŸ   ræ   rœ   ©rŽ   r  rè   s      r"   Úget_activities_fordatezGarmin.get_activities_fordate  sE   € ô (¨°Ó;ˆØ×5Ñ5Ð6°a¸°yÐAˆÜ�‰Ð8¸'ÔBà�‰˜sÓ#Ð#r+   Úactivity_idÚtitlec                 ól   — | j                   › d|› �}||dœ}| j                  j                  d||d¬«      S )zSet name for activity with id.rá   )Ú
activityIdÚactivityNamerœ   T©r   r  )rx   r‰   r�  )rŽ   r  r  rè   r1  s        r"   Úset_activity_namezGarmin.set_activity_name  s@   € ð ×-Ñ-Ð.¨a°¨}Ð=ˆØ!,¸eÑDˆà�z‰z�~‰~˜l¨C°gÀ4ˆ~ÓHÐHr+   Útype_idÚtype_keyÚparent_type_idc                 ó    — | j                   › d|› �}||||dœdœ}t        j                  d|«       | j                  j	                  d||d¬«      S )Nrá   )ÚtypeIdÚtypeKeyÚparentTypeId)r  ÚactivityTypeDTOzChanging activity type: %srœ   Tr  )rx   rŸ   ræ   r‰   r�  )rŽ   r  r  r  r  rè   r1  s          r"   Úset_activity_typezGarmin.set_activity_type&  s_   € ð ×-Ñ-Ð.¨a°¨}Ð=ˆà%à!Ø#Ø .ñ ñ
ˆô 	�‰Ð1°7Ô;Ø�z‰z�~‰~˜l¨C°gÀ4ˆ~ÓHÐHr+   r1  c                 ó˜   — | j                   › }t        j                  dt        |«      «       | j                  j                  d||d¬«      S )NzUploading manual activity: %srœ   Tr  )rx   rŸ   ræ   r   r‰   r  )rŽ   r1  rè   s      r"   Ú create_manual_activity_from_jsonz'Garmin.create_manual_activity_from_json9  s>   € Ø×-Ñ-Ð.ˆÜ�‰Ð4´c¸'³lÔCØ�z‰z�‰˜|¨S°wÀDˆÓIÐIr+   Ústart_datetimeÚ	time_zoneÚdistance_kmÚduration_minÚactivity_namec           	      ó\   — d|idddœd|i|ddi||dz  |d	z  d
œdœ}| j                  |«      S )aƒ  
        Create a private activity manually with a few basic parameters.
        type_key - Garmin field representing type of activity. See https://connect.garmin.com/modern/main/js/properties/activity_types/activity_types.properties
                    Value to use is the key without 'activity_type_' prefix, e.g. 'resort_skiing'
        start_datetime - timestamp in this pattern "2023-12-02T10:00:00.000"
        time_zone - local timezone of the activity, e.g. 'Europe/Paris'
        distance_km - distance of the activity in kilometers
        duration_min - duration of the activity in minutes
        activity_name - the title
        r  é   Úprivate)r  r  r#  ÚautoCalcCaloriesTr   rÏ  )ÚstartTimeLocalÚdistanceÚduration)r  ÚaccessControlRuleDTOÚtimeZoneUnitDTOr  ÚmetadataDTOÚ
summaryDTO)r"  )rŽ   r#  r$  r  r%  r&  r'  r1  s           r"   Úcreate_manual_activityzGarmin.create_manual_activity>  s]   € ð( !*¨8Ð4Ø/0¸YÑ$GØ )¨9Ð5Ø)à" Dðð #1Ø'¨$Ñ.Ø(¨2Ñ-ññ
ˆð ×4Ñ4°WÓ=Ð=r+   c                 óÒ   — | j                  dd«      }|r#t        |t        «      rt        |«      dkD  r|d   S |r.t        |t        «      rd|v r|d   }|rt        |«      dkD  r|d   S y)zReturn last activity.r   r   éÿÿÿÿÚactivityListN)r  r   r{  rÁ   rù   )rŽ   r  Úactivity_lists      r"   Úget_last_activityzGarmin.get_last_activitya  sq   € ð ×(Ñ(¨¨AÓ.ˆ
Ùœ* Z´Ô6¼3¸z»?ÈQÒ;NØ˜b‘>Ð!áœ: j´$Ô7¸NÈjÑ<Xà& ~Ñ6ˆMÙ¤ ]Ó!3°aÒ!7Ø$ RÑ(Ð(àr+   Úactivity_pathc                 óX  — |st        d«      ‚t        |t        «      st        d«      ‚t        |«      }|j	                  «       st        d|› �«      ‚|j                  «       st        d|› �«      ‚|j                  }|st        d«      ‚|j                  d«      }t        |«      dk  rt        d|› �«      ‚|d	   }|j                  «       t        j                  j                  v }|rM	 |j                  d
«      5 }d||fi}| j                   }	| j"                  j%                  d|	|d¬«      cddd«       S dj+                  t        j                  j                  j-                  «       «      }t        d|› d|› �«      ‚# 1 sw Y   nxY wy# t&        $ r}
t)        d|› d|
› �«      |
‚d}
~
ww xY w)z(Upload activity in fit format from file.zactivity_path cannot be emptyzactivity_path must be a stringzFile not found: zpath is not a file: z%invalid file path - no filename foundrã  r)  zFile has no extension: r5  Úrbr  rœ   Tr  NzFailed to read file r   r\  zInvalid file format 'z'. Allowed formats: )r   r   r   r	   ÚexistsrÊ   Úis_filer^  ÚsplitrÁ   Ú#GarminConnectInvalidFileFormatErrorÚupperr<   ÚActivityUploadFormatÚ__members__Úopenr‚   r‰   r  ÚOSErrorr¢   ÚjoinÚkeys)rŽ   r9  ÚpÚfile_base_nameÚ
file_partsÚfile_extensionÚallowed_file_extensionÚfile_handler  rè   r!   Úallowed_formatss               r"   Úupload_activityzGarmin.upload_activityp  sÎ  € ñ
 ÜÐ<Ó=Ð=ä˜-¬Ô-ÜÐ=Ó>Ð>ô �ÓˆØ�x‰xŒzÜ#Ð&6°}°oÐ$FÓGÐGð �y‰yŒ{ÜÐ3°M°?ÐCÓDÐDàŸ™ˆáÜÐDÓEÐEð $×)Ñ)¨#Ó.ˆ
Üˆz‹?˜QÒÜ5Ø)¨-¨Ð9óð ð $ B™ˆà× Ñ Ó"¤f×&AÑ&A×&MÑ&MÐMð 	ñ "ð	à—V‘V˜D“\ð U [Ø# n°kÐ%BÐC�EØ×4Ñ4�CØŸ:™:Ÿ?™?¨<¸ÀEÈt˜?ÓT÷Uñ Uð #Ÿi™i¬×(CÑ(C×(OÑ(O×(TÑ(TÓ(VÓWˆOÜ5Ø'¨Ð'7Ð7KÈOÐK\Ð]óð ÷Uð Uúð Uøô ò Ü2Ø*¨=¨/¸¸A¸3Ð?óàðûðús0   Ã(F	 Ã91E<Ä*	F	 Å<FÆF	 Æ		F)ÆF$Æ$F)c                 óŽ   — | j                   › d|› �}t        j                  d|«       | j                  j	                  dd|d¬«      S )z!Delete activity with specified idrá   zDeleting activity with id %sr@  rœ   TrA  )r‡   rŸ   ræ   r‰   rB  ©rŽ   r  rè   s      r"   Údelete_activityzGarmin.delete_activity¦  sR   € ð ×8Ñ8Ð9¸¸;¸-ÐHˆÜ�‰Ð3°[ÔAà�z‰z×!Ñ!ØØØØð	 "ó 
ð 	
r+   Ú	sortorderc                 ó¸  — g }d}d}| j                   }t        |d«      }|�t        |d«      }|t        |«      t        |«      dœ}	|r||	d<   |rt        |«      |	d<   |rt        |«      |	d<   t        j	                  d	||«       	 t        |«      |	d
<   t        j	                  d|||z   «       | j                  ||	¬«      }
|
r|j                  |
«       ||z   }n	 |S ŒX)aš  
        Fetch available activities between specific dates
        :param startdate: String in the format YYYY-MM-DD
        :param enddate: (Optional) String in the format YYYY-MM-DD
        :param activitytype: (Optional) Type of activity you are searching
                             Possible values are [cycling, running, swimming,
                             multi_sport, fitness_equipment, hiking, walking, other]
        :param sortorder: (Optional) sorting direction. By default, Garmin uses descending order by startLocal field.
                          Use "asc" to get activities from oldest to newest.
        :return: list of JSON activities
        r   rC   rþ   rÿ   )r  rî   r¿  r  r	  Ú	sortOrderz+Requesting activities by date from %s to %srî   zRequesting activities %d to %drã   )rv   r#   r   rŸ   ræ   rœ   Úextend)rŽ   rþ   rÿ   r  rR  r  rî   r¿  rè   rä   Úacts              r"   Úget_activities_by_datezGarmin.get_activities_by_date³  sø   € ð& ˆ
ØˆØˆð ×,Ñ,ˆÜ)¨)°[ÓAˆ	ØÐÜ+¨G°YÓ?ˆGà"Ü˜“ZÜ˜“Zñ
ˆñ
 Ø 'ˆF�9ÑÙÜ%(¨Ó%6ˆF�>Ñ"ÙÜ"% i£.ˆF�;Ñä�‰ÐBÀIÈwÔWØÜ! %›jˆF�7‰OÜ�L‰LÐ9¸5À%È%Á-ÔPØ—/‘/ #¨f�/Ó5ˆCÙØ×!Ñ! #Ô&Ø ™‘ààÐð r+   ÚmetricÚgroupbyactivitiesc                 óö   — | j                   }t        |d«      }t        |d«      }t        |«      t        |«      dt        |«      t        |«      dœ}t        j	                  d||«       | j                  ||¬«      S )aÐ  
        Fetch progress summary data between specific dates
        :param startdate: String in the format YYYY-MM-DD
        :param enddate: String in the format YYYY-MM-DD
        :param metric: metric to be calculated in the summary:
            "elevationGain", "duration", "distance", "movingDuration"
        :param groupbyactivities: group the summary by activity type
        :return: list of JSON activities with their aggregated progress summary
        rþ   rÿ   Úlifetime)r  r  rl  ÚgroupByParentActivityTyperX  z-Requesting fitnessstats by date from %s to %srã   )r{   r#   r   rŸ   ræ   rœ   )rŽ   rþ   rÿ   rX  rY  rè   rä   s          r"   Ú"get_progress_summary_between_datesz)Garmin.get_progress_summary_between_datesé  sy   € ð" ×.Ñ.ˆÜ)¨)°[ÓAˆ	Ü'¨°Ó;ˆä˜Y›Ü˜7“|Ø%Ü),Ð->Ó)?Ü˜&“kñ
ˆô 	�‰Ø;¸YÈô	
ð �‰˜s¨6ˆÓ2Ð2r+   c                 óf   — | j                   }t        j                  d«       | j                  |«      S )NzRequesting activity types)ry   rŸ   ræ   rœ   r¢  s     r"   Úget_activity_typeszGarmin.get_activity_types
  s)   € Ø×0Ñ0ˆÜ�‰Ð0Ô1Ø�‰˜sÓ#Ð#r+   r¦   c                 ó’  — g }| j                   }h d£}||vrt        d|› �«      ‚t        |d«      }t        |d«      }|t        |«      t        |«      ddœ}t        j                  d|«       	 t        |«      |d<   t        j                  d||||z   d	z
  «       | j                  ||¬
«      }|r|j                  |«       ||z   }n	 |S Œ\)aj  
        Fetch all goals based on status
        :param status: Status of goals (valid options are "active", "future", or "past")
        :type status: str
        :param start: Initial goal index
        :type start: int
        :param limit: Pagination limit when retrieving goals
        :type limit: int
        :return: list of goals in JSON format
        >   ÚpastÚactiveÚfuturezstatus must be one of rî   r¿  Úasc)r¦   rî   r¿  rT  zRequesting %s goalszRequesting %s goals %d to %dr   rã   )ri   r   r2   r   rŸ   ræ   rœ   rU  )	rŽ   r¦   rî   r¿  Úgoalsrè   Úvalid_statusesrä   Ú
goals_jsons	            r"   Ú	get_goalszGarmin.get_goals  sà   € ð ˆØ×+Ñ+ˆÚ5ˆØ˜Ñ'ÜÐ5°nÐ5EÐFÓGÐGÜ*¨5°'Ó:ˆÜ*¨5°'Ó:ˆàÜ˜“ZÜ˜“ZØñ	
ˆô 	�‰Ð*¨FÔ3ØÜ! %›jˆF�7‰OÜ�L‰LØ.°¸¸uÀu¹}ÈqÑ?Pôð Ÿ™¨°V˜Ó<ˆJÙØ—‘˜ZÔ(Ø ™‘ààˆð r+   ÚuserProfileNumberc                 ór   — | j                   › d|› �}t        j                  d|«       | j                  |«      S )zReturn all user gear.z?userProfilePk=zRequesting gear for user %s)rƒ   rŸ   ræ   rœ   ©rŽ   ri  rè   s      r"   Úget_gearzGarmin.get_gear:  s:   € à×)Ñ)Ð*¨/Ð:KÐ9LÐMˆÜ�‰Ð2Ð4EÔFà�‰˜sÓ#Ð#r+   ÚgearUUIDc                 ór   — | j                   › d|› �}t        j                  d|«       | j                  |«      S )Nzstats/z%Requesting gear stats for gearUUID %s©r„   rŸ   ræ   rœ   )rŽ   rm  rè   s      r"   Úget_gear_statszGarmin.get_gear_statsA  s7   € Ø×1Ñ1Ð2°&¸¸
ÐCˆÜ�‰Ð<¸hÔGØ�‰˜sÓ#Ð#r+   c                 ót   — | j                   › d|› d�}t        j                  d|«       | j                  |«      S )Nzuser/z/activityTypesz$Requesting gear defaults for user %sro  rk  s      r"   Úget_gear_defaultszGarmin.get_gear_defaultsF  sC   € à×/Ñ/Ð0°Ø Ð! ð1ð 	ô 	�‰Ð;Ð=NÔOØ�‰˜sÓ#Ð#r+   r	  ÚdefaultGearc                 ó‚   — |rdnd}|rdnd}| j                   › |› d|› |› �}| j                  j                  |d|d¬«      S )	Nz/default/trueÚ ÚPUTr@  z/activityType/rœ   TrA  )r„   r‰   rB  )rŽ   r	  rm  rs  ÚdefaultGearStringÚmethod_overriderè   s          r"   Úset_gear_defaultzGarmin.set_gear_defaultN  sa   € ñ 0;™OÀÐÙ#.™%°Hˆà×/Ñ/Ð0°°
ð ;Ø(˜>Ð*;Ð)<ð>ð 	ð �z‰z×!Ñ! /°<ÀÈ$Ð!ÓOÐOr+   c                   óV   — e Zd ZdZ e«       Z e«       Z e«       Z e«       Z e«       Z	y)úGarmin.ActivityDownloadFormatzActivity variables.N)
Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   ÚORIGINALÚTCXÚGPXÚKMLÚCSVr¶   r+   r"   ÚActivityDownloadFormatr{  Y  s(   „ Ù!á“6ˆÙ‹fˆÙ‹fˆÙ‹fˆÙ‹f‰r+   r…  c                   ó6   — e Zd Z e«       Z e«       Z e«       Zy)úGarmin.ActivityUploadFormatN)r|  r}  r~  r   ÚFITr‚  r�  r¶   r+   r"   rA  r‡  b  s   „ Ù‹fˆÙ‹fˆÙ‹f‰r+   rA  Údl_fmtc                 ó4  — t        |«      }t        j                  j                  | j                  › d|› �t        j                  j
                  | j                  › d|› �t        j                  j                  | j                  › d|› �t        j                  j                  | j                  › d|› �t        j                  j                  | j                  › d|› �i}||vrt        d|› d�«      ‚||   }t        j                  d|«       | j!                  |«      S )zÕ
        Downloads activity in requested format and returns the raw bytes. For
        "Original" will return the zip file content, up to user to extract it.
        "CSV" will return a csv of the splits.
        rá   zunexpected value z for dl_fmtzDownloading activity from %s)r   r<   r…  r€  r}   r�  r~   r‚  r   rƒ  r€   r„  r�   r   rŸ   ræ   r¨   )rŽ   r  r‰  Úurlsrè   s        r"   Údownload_activityzGarmin.download_activityg  s  € ô ˜+Ó&ˆä×)Ñ)×2Ñ2°t×7WÑ7WÐ6XÐXYÐZeÐYfÐ4gÜ×)Ñ)×-Ñ-°$×2RÑ2RÐ1SÐSTÐU`ÐTaÐ/bÜ×)Ñ)×-Ñ-°$×2RÑ2RÐ1SÐSTÐU`ÐTaÐ/bÜ×)Ñ)×-Ñ-°$×2RÑ2RÐ1SÐSTÐU`ÐTaÐ/bÜ×)Ñ)×-Ñ-°$×2RÑ2RÐ1SÐSTÐU`ÐTaÐ/bð
ˆð ˜ÑÜÐ0°°¸ÐDÓEÐEØ�6‰lˆä�‰Ð3°SÔ9à�}‰}˜SÓ!Ð!r+   c                 óŠ   — t        |«      }| j                  › d|› d�}t        j                  d|«       | j	                  |«      S )zReturn activity splits.rá   z/splitsz$Requesting splits for activity id %s©r   rx   rŸ   ræ   rœ   rP  s      r"   Úget_activity_splitszGarmin.get_activity_splits�  sE   € ô ˜+Ó&ˆØ×-Ñ-Ð.¨a°¨}¸GÐDˆÜ�‰Ð;¸[ÔIà�‰˜sÓ#Ð#r+   c                 óŠ   — t        |«      }| j                  › d|› d�}t        j                  d|«       | j	                  |«      S )z£Return typed activity splits. Contains similar info to `get_activity_splits`, but for certain activity types
        (e.g., Bouldering), this contains more detail.rá   z/typedsplitsz*Requesting typed splits for activity id %srŽ  rP  s      r"   Úget_activity_typed_splitsz Garmin.get_activity_typed_splitsŠ  sE   € ô ˜+Ó&ˆØ×-Ñ-Ð.¨a°¨}¸LÐIˆÜ�‰ÐAÀ;ÔOà�‰˜sÓ#Ð#r+   c                 óŠ   — t        |«      }| j                  › d|› d�}t        j                  d|«       | j	                  |«      S )z Return activity split summaries.rá   z/split_summariesz-Requesting split summaries for activity id %srŽ  rP  s      r"   Úget_activity_split_summariesz#Garmin.get_activity_split_summaries”  sF   € ô ˜+Ó&ˆØ×-Ñ-Ð.¨a°¨}Ð<LÐMˆÜ�‰ÐDÀkÔRà�‰˜sÓ#Ð#r+   c                 óŠ   — t        |«      }| j                  › d|› d�}t        j                  d|«       | j	                  |«      S )zReturn activity weather.rá   z/weatherz%Requesting weather for activity id %srŽ  rP  s      r"   Úget_activity_weatherzGarmin.get_activity_weather�  sE   € ô ˜+Ó&ˆØ×-Ñ-Ð.¨a°¨}¸HÐEˆÜ�‰Ð<¸kÔJà�‰˜sÓ#Ð#r+   c                 óŠ   — t        |«      }| j                  › d|› d�}t        j                  d|«       | j	                  |«      S )z'Return activity heartrate in timezones.rá   z/hrTimeInZonesz.Requesting HR time-in-zones for activity id %srŽ  rP  s      r"   Úget_activity_hr_in_timezonesz#Garmin.get_activity_hr_in_timezones¦  sE   € ô ˜+Ó&ˆØ×-Ñ-Ð.¨a°¨}¸NÐKˆÜ�‰ÐEÀ{ÔSà�‰˜sÓ#Ð#r+   c                 óˆ   — t        |«      }| j                  › d|› �}t        j                  d|«       | j	                  |«      S )z0Return activity summary, including basic splits.rá   z3Requesting activity summary data for activity id %srŽ  rP  s      r"   Úget_activityzGarmin.get_activity¯  sC   € ô ˜+Ó&ˆØ×-Ñ-Ð.¨a°¨}Ð=ˆÜ�‰ÐJÈKÔXà�‰˜sÓ#Ð#r+   ÚmaxchartÚmaxpolyc                 óì   — t        |«      }t        |d«      }t        |d«      }t        |«      t        |«      dœ}| j                  › d|› d�}t        j	                  d|«       | j                  ||¬«      S )zReturn activity details.rš  r›  )ÚmaxChartSizeÚmaxPolylineSizerá   z/detailsz%Requesting details for activity id %srã   )r   r2   rx   rŸ   ræ   rœ   )rŽ   r  rš  r›  rä   rè   s         r"   Úget_activity_detailszGarmin.get_activity_details¸  ss   € ô
 ˜+Ó&ˆÜ-¨h¸
ÓCˆÜ,¨W°iÓ@ˆÜ"% h£-ÄCÈÃLÑQˆØ×-Ñ-Ð.¨a°¨}¸HÐEˆÜ�‰Ð<¸kÔJà�‰˜s¨6ˆÓ2Ð2r+   c                 óž   — t        t        |«      d«      }| j                  › d|› d�}t        j	                  d|«       | j                  |«      S )zReturn activity exercise sets.r  rá   z/exerciseSetsz+Requesting exercise sets for activity id %s)r2   r/   rx   rŸ   ræ   rœ   rP  s      r"   Úget_activity_exercise_setsz!Garmin.get_activity_exercise_setsÆ  sL   € ô 1´°[Ó1AÀ=ÓQˆØ×-Ñ-Ð.¨a°¨}¸MÐJˆÜ�‰ÐBÀKÔPà�‰˜sÓ#Ð#r+   c                 ó°   — t        t        |«      d«      }dt        |«      i}| j                  }t        j                  d|«       | j                  ||¬«      S )z"Return gears used for activity id.r  r  z"Requesting gear for activity_id %srã   )r2   r/   r   rƒ   rŸ   ræ   rœ   )rŽ   r  rä   rè   s       r"   Úget_activity_gearzGarmin.get_activity_gearÏ  sU   € ô 1´°[Ó1AÀ=ÓQˆàœ#˜kÓ*ð
ˆð ×&Ñ&ˆÜ�‰Ð9¸;ÔGà�‰˜s¨6ˆÓ2Ð2r+   c                 óÄ   — t        |«      }t        |d«      }t        |t        «      }| j                  › |› d|› �}t
        j                  d|«       | j                  |«      S )a  Return activities where gear uuid was used.
        :param gearUUID: UUID of the gear to get activities for
        :param limit: Maximum number of activities to return (default: 1000)
        :return: List of activities where the specified gear was used
        r¿  z/gear?start=0&limit=z%Requesting activities for gearUUID %s)r   r2   Úminr
  rw   rŸ   ræ   rœ   )rŽ   rm  r¿  rè   s       r"   Úget_gear_activitieszGarmin.get_gear_activitiesÛ  sb   € ô �x“=ˆÜ*¨5°'Ó:ˆä�EÔ-Ó.ˆØ×7Ñ7Ð8¸¸
ÐBVÐW\ÐV]Ð^ˆÜ�‰Ð<¸hÔGà�‰˜sÓ#Ð#r+   c                 óf   — | j                   }t        j                  d«       | j                  |«      S )zGet all users settings.zRequesting user profile.)rH   rŸ   ræ   rœ   r¢  s     r"   Úget_user_profilezGarmin.get_user_profileì  s+   € ð ×3Ñ3ˆÜ�‰Ð/Ô0à�‰˜sÓ#Ð#r+   c                 óf   — | j                   }t        j                  d«       | j                  |«      S )zGet user settings.zGetting userprofile settings)rI   rŸ   ræ   rœ   r¢  s     r"   Úget_userprofile_settingszGarmin.get_userprofile_settingsô  s+   € ð ×:Ñ:ˆÜ�‰Ð3Ô4à�‰˜sÓ#Ð#r+   c                 óÀ   — t        |d«      }| j                  › d|› �}t        j                  d|«       | j                  j                  d|d¬«      j                  «       S )z{
        Request reload of data for a specific date. This is necessary because
        Garmin offloads older data.
        rÜ   rá   z!Requesting reload of data for %s.rœ   TrA  )r#   r…   rŸ   ræ   r‰   r  r   rO  s      r"   Úrequest_reloadzGarmin.request_reloadü  sX   € ô & e¨WÓ5ˆØ×/Ñ/Ð0°°%°Ð9ˆÜ�‰Ð8¸%Ô@à�z‰z�‰˜|¨S°dˆÓ;×@Ñ@ÓBÐBr+   c                 ó®   — | j                   › d�}t        |d«      }t        |d«      }t        j	                  d||«       ||dœ}| j                  ||¬«      S )zHReturn workouts starting at offset `start` with at most `limit` results.z	/workoutsrî   r¿  z)Requesting workouts from %d with limit %drÁ  rã   )r†   r0   r2   rŸ   ræ   rœ   rÂ  s        r"   Úget_workoutszGarmin.get_workouts  s]   € ð ×%Ñ%Ð& iÐ0ˆÜ.¨u°gÓ>ˆÜ*¨5°'Ó:ˆÜ�‰Ð@À%ÈÔOØ ¨5Ñ1ˆØ�‰˜s¨6ˆÓ2Ð2r+   Ú
workout_idc                 óp   — t        t        |«      d«      }| j                  › d|› �}| j                  |«      S )zReturn workout by id.r¯  z	/workout/)r2   r/   r†   rœ   ©rŽ   r¯  rè   s      r"   Úget_workout_by_idzGarmin.get_workout_by_id  s:   € ô 0´°J³ÀÓNˆ
Ø×%Ñ%Ð& i°
¨|Ð<ˆØ�‰˜sÓ#Ð#r+   c                 óœ   — t        t        |«      d«      }| j                  › d|› �}t        j	                  d|«       | j                  |«      S )zDownload workout by id.r¯  z/workout/FIT/zDownloading workout from %s)r2   r/   r†   rŸ   ræ   r¨   r±  s      r"   Údownload_workoutzGarmin.download_workout  sI   € ô 0´°J³ÀÓNˆ
Ø×%Ñ%Ð& m°J°<Ð@ˆÜ�‰Ð2°CÔ8à�}‰}˜SÓ!Ð!r+   Úworkout_jsonc                 ó|  — | j                   › d�}t        j                  d|«       t        |t        «      rddl}	 |j                  |«      }n|}t        |t        t        z  «      st        d«      ‚| j                  j                  d||d¬	«      j                  «       S # t        $ r}t        d|› �«      |‚d}~ww xY w)
zUpload workout using json data.z/workoutzUploading workout using %sr   Nzinvalid workout_json string: z+workout_json must be a JSON object or arrayrœ   Tr  )r†   rŸ   ræ   r   r   r   rÂ   r£   r   rù   r{  r‰   r  )rŽ   rµ  rè   Ú_jsonr1  r!   s         r"   Úupload_workoutzGarmin.upload_workout"  sµ   € ð
 ×%Ñ%Ð& hÐ/ˆÜ�‰Ð1°3Ô7ä�l¤CÔ(Û ðMØŸ+™+ lÓ3‘ð #ˆGÜ˜'¤4¬$¡;Ô/ÜÐJÓKÐKØ�z‰z�‰˜|¨S°wÀDˆÓI×NÑNÓPÐPøô ò MÜ Ð#@ÀÀÐ!DÓEÈ1ÐLûðMús   »B Â	B;Â'B6Â6B;c                 óŠ   — t        |d«      }| j                  › d|› �}t        j                  d|«       | j	                  |«      S )zReturn menstrual data for date.r  rá   z%Requesting menstrual data for date %s)r#   rg   rŸ   ræ   rœ   r  s      r"   Úget_menstrual_data_for_datez"Garmin.get_menstrual_data_for_date7  sE   € ô (¨°Ó;ˆØ×:Ñ:Ð;¸1¸W¸IÐFˆÜ�‰Ð<¸gÔFà�‰˜sÓ#Ð#r+   c                 óª   — t        |d«      }t        |d«      }| j                  › d|› d|› �}t        j                  d||«       | j	                  |«      S )zHReturn summaries of cycles that have days between startdate and enddate.rþ   rÿ   rá   z1Requesting menstrual data for dates %s through %s)r#   rf   rŸ   ræ   rœ   )rŽ   rþ   rÿ   rè   s       r"   Úget_menstrual_calendar_dataz"Garmin.get_menstrual_calendar_data@  s]   € ô
 *¨)°[ÓAˆ	Ü'¨°Ó;ˆØ×;Ñ;Ð<¸A¸i¸[ÈÈ'ÈÐSˆÜ�‰Ø?ÀÈGô	
ð �‰˜sÓ#Ð#r+   c                 óh   — | j                   › }t        j                  d«       | j                  |«      S )z!Return snapshot of pregnancy dataz"Requesting pregnancy snapshot data)rh   rŸ   ræ   rœ   r¢  s     r"   Úget_pregnancy_summaryzGarmin.get_pregnancy_summaryN  s.   € ð ×;Ñ;Ð<ˆÜ�‰Ð9Ô:à�‰˜sÓ#Ð#r+   Úqueryc                 óf  — t        |t        «      r|j                  d«      xs dnd}t        |t        «      r,t        |j                  d«      xs i j	                  «       «      ng }t
        j                  d||«       | j                  j                  d| j                  |¬«      j                  «       S )a  Execute a POST to Garmin's GraphQL endpoint.

        Args:
            query: A GraphQL request body, e.g. {"query": "...", "variables": {...}}
            See example.py for example queries.
        Returns:
            Parsed JSON response as a dict.
        ÚoperationNameÚunnamedÚ	variablesz%Querying Garmin GraphQL op=%s vars=%srœ   r,  )r   rù   rÅ   ÚsortedrF  rŸ   ræ   r‰   r  rˆ   r   )rŽ   r¿  ÚopÚ	vars_keyss       r"   Úquery_garmin_graphqlzGarmin.query_garmin_graphqlV  sŸ   € ô ˜%¤Ô&ð �Y‰Y�Ó'Ò4©9àð 	ô ˜%¤Ô&ô �E—I‘I˜kÓ*Ò0¨b×6Ñ6Ó8Ô9àð 	ô
 	�‰Ð<¸bÀ)ÔLØ�z‰z�‰Ø˜$×6Ñ6¸Uð ó 
ç
‰$‹&ð	r+   c                 ó.   — t         j                  d«       y)zLog user out of session.z@Deprecated: Alternative is to delete the login tokens to logout.N)rŸ   rê   rØ   s    r"   ÚlogoutzGarmin.logouto  s   € ô 	�‰ØNõ	
r+   )NNFNFrµ   )NNNNNNNNNNN)r   ru  )r   ru  ru  )F)ru  ru  )NN)NNN)r   rC   N)r-  T)rb  r   é   )T)iÐ  i   )r   )r   éd   )r   N)xr|  r}  r~  r  r   r(   r   r�   r
   rœ   r¨   ÚtuplerÄ   rù   rÔ   rÙ   rÛ   rß   rÞ   r{  rë   rí   ró   rõ   rý   rø   Úfloatr"  r/   r2  r5  r:  r=  rC  rK  rM  rP  rb  rd  rg  ri  r   r‡  r“  r•  r—  r™  r›  rž  r   r£  r¥  r©  r¾  rÃ  rÇ  rÉ  rË  rÍ  rÑ  rÓ  rØ  rÚ  rÜ  rà  rè  rê  rì  rî  rð  rô  rö  rü  r  r  r  r  r  r   r"  r3  r8  rN  rQ  rW  r]  r_  rh  rl  rp  rr  ry  r   r…  rA  r�  ÚbytesrŒ  r�  r‘  r“  r•  r—  r™  rŸ  r¡  r£  r¦  r¨  rª  r¬  r®  r²  r´  r¸  rº  r¼  r¾  rÇ  rÉ  r¶   r+   r"   r<   r<   ^   su  „ Ù6ð !Ø#ØØ/3Ø#ñt à�T‰zðt ð ˜‘*ðt ð ð	t ð
 ˜R ˜WÑ%¨Ñ,ðt ð ðt ð 
ót ðl!P˜sð !P¨cð !P°có !PðFN˜Sð N¨Cð N°Có Nñ:{L 3¨¡:ð {L¸¸sÀT¹zÈ3ÐQUÉ:Ð?UÑ9Vó {Lðz Ø   c ™Nð Ø69ð à	ˆs�Cˆx‰ó ð ˜s T™zó ð
   t¡ó  ð
,˜sð , t¨C°¨H¡~ó ,ð cð ¨d°3¸°8©nó ð( Cð ¨D°°c¸3°h±Ñ,@ó ð$ ð ¨¨S°#¨X©ó ð $ Sð $¨sð $°t¸DÀÀcÀ¹NÑ7Kó $ð& Sð ¨T°#°s°(©^ó ð:%¨ð %°°S¸#°X±ó %ð 59ñ3Øð3Ø'*¨T¡zð3à	ˆc�3ˆh‰ó3ð6 %)Ø*.Ø*.Ø"&Ø$(Ø"&Ø#'Ø(,Ø&*Ø,0Ø ñ+Pà˜‘:ð+Pð ð+Pð ˜T‘\ð	+Pð
 ! 4™<ð+Pð ! 4™<ð+Pð ˜4‘<ð+Pð ˜T‘\ð+Pð ˜4‘<ð+Pð ˜D‘Lð+Pð  ™ð+Pð ˜t‘|ð+Pð # T™\ð+Pð �T‰\ð+Pð 
ˆc�3ˆh‰ó+Pð\ JLñGØ˜E‘kðGØ,/ðGØCFðGà	ˆc�3ˆh‰óGðD ØØñ+Gà�e‘ð+Gð ð+Gð ð	+Gð
 ð+Gð 
ˆc�3ˆh‰ó+GðZ	3 sð 	3°Sð 	3¸TÀ#ÀsÀ(¹^ó 	3ð3¨ð 3°°c¸3°h±ó 3ð
¨ð 
°Sð 
¸Só 
ñ cð °tð ÈÈdÉ
ó ð2 59ñ3Øð3Ø'*¨T¡zð3à	ˆd�3˜�8‰nÑ	ó3ð&$¨Sð $°T¸$¸sÀC¸x¹.Ñ5Ió $ð$ Øñ"Gàð"Gð ð"Gð ð	"Gð
 ð"Gð ð"Gð 
ˆc�3ˆh‰ó"GðJ 59ñ3Øð3Ø'*¨T¡zð3à	ˆc�3ˆh‰ó3ð&
¨Sð 
¸ð 
ÀÀcÈ3ÀhÁó 
ð$ Sð $¨T°#°s°(©^ó $ð Ø(,Ø&*Ø"òcJð ðcJð ˜$‘J Ñ%ð	cJð
 ˜‘*˜tÑ#ðcJð ðcJð 
ˆc�3ˆh‰ócJðP !%Ø ñ	MFàðMFð ˜‘:ðMFð �T‰zð	MFð
 
ˆc�3ˆh‰óMFð^$¨ð $°°S¸#°X±ó $ð$¨#ð $°$°s¸C°x±.ó $ð$ 3ð $¨4°°S°©>ó $ð$°ð $¸¸SÀ#¸X¹ó $ð$¨ð $°°S¸#°X±ó $ð
$¨ð 
$°°S¸#°X±ó 
$ð$ T¨#¨s¨(¡^ó $ð$ 4¨¨S°#¨X©Ñ#7ó $ðK d¨4°°S°©>Ñ&:ó Kð'¨¨T°#°s°(©^Ñ(<ó 'ð@	3¨#ð 	3°cð 	3¸dÀ3ÈÀ8¹nó 	3ð	3¨#ð 	3°cð 	3¸dÀ3ÈÀ8¹nó 	3ð	3°Cð 	3Àð 	3ÈÈSÐRUÈXÉó 	3ð3Øð3Ø!$ð3à	ˆc�3ˆh‰ó3ð3Øð3Ø!$ð3à	ˆc�3ˆh‰ó3ð3 Cð 3¨D°°c°©Nó 3ð$ Sð $¨T°#°s°(©^ó $ð3 ð 3¨¨c°3¨h©ó 3ð$ #ð $¨$¨s°C¨x©.¸4Ñ*?ó $ð$¨Cð $°D¸¸c¸±Nó $ð 59ñ7Øð7Ø'*¨T¡zð7à	ˆc�3ˆh‰ó7ð> !%Ø"Ø ñ	/Xà˜‘:ð/Xð �t‘ð/Xð �T‰zð	/Xð
 
ˆc�3ˆh‰ó/Xðb$¨ð $°°c¸3°h±ó $ð$¨ð $°°c¸3°h±ó $ð 59ñ7Øð7Ø'*¨T¡zð7à	ˆc�3ˆh‰ó7ð:$˜T $ s¨C x¡.Ñ1ó $ð$¨Sð $°T¸#¸s¸(±^ó $ð$¨T°#°s°(©^ó $ð EIñ(Øð(Ø),ð(Ø7:¸T±zð(à	ˆd�3˜�8‰nÑ	ó(ð* 4¨¡9ó ð$ d¨3°¨8¡nó $ð ØØ#'ñ	"àð"ð ð"ð ˜D‘jð	"ð
 
ˆc�3ˆh‰˜$˜s™)Ñ	#ó"ðH$¨cð $°d¸3À¸8±nó $ðI¨Sð I¸ð IÀó IðIàðIð ðIð ð	Ið
 ðIð 
óIð&J¸¸SÀ#¸X¹ð JÈ3ó Jð
!>àð!>ð ð!>ð ð	!>ð
 ð!>ð ð!>ð ð!>ð 
ó!>ðF 4¨¨S¨¡>°DÑ#8ó ð4¨Sð 4°Só 4ðl
¨3ð 
°3ó 
ð  #Ø#'Ø $ñ4àð4ð �t‘ð4ð ˜D‘jð	4ð
 ˜‘:ð4ð 
ˆd�3˜�8‰nÑ	ó4ðt !Ø"&ñ3àð3ð ð3ð ð	3ð
  ð3ð 
ˆc�3ˆh‰ó3ðB$ D¨¨c¨¡Nó $ð DFñ)Øð)Ø-0ð)Ø=@ð)à	ˆd�3˜�8‰nÑ	ó)ðV$¨#ð $°$°s¸C°x±.ó $ð$ sð $¨t°C¸°H©~ó $ð
$°3ð $¸4ÀÀSÀ¹>ó $ð EIñ	PØð	PØ+.ð	PØ=Að	Pà	ó	Pô ô ô˜tô ð *@×)CÑ)Cñ"àð"ð 'ð"ð 
ó	"ð4$¨sð $°t¸CÀ¸H±~ó $ð$°Sð $¸TÀ#ÀsÀ(¹^ó $ð$¸ð $ÀÀSÈ#ÀXÁó $ð$°ð $¸¸SÀ#¸X¹ó $ð$¸ð $ÀÀSÈ#ÀXÁó $ð$¨ð $°°S¸#°X±ó $ð FJñ3Øð3Ø*-ð3Ø?Bð3à	ˆc�3ˆh‰ó3ð$°c¸C±ið $ÀDÈÈcÈÁNó $ð
3¨S°3©Yð 
3¸4ÀÀSÀ¹>ó 
3ð +/ñ$Øð$Ø$'ð$à	ˆd�3˜�8‰nÑ	ó$ð"$ $ s¨C x¡.ó $ð$¨$¨s°C¨x©.ó $ð
C Cð 
C¨D°°c°©Nó 
Cñ3 #ð 3°#ð 3ÀÀSÈ#ÀXÁó 3ð$¨C°#©Ið $¸$¸sÀC¸x¹.ó $ð"¨3°©9ð "¸ó "ðQØ   c ™N¨T°#©YÑ6¸Ñ<ðQà	ˆc�3ˆh‰óQð*$°3ð $¸4ÀÀSÀ¹>ó $ð$Øð$Ø'*ð$à	ˆc�3ˆh‰ó$ð$ t¨C°¨H¡~ó $ð¨$¨s°C¨x©.ð ¸TÀ#ÀsÀ(¹^ó ô2
r+   r<   c                   ó   — e Zd ZdZy)r¢   z)Raised when communication ended in error.N©r|  r}  r~  r  r¶   r+   r"   r¢   r¢   w  s   „ Ú3r+   r¢   c                   ó   — e Zd ZdZy)r¡   z#Raised when rate limit is exceeded.NrÐ  r¶   r+   r"   r¡   r¡   {  s   „ Ú-r+   r¡   c                   ó   — e Zd ZdZy)r    z%Raised when authentication is failed.NrÐ  r¶   r+   r"   r    r      s   „ Ú/r+   r    c                   ó   — e Zd ZdZy)r?  z7Raised when an invalid file format is passed to upload.NrÐ  r¶   r+   r"   r?  r?  ƒ  s   „ ÚAr+   r?  )r   )r$   )/r  Úloggingr&   r¿   r   Úcollections.abcr   r   r   r   Úenumr   r   Úpathlibr	   Útypingr
   r‰   rÆ   Ú	garth.excr   r   r   Úfitr   Ú	getLoggerr|  rŸ   r
  rŽ  r   r    r-  r   r#   r/   rÍ  r*   r0   r2   r:   r<   r£   r¢   r¡   r    r?  r¶   r+   r"   ú<module>rÜ     s8  ðÙ .ã Û Û 	Û 	Ý $ß -Ñ -ß Ý Ý ã Û ß 4Ý å !à	ˆ×	Ñ	˜8Ó	$€ð Ð ØÐ Ø*Ð Ø€Ø˜E�]Ð ñ Cð °Sð Àcó ð. +2ñØ�‰;ðØ$'ðàˆ5�[óñ ¨#ð ¸3ð ÈSó ñ cð °sð Èó ðI�ð I˜Só I÷
V 
ñ V 
ôr@4 9ô 4ô.¨	ô .ô0 yô 0ôB¨)õ Br+   