Ejemplo n.º 1
0
def get_weight(creds):
    client = NokiaApi(creds)

    # Refresh credentials if necessary
    # creds = client.get_credentials()

    # http://developer.withings.com/oauth2/#tag/measure%2Fpaths%2Fhttps%3A~1~1wbsapi.withings.net~1measure%3Faction%3Dgetmeas%2Fget
    # lastupdate for syncing...
    # 'timezone': 'America/Los_Angeles',
    # 'updatetime': <Arrow [2018-10-12T08:14:44+00:00]>}

    measures = client.get_measures(meastype=1,
                                   category=1,
                                   lastupdate=1534748400)  # limit=1)
    for measure in measures:
        '''
    pprint(vars(measure))
    pprint('---')
    pprint(vars(measures))
    sys.exit()
    '''

        pprint(measure.date)
        pprint(measure.weight)
        print()
Ejemplo n.º 2
0
def pull_withings_data():
    # UTC dates will get sampled into daily
    if withings_connected():
        client = NokiaApi(nokia_creds(current_token_dict()),
                          refresh_cb=save_withings_token)
        df = pd.DataFrame(
            [measure.__dict__ for measure in client.get_measures()])
        df['date_utc'] = df['date'].apply(lambda x: datetime.strptime(
            str(x.format('YYYY-MM-DD HH:mm:ss')), '%Y-%m-%d %H:%M:%S'))
        df = df.drop(columns=['date'])
        df = df.set_index(df['date_utc'])
        df = df[['weight', 'fat_ratio', 'hydration']]
        # Convert to lbs
        df['weight'] *= 2.20462

        # Filter to days later than what is already in db
        session, engine = db_connect()
        withings_max_date = session.query(func.max(
            withings.date_utc)).first()[0]
        withings_max_date = datetime.strptime(
            '1991-08-30 00:00:00', '%Y-%m-%d %H:%M:%S'
        ) if not withings_max_date else withings_max_date
        engine.dispose()
        session.close()

        df = df[(df.index > withings_max_date) & (~np.isnan(df['weight'])) &
                (~np.isnan(df['fat_ratio']))]
        if len(df) > 0:
            dash_app.server.logger.info('New withings measurements found!')
            df.to_sql('withings', engine, if_exists='append', index=True)
Ejemplo n.º 3
0
 def test_attributes(self):
     """ Make sure the NokiaApi objects have the right attributes """
     assert hasattr(NokiaApi, 'URL')
     creds = NokiaCredentials(user_id='FAKEID')
     api = NokiaApi(creds)
     assert hasattr(api, 'credentials')
     assert hasattr(api, 'oauth')
     assert hasattr(api, 'client')
Ejemplo n.º 4
0
 def test_attributes(self):
     """ Make sure the NokiaApi objects have the right attributes """
     assert hasattr(NokiaApi, 'URL')
     creds = NokiaCredentials(user_id='FAKEID', token_expiry='123412341234')
     api = NokiaApi(creds)
     assert hasattr(api, 'credentials')
     assert hasattr(api, 'token')
     assert hasattr(api, 'client')
     assert hasattr(api, 'refresh_cb')
Ejemplo n.º 5
0
 def test_attribute_defaults(self):
     """
     Make sure NokiaApi object attributes have the correct defaults
     """
     self.assertEqual(NokiaApi.URL, 'https://api.health.nokia.com')
     creds = NokiaCredentials(user_id='FAKEID')
     api = NokiaApi(creds)
     self.assertEqual(api.credentials, creds)
     self.assertEqual(api.client.auth, api.oauth)
     self.assertEqual(api.client.params, {'userid': creds.user_id})
Ejemplo n.º 6
0
 def __init__(self, config):
     """Initialize the data object."""
     from nokia import NokiaApi, NokiaCredentials
     credentials = NokiaCredentials(config.get("access_token"),
                                    config.get("access_token_secret"),
                                    config.get("consumer_key"),
                                    config.get("consumer_secret"),
                                    config.get("user_id"))
     self._api = NokiaApi(credentials)
     self.data = None
     self._update()
Ejemplo n.º 7
0
 def test_attribute_defaults(self):
     """
     Make sure NokiaApi object attributes have the correct defaults
     """
     self.assertEqual(NokiaApi.URL, 'https://api.health.nokia.com')
     creds = NokiaCredentials(user_id='FAKEID', token_expiry='123412341234')
     api = NokiaApi(creds)
     self.assertEqual(api.credentials, creds)
     self.assertEqual(api.client.params, {})
     self.assertEqual(api.client.token, api.token)
     self.assertEqual(api.refresh_cb, None)
Ejemplo n.º 8
0
def withings_connected():
    token_dict = current_token_dict()
    try:
        if token_dict:
            creds = nokia_creds(token_dict)
            client = NokiaApi(credentials=creds,
                              refresh_cb=save_withings_token)
            measures = client.get_measures(limit=1)
            dash_app.server.logger.debug('Withings Connected')
            return True
    except BaseException as e:
        dash_app.server.logger.error('Withings not connected')
        dash_app.server.logger.error(e)
        return False
Ejemplo n.º 9
0
 def setUp(self):
     self.mock_api = True
     if self.mock_api:
         self.creds = NokiaCredentials()
     else:
         config = configparser.ConfigParser()
         config.read('nokia.conf')
         self.creds = NokiaCredentials(
             consumer_key=config.get('nokia', 'consumer_key'),
             consumer_secret=config.get('nokia', 'consumer_secret'),
             access_token=config.get('nokia', 'access_token'),
             access_token_secret=config.get('nokia', 'access_token_secret'),
             user_id=config.get('nokia', 'user_id'))
     self.api = NokiaApi(self.creds)
Ejemplo n.º 10
0
    def __init__(self, smarthome, consumer_key, consumer_secret, access_token, access_token_secret, user_id, cycle=300):
        self.logger = logging.getLogger(__name__)
        self._sh = smarthome
        self._consumer_key = consumer_key
        self._consumer_secret = consumer_secret
        self._access_token = access_token
        self._access_token_secret = access_token_secret
        self._auth = NokiaAuth(self._consumer_key, self._consumer_secret)
        self._user_id = user_id
        self._creds = NokiaCredentials(self._access_token, self._access_token_secret, self._consumer_key,
                                       self._consumer_secret, self._user_id)
        self._client = NokiaApi(self._creds)

        self._cycle = cycle
        self._items = {}

        if not self.init_webinterface():
            self._init_complete = False
Ejemplo n.º 11
0
def refresh_weight(cfg_file, engine, db_df):
    print("REFRESHING WEIGHT...")
    parser = configparser.ConfigParser()
    parser.read(cfg_file)
    client_id = parser.get('nokia', 'client_id')
    client_secret = parser.get('nokia', 'client_secret')
    access_token = parser.get('nokia', 'access_token')
    token_expiry = parser.get('nokia', 'token_expiry')
    token_type = parser.get('nokia', 'token_type')
    refresh_token = parser.get('nokia', 'refresh_token')
    user_id = parser.get('nokia', 'user_id')

    creds = NokiaCredentials(access_token=access_token,
                             token_expiry=token_expiry,
                             token_type=token_type,
                             refresh_token=refresh_token,
                             user_id=user_id,
                             client_id=client_id,
                             consumer_secret=client_secret)
    client = NokiaApi(
        creds, refresh_cb=(lambda x: persist_nokia_refresh_token(x, cfg_file)))

    [date_start, date_end] = get_target_date_endpoints('weight', db_df)
    date_query = date_start
    date_diff = date_end - date_query
    days = date_diff.days + 2

    measures = client.get_measures(meastype=1, limit=days)
    weight_json = [{
        'weight': (float("{:.1f}".format(x.weight * 2.20462))),
        'date': x.date.strftime('%Y-%m-%d')
    } for x in measures]
    date_values = [[pd.to_datetime(x['date']), x['weight']]
                   for x in weight_json]
    date_values_imp = [[pd.to_datetime(x['date']), np.nan]
                       for x in weight_json]
    updated_df = insert_values(date_values, 'weight', db_df)
    updated_df = insert_values(date_values_imp, 'weight_imputed', updated_df)

    with engine.connect() as conn, conn.begin():
        updated_df.to_sql('fitness', conn, if_exists='replace')

    return updated_df
Ejemplo n.º 12
0
    def test_set_token_refresh_cb(self):
        """
        Make sure set_token calls refresh_cb when specified
        """
        timestamp = int((datetime.datetime.utcnow() -
                         datetime.datetime(1970, 1, 1)).total_seconds())
        creds = NokiaCredentials(token_expiry=timestamp)
        refresh_cb = MagicMock()
        api = NokiaApi(creds, refresh_cb=refresh_cb)
        token = {
            'access_token': 'fakeat',
            'refresh_token': 'fakert',
            'expires_in': 100,
        }

        api.set_token(token)

        self.assertEqual(api.token, token)
        refresh_cb.assert_called_once_with(token)
