Example #1
0
def sync(withings_username, withings_password, withings_shortname,
         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)

    # Withings API
    withings = WithingsAccount(withings_username, withings_password)
    user = withings.get_user_by_shortname(withings_shortname)
	
    if not user:
        print 'could not find user: %s' % withings_shortname
        return
    #if not user.ispublic:
    #    print 'user %s has not opened withings data' % withings_shortname
    #    return
    startdate = int(time.mktime(fromdate.timetuple()))
    enddate = int(time.mktime(todate.timetuple())) + 86399
    groups = user.get_measure_groups(startdate=startdate, enddate=enddate)

    # create fit file
    verbose_print('generating fit file...\n')
    fit = FitEncoder_Weight()
    fit.write_file_info()
    fit.write_file_creator()

    for group in groups:
        # get extra physical measurements

        from measurements import Measurements 
        measurements = Measurements()
    
        dt = group.get_datetime()
        weight = group.get_weight()
        fat_ratio = group.get_fat_ratio()
        muscle_mass = group.get_muscle_mass()
        bone_mass=group.get_bone_mass()
        hydro = group.get_hydro()
        # mass_hydro to percent_hydro conversion
        ratio = 100 / weight
        hydro = hydro * ratio
        bone_mass = group.get_bone_mass()
        fit.write_device_info(timestamp=dt)
        fit.write_weight_scale(timestamp=dt, 
            weight=weight, 
            percent_fat=fat_ratio, 
            percent_hydration=hydro,
            muscle_mass=muscle_mass,
			bone_mass=bone_mass,
            )
        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

	verbose_print("Fit file: " + fit.getvalue())

    # garmin connect
    garmin = GarminConnect()
    session = garmin.login(garmin_username, garmin_password)
    verbose_print('attempting to upload fit file...\n')
    r = garmin.upload_file(fit.getvalue(), session)
    if r:
        verbose_print('weight.fit has been successfully uploaded!\n')
        print("Their is no new measurement to sync.")
        save_config()
        sys.exit(0);

    if service == 'garmin':

        next_sync = groups[-1].date.timestamp

        # Do not repeatidly sync the same value
        if next_sync == last_sync:
            print('Last measurement was already synced')
            save_config()
            sys.exit(0)

        # create fit file
        fit = FitEncoder_Weight()
        fit.write_file_info()
        fit.write_file_creator()
        fit.write_device_info(timestamp=next_sync)
        for m in groups:
            weight = m.get_measure(types['weight']);
            if weight:
                fit.write_weight_scale(timestamp=m.date.timestamp, weight=weight, percent_fat=m.get_measure(types['fat_ratio']),
                    percent_hydration=m.get_measure(types['hydration']), bone_mass=m.get_measure(types['bone_mass']), muscle_mass=m.get_measure(types['muscle_mass']))

        fit.finish()

        garmin = GarminConnect()
        session = garmin.login(config.get('garmin','username'), config.get('garmin','password'))
        r = garmin.upload_file(fit.getvalue(), session)
        if r:
Example #3
0
def sync(garmin_username, garmin_password, trainerroad_username,
         trainerroad_password, fromdate, todate, no_upload, verbose):
    def verbose_print(s):
        if verbose:
            if no_upload:
                sys.stderr.write(s)
            else:
                sys.stdout.write(s)

    # Withings API
    withings = WithingsAccount()

    startdate = int(time.mktime(fromdate.timetuple()))
    enddate = int(time.mktime(todate.timetuple())) + 86399

    groups = withings.getMeasurements(startdate=startdate, enddate=enddate)

    # create fit file
    verbose_print('generating fit file...\n')
    fit = FitEncoder_Weight()
    fit.write_file_info()
    fit.write_file_creator()

    last_dt = None
    last_weight = 0

    for group in groups:
        # get extra physical measurements

        dt = group.get_datetime()
        weight = group.get_weight()
        fat_ratio = group.get_fat_ratio()
        muscle_mass = group.get_muscle_mass()
        hydration = group.get_hydration()
        bone_mass = group.get_bone_mass()

        fit.write_device_info(timestamp=dt)
        fit.write_weight_scale(timestamp=dt,
                               weight=weight,
                               percent_fat=fat_ratio,
                               percent_hydration=(hydration * 100.0 /
                                                  weight) if
                               (hydration and weight) else None,
                               bone_mass=bone_mass,
                               muscle_mass=muscle_mass)
        verbose_print('appending weight scale record... %s %skg %s%%\n' %
                      (dt, weight, fat_ratio))
        last_dt = dt
        last_weight = weight
    fit.finish()

    # garmin connect

    if trainerroad_username and last_weight > 0:
        print('Trainerroad username set -- attempting to sync')
        print(" Last weight {}".format(last_weight))
        print(" Measured {}".format(last_dt))

        tr = trainerroad.TrainerRoad(trainerroad_username,
                                     trainerroad_password)
        tr.connect()
        print("Current TrainerRoad weight: {} kg ".format(tr.weight))
        print("Updating TrainerRoad weight to {} kg".format(last_weight))
        tr.weight = round(last_weight, 1)
        tr.disconnect()
        print("TrainerRoad update done!\n")

    else:
        print('No Trainerroad username or a new measurement - skipping sync')

    if no_upload:
        sys.stdout.buffer.write(fit.getvalue())
        return

    if garmin_username:
        garmin = GarminConnect()
        session = garmin.login(garmin_username, garmin_password)
        verbose_print('attempting to upload fit file...\n')
        r = garmin.upload_file(fit.getvalue(), session)
        if r:
            print("Fit file uploaded to Garmin Connect")
    else:
        print('No Garmin username - skipping sync\n')
