Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Uploading Workouts #185

Open
euanChalmers02 opened this issue Jan 9, 2024 · 12 comments
Open

Uploading Workouts #185

euanChalmers02 opened this issue Jan 9, 2024 · 12 comments

Comments

@euanChalmers02
Copy link

Could anyone advise on if I have made any mistakes in creating an example for creating a workout using the API as part of a package fork? current works to list all workout but not creating new?


       garmin_workouts = (
            "/workout-service"
        )
        url = f"{garmin_workouts}/workout"

        expected_workout_payload = {
            'workoutId': "random_id",
            'ownerId': "random",
            'workoutName': 'Any workout name',
            'description': 'FTP 200, TSS 1, NP 114, IF 0.57',
            'sportType': {'sportTypeId': 2, 'sportTypeKey': 'cycling'},
            'workoutSegments': [
                {
                    'segmentOrder': 1,
                    'sportType': {'sportTypeId': 2, 'sportTypeKey': 'cycling'},
                    'workoutSteps': [
                        {'type': 'ExecutableStepDTO', 'stepOrder': 1,
                         'stepType': {'stepTypeId': 3, 'stepTypeKey': 'interval'}, 'childStepId': None,
                         'endCondition': {'conditionTypeId': 2, 'conditionTypeKey': 'time'}, 'endConditionValue': 60,
                         'targetType': {'workoutTargetTypeId': 2, 'workoutTargetTypeKey': 'power.zone'},
                         'targetValueOne': 95, 'targetValueTwo': 105},
                        {'type': 'ExecutableStepDTO', 'stepOrder': 2,
                         'stepType': {'stepTypeId': 3, 'stepTypeKey': 'interval'}, 'childStepId': None,
                         'endCondition': {'conditionTypeId': 2, 'conditionTypeKey': 'time'}, 'endConditionValue': 120,
                         'targetType': {'workoutTargetTypeId': 2, 'workoutTargetTypeKey': 'power.zone'},
                         'targetValueOne': 114, 'targetValueTwo': 126}
                    ]
                }
            ]
        }

        response = self.garth.post("save", url, json=expected_workout_payload)
        print("Response: "+str(response))
        return response
        ```
@matin
Copy link
Contributor

matin commented Jan 13, 2024

What response are you receiving?

At first glance, you're missing api=True in self.garth.post(). Without that flag, it won't pass the auth tokens in the request.

@euanChalmers02
Copy link
Author

euanChalmers02 commented Jan 14, 2024

The following extra methods should work for other commands (within init) :
`
def get_workouts(self):
#only gets first 100
url = f"{self.garmin_workouts}/workouts"
logger.debug("Requesting user summary")
params = {
"start": 0,
"limit": 100
}
response = self.connectapi(url, params=params)
return response

def get_workout_by_id(self,workoutID):
    url = f"{self.garmin_workouts}/workout/"+workoutID
    response = self.connectapi(url)
    return response

