def garmin_upload(player_id, activity): try: from garmin_uploader.workflow import Workflow except ImportError: logger.warn( "garmin_uploader is not installed. Skipping Garmin upload attempt." ) return profile_dir = '%s/%s' % (STORAGE_DIR, player_id) try: with open('%s/garmin_credentials.txt' % profile_dir, 'r') as f: username = f.readline().rstrip('\r\n') password = f.readline().rstrip('\r\n') except: logger.warn( "Failed to read %s/garmin_credentials.txt. Skipping Garmin upload attempt." % profile_dir) return try: with open('%s/last_activity.fit' % profile_dir, 'wb') as f: f.write(activity.fit) except: logger.warn("Failed to save fit file. Skipping Garmin upload attempt.") return try: w = Workflow(['%s/last_activity.fit' % profile_dir], activity_name=activity.name, username=username, password=password) w.run() except: logger.warn("Garmin upload failed. No internet?")
def uploadToGarmin(paths, garminUsername, garminPassword, activityType, activityName): try: workflow = Workflow(paths, garminUsername, garminPassword, activityType, activityName) workflow.run() except Exception as e: logger.error("Failed to upload to Garmin Connect. - {}".format(e)) raise e
def upload_to_garmin(paths, username=None, password=None, activity_name=None, activity_type=None, verbose=2): workflow = Workflow(activity_name=activity_name, activity_type=activity_type, password=password, paths=paths, username=username, verbose=2) workflow.run()
def main(): """ CLI Entry point """ base_dir = os.path.realpath(os.path.dirname(__file__)) parser = argparse.ArgumentParser( formatter_class=argparse.RawDescriptionHelpFormatter, description='A script to upload .TCX, .GPX, and .FIT' 'files to the Garmin Connect web site.', epilog=open(os.path.join(base_dir, 'help.txt')).read(), ) parser.add_argument( 'paths', type=str, nargs='+', help='Path and name of file(s) to upload, list file name, or directory' 'name containing fitness files.') parser.add_argument( '-a', '--name', dest='activity_name', type=str, help='Sets the activity name for the upload file. This option is' 'ignored if multiple upload files are given.') parser.add_argument( '-t', '--type', dest='activity_type', type=str, help='Sets activity type for ALL files in filename list, except files' 'described inside a csv list file.') parser.add_argument('-u', '--username', dest='username', type=str, help='Garmin Connect user login') parser.add_argument('-p', '--password', dest='password', type=str, help='Garmin Connect user password') parser.add_argument( '-v', '--verbose', dest='verbose', type=int, default=2, choices=[1, 2, 3, 4, 5], help='Verbose - select level of verbosity. 1=DEBUG(most verbose),' ' 2=INFO, 3=WARNING, 4=ERROR, 5= CRITICAL(least verbose).' ' [default=2]') # Run workflow with these options options = parser.parse_args() try: workflow = Workflow(**vars(options)) workflow.run() except Exception as e: print('Error: {}'.format(e)) return 1 # erroneous exit code return 0
def sync(csv_file, garmin_username, garmin_password, fromdate, todate, no_upload, verbose): def verbose_print(s): if verbose: if no_upload: sys.stderr.write(s) else: sys.stdout.write(s) if csv_file == '': verbose_print("--csv_file is required\n") exit(1) if not(os.path.isfile(csv_file)): verbose_print("File " + csv_file + " not found\n") exit(1) # OpenScale CSV osc = OpenScaleCSV() osc.load(csv_file) startdate = int(time.mktime(fromdate.timetuple())) enddate = int(time.mktime(todate.timetuple())) + 86399 groups = [] for ix in range(0, osc.records()): item = osc.record(ix) dt = int(time.mktime(item['dateTime'].timetuple())) if dt < startdate: continue if dt > enddate: continue groups.append(item) # create fit file verbose_print('generating fit file...\n') fit = FitEncoder_Weight() fit.write_file_info() fit.write_file_creator() for group in groups: dt = group['dateTime'] weight = group['weight'] fat_ratio = group['fat'] fit.write_device_info(timestamp=dt) fit.write_weight_scale(timestamp=dt, weight=weight, percent_fat=fat_ratio) verbose_print('appending weight scale record... %s %skg %s%%\n' % (dt, weight, fat_ratio)) fit.finish() if no_upload: sys.stdout.write(fit.getvalue()) return # create temporary file fi, fn = mkstemp() fn = fn + '.fit' fp = open(fn, 'w') fp.write(fit.getvalue()) fp.close() # garmin connect verbose_print('attempting to upload fit file...\n') workflow = Workflow(paths=[fn], username=garmin_username, password=garmin_password) workflow.run()
def main(): args = parse_arguments() files = sorted(set(args.files)) file_rex = re.compile(".*tr(\d{4})(\d{2})(\d{2})(\d{2})(\d{2}).csv", re.IGNORECASE) laps = [] lap = None for f in files: m = file_rex.match(f) if not m: raise KeyError("Error: unknown file naming format: {}".format(f)) starttime = datetime.datetime(int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4)), int(m.group(5))) # Collapse close (5sec) or overlapping laps if laps: tdelta = starttime - laps[-1].EndTime() lap = laps.pop() if tdelta.total_seconds() < 5 else None if not lap: lap = Lap(starttime) with open(f, newline="") as csvfile: reader = csv.reader(csvfile, delimiter=",") for row in reader: if row_is_header(row): continue if row_is_totals(row): break if row_is_incomplete(row): continue values = dict(zip(stat_keys, [int(n) for n in row])) lap.XTrainerSample(values) # Use lap but only if it has data if len(lap): laps.append(lap) # Split into sessions (more than 20 minutes in between laps) lapsplit = [ idx for idx, (l1, l2) in enumerate(pairwise(laps), 1) if l2.StartTime() - l1.EndTime() > datetime.timedelta(minutes=20) ] lapsplit = [0] + lapsplit + [len(laps)] sessions = [laps[i:j] for i, j in pairwise(lapsplit)] tcx_files = [] for laps in sessions: # Add rest laps restlaps = [] for l1, l2 in pairwise(laps): restlap = Lap(l1.EndTime() + datetime.timedelta(seconds=1), False) restlap.RestSample(l2.StartTime() - datetime.timedelta(seconds=1), l1.HeartRateBpm()) restlaps.append(restlap) for idx, restlap in enumerate(restlaps, 1): laps.insert(idx * 2 - 1, restlap) # Recalculate distance and altitude start_distance = start_altitude = 0.0 for lap in laps: start_distance = lap.UpdateDistance(start_distance) start_altitude = lap.UpdateAltitude(start_altitude) # Garmin altitude graph does not like altitudes below -500m, hence # adjust altitude to have 10m as lowest point start_altitude = 10.0 - min([lap.MinimumAltitude() for lap in laps]) for lap in laps: start_altitude = lap.UpdateAltitude(start_altitude) tcx_file = write_xml(laps) tcx_files.append(tcx_file) totsec = sum([l.TotalTimeSeconds() for l in laps]) print("active time: {}".format(datetime.timedelta(seconds=totsec))) totdist = sum([l.DistanceMeters() for l in laps]) print("total distance: {0:.2f}km".format(totdist / 1000)) totwatt = sum([l.Sum('watt') for l in laps]) totlen = sum([len(l) for l in laps]) print("avg watt: {0:.2f}W".format(totwatt / totlen)) for i in [1, 10, 30, 60, 120]: print("max {}s watt: {:.0f}W".format( i, max([l.MaximumWatts(i) for l in laps]))) print("max speed: {}km/t".format(max([l.MaximumSpeed() for l in laps]))) if args.upload and tcx_files: for tcx in tcx_files: try: workflow = Workflow([tcx], args.username, args.password, activity_type="indoor_cycling", activity_name="X-trainer indoor cycling", verbose=5 if args.verbose else 2) workflow.run() except Exception as e: print("Error: {}".format(str(e))) sys.exit(1)