Example #4
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()
Example #5
0
def sync(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 len(garmin_username) == 0 or len(garmin_password) == 0:
        print("Garmin username or password not set!")
        return

    # Withings API
    withings = WithingsAccount()

    startdate = int(time.mktime(fromdate.timetuple()))
    enddate = int(time.mktime(todate.timetuple())) + 86399

    groups = withings.getMeasurements(startdate=startdate, enddate=enddate)

    # create fit file
    verbose_print('generating fit file...\n')
    fit = FitEncoder_Weight()
    fit.write_file_info()
    fit.write_file_creator()

    for group in groups:
        # get extra physical measurements

        dt = group.get_datetime()
        weight = group.get_weight()
        fat_ratio = group.get_fat_ratio()
        muscle_mass = group.get_muscle_mass()
        hydration = group.get_hydration()
        bone_mass = group.get_bone_mass()

        fit.write_device_info(timestamp=dt)
        fit.write_weight_scale(timestamp=dt,
                               weight=weight,
                               percent_fat=fat_ratio,
                               percent_hydration=(hydration * 100.0 /
                                                  weight) if
                               (hydration and weight) else None,
                               bone_mass=bone_mass,
                               muscle_mass=muscle_mass)
        verbose_print('appending weight scale record... %s %skg %s%%\n' %
                      (dt, weight, fat_ratio))
    fit.finish()

    if no_upload:
        sys.stdout.buffer.write(fit.getvalue())
        return

    #out_file = open('test.fit', 'wb')
    #out_file.write(fit.getvalue())

    # verbose_print("Fit file: " + fit.getvalue())

    # garmin connect
    garmin = GarminConnect()
    session = garmin.login(garmin_username, garmin_password)
    verbose_print('attempting to upload fit file...\n')
    r = garmin.upload_file(fit.getvalue(), session)
    if r:
        print("Fit file uploaded to Garmin Connect")
def sync(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 len(garmin_username) == 0 or len(garmin_password) == 0:
		print("Garmin username or password not set!")
		return
		
	
	# Withings API
	withings = WithingsAccount()

	startdate = int(time.mktime(fromdate.timetuple()))
	enddate = int(time.mktime(todate.timetuple())) + 86399

	groups = withings.getMeasurements(startdate=startdate, enddate=enddate)

	# create fit file
	verbose_print('generating fit file...\n')
	fit = FitEncoder_Weight()
	fit.write_file_info()
	fit.write_file_creator()

	for group in groups:
		# get extra physical measurements

		dt = group.get_datetime()
		weight = group.get_weight()
		fat_ratio = group.get_fat_ratio()
		muscle_mass = group.get_muscle_mass()
		hydration = group.get_hydration()
		bone_mass = group.get_bone_mass()

		fit.write_device_info(timestamp=dt)
		fit.write_weight_scale(timestamp=dt,
			weight=weight,
			percent_fat=fat_ratio,
			percent_hydration=(hydration*100.0/weight) if (hydration and weight) else None,
			bone_mass=bone_mass,
			muscle_mass=muscle_mass
			)
		verbose_print('appending weight scale record... %s %skg %s%%\n' % (dt, weight, fat_ratio))
	fit.finish()

	if no_upload:
		sys.stdout.buffer.write(fit.getvalue())
		return

	#out_file = open('test.fit', 'wb')
	#out_file.write(fit.getvalue())

	# verbose_print("Fit file: " + fit.getvalue())

	# garmin connect
	garmin = GarminConnect()
	session = garmin.login(garmin_username, garmin_password)
	verbose_print('attempting to upload fit file...\n')
	r = garmin.upload_file(fit.getvalue(), session)
	if r:
		print("Fit file uploaded to Garmin Connect")
    else:
        print(
            "You must provide the name of the service to setup. Available services are: nokia, garmin, smashrun."
        )
        sys.exit(1)

    if service == 'garmin':

        # Do not repeatidly sync the same value
        if config.has_option('garmin', 'last_sync'):
            if m.date.timestamp == int(config.get('garmin', 'last_sync')):
                print('Last measurement was already synced')
                sys.exit(0)

        # create fit file
        fit = FitEncoder_Weight()
        fit.write_file_info()
        fit.write_file_creator()
        fit.write_device_info(timestamp=m.date.timestamp)
        fit.write_weight_scale(timestamp=m.date.timestamp, weight=weight)

        fit.finish()

        garmin = GarminConnect()
        session = garmin.login(config.get('garmin', 'username'),
                               config.get('garmin', 'password'))
        r = garmin.upload_file(fit.getvalue(), session)
        if r:
            print('Weight has been successfully updated to Garmin!')
            config.set('garmin', 'last_sync', str(m.date.timestamp))
def mqtt_on_message(client, userdata, msg):
    logger.info(f'Received payload: {msg.payload}')
    try:
        data = json.loads(msg.payload)
    except json.decoder.JSONDecodeError:
        logger.error('Could not parse JSON, ignoring')
        return

    # At this point, the payload is valid: let's ack
    mqttPub.single(
        config['mqtt']['topic_ack'],
        payload="1",  # TODO: hard-coded, leave as is or ok?
        hostname=config['mqtt']['host'],
        port=config['mqtt']['port'],
        auth={
            'username': config['mqtt']['username'],
            'password': config['mqtt']['password']
        })

    # Has this entry been processed before? (MQTT messages are retained)
    if check_entry_already_processed(data):
        logger.info('Data is stale, ignoring')
        return
    else:
        logger.info('Data looks fresh, continuing')

    height = float(config['garmin']['height'])

    # Weight has to be within the 10kg-200kg range. Metrics calculation will
    # fail if not within that range. Probably a bogus measurement anyway. Just
    # move on.
    weight = float(data.get('Weight', 0))
    if not weight or not 10 < weight < 200:
        logger.error('No weight data or weight value bogus, ignoring')
        return

    # Compute metrics if both weight and impedance are present.
    # Weight is already checked, additional check for impedance.
    if data.get('Impedance'):
        metrics = bodyMetrics(
            weight=weight,
            height=height,
            age=float(
                (datetime.date.today() - config['garmin']['dateOfBirth']).days
                / 365.25),
            sex=config['garmin']['sex'],
            impedance=float(data['Impedance']))

    dtFormat = '%Y %m %d %H %M %S'
    try:
        dt = datetime.datetime.strptime(data.get('Timestamp'), dtFormat)
    except (TypeError, ValueError):
        # Cannot parse timestamp. Assuming measurement was done just now.
        dt = datetime.datetime.now()

    # Data dict prep
    metrics_dict = {
        'timestamp': dt,
        'weight': metrics.weight,
        'bmi': metrics.getBMI(),
        'percent_fat': metrics.getFatPercentage(),
        'percent_hydration': metrics.getWaterPercentage(),
        'visceral_fat_mass': metrics.getVisceralFat(),
        'bone_mass': metrics.getBoneMass(),
        'muscle_mass': metrics.getMuscleMass(),
        'basal_met': metrics.getBMR(),
    }

    # Prepare Garmin data object
    fit = FitEncoder_Weight()
    fit.write_file_info()
    fit.write_file_creator()
    fit.write_device_info(timestamp=dt)
    if metrics:
        fit.write_weight_scale(**metrics_dict)
    else:
        fit.write_weight_scale(timestamp=dt,
                               weight=metrics.weight,
                               bmi=weight / (height / 100)**2)
    fit.finish()

    # Local save: HA sensor file (file contains the last entry and that's it)
    with open(config['last_meas'], 'w') as fp:
        json.dump(metrics_dict, fp, default=str)

    # Local save: full history
    try:
        with open(config['full_meas'], 'r') as fp:
            full_meas = json.load(fp)
    except FileNotFoundError:
        full_meas = dict(entries=[])

    if not any(entry['timestamp'] == metrics_dict.pop('timestamp', None)
               for entry in full_meas['entries']):
        new_entry = {'timestamp': dt, 'data': metrics_dict}
        full_meas['entries'].append(new_entry)
        with open(config['full_meas'], 'w') as fp:
            json.dump(full_meas, fp, indent=4, default=str)

    garmin = GarminConnect()
    try:
        garminSession = garmin.login(config['garmin']['username'],
                                     config['garmin']['password'])
    except (requests.exceptions.ConnectionError, APIException):
        logger.error('Could not connect to Garmin Connect')
        return

    req = garmin.upload_file(fit.getvalue(), garminSession)
    if req:
        logger.info('Upload to Garmin succeeded')
    else:
        logger.info('Upload to Garmin failed')

    # Local save: last timestamp info (for `check_entry_already_processed`)
    with open(config['last_ts'], 'w') as fp:
        json.dump(data, fp)
Example #9
0
    'physique_rating': None,
}

for key, value in values.iteritems():
    values[key] = raw_float('Enter %s: ' % key.replace('_', ' '))

if (values['weight'] and values['percent_fat'] and values['muscle_mass']
        and not values['bone_mass']):
    calc_bone_mass = raw_input('Approximate bone mass'
                               ' from other settings? (y/N) ')
    if calc_bone_mass == 'y':
        fat_weight = values['weight'] * values['percent_fat'] / 100
        calculated = values['weight'] - values['muscle_mass'] - fat_weight
        values['bone_mass'] = max(0, calculated)

timestamp = raw_input('Time (e.g. 2015-01-31-23-01): ')
try:
	values['timestamp'] = datetime.strptime(timestamp, '%Y-%m-%d-%H-%M')
except:
        print '- Date not recognized, defaulting to now'
	values['timestamp'] = datetime.now()

fit = FitEncoder_Weight()
fit.write_weight_scale(**values)
fit.finish()

a = open('weight-scale_%s.fit' %
         values['timestamp'].strftime('%Y-%m-%d-%H-%M'), 'w')

a.write(fit.get_value())
Example #10
0
#    'visceral_fat_mass': None,
#    'visceral_fat_rating': None,
#    'physique_rating': None,
}

if len(sys.argv) > 2:
    timestamp = sys.argv[2]
else:
    values['timestamp'] = datetime.now()
try:
        values['timestamp'] = datetime.strptime(timestamp, '%Y-%m-%d-%H-%M')
except:
        print('- Date not recognized, defaulting to now')
        values['timestamp'] = datetime.now()

fit = FitEncoder_Weight()
fit.write_file_info()
fit.write_file_creator()
fit.write_weight_scale(**values)
fit.finish()

if garmin_username:
    garmin = GarminConnect()
    session = garmin.login(garmin_username, garmin_password)
    print(session)
    print('attempting to upload fit file...')
    r = garmin.upload_file(fit.getvalue(), session)
    print(r)
    if r:
        print('Fit file uploaded to Garmin Connect')
    else:
Example #11
0
def sync(withings_username, withings_password, withings_shortname,
         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)

    # Withings API
    withings = WithingsAccount(withings_username, withings_password)
    user = withings.get_user_by_shortname(withings_shortname)
    if not user:
        print 'could not find user: %s' % withings_shortname
        return
    if not user.ispublic:
        print 'user %s has not opened withings data' % withings_shortname
        return
    startdate = int(time.mktime(fromdate.timetuple()))
    enddate = int(time.mktime(todate.timetuple())) + 86399
    groups = user.get_measure_groups(startdate=startdate, enddate=enddate)

    # create fit file
    verbose_print('generating fit file...\n')
    fit = FitEncoder_Weight()
    fit.write_file_info()
    fit.write_file_creator()

    for group in groups:
        # get extra physical measurements

        from measurements import Measurements 
        measurements = Measurements()
    
        dt = group.get_datetime()
        weight = group.get_weight()
        fat_ratio = group.get_fat_ratio()
        fit.write_device_info(timestamp=dt)
        fit.write_weight_scale(timestamp=dt, 
            weight=weight, 
            percent_fat=fat_ratio, 
            percent_hydration=measurements.getPercentHydration()
            )
        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

    # garmin connect
    garmin = GarminConnect()
    cookie = garmin.login(garmin_username, garmin_password)
    verbose_print('attempting to upload fit file...\n')
    r = garmin.upload_file(fit.getvalue(), cookie)
    if r:
        verbose_print('weight.fit has been successfully uploaded!\n')
Example #12
0
            raise GenerateError('invalid username or password')
        raise
    if not user:
        raise GenerateError('could not find user: %s' % shortname)
    if not user.ispublic:
        raise GenerateError('user %s has not opened withings data' % shortname)

    startdate = strtotimestamp(request.form.get('startdate'))
    enddate = strtotimestamp(request.form.get('enddate'))
    if enddate:
        enddate += 86399  # 11:59:59
    groups = user.get_measure_groups(startdate=startdate, enddate=enddate)
    if len(groups) == 0:
        raise GenerateError('no weight scale data is available')

    fit = FitEncoder_Weight()
    fit.write_file_info()
    fit.write_file_creator()

    for group in groups:
        dt = group.get_datetime()
        weight = group.get_weight()
        fat_ratio = group.get_fat_ratio()
        fit.write_device_info(timestamp=dt)
        fit.write_weight_scale(timestamp=dt, weight=weight, percent_fat=fat_ratio)
    fit.finish()
    fit.buf.seek(0)
    return fit.buf

def strtotimestamp(s):
    try:
        next_sync = groups[-1].date.timestamp

        # Do not repeatidly sync the same value
        if next_sync == last_sync:
            print('Last measurement was already synced')
            save_config()
            sys.exit(0)

        # Get height for BMI calculation
        height = None
        m = client_nokia.get_measures(limit=1, meastype=types['height'])
        if len(m):
            height = m[0].get_measure(types['height'])

        # create fit file
        fit = FitEncoder_Weight()

        fit.write_file_info()
        fit.write_file_creator()

        fit.write_device_info(timestamp=next_sync)
        for m in groups:
            weight = m.get_measure(types['weight'])
            if weight:
                hyd_percent = None
                fat = None
                bone = None
                muscle = None
                if m.get_measure(types['fat_ratio']):
                    fat = m.get_measure(types['fat_ratio'])
Example #14
0
def sync(withings_username, withings_password, withings_shortname,
         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)

    # Withings API
    withings = WithingsAccount(withings_username, withings_password)
    user = withings.get_user_by_shortname(withings_shortname)
    if not user:
        print 'could not find user: %s' % withings_shortname
        return
    if not user.ispublic:
        print 'user %s has not opened withings data' % withings_shortname
        return
    startdate = int(time.mktime(fromdate.timetuple()))
    enddate = int(time.mktime(todate.timetuple())) + 86399
    groups = user.get_measure_groups(startdate=startdate, enddate=enddate)

    # 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.get_datetime()
        weight = group.get_weight()
        fat_ratio = group.get_fat_ratio()
        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

    # garmin connect
    garmin = GarminConnect()
    garmin.login(garmin_username, garmin_password)
    verbose_print('attempting to upload fit file...\n')
    r = garmin.upload_file(fit.getvalue())
    if r:
        verbose_print('weight.fit has been successfully uploaded!\n')
Example #15
0
def nokia_sync(force=False):
    config = get_config()

    n = config['nokia']
    creds = NokiaCredentials(n['access_token'], n['token_expiry'],
                             n['token_type'], n['refresh_token'], n['user_id'],
                             n['client_id'], n['consumer_secret'])

    nokia_client = NokiaApi(creds, refresh_cb=nokia_refresh_cb)

    measures = nokia_client.get_measures()
    measure = measures[0]

    logger.info('Recieved {} measurements'.format(len(measures)))

    # Now check if we need to update
    last_update = max([m.date.timestamp for m in measures])

    logger.info('Last measurement at {}'.format(last_update))
    logger.info('Last update at {}'.format(config['nokia']['last_update']))

    if (config['nokia']['last_update'] >= last_update) and not force:
        logger.info('No new weight updates')
        return measures

    msg = ''

    fit = FitEncoder_Weight()
    fit.write_file_info()
    fit.write_file_creator()
    fit.write_device_info(datetime.timestamp(datetime.now()))

    for measure in measures:
        if (config['nokia']['last_update'] < measure.date.timestamp) or force:

            if measure.weight is not None:
                bmi = measure.weight / config['nokia']['height']**2

                msg += 'New measurement at {} ({})\n'.format(
                    str(measure.date.datetime), measure.date.humanize())

                msg += 'New weight = {} kg\n'.format(measure.weight)
                msg += 'New fat ratio= {} %\n'.format(measure.fat_ratio)
                msg += 'New hydration = {} %\n'.format(measure.hydration)
                msg += 'New bone mass = {} kg\n'.format(measure.bone_mass)
                msg += 'New muscle mass = {} kg\n'.format(measure.muscle_mass)
                msg += 'Calculated BMI = {} kg.m^-2\n'.format(bmi)

                for m in msg.splitlines():
                    logger.info(m)

                # Sync Garmin

                logger.info('Syncing weight of {} with GARMIN.'.format(
                    measure.weight))

                fit.write_weight_scale(timestamp=measure.date.timestamp,
                                       weight=measure.weight,
                                       percent_fat=measure.fat_ratio,
                                       percent_hydration=measure.hydration,
                                       bone_mass=measure.bone_mass,
                                       muscle_mass=measure.muscle_mass,
                                       bmi=bmi)

    fit.finish()

    with GarminClient(config['garmin']['username'],
                      config['garmin']['password']) as client:
        client.upload_activity(io.BytesIO(fit.getvalue()), 'fit')

    # Sync Strava

    measure = measures[0]
    ts = datetime.timestamp(datetime.now())
    ts -= (config['nokia']['weight_int'] * 86400)
    weight = [m.weight for m in measures if m.date.timestamp >= ts]

    logger.info("Averaging {} weight measurements".format(len(weight)))

    weight = mean(weight)

    if (config['nokia']['last_update'] != measure.date.timestamp) or force:
        logger.info('Syncing weight of {} with STRAVA.'.format(measure.weight))
        strava = Strava(config['strava'])
        strava_token = strava.connect()
        config['strava'] = strava_token
        strava.client.update_athlete(weight=weight)

        msg += 'Synced weight of {} with Strava\n'.format(measure.weight)

    config = get_config()
    config['nokia']['last_update'] = max([m.date.timestamp for m in measures])
    write_config(config)

    send_email('New Weight Sync', msg)

    return measures