def download_workout_by_id(self, workoutID):
    url = f"{self.garmin_workouts}/workout/FIT/" + workoutID
    response = self.connectapi(url)

    with open("Download_Workout"+workoutID, "wb") as f:
        f.write(response.content)

    return response
    `

@cyberjunky
Copy link
Owner

I added the calls to the new version (to be released tomorrow) I renamed

def download_workout_by_id(self, workoutID):

to:

def download_workout(self, workoutID):

So it named the same as the other download methods

@cyberjunky
Copy link
Owner

Oh wait I didn't include upload_workout(), need to look at that.

@cyberjunky
Copy link
Owner

@euanChalmers02 Did you get the upload working, if so how? ;-)

@cyberjunky
Copy link
Owner

I added the get and download methods to version 0.2.13, didn't get het upload function to work yet though.

@euanChalmers02
Copy link
Author

Thanks alot very helpful, and no I did some trial and error but no luck and have reverted to copying files directly from PC due to this being deprecated by garmin I think?

@OscarSalgado
Copy link

Workout upload works fine via workout-service, you just need the correct payload (workout json structure). May be a bit tricky depending on sport, duration, intensity, etc.

@euanChalmers02
Copy link
Author

Great, Would you happen to have an example payload I can use to develop some tests /examples for different sports?

@OscarSalgado
Copy link

Feel free to check https://github.com/OscarSalgado/garmin-workouts

It is not as documented as it should be but I hope you can follow the rationale behind. I tried to simplify workout definition as much as possible.

Intensively tested for running workouts, although I made some tests for the rest of sports. Happy to help

@HansBaldzuhn
Copy link

Hello,
i'm looking for a simple way to upload workout on garminconnect. I see that the function upload_workout has been commented, and the code doesn't work (hence the commenting I suppose ^^)

@cyberjunky and @euanChalmers02 do you by any chance have something working on your side ?

@euanChalmers02
Copy link
Author

Hi, Yes, you are correct. The code doesn't work on testing again, assuming you uncomment relevant sections. The upload works if you use a valid JSON payload, as seen when calling find workout by id (large JSON structure). I am sure there is a way to simplify this, but currently, using a payload such as this for upload will work.

Added to line 52 in example.py and then running using Q:

Please let me know if this doesnt works and if you find a nice way to create/ generate these upload json as that was where i failed last time.

Thanks

`workout_example = {'workoutId': 1055636, 'ownerId': 10788552, 'workoutName': 'Simple session', 'updatedDate': '2018-07-05T17:34:04.0', 'createdDate': '2018-05-08T09:14:50.0', 'sportType': {'sportTypeId': 1, 'sportTypeKey': 'running', 'displayOrder': 1}, 'author': {}, 'estimatedDurationInSecs': 1200, 'workoutSegments': [{'segmentOrder': 1, 'sportType': {'sportTypeId': 1, 'sportTypeKey': 'running', 'displayOrder': 1}, 'workoutSteps': [{'type': 'ExecutableStepDTO', 'stepId': 633927266, 'stepOrder': 1, 'stepType': {'stepTypeId': 1, 'stepTypeKey': 'warmup', 'displayOrder': 1}, 'endCondition': {'conditionTypeId': 2, 'conditionTypeKey': 'time', 'displayOrder': 2, 'displayable': True}, 'endConditionValue': 180.0, 'targetType': {'workoutTargetTypeId': 1, 'workoutTargetTypeKey': 'no.target', 'displayOrder': 1}, 'strokeType': {'strokeTypeId': 0, 'displayOrder': 0}, 'equipmentType': {'equipmentTypeId': 0, 'displayOrder': 0}}, {'type': 'RepeatGroupDTO', 'stepId': 633927267, 'stepOrder': 2, 'stepType': {'stepTypeId': 6, 'stepTypeKey': 'repeat', 'displayOrder': 6}, 'childStepId': 1, 'numberOfIterations': 6, 'workoutSteps': [{'type': 'ExecutableStepDTO', 'stepId': 705526052, 'stepOrder': 3, 'stepType': {'stepTypeId': 3, 'stepTypeKey': 'interval', 'displayOrder': 3}, 'childStepId': 1, 'endCondition': {'conditionTypeId': 2, 'conditionTypeKey': 'time', 'displayOrder': 2, 'displayable': True}, 'endConditionValue': 60.0, 'targetType': {'workoutTargetTypeId': 1, 'workoutTargetTypeKey': 'no.target', 'displayOrder': 1}, 'strokeType': {'strokeTypeId': 0, 'displayOrder': 0}, 'equipmentType': {'equipmentTypeId': 0, 'displayOrder': 0}}, {'type': 'ExecutableStepDTO', 'stepId': 705526053, 'stepOrder': 4, 'stepType': {'stepTypeId': 4, 'stepTypeKey': 'recovery', 'displayOrder': 4}, 'childStepId': 1, 'endCondition': {'conditionTypeId': 2, 'conditionTypeKey': 'time', 'displayOrder': 2, 'displayable': True}, 'endConditionValue': 60.0, 'targetType': {'workoutTargetTypeId': 1, 'workoutTargetTypeKey': 'no.target', 'displayOrder': 1}, 'strokeType': {'strokeTypeId': 0, 'displayOrder': 0}, 'equipmentType': {'equipmentTypeId': 0, 'displayOrder': 0}}], 'endConditionValue': 6.0, 'endCondition': {'conditionTypeId': 7, 'conditionTypeKey': 'iterations', 'displayOrder': 7, 'displayable': False}, 'smartRepeat': False}, {'type': 'RepeatGroupDTO', 'stepId': 633927270, 'stepOrder': 5, 'stepType': {'stepTypeId': 6, 'stepTypeKey': 'repeat', 'displayOrder': 6}, 'childStepId': 2, 'numberOfIterations': 3, 'workoutSteps': [{'type': 'ExecutableStepDTO', 'stepId': 633927271, 'stepOrder': 6, 'stepType': {'stepTypeId': 3, 'stepTypeKey': 'interval', 'displayOrder': 3}, 'childStepId': 2, 'endCondition': {'conditionTypeId': 2, 'conditionTypeKey': 'time', 'displayOrder': 2, 'displayable': True}, 'endConditionValue': 30.0, 'targetType': {'workoutTargetTypeId': 1, 'workoutTargetTypeKey': 'no.target', 'displayOrder': 1}, 'strokeType': {'strokeTypeId': 0, 'displayOrder': 0}, 'equipmentType': {'equipmentTypeId': 0, 'displayOrder': 0}}, {'type': 'ExecutableStepDTO', 'stepId': 633927272, 'stepOrder': 7, 'stepType': {'stepTypeId': 4, 'stepTypeKey': 'recovery', 'displayOrder': 4}, 'childStepId': 2, 'endCondition': {'conditionTypeId': 2, 'conditionTypeKey': 'time', 'displayOrder': 2, 'displayable': True}, 'endConditionValue': 30.0, 'targetType': {'workoutTargetTypeId': 1, 'workoutTargetTypeKey': 'no.target', 'displayOrder': 1}, 'strokeType': {'strokeTypeId': 0, 'displayOrder': 0}, 'equipmentType': {'equipmentTypeId': 0, 'displayOrder': 0}}], 'endConditionValue': 3.0, 'endCondition': {'conditionTypeId': 7, 'conditionTypeKey': 'iterations', 'displayOrder': 7, 'displayable': False}, 'smartRepeat': False}, {'type': 'ExecutableStepDTO', 'stepId': 633927273, 'stepOrder': 8, 'stepType': {'stepTypeId': 2, 'stepTypeKey': 'cooldown', 'displayOrder': 2}, 'endCondition': {'conditionTypeId': 2, 'conditionTypeKey': 'time', 'displayOrder': 2, 'displayable': True}, 'endConditionValue': 120.0, 'targetType': {'workoutTargetTypeId': 1, 'workoutTargetTypeKey': 'no.target', 'displayOrder': 1}, 'strokeType': {'strokeTypeId': 0, 'displayOrder': 0}, 'equipmentType': {'equipmentTypeId': 0, 'displayOrder': 0}}]}]}

`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants