matin / garth

Garmin SSO auth + Connect Python client
MIT License
305 stars 22 forks source link

Make awake_sleep_seconds optional and support None #31

Closed nzigel closed 1 year ago

nzigel commented 1 year ago

I have some days in my Garmin Sleep data where I have no restless moments sleeping this results in an error:

daily_sleep_dto.awake_sleep_seconds Input should be a valid integer [type=int_type, input_value=None, input_type=NoneType]

matin commented 1 year ago

That's impressive! I didn't realize that was possible.

nzigel commented 1 year ago

When I call garth.SleepData.get("2023-03-03")

I get - SleepData(daily_sleep_dto=DailySleepDTO(id=1677749580000, user_profile_pk=47111956, calendar_date=datetime.date(2023, 3, 3), sleep_time_seconds=25860, nap_time_seconds=0, sleep_window_confirmed=True, sleep_window_confirmation_type='enhanced_confirmed_final', sleep_start_timestamp_gmt=1677749580000, sleep_end_timestamp_gmt=1677775440000, sleep_start_timestamp_local=1677796380000, sleep_end_timestamp_local=1677822240000, unmeasurable_sleep_seconds=0, deep_sleep_seconds=5100, light_sleep_seconds=14400, rem_sleep_seconds=6360, awake_sleep_seconds=0, device_rem_capable=True, retro=False, sleep_from_device=True, sleep_version=2, awake_count=0, sleep_scores=SleepScores(total_duration=Score(qualifier_key='GOOD', optimal_start=28800.0, optimal_end=28800.0, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), stress=Score(qualifier_key='EXCELLENT', optimal_start=0.0, optimal_end=15.0, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), awake_count=Score(qualifier_key='EXCELLENT', optimal_start=0.0, optimal_end=1.0, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), overall=Score(qualifier_key='EXCELLENT', optimal_start=None, optimal_end=None, value=90, ideal_start_in_seconds=None, ideal_end_in_seconds=None), rem_percentage=Score(qualifier_key='EXCELLENT', optimal_start=21.0, optimal_end=31.0, value=25, ideal_start_in_seconds=5430.6, ideal_end_in_seconds=8016.6), restlessness=Score(qualifier_key='EXCELLENT', optimal_start=0.0, optimal_end=5.0, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), light_percentage=Score(qualifier_key='EXCELLENT', optimal_start=30.0, optimal_end=64.0, value=56, ideal_start_in_seconds=7758.0, ideal_end_in_seconds=16550.4), deep_percentage=Score(qualifier_key='EXCELLENT', optimal_start=16.0, optimal_end=33.0, value=20, ideal_start_in_seconds=4137.6, ideal_end_in_seconds=8533.8)), auto_sleep_start_timestamp_gmt=None, auto_sleep_end_timestamp_gmt=None, sleep_quality_type_pk=None, sleep_result_type_pk=None, average_sp_o2_value=None, lowest_sp_o2_value=None, highest_sp_o2_value=None, average_sp_o2_hr_sleep=None, average_respiration_value=14.0, lowest_respiration_value=12.0, highest_respiration_value=17.0, avg_sleep_stress=12.0, age_group='ADULT', sleep_score_feedback='POSITIVE_OPTIMAL_STRUCTURE', sleep_score_insight='NONE'), sleep_movement=None)

Note the awake_sleep_seconds=0 in the response above.

matin commented 1 year ago

Impressive! I wonder what your results are when you run this: https://colab.research.google.com/github/matin/garth/blob/main/colabs/sleep.ipynb

nzigel commented 1 year ago

When I run the notebook above on the

sleep_data = [sd.daily_sleep_dto for sd in garth.SleepData.list(latest, 90)]

line I get 5 validation errors for SleepData

daily_sleep_dto -> unmeasurable_sleep_seconds none is not an allowed value (type=type_error.none.not_allowed) daily_sleep_dto -> deep_sleep_seconds none is not an allowed value (type=type_error.none.not_allowed) daily_sleep_dto -> light_sleep_seconds none is not an allowed value (type=type_error.none.not_allowed) daily_sleep_dto -> rem_sleep_seconds none is not an allowed value (type=type_error.none.not_allowed) daily_sleep_dto -> awake_sleep_seconds none is not an allowed value (type=type_error.none.not_allowed)

This is related to a me flying back from Europe on the 23rd of July and getting a very strange sleep score for the sleeping on the plane crossing timezones.

SleepData(daily_sleep_dto=DailySleepDTO(id=1690085700000, user_profile_pk=47111956, calendar_date=datetime.date(2023, 7, 23), sleep_time_seconds=7380, nap_time_seconds=0, sleep_window_confirmed=True, sleep_window_confirmation_type='enhanced_confirmed_final', sleep_start_timestamp_gmt=1690085700000, sleep_end_timestamp_gmt=1690093440000, sleep_start_timestamp_local=1690128900000, sleep_end_timestamp_local=1690136640000, unmeasurable_sleep_seconds=0, deep_sleep_seconds=2700, light_sleep_seconds=4020, rem_sleep_seconds=660, awake_sleep_seconds=360, device_rem_capable=True, retro=False, sleep_from_device=True, sleep_version=2, awake_count=1, sleep_scores=SleepScores(total_duration=Score(qualifier_key='INVALID', optimal_start=28800.0, optimal_end=28800.0, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), stress=Score(qualifier_key='INVALID', optimal_start=0.0, optimal_end=15.0, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), awake_count=Score(qualifier_key='INVALID', optimal_start=0.0, optimal_end=1.0, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), overall=Score(qualifier_key='INVALID', optimal_start=None, optimal_end=None, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), rem_percentage=Score(qualifier_key='INVALID', optimal_start=21.0, optimal_end=31.0, value=9, ideal_start_in_seconds=1549.8, ideal_end_in_seconds=2287.8), restlessness=Score(qualifier_key='INVALID', optimal_start=None, optimal_end=None, value=None, ideal_start_in_seconds=None, ideal_end_in_seconds=None), light_percentage=Score(qualifier_key='INVALID', optimal_start=30.0, optimal_end=64.0, value=54, ideal_start_in_seconds=2214.0, ideal_end_in_seconds=4723.2), deep_percentage=Score(qualifier_key='INVALID', optimal_start=16.0, optimal_end=33.0, value=37, ideal_start_in_seconds=1180.8, ideal_end_in_seconds=2435.4)), auto_sleep_start_timestamp_gmt=None, auto_sleep_end_timestamp_gmt=None, sleep_quality_type_pk=None, sleep_result_type_pk=None, average_sp_o2_value=None, lowest_sp_o2_value=None, highest_sp_o2_value=None, average_sp_o2_hr_sleep=None, average_respiration_value=15.0, lowest_respiration_value=13.0, highest_respiration_value=19.0, avg_sleep_stress=16.0, age_group='ADULT', sleep_score_feedback='NONE', sleep_score_insight='NONE'), sleep_movement=[...])

View of the day from Garmin Connect https://1drv.ms/i/s!AmsWWl__IBkhubljzWZe0ym9HNxlNg?e=fSRz1C

matin commented 1 year ago

Want to set all of those fields causing validation errors as Optional?

Everyone should be able to run that Colab.

nzigel commented 1 year ago

done

matin commented 1 year ago

@nzigel released 0.4.41.

Can you try running the Colab again?

You'll need to delete the environment and starting a new one to make sure you get the latest and greatest.