示例#1
0
    def index(self,
              user=None,
              userData={},
              methods=None,
              token=None,
              callerToken=None,
              **kwargs):
        """Main entry point - get Fitbit data for a single user"""
        if not user:
            self.igor.app.raiseHTTPError(
                "400 Fitbitplugin requires user argument")
        self.user = user
        self.token = token
        if not 'token' in userData:
            self.igor.app.raiseHTTPError(
                "403 Fitbitplugin requires 'token' plugindata for user '%s'" %
                user)
        oauthSettings = userData['token']
        for k in KEYS_PER_USER:
            if not k in oauthSettings:
                self.igor.app.raiseHTTPError(
                    "403 Fitbitplugin 'token' plugindata for user '%s' misses '%s'"
                    % (user, k))
        for k in KEYS_PER_APP:
            if not k in self.pluginData:
                self.igor.app.raiseHTTPError(
                    "403 Fitbitplugin requires global plugindata '%s'" % k)
            oauthSettings[k] = self.pluginData[k]

        fb = Fitbit(refresh_cb=self._refresh, **oauthSettings)

        # Populate kwargs from userData, unless already specified in the parameters
        for k, v in list(userData.items()):
            if k != 'token' and k != 'methods' and not k in kwargs:
                kwargs[k] = v
        # Convert to strings (fitbit library doesn't like unicode)
        for k, v in list(kwargs.items()):
            kwargs[k] = v

        results = {}
        if methods == None:
            methods = userData.get('methods', 'get_bodyweight')
        methods = methods.split(',')
        for method in methods:
            if DEBUG: print('xxxjack calling method', method, 'with', kwargs)
            m = getattr(fb, method)
            try:
                item = m(**kwargs)
            except oauthlib.oauth2.rfc6749.errors.OAuth2Error as ex:
                descr = ex.description
                if not descr:
                    descr = str(ex)
                self.igor.app.raiseHTTPError("502 Fitbit OAuth2 error: %s" %
                                             descr)
            except Exception as ex:
                print('Exception in fitbit.%s with args %s' %
                      (method, repr(kwargs)))
                traceback.print_exc(file=sys.stdout)
                self.igor.app.raiseHTTPError("502 fitbit error %s" % repr(ex))
            if DEBUG: print("xxxjack method", method, "returned", m)
            results.update(item)

        self.igor.databaseAccessor.put_key('sensors/%s/%s' %
                                           (self.pluginName, user),
                                           'application/x-python-object',
                                           None,
                                           results,
                                           'application/x-python-object',
                                           token,
                                           replace=True)
        return str(results)
示例#2
0
def setup_platform(
    opp: OpenPeerPower,
    config: ConfigType,
    add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Set up the Fitbit sensor."""
    config_path = opp.config.path(FITBIT_CONFIG_FILE)
    if os.path.isfile(config_path):
        config_file: ConfigType = cast(ConfigType, load_json(config_path))
        if config_file == DEFAULT_CONFIG:
            request_app_setup(opp,
                              config,
                              add_entities,
                              config_path,
                              discovery_info=None)
            return
    else:
        save_json(config_path, DEFAULT_CONFIG)
        request_app_setup(opp,
                          config,
                          add_entities,
                          config_path,
                          discovery_info=None)
        return

    if "fitbit" in _CONFIGURING:
        opp.components.configurator.request_done(_CONFIGURING.pop("fitbit"))

    access_token: str | None = config_file.get(ATTR_ACCESS_TOKEN)
    refresh_token: str | None = config_file.get(ATTR_REFRESH_TOKEN)
    expires_at: int | None = config_file.get(ATTR_LAST_SAVED_AT)
    if (access_token is not None and refresh_token is not None
            and expires_at is not None):
        authd_client = Fitbit(
            config_file.get(CONF_CLIENT_ID),
            config_file.get(CONF_CLIENT_SECRET),
            access_token=access_token,
            refresh_token=refresh_token,
            expires_at=expires_at,
            refresh_cb=lambda x: None,
        )

        if int(time.time()) - expires_at > 3600:
            authd_client.client.refresh_token()

        unit_system = config.get(CONF_UNIT_SYSTEM)
        if unit_system == "default":
            authd_client.system = authd_client.user_profile_get(
            )["user"]["locale"]
            if authd_client.system != "en_GB":
                if opp.config.units.is_metric:
                    authd_client.system = "metric"
                else:
                    authd_client.system = "en_US"
        else:
            authd_client.system = unit_system

        dev = []
        registered_devs = authd_client.get_devices()
        clock_format = config.get(CONF_CLOCK_FORMAT, DEFAULT_CLOCK_FORMAT)
        for resource in config.get(CONF_MONITORED_RESOURCES,
                                   FITBIT_DEFAULT_RESOURCES):

            # monitor battery for all linked FitBit devices
            if resource == "devices/battery":
                for dev_extra in registered_devs:
                    dev.append(
                        FitbitSensor(
                            authd_client,
                            config_path,
                            resource,
                            opp.config.units.is_metric,
                            clock_format,
                            dev_extra,
                        ))
            else:
                dev.append(
                    FitbitSensor(
                        authd_client,
                        config_path,
                        resource,
                        opp.config.units.is_metric,
                        clock_format,
                    ))
        add_entities(dev, True)

    else:
        oauth = FitbitOauth2Client(config_file.get(CONF_CLIENT_ID),
                                   config_file.get(CONF_CLIENT_SECRET))

        redirect_uri = f"{get_url(opp)}{FITBIT_AUTH_CALLBACK_PATH}"

        fitbit_auth_start_url, _ = oauth.authorize_token_url(
            redirect_uri=redirect_uri,
            scope=[
                "activity",
                "heartrate",
                "nutrition",
                "profile",
                "settings",
                "sleep",
                "weight",
            ],
        )

        opp.http.register_redirect(FITBIT_AUTH_START, fitbit_auth_start_url)
        opp.http.register_view(
            FitbitAuthCallbackView(config, add_entities, oauth))

        request_oauth_completion(opp)
示例#3
0
def run_api_poller():
    cfg_path = try_getenv('CONFIG_PATH')
    db_host = try_getenv('DB_HOST')
    db_port = try_getenv('DB_PORT')
    db_user = try_getenv('DB_USER')
    db_password = try_getenv('DB_PASSWORD')
    db_name = try_getenv('DB_NAME')
    redirect_url = try_getenv('CALLBACK_URL')
    units = try_getenv('UNITS', 'it_IT')

    # These are required vars, that we first  try to load from file
    client_id = try_load_var(cfg_path, 'client_id')
    client_secret = try_load_var(cfg_path, 'client_secret')
    access_token = try_load_var(cfg_path, 'access_token')
    refresh_token = try_load_var(cfg_path, 'refresh_token')
    expires_at = try_load_var(cfg_path, 'expires_at')

    # If any of the required vars is not in file, try to read from env
    # If read, save
    if not client_id:
        client_id = try_getenv('CLIENT_ID')
        save_var(cfg_path, 'client_id', client_id)
    if not client_secret:
        client_secret = try_getenv('CLIENT_SECRET')
        save_var(cfg_path, 'client_secret', client_secret)
    if not access_token:
        access_token = try_getenv('ACCESS_TOKEN')
        save_var(cfg_path, 'access_token', access_token)
    if not refresh_token:
        refresh_token = try_getenv('REFRESH_TOKEN')
        save_var(cfg_path, 'refresh_token', refresh_token)
    if not expires_at:
        expires_at = try_cast_to_int(try_getenv('EXPIRES_AT'))
        save_var(cfg_path, 'expires_at', str(expires_at))

    logger.debug(
        "client_id: %s, client_secret: %s, access_token: %s, refresh_token: %s, expires_at: %s",
        client_id, client_secret, access_token, refresh_token, expires_at)

    if not client_id:
        logging.critical("client_id missing, aborting!")
        sys.exit(1)
    if not client_secret:
        logging.critical("client_secret missing, aborting!")
        sys.exit(1)
    if not access_token:
        logging.critical("access_token missing, aborting!")
        sys.exit(1)
    if not refresh_token:
        logging.critical("refresh_token missing, aborting!")
        sys.exit(1)

    api_client = Fitbit(client_id=client_id,
                        client_secret=client_secret,
                        access_token=access_token,
                        refresh_token=refresh_token,
                        redirect_uri=redirect_url,
                        refresh_cb=partial(write_updated_credentials,
                                           cfg_path),
                        system=Fitbit.METRIC)

    user_profile = None
    while True:
        try:
            user_profile = api_client.user_profile_get()
            break
        except Timeout as ex:
            logger.warning('Request timed out, retrying in 15 seconds...')
            time.sleep(15)
        except HTTPServerError as ex:
            logger.warning(
                'Server returned exception (5xx), retrying in 15 seconds (%s)',
                ex)
            time.sleep(15)
        except HTTPTooManyRequests as ex:
            # 150 API calls done, and python-fitbit doesn't provide the retry-after header, so stop trying
            # and allow the limit to reset, even if it costs us one hour
            logger.info('API limit reached, sleeping for 3610 seconds!')
            time.sleep(3610)
        except Exception as ex:
            logger.exception('Got some unexpected exception')
            raise

    member_since = user_profile.get('user', {}).get('memberSince',
                                                    '1970-01-01')
    member_since_dt = parse(member_since, ignoretz=True)
    member_since_ts = parse(member_since, ignoretz=True).timestamp()
    logger.info('User is member since: %s (ts: %s)', member_since,
                member_since_ts)

    cur_day = datetime.utcnow()

    db_client = InfluxDBClient(db_host, db_port, db_user, db_password, db_name)
    for one_db in db_client.get_list_database():
        if one_db['name'] == db_name:
            break
    else:
        db_client.create_database(db_name)
    db_client.close()

    # First try to fill any gaps: between User_member_since and first_ts,
    # and then between last_ts and cur_day
    while True:
        for meas, series_list in BASE_SERIES.items():
            for series in series_list:
                resource = '{}/{}'.format(meas, series)
                if '_' in meas:
                    resource = resource.replace('_', '/', 1)
                if resource == 'sleep/sleep':
                    # Sleep is special, is its own main category
                    resource = 'sleep'

                db_client = InfluxDBClient(db_host, db_port, db_user,
                                           db_password, db_name)

                key_series = series
                if isinstance(series_list, dict) and series_list.get(series):
                    # Datapoints are retrieved with all keys in the same dict, so makes no sense to retrieve individual
                    # series names. Use one series as the key series.
                    key_series = series_list[series]['key_series']

                first_ts = get_first_timestamp_for_measurement(db_client,
                                                               meas,
                                                               key_series,
                                                               min_ts=cur_day)
                last_ts = get_last_timestamp_for_measurement(db_client,
                                                             meas,
                                                             key_series,
                                                             min_ts=cur_day)
                profile_to_first = int(
                    (first_ts - member_since_dt) / timedelta(days=1))
                last_to_current = int((cur_day - last_ts) / timedelta(days=1))
                logger.debug(
                    'key_series: %s, first_ts: %s, last_ts: %s, profile_to_first: %s, last_to_current: %s',
                    key_series, first_ts, last_ts, profile_to_first,
                    last_to_current)
                db_client.close()

                intervals_to_fetch = []
                if profile_to_first > 1:
                    append_between_day_series(intervals_to_fetch,
                                              member_since_dt, first_ts)
                if last_to_current > 1:
                    append_between_day_series(intervals_to_fetch, last_ts,
                                              cur_day)
                if not intervals_to_fetch:
                    logger.info(
                        'No gaps to fetch for %s, %s: fetching last day only',
                        meas, series)
                    intervals_to_fetch.append((
                        cur_day,
                        cur_day,
                    ))

                # DB can't be open here, because fitbit_fetch_datapoints can hang for a long time
                if meas == 'sleep':
                    api_client.API_VERSION = '1.2'
                datapoints = fitbit_fetch_datapoints(api_client, meas, series,
                                                     resource,
                                                     intervals_to_fetch)
                if meas == 'sleep':
                    api_client.API_ENDPOINT = '1'
                converted_dps = []
                for one_d in datapoints:
                    if not one_d:
                        continue
                    if isinstance(series_list,
                                  dict) and series_list.get(series):
                        new_dps = series_list[series]['transform'](one_d)
                        for one_dd in new_dps:
                            converted_dps.append(
                                create_api_datapoint_meas_series(
                                    one_dd['meas'], one_dd['series'],
                                    one_dd['value'], one_dd['dateTime']))
                    else:
                        converted_dps.append(
                            create_api_datapoint_meas_series(
                                meas, series, one_d.get('value'),
                                one_d.get('dateTime')))

                db_client = InfluxDBClient(db_host, db_port, db_user,
                                           db_password, db_name)
                precision = 'h'
                if meas == 'sleep':
                    precision = 's'
                logger.debug(
                    'Going to write %s points, key_series: %s, first_ts: %s, last_ts: %s, profile_to_first: %s, last_to_current: %s',
                    len(converted_dps), key_series, first_ts, last_ts,
                    profile_to_first, last_to_current)
                logger.debug('First 3: %s', converted_dps[:3])
                logger.debug('Last 3: %s', converted_dps[-3:])
                if not db_client.write_points(converted_dps,
                                              time_precision=precision,
                                              batch_size=2500):
                    logger.critical(
                        'key_series: %s, first_ts: %s, last_ts: %s, profile_to_first: %s, last_to_current: %s',
                        key_series, first_ts, last_ts, profile_to_first,
                        last_to_current)
                    raise Exception('Unable to write points!')
                db_client.close()
        logger.info('All series processed, sleeping for 4h')
        time.sleep(3610 * 4)

    sys.exit(0)
示例#4
0
 def setUp(self):
     self.fb = Fitbit('x', 'y')
示例#5
0
    def setUp(self):
        self.fb = Fitbit('x', 'y')
        self.fb_timeout = Fitbit('x', 'y', timeout=10)

        self.test_url = 'invalid://do.not.connect'
示例#6
0
def run():
    client_id, client_secret = _get_client_details()
    access_token, refresh_token, expires_at = _get_user_details()

    # print(f'Running Fitbit request with details: {client_id} {client_secret}'
    #      f' {access_token} {refresh_token} {expires_at}')
    auth2_client = Fitbit(client_id, client_secret, oauth2=True,
                          access_token=access_token,
                          refresh_token=refresh_token, expires_at=expires_at,
                          refresh_cb=refresh_callback)

    fitbit_url = FITBIT_API + _get_api_call(1)
    json_response = auth2_client.make_request(fitbit_url)
    _write_results(json_response,RESULT_FILE)

    length = len(json_response["activities-heart-intraday"]['dataset'])
    heart_min_data = json_response["activities-heart-intraday"]['dataset']    
    HR_hour_data = {} 
    HR_min_data = {} 
    for i in range(0,length):
        if(i%60 == 0):
            if heart_min_data[i]["time"].split(":")[0][0] == '0':
                HR_min_data[heart_min_data[i]["time"].split(":")[0][1]] = [heart_min_data[i]["value"]]
            else:
                HR_min_data[heart_min_data[i]["time"].split(":")[0]] = [heart_min_data[i]["value"]]
        else:
            if heart_min_data[i]["time"].split(":")[0][0] == '0':
                HR_min_data[heart_min_data[i]["time"].split(":")[0][1]].append(heart_min_data[i]["value"])
            else:
                HR_min_data[heart_min_data[i]["time"].split(":")[0]].append(heart_min_data[i]["value"])

    for i,j in HR_min_data.items():
        HR_hour_data[i] = int(sum(j)/len(j))
        
    print(HR_hour_data)
    
    fitbit_url = FITBIT_API + _get_api_call(2)
    json_response = auth2_client.make_request(fitbit_url)
    _write_results(json_response,RESULT_FILE2)

    sleep_data = {}
    for i in json_response["sleep"]:
        sleep_data[i['dateOfSleep']]= i['minutesAsleep']

    print(sleep_data)

    fitbit_url = FITBIT_API + _get_api_call(3)
    json_response = auth2_client.make_request(fitbit_url)
    _write_results(json_response,RESULT_FILE3)

    calories = {}
    for date in json_response["activities-log-calories"]:
        calories[date['dateTime']]= int(date['value'])
    print(calories)
    print(json_response)


    fitbit_url = FITBIT_API + _get_api_call(4)
    json_response = auth2_client.make_request(fitbit_url)
    _write_results(json_response,RESULT_FILE4)
    
    steps_date = {}
    weekly_steps = {}
    print(json_response["activities-log-steps"])
    for date in json_response["activities-log-steps"]:
        steps_date[date['dateTime']]= int(date['value'])
    print(steps_date)

    for i in steps_date:
            if i != 0:
                date = i
                weekday = datetime.datetime.strptime(date, '%Y-%m-%d').weekday()
                weekly_steps[weekdays[weekday]] = steps_date[i]
    print(weekly_steps)
示例#7
0
def setup_platform(
    hass: HomeAssistant,
    config: ConfigType,
    add_entities: AddEntitiesCallback,
    discovery_info: DiscoveryInfoType | None = None,
) -> None:
    """Set up the Fitbit sensor."""
    config_path = hass.config.path(FITBIT_CONFIG_FILE)
    if os.path.isfile(config_path):
        config_file: ConfigType = cast(ConfigType, load_json(config_path))
        if config_file == DEFAULT_CONFIG:
            request_app_setup(hass,
                              config,
                              add_entities,
                              config_path,
                              discovery_info=None)
            return
    else:
        save_json(config_path, DEFAULT_CONFIG)
        request_app_setup(hass,
                          config,
                          add_entities,
                          config_path,
                          discovery_info=None)
        return

    if "fitbit" in _CONFIGURING:
        hass.components.configurator.request_done(_CONFIGURING.pop("fitbit"))

    access_token: str | None = config_file.get(ATTR_ACCESS_TOKEN)
    refresh_token: str | None = config_file.get(ATTR_REFRESH_TOKEN)
    expires_at: int | None = config_file.get(ATTR_LAST_SAVED_AT)
    if (access_token is not None and refresh_token is not None
            and expires_at is not None):
        authd_client = Fitbit(
            config_file.get(CONF_CLIENT_ID),
            config_file.get(CONF_CLIENT_SECRET),
            access_token=access_token,
            refresh_token=refresh_token,
            expires_at=expires_at,
            refresh_cb=lambda x: None,
        )

        if int(time.time()) - expires_at > 3600:
            authd_client.client.refresh_token()

        if (unit_system := config[CONF_UNIT_SYSTEM]) == "default":
            authd_client.system = authd_client.user_profile_get(
            )["user"]["locale"]
            if authd_client.system != "en_GB":
                if hass.config.units.is_metric:
                    authd_client.system = "metric"
                else:
                    authd_client.system = "en_US"
        else:
            authd_client.system = unit_system

        registered_devs = authd_client.get_devices()
        clock_format = config[CONF_CLOCK_FORMAT]
        monitored_resources = config[CONF_MONITORED_RESOURCES]
        entities = [
            FitbitSensor(
                authd_client,
                config_path,
                description,
                hass.config.units.is_metric,
                clock_format,
            ) for description in FITBIT_RESOURCES_LIST
            if description.key in monitored_resources
        ]
        if "devices/battery" in monitored_resources:
            entities.extend([
                FitbitSensor(
                    authd_client,
                    config_path,
                    FITBIT_RESOURCE_BATTERY,
                    hass.config.units.is_metric,
                    clock_format,
                    dev_extra,
                ) for dev_extra in registered_devs
            ])
        add_entities(entities, True)
示例#8
0
# if args['debug']:
#     logging.basicConfig(level = logging.DEBUG)
# else:
#     logging.basicConfig(level=logging.INFO)

# set up connection to INDX
# password = getpass.getpass()
# indx = IndxClient(args['address'], args['box'], args['user'], args['passwd'], "Fitbit Connector")

# set up connection to Fitbit
consumer_key = "9cc7928d03fa4e1a92eda0d01ede2297"
consumer_secret = "340ea36a974e47738a335c0cccfe1fcf"

# fitbit = Fitbit(consumer_key, consumer_secret, access_token_key, access_token_secret)
fitbit = Fitbit(consumer_key, consumer_secret)
if (fitbit.token == None):
    gotourl = fitbit.get_token_url()
    pin = raw_input("Please input you PIN: ")
    fitbit.get_token_with_pin(pin)

fitbit_min = FitbitIntraDay(fitbit)

# def get_fitbit_data():
# 	from_date = args['from_date']
# 	to_date = args['to_date']
# 	print '\nget activities tracker steps:\n'
# 	return fitbit_ts.get_activities_tracker_steps(to_date, from_date)


def transform_fitbit_response(response):
def setup_platform(hass, config, add_entities, discovery_info=None):
    """Set up the Fitbit sensor."""
    config_path = hass.config.path(config.get(CONF_FILENAME))
    name = config.get(CONF_NAME)
    configuring_name = "fitbit" if name is None else "fitbit_" + name

    if os.path.isfile(config_path):
        config_file = load_json(config_path)
        if config_file == DEFAULT_CONFIG:
            request_app_setup(hass,
                              config,
                              add_entities,
                              config_path,
                              discovery_info=None)
            return False
    else:
        save_json(config_path, DEFAULT_CONFIG)
        request_app_setup(hass,
                          config,
                          add_entities,
                          config_path,
                          discovery_info=None)
        return False

    if configuring_name in _CONFIGURING:
        hass.components.configurator.request_done(
            _CONFIGURING.pop(configuring_name))

    access_token = config_file.get(ATTR_ACCESS_TOKEN)
    refresh_token = config_file.get(ATTR_REFRESH_TOKEN)
    expires_at = config_file.get(ATTR_LAST_SAVED_AT)
    if None not in (access_token, refresh_token):
        authd_client = Fitbit(
            config_file.get(CONF_CLIENT_ID),
            config_file.get(CONF_CLIENT_SECRET),
            access_token=access_token,
            refresh_token=refresh_token,
            expires_at=expires_at,
            refresh_cb=lambda x: None,
        )

        if int(time.time()) - expires_at > 3600:
            authd_client.client.refresh_token()

        unit_system = config.get(CONF_UNIT_SYSTEM)
        if unit_system == "default":
            authd_client.system = authd_client.user_profile_get(
            )["user"]["locale"]
            if authd_client.system != "en_GB":
                if hass.config.units.is_metric:
                    authd_client.system = "metric"
                else:
                    authd_client.system = "en_US"
        else:
            authd_client.system = unit_system

        dev = []
        registered_devs = authd_client.get_devices()
        clock_format = config.get(CONF_CLOCK_FORMAT)
        for resource in config.get(CONF_MONITORED_RESOURCES):

            # monitor battery for all linked FitBit devices
            if resource == "devices/battery":
                for dev_extra in registered_devs:
                    dev.append(
                        FitbitSensor(
                            authd_client,
                            config_path,
                            resource,
                            name,
                            hass.config.units.is_metric,
                            clock_format,
                            dev_extra,
                        ))
            else:
                dev.append(
                    FitbitSensor(
                        authd_client,
                        config_path,
                        resource,
                        name,
                        hass.config.units.is_metric,
                        clock_format,
                    ))
        add_entities(dev, True)

    else:
        oauth = FitbitOauth2Client(config_file.get(CONF_CLIENT_ID),
                                   config_file.get(CONF_CLIENT_SECRET))

        redirect_uri = f"{get_url(hass, prefer_external=True)}{FITBIT_AUTH_CALLBACK_PATH}"

        fitbit_auth_start_url, _ = oauth.authorize_token_url(
            redirect_uri=redirect_uri,
            scope=[
                "activity",
                "heartrate",
                "nutrition",
                "profile",
                "settings",
                "sleep",
                "weight",
            ],
        )

        hass.http.register_redirect(FITBIT_AUTH_START, fitbit_auth_start_url)
        hass.http.register_view(
            FitbitAuthCallbackView(config, add_entities, oauth))

        request_oauth_completion(hass, configuring_name)
示例#10
0
 def setUp(self):
     self.fb = Fitbit(consumer_key='x', consumer_secret='y')