diff --git a/garminscript.py b/garminscript.py index b288cd1e..9cb803af 100644 --- a/garminscript.py +++ b/garminscript.py @@ -28,23 +28,24 @@ payload = { 'workoutSourceId': 'Rowsandall.com', 'steps': [ { - 'type': 'WorkoutStep', 'stepOrder': 0, + 'type': 'WorkoutStep', + 'stepOrder': 0, #'repeatType': 'Step', - 'repeatValue': 1, + #'repeatValue': 1, 'intensity': 'ACTIVE', - 'description': '0', + 'description': 'At 220W', 'durationType': 'TIME', 'durationValue': 1800, - 'durationValueType': 'METER', + 'durationValueType': None, 'targetType': 'POWER', - 'targetValue': 1226, + 'targetValue': 226, 'targetValueLow': None, 'targetValueHigh': None, } ] } -payload = { +payload2 = { "workoutName": "Test", "description": "Test", "sport": "CYCLING", @@ -55,16 +56,93 @@ payload = { "intensity": "INTERVAL", "description": "Free Ride", "durationType": "TIME", - "durationValue": 300, + "durationValue": 1800, "durationValueType": None, "targetType": "POWER", - "targetValue": None, - "targetValueLow": 0, - "targetValueHigh": 0.7, - "targetValueType": "PERCENT", + "targetValue": 226, + "targetValueLow": None, + "targetValueHigh": None, + "targetValueType": None, "exerciseCategory": None }]} +payload = {'workoutName': '4x1000m', + 'sport': 'GENERIC', + 'description': 'Uploaded from Rowsandall.com', + 'estimatedDurationInSecs': 2700, + 'estimatedDistanceInMeters': 8768, + 'workoutProvider': 'Rowsandall.com', + 'workoutSourceId': 'Rowsandall.com', + 'steps': [{'type': 'WorkoutStep', + 'stepOrder': 0, + 'repeatType': None, + 'repeatValue': 1, + 'intensity': 'INTERVAL', + 'description': '0', + 'durationType': 'DISTANCE', + 'durationValue': 2000, + 'durationValueType': 'METER', + 'targetType': None, + 'targetValue': None, + 'targetValueLow': None, + 'targetValueHigh': None}, + {'type': 'WorkoutRepeatStep', + 'stepOrder': 1, + 'repeatType': 'REPEAT_UNTIL_STEPS_CMPLT', + 'repeatValue': 4, + 'intensity': 'INTERVAL', + 'description': '3', + 'durationType': 'REPS', + 'durationValue': None, + 'durationValueType': None, + 'targetType': None, + 'targetValue': None, + 'targetValueLow': None, + 'targetValueHigh': None, + 'steps': [{'type': 'WorkoutStep', + 'stepOrder': 2, + 'repeatType': None, + 'repeatValue': 1, + 'intensity': 'INTERVAL', + 'description': '1', + 'durationType': 'DISTANCE', + 'durationValue': 1000, + 'durationValueType': 'METER', + #'targetType': 'CADENCE', + #'targetValue': 25, + #'targetValueLow': None, + #'targetValueHigh': None + }, + {'type': 'WorkoutStep', + 'stepOrder': 3, + 'repeatType': None, + 'repeatValue': 1, + 'intensity': 'REST', + 'description': '2', + 'durationType': 'TIME', + 'durationValue': 60, + 'durationValueType': None, + 'targetType': None, + 'targetValue': None, + 'targetValueLow': None, + 'targetValueHigh': None}]}, + {'type': 'WorkoutStep', + 'stepOrder': 4, + 'repeatType': None, + 'repeatValue': 1, + 'intensity': 'INTERVAL', + 'description': '4', + 'durationType': 'DISTANCE', + 'durationValue': 2000, + 'durationValueType': 'METER', + 'targetType': None, + 'targetValue': None, + 'targetValueLow': None, + 'targetValueHigh': None}]} + + + + print(json.dumps(payload)) @@ -95,4 +173,17 @@ response = requests.post(url,auth=authheaders,json=payload) # build base_string print(response.status_code) -print(response.text) + +print(response.json()) +garmin_workout_id = response.json()['workoutId'] +url = 'http://apis.garmin.com/training-api/schedule' + +payload = { + 'workoutId': garmin_workout_id, + 'date': '2021-05-16' +} + + +response = requests.post(url,auth=authheaders,json=payload) +print(response.status_code) +print(response.json()) diff --git a/rowers/garmin_stuff.py b/rowers/garmin_stuff.py index 6d255b64..1636e48e 100644 --- a/rowers/garmin_stuff.py +++ b/rowers/garmin_stuff.py @@ -27,13 +27,6 @@ from rowsandall_app.settings import ( from pytz import timezone as tz, utc -#try: -# import http.client as http_client -#except ImportError: - # Python 2 -# import httplib as http_client -#http_client.HTTPConnection.debuglevel = 1 - # You must initialize logging, otherwise you'll not see debug output. #logging.basicConfig() #logging.getLogger().setLevel(logging.DEBUG) @@ -82,6 +75,36 @@ columns = { 'bikeCadenceInRPM':' Cadence (stokes/min)', } +targettypes = { + "Speed": "SPEED", + "HeartRate": "HEART_RATE", + "Open": "OPEN", + "Cadence": "CADENCE", + "Power": "POWER", + "Grade": "GRADE", + "Resistance": "RESISTANCE", + "Power3s": "POWER_3S", + "Power10s": "POWER_10S", + "Power30s": "POWER_30S", + "PowerLap": "POWER_LAP", + "SwimStroke": "SWIM_STROKE", + "SpeedLap": "SPEED_LAP", + "HeartRateLap": "HEART_RATE_LAP" +} + +repeattypes = { + "RepeatUntilStepsCmplt": "REPEAT_UNTIL_STEPS_CMPLT", + "RepeatUntilTime": "REPEAT_UNTIL_TIME", + "RepeatUntilDistance": "REPEAT_UNTIL_TIME", + "RepeatUntilCalories": "REPEAT_UNTIL_CALORIES" , + "RepeatUntilHrLessThan": "REPEAT_UNTIL_HR_LESS_THAN" , + "RepeatUntilHrGreaterThan": "REPEAT_UNTIL_HR_GREATER_THAN", + "RepeatUntilPowerLessThan": "REPEAT_UNTIL_POWER_LESS_THAN", + "RepeatUntilPowerGreaterThan": "REPEAT_UNTIL_POWER_GREATER_THAN", + "RepeatUntilPowerLapLessThan": "REPEAT_UNTIL_POWER_LAP_LESS_THAN", + "RepeatUntilPowerLapGreaterThan": "REPEAT_UNTIL_POWER_LAP_GREATER_THAN", +} + def garmin_authorize(): # pragma: no cover redirect_uri = oauth_data['redirect_uri'] client_secret = oauth_data['client_secret'] @@ -179,9 +202,11 @@ from rowers import utils def step_to_garmin(step,order=0): durationtype = step['dict']['durationType'] durationvalue = step['dict']['durationValue'] - durationvaluetype = '' + durationvaluetype = None try: - intensity = step['dict']['intensity'] + intensity = step['dict']['intensity'].upper() + if intensity.lower() == 'active': + intensity = 'INTERVAL' except KeyError: intensity = None #durationvaluetype = '' @@ -197,56 +222,87 @@ def step_to_garmin(step,order=0): if durationvalue <= 100: durationvaluetype = 'PERCENT' else: - durationvaluetype = '' + durationvaluetype = None durationvalue -= 100 elif durationtype == 'HrGreaterThan': # pragma: no cover durationtype = 'HR_GREATER_THAN' if durationvalue <= 100: durationvaluetype = 'PERCENT' else: - durationvaluetype = '' + durationvaluetype = None durationvalue -= 100 elif durationtype == 'PowerLessThan': # pragma: no cover durationtype = 'POWER_LESS_THAN' if durationvalue <= 1000: durationvaluetype = 'PERCENT' else: - durationvaluetype = '' + durationvaluetype = None durationvalue -= 1000 elif durationtype == 'PowerGreaterThan': # pragma: no cover durationtype = 'POWER_GREATER_THAN' if durationvalue <= 1000: durationvaluetype = 'PERCENT' else: - durationvaluetype = '' + durationvaluetype = None durationvalue -= 1000 elif durationtype == 'Reps': # pragma: no cover durationtype = 'REPS' try: targetType = step['dict']['targetType'] + targetType = targettypes[targetType] except KeyError: targetType = None try: targetValue = step['dict']['targetValue'] + if targetValue == 0: + targetValue = None except KeyError: targetValue = None try: targetValueLow = step['dict']['targetValueLow'] + if targetValueLow == 0: + targetValueLow = None except KeyError: targetValueLow = None try: - targetValueHigh = step['dict']['targetValueHigh'], + targetValueHigh = step['dict']['targetValueHigh'] + if targetValueHigh == 0: + targetValueHigh = None except KeyError: targetValueHigh = None + if targetType.lower() == "power": + targetType = 'POWER' + if targetValue is not None and targetValue > 1000: + targetValue -= 1000 + if targetValueHigh is not None and targetValueHigh > 1000: + targetValueHigh -= 1000 + if targetValueLow is not None and targetValueLow > 1000: + targetValueLow -= 1000 + + if targetValue is None and targetValueLow is None and targetValueHigh is None: + targetType = None + + steptype = 'WorkoutRepeatStep' + if step['type'].lower() == 'step': + steptype = 'WorkoutStep' + + repeattype = None + if steptype == 'WorkoutRepeatStep': + repeattype = repeattypes[step['dict']['durationType']] + durationtype = 'REPS' + durationvalue = None + durationvaluetype = None + targetType = None + targetValue = None out = { - 'type': step['type'], + 'type': steptype, 'stepOrder':order, - 'repeatType':step['type'], + 'repeatType':repeattype, 'repeatValue':step['repeatValue'], 'intensity':intensity, 'description':step['dict']['wkt_step_name'], @@ -303,30 +359,10 @@ def ps_to_garmin(ps,r): lijst.append(gstep) payload['steps'] = lijst - url = 'https://apis.garmin.com/training-api/workout/' - garmin = OAuth1Session(oauth_data['client_id'], - client_secret=oauth_data['client_secret'], - resource_owner_key=r.garmintoken, - resource_owner_secret=r.garminrefreshtoken, - signature_method='HMAC-SHA1', - encoding='base64' - ) + return payload - response = garmin.post(url,data=payload) - - #POST /training-api/workout?undefined HTTP/1.1 - #Authorization: OAuth oauth_nonce="3347376452", oauth_signature="jM8%2BCsflDfmB6SGYFIEFa%2BKRBOU%3D", oauth_token="673806b7-aa7b-4064-8290-2dd1b0236ae6", oauth_consumer_key="ca29ba5e-6868-4468-987d-4ee60a1f04bf", oauth_timestamp="1616050850", oauth_signature_method="HMAC-SHA1", oauth_version="1.0" - #Host: apis.garmin.com - #Accept: */* - - #curl -v --header 'Authorization: OAuth oauth_nonce="3347376452", oauth_signature="jM8%2BCsflDfmB6SGYFIEFa%2BKRBOU%3D", oauth_token="673806b7-aa7b-4064-8290-2dd1b0236ae6", oauth_consumer_key="ca29ba5e-6868-4468-987d-4ee60a1f04bf", oauth_timestamp="1616050850", oauth_signature_method="HMAC-SHA1", oauth_version="1.0"' 'https://apis.garmin.com/training-api/workout' - - #Authorization: OAuth oauth_nonce="3347376452", oauth_signature="jM8%2BCsflDfmB6SGYFIEFa%2BKRBOU%3D", oauth_token="673806b7-aa7b-4064-8290-2dd1b0236ae6", oauth_consumer_key="ca29ba5e-6868-4468-987d-4ee60a1f04bf", oauth_timestamp="1616050850", oauth_signature_method="HMAC-SHA1", oauth_version="1.0" - - return response - def get_garmin_permissions(user): # pragma: no cover r = Rower.objects.get(user=user) @@ -334,15 +370,18 @@ def get_garmin_permissions(user): # pragma: no cover s = "Token doesn't exist. Need to authorize" return custom_exception_handler(401,s) - garmin = OAuth1Session(oauth_data['client_id'], - client_secret=oauth_data['client_secret'], - resource_owner_key=r.garmintoken, - resource_owner_secret=r.garminrefreshtoken, - ) + garminheaders = OAuth1( + client_key = oauth_data['client_id'], + client_secret=oauth_data['client_secret'], + resource_owner_key=r.garmintoken, + resource_owner_secret=r.garminrefreshtoken, + signature_method='HMAC-SHA1', + ) - url = 'https://apis.garmin.com/userPermissions/' - result = garmin.get(url) + url = 'https://apis.garmin.com/userPermissions' + + result = requests.get(url,auth=garminheaders) if result.status_code == 200: return result.json() @@ -351,31 +390,58 @@ def get_garmin_permissions(user): # pragma: no cover def garmin_session_create(ps,user): # pragma: no cover if not ps.steps: + print('aap') return 0 if not garmin_can_export_session(user): + print('noot') return 0 - garmindict = ps_to_garmin(ps) - r = Rower.objects.get(user=user) if (r.garmintoken == '') or (r.garmintoken is None): s = "Token doesn't exist. Need to authorize" return custom_exception_handler(401,s) - garmin = OAuth1Session(oauth_data['client_id'], - client_secret=oauth_data['client_secret'], - resource_owner_key=r.garmintoken, - resource_owner_secret=r.garminrefreshtoken, - ) + payload = ps_to_garmin(ps,r) - url = 'http://apis.garmin.com/training-api/schedule/' + url = 'https://apis.garmin.com/training-api/workout' + + garminheaders = OAuth1( + client_key = oauth_data['client_id'], + client_secret=oauth_data['client_secret'], + resource_owner_key=r.garmintoken, + resource_owner_secret=r.garminrefreshtoken, + signature_method='HMAC-SHA1', + ) + + response = requests.post(url,auth=garminheaders,json=payload) + print(response.status_code,response.text) - response = garmin.post(url,data=garmindict) if response.status_code != 200: return 0 - return response.json()['workoutId'] + garmin_workout_id = response.json()['workoutId'] + + + url = 'http://apis.garmin.com/training-api/schedule' + + payload = { + 'workoutId': garmin_workout_id, + 'date': ps.preferreddate.strftime('%Y-%m-%d') + } + + + response = requests.post(url,auth=garminheaders,json=payload) + print(response.status_code,response.text) + + if response.status_code != 200: + return 0 + + ps.garmin_schedule_id = response.json() + ps.garmin_workout_id = garmin_workout_id + ps.save() + + return garmin_workout_id def garmin_getworkout(garminid,r,activity): starttime = activity['startTimeInSeconds'] diff --git a/rowers/models.py b/rowers/models.py index efac1c2d..7d612fef 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2399,6 +2399,8 @@ class PlannedSession(models.Model): steps = PlannedSessionStepField(default={},null=True) interval_string = models.TextField(max_length=1000,default=None,blank=True,null=True, verbose_name='Interval String (optional)') + garmin_workout_id = models.BigIntegerField(default=0) + garmin_schedule_id = models.BigIntegerField(default=0) tags = TaggableManager(blank=True)