Ejemplo n.º 13
0
    def test_set_token(self):
        """
        Make sure NokiaApi.set_token makes the expected changes
        """
        timestamp = int((datetime.datetime.utcnow() -
                         datetime.datetime(1970, 1, 1)).total_seconds())
        creds = NokiaCredentials(token_expiry=timestamp)
        api = NokiaApi(creds)
        token = {
            'access_token': 'fakeat',
            'refresh_token': 'fakert',
            'expires_in': 100,
        }

        api.set_token(token)

        self.assertEqual(api.token, token)
        self.assertEqual(api.get_credentials().access_token, 'fakeat')
        self.assertEqual(api.get_credentials().refresh_token, 'fakert')
        # Need to check 100 or 101 in case a second ticked over during testing
        self.assertTrue(
            int(api.credentials.token_expiry) == (timestamp + 100)
            or int(api.credentials.token_expiry) == (timestamp + 101))
Ejemplo n.º 14
0
 def __init__(self):
     try:
         with open('personal_dashboard/nokia_data.pkl',
                   'rb') as pickle_file:
             nokia = pickle.load(pickle_file)
             self.measures = nokia.get_measures()
             measures = nokia.get_measures(limit=1)
             self.weight = round(float(measures[0].weight) * 2.20462, 2)
             pickle_file.close()
     except:
         auth = NokiaAuth(WITHINGS_KEYS['API_KEY'],
                          WITHINGS_KEYS['API_SECRET'])
         authorize_url = auth.get_authorize_url()
         print("Go to %s allow the app and copy your oauth_verifier" %
               authorize_url)
         oauth_verifier = input('Please enter your oauth_verifier: ')
         creds = auth.get_credentials(oauth_verifier)
         client = NokiaApi(creds)
         with open('personal_dashboard/nokia_data.pkl', 'wb') as output:
             pickle.dump(client, output, pickle.HIGHEST_PROTOCOL)
         self.measures = client.get_measures()
         measures = client.get_measures(limit=1)
         #Convert Kg to Lbs
         self.weight = round(float(measures[0].weight) * 2.20462, 2)
Ejemplo n.º 15
0
 def setUp(self):
     self.mock_api = True
     creds_attrs = [
         'access_token',
         'token_expiry',
         'token_type',
         'refresh_token',
         'user_id',
         'client_id',
         'consumer_secret',
     ]
     if self.mock_api:
         creds_args = {a: 'fake' + a for a in creds_attrs}
         creds_args.update({
             'token_expiry': '123412341234',
             'token_type': 'Bearer',
         })
         self.creds = NokiaCredentials(**creds_args)
     else:
         config = configparser.ConfigParser()
         config.read('nokia.conf')
         creds_args = {a: config.get('nokia', a) for a in creds_attrs}
         self.creds = NokiaCredentials(**creds_args)
     self.api = NokiaApi(self.creds)
 def _add_device(creds):
     client = NokiaApi(creds)
     nokia = NokiaSensor(hass, client)
     yield from nokia.async_update()
     return async_add_devices([nokia])
Ejemplo n.º 17
0
 def _add_device(creds):
     client = NokiaApi(creds)
     withings = WithingsSensor(hass, client)
     yield from withings.async_update()
     return async_add_devices([withings])
