garmin-uploader icon indicating copy to clipboard operation
garmin-uploader copied to clipboard

Garmin Two-Step Verification

Open ame9895 opened this issue 2 years ago • 9 comments

Thank you so much for building this program! I recently bought a Garmin device that requires two-step verification (Garmin Bounce watch). Adding two-step unfortunately broke this uploader. Any idea if you'd be able to implement a prompt for entering a 2FA code (Garmin only supports email and SMS, no TOTP)? Garmin does have a "remember device" option, so maybe you'd only have to enter the code one time. Thanks!

ame9895 avatar May 12 '23 13:05 ame9895

Any luck on this one ? this is really required. Some new watches force to have 2FA setup without any way to turn it off. Happy to help in anyways.

svanhoutte avatar Sep 28 '23 14:09 svanhoutte

Maybe garth is a better option, it supports MFA.

https://github.com/matin/garth#authenticate-and-save-session

But my account does not require 2FA, not sure if you need to re-enter the code when the session expires and you need to log in again.

oldnapalm avatar Sep 28 '23 15:09 oldnapalm

I was going to suggest garth. I'd been using your https://github.com/svanhoutte/wyze_garmin_sync package, @svanhoutte , but my kids' Garmin Bounce watches require 2FA so I'd been out of luck. Using https://github.com/cyberjunky/python-garminconnect and a tiny version of the example.py script, I was able to modify your connect bash script to use this authentication method while still using your wyze connection/download scripts.

ame9895 avatar Sep 28 '23 15:09 ame9895

@ame9895 do you mind sharing what you did ? that sounds promising.

svanhoutte avatar Sep 28 '23 18:09 svanhoutte

It’s a bad hack job, but I just removed a bunch of the menu and other features from the example.py, renamed it to scale_upload.py and used this as the main body:

# Main program loop
# Display header and login
print("\n*** Garmin Connect API Demo by cyberjunky ***\n")

\# Init API
if not api:
    api = init_api(email, password)

if api:
    print("\n Uploading file...\n")
    try:
      # Upload activity from file
      display_json(
        f"api.upload_activity({activityfile})",
        api.upload_activity(activityfile),
      )
    except FileNotFoundError:
        print(f"File to upload not found: {activityfile}")

    \#api.upload_activity(activityfile)
else:
    api = init_api(email, password)

Then in connect_sync.legacy.sh I just replaced the gupload call with:

if python3 /home/user/scale_upload.py ; then

ame9895 avatar Sep 28 '23 20:09 ame9895

Edit: garth added upload support https://github.com/matin/garth#upload

If you just want to upload a fit file and nothing else

import os
import sys
import garth
from getpass import getpass

if len(sys.argv) < 2:
    print("Use %s <file name>" % sys.argv[0])
    exit()

if not os.path.isfile(sys.argv[1]):
    print("File %s not found" % sys.argv[1])
    exit()

tokens_dir = './tokens'

try:
    garth.resume(tokens_dir)
    garth.client.username
except:
    email = input("Enter email address: ")
    password = getpass("Enter password: ")
    try:
        garth.login(email, password)
        garth.save(tokens_dir)
    except Exception as exc:
        print(repr(exc))
        exit()

with open(sys.argv[1], "rb") as f:
    garth.client.upload(f)

oldnapalm avatar Sep 28 '23 23:09 oldnapalm

@oldnapalm thanks man that was super helpful. I have my script working with 2FA now !

svanhoutte avatar Sep 30 '23 13:09 svanhoutte

@svanhoutte no problem, glad it worked. Since you use the script exit code in connect_sync.sh it's a good idea to run the upload in try and return 1 in case of exception (also change exit() in lines 8, 12 and 34 to sys.exit(1))

try:
    with open(sys.argv[1], "rb") as f:
        garth.client.upload(f)
except Exception as exc:
    print(repr(exc))
    sys.exit(1)

sys.exit(0)

oldnapalm avatar Sep 30 '23 19:09 oldnapalm

@oldnapalm Thanks for that, I ll update the script soon on my side.

svanhoutte avatar Sep 30 '23 20:09 svanhoutte