Ejemplo n.º 18
0
    def _update(self):
        """
        Updates information on diverse items
        Mappings:
        ('weight', 1),
        ('height', 4),
        ('fat_free_mass', 5),
        ('fat_ratio', 6),
        ('fat_mass_weight', 8),
        ('diastolic_blood_pressure', 9),
        ('systolic_blood_pressure', 10),
        ('heart_pulse', 11),
        ('temperature', 12),
        ('spo2', 54),
        ('body_temperature', 71),
        ('skin_temperature', 72),
        ('muscle_mass', 76),
        ('hydration', 77),
        ('bone_mass', 88),
        ('pulse_wave_velocity', 91)
        """

        if 'access_token' not in self.get_items(
        ) or 'token_expiry' not in self.get_items(
        ) or 'token_type' not in self.get_items(
        ) or 'refresh_token' not in self.get_items():
            self.logger.error(
                "Plugin '{}': Mandatory Items for OAuth2 Data do not exist. Verify that you have items with withings_type: token_expiry, token_type, refresh_token and access_token in your item tree."
                .format(self.get_fullname()))
            return

        if self._client is None:
            if self.get_item('access_token')(
            ) and self.get_item('token_expiry')() > 0 and self.get_item(
                    'token_type')() and self.get_item('refresh_token')():

                if (self.shtime.now() < datetime.datetime.fromtimestamp(
                        self.get_item('token_expiry')(),
                        tz=self.shtime.tzinfo())):
                    self.logger.debug(
                        "Plugin '{}': Token is valid, will expire on {}.".
                        format(
                            self.get_fullname(),
                            datetime.datetime.fromtimestamp(
                                self.get_item('token_expiry')(),
                                tz=self.shtime.tzinfo()).strftime(
                                    '%d.%m.%Y %H:%M:%S')))
                    self.logger.debug(
                        "Plugin '{}': Initializing NokiaCredentials: access_token - {} token_expiry - {} token_type - {} refresh_token - {} user_id - {} client_id - {} consumer_secret - {}"
                        .format(self.get_fullname(),
                                self.get_item('access_token')(),
                                self.get_item('token_expiry')(),
                                self.get_item('token_type')(),
                                self.get_item('refresh_token')(),
                                self._user_id, self._client_id,
                                self._consumer_secret))
                    self._creds = NokiaCredentials(
                        self.get_item('access_token')(),
                        self.get_item('token_expiry')(),
                        self.get_item('token_type')(),
                        self.get_item('refresh_token')(), self._user_id,
                        self._client_id, self._consumer_secret)
                    self._client = NokiaApi(self._creds,
                                            refresh_cb=self._store_tokens)
                else:
                    self.logger.error(
                        "Plugin '{}': Token is expired, run OAuth2 again from Web Interface (Expiry Date: {})."
                        .format(
                            self.get_fullname(),
                            datetime.datetime.fromtimestamp(
                                self.get_item('token_expiry')(),
                                tz=self.shtime.tzinfo()).strftime(
                                    '%d.%m.%Y %H:%M:%S')))
                    return
            else:
                self.logger.error(
                    "Plugin '{}': Items for OAuth2 Data are not set with required values. Please run process via WebGUI of the plugin."
                    .format(self.get_fullname()))
                return
        measures = self._client.get_measures()
        last_measure = measures[0]

        if last_measure.get_measure(
                11) is not None and 'heart_pulse' in self._items:
            self._items['heart_pulse'](last_measure.get_measure(11))
            self.logger.debug("Plugin '{}': heart_pulse - {}".format(
                self.get_fullname(), last_measure.get_measure(11)))

        # Bugfix for strange behavior of returning heart_pulse as seperate dataset..
        if last_measure.get_measure(1) is None:
            last_measure = measures[1]

        if last_measure.get_measure(1) is not None and 'weight' in self._items:
            self._items['weight'](last_measure.get_measure(1))
            self.logger.debug("Plugin '{}': weight - {}".format(
                self.get_fullname(), last_measure.get_measure(1)))

        if last_measure.get_measure(4) is not None and 'height' in self._items:
            self._items['height'](last_measure.get_measure(4))
            self.logger.debug("Plugin '{}': height - {}".format(
                self.get_fullname(), last_measure.get_measure(4)))

        if last_measure.get_measure(
                5) is not None and 'fat_free_mass' in self._items:
            self._items['fat_free_mass'](last_measure.get_measure(5))
            self.logger.debug("Plugin '{}': fat_free_mass - {}".format(
                self.get_fullname(), last_measure.get_measure(5)))

        if last_measure.get_measure(
                6) is not None and 'fat_ratio' in self._items:
            self._items['fat_ratio'](last_measure.get_measure(6))
            self.logger.debug("Plugin '{}': fat_ratio - {}".format(
                self.get_fullname(), last_measure.get_measure(6)))

        if last_measure.get_measure(
                8) is not None and 'fat_mass_weight' in self._items:
            self._items['fat_mass_weight'](last_measure.get_measure(8))
            self.logger.debug("Plugin '{}': fat_mass_weight - {}".format(
                self.get_fullname(), last_measure.get_measure(8)))

        if last_measure.get_measure(
                9) is not None and 'diastolic_blood_pressure' in self._items:
            self._items['diastolic_blood_pressure'](
                last_measure.get_measure(9))
            self.logger.debug(
                "Plugin '{}': diastolic_blood_pressure - {}".format(
                    self.get_fullname(), last_measure.get_measure(9)))

        if last_measure.get_measure(
                10) is not None and 'systolic_blood_pressure' in self._items:
            self._items['systolic_blood_pressure'](
                last_measure.get_measure(10))
            self.logger.debug(
                "Plugin '{}': systolic_blood_pressure - {}".format(
                    self.get_fullname(), last_measure.get_measure(10)))

        if last_measure.get_measure(
                11) is not None and 'heart_pulse' in self._items:
            self._items['heart_pulse'](last_measure.get_measure(11))
            self.logger.debug("Plugin '{}': heart_pulse - {}".format(
                self.get_fullname(), last_measure.get_measure(11)))

        if last_measure.get_measure(
                12) is not None and 'temperature' in self._items:
            self._items['temperature'](last_measure.get_measure(12))
            self.logger.debug("Plugin '{}': temperature - {}".format(
                self.get_fullname(), last_measure.get_measure(12)))

        if last_measure.get_measure(54) is not None and 'spo2' in self._items:
            self._items['spo2'](last_measure.get_measure(54))
            self.logger.debug("Plugin '{}': spo2 - {}".format(
                self.get_fullname(), last_measure.get_measure(54)))

        if last_measure.get_measure(
                71) is not None and 'body_temperature' in self._items:
            self._items['body_temperature'](last_measure.get_measure(71))
            self.logger.debug("Plugin '{}': body_temperature - {}".format(
                self.get_fullname(), last_measure.get_measure(71)))

        if last_measure.get_measure(
                72) is not None and 'skin_temperature' in self._items:
            self._items['skin_temperature'](last_measure.get_measure(72))
            self.logger.debug("Plugin '{}': skin_temperature - {}".format(
                self.get_fullname(), last_measure.get_measure(72)))

        if last_measure.get_measure(
                76) is not None and 'muscle_mass' in self._items:
            self._items['muscle_mass'](last_measure.get_measure(76))
            self.logger.debug("Plugin '{}': muscle_mass - {}".format(
                self.get_fullname(), last_measure.get_measure(76)))

        if last_measure.get_measure(
                77) is not None and 'hydration' in self._items:
            self._items['hydration'](last_measure.get_measure(77))
            self.logger.debug("Plugin '{}': hydration - {}".format(
                self.get_fullname(), last_measure.get_measure(77)))

        if last_measure.get_measure(
                88) is not None and 'bone_mass' in self._items:
            self._items['bone_mass'](last_measure.get_measure(88))
            self.logger.debug("Plugin '{}': bone_mass - {}".format(
                self.get_fullname(), last_measure.get_measure(88)))

        if last_measure.get_measure(
                91) is not None and 'pulse_wave_velocity' in self._items:
            self._items['pulse_wave_velocity'](last_measure.get_measure(91))
            self.logger.debug("Plugin '{}': pulse_wave_velocity - {}".format(
                self.get_fullname(), last_measure.get_measure(91)))

        if 'height' in self._items and (
                'bmi' in self._items or 'bmi_text'
                in self._items) and last_measure.get_measure(1) is not None:
            if self._items['height']() > 0:
                bmi = round(
                    last_measure.get_measure(1) /
                    ((self._items['height']()) * (self._items['height']())), 2)
                if 'bmi' in self._items:
                    self._items['bmi'](bmi)
                if 'bmi_text' in self._items:
                    if bmi < 16:
                        self._items['bmi_text']('starkes Untergewicht')
                    elif 16 <= bmi < 17:
                        self._items['bmi_text']('mäßiges Untergewicht ')
                    elif 17 <= bmi < 18.5:
                        self._items['bmi_text']('leichtes Untergewicht ')
                    elif 18.5 <= bmi < 25:
                        self._items['bmi_text']('Normalgewicht')
                    elif 25 <= bmi < 30:
                        self._items['bmi_text']('Präadipositas (Übergewicht)')
                    elif 30 <= bmi < 35:
                        self._items['bmi_text']('Adipositas Grad I')
                    elif 35 <= bmi < 40:
                        self._items['bmi_text']('Adipositas Grad II')
                    elif 40 <= bmi:
                        self._items['bmi_text']('Adipositas Grad III')
            else:
                self.logger.error(
                    "Plugin '{}': Cannot calculate BMI: height is 0, please set height (in m) for height item manually."
                    .format(self.get_fullname()))
        else:
            self.logger.error(
                "Plugin '{}': Cannot calculate BMI: height and / or bmi item missing."
                .format(self.get_fullname()))
Ejemplo n.º 19
0
 def test_get_credentials(self):
     """
     Make sure NokiaApi returns the credentials as expected
     """
     creds = NokiaCredentials(token_expiry=0)
     api = NokiaApi(creds)
Ejemplo n.º 20
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