示例#1
0
文件: main.py 项目: kcinnick/fitnick
def get_heart_rate_zone_today():
    """
    Endpoint for getting heart rate zone data from the FitBit API.
    :return:
    """
    heart_rate_zone = HeartRateTimeSeries(config={'database': 'fitbit'})
    form = DateForm(request.form)
    value = 'Updated heart rate zone data for {}.'

    search_date = str(date.today())

    if request.method == 'POST':
        if request.form.get(
                'year_options'
        ):  # set search_date, default to today if none supplied
            search_date = f"{request.form['year_options']}-{request.form['month_options']}-{request.form['day_options']}"
        # collect search date information from the dropdown forms if they're all supplied.
        rows = heart_rate_zone.get_heart_rate_zone_for_day(
            database='fitbit', target_date=search_date)
        rows = [i for i in rows]
    else:  # request.method == 'GET'
        # no date supplied, just return data for today.
        heart_rate_zone.config = {'base_date': date.today(), 'period': '1d'}
        statement = heart_daily_table.select().where(
            heart_daily_table.columns.date == str(date.today()))
        rows = Database(database='fitbit',
                        schema='heart').engine.execute(statement)

    return render_template(template_name_or_list="index.html",
                           value=value.format(search_date),
                           rows=rows,
                           form=form,
                           month_options=month_options,
                           day_options=day_options,
                           year_options=year_options)
示例#2
0
    def get_heart_rate_zone_for_day(self,
                                    database: str = 'fitbit',
                                    target_date: str = 'today'):
        """
        Retrieves heart rate data for one day only.
        This method should not be used to add batch data - i.e., iterating
        through a list of dates is likely to trigger rate limit errors.
        :param database: Database to insert into.
        :param target_date: Date to retrieve heart rate zone data for.
        :return:
        """
        if target_date != 'today':
            self.config.update({
                'base_date': target_date,
                'end_date': target_date,
                'database': database
            })
        else:
            today = date.today().strftime('%Y-%m-%d')
            self.config.update({
                'base_date': today,
                'end_date': today,
                'database': database
            })

        db = Database(database=database, schema=self.config['schema'])
        rows = self.insert_data(db, table=heart_daily_table)

        return rows
示例#3
0
def check_if_steps_need_update(base_date='2021-01-01'):
    activity_api = Activity(config={'base_date': base_date})
    response = activity_api.query_daily_activity_summary()
    steps_total = response['summary']['steps']
    #  get steps in db

    database = Database('fitbit', 'activity')
    connection = database.engine.connect()
    response = connection.execute(
        "select * from activity.steps_intraday where date = '{}'".format(
            base_date)).fetchall()
    steps_intraday = 0
    for result in response:
        steps_intraday += result[2]

    if steps_total != steps_intraday:
        match = False
        msg = '\nSteps total does not equal steps intraday.\nNeed to rerun get_steps for {}'.format(
            base_date)
        comparison = '\nSteps total: {}\nSteps intraday: {}'.format(
            steps_total, steps_intraday)
        print(msg)
        print(comparison)
    else:
        match = True
        msg = '\nSteps total matches steps intraday.'
        print(msg)

    return match
示例#4
0
    def insert_data(self):
        """
        Extracts, transforms & loads the data specified by the self.config dict.
        :return:
        """

        data = self.query()
        parsed_rows = self.parse_response(data)
        db = Database(self.config['database'], schema=self.config['schema'])
        session = sessionmaker(bind=db.engine)()
        for row in parsed_rows:
            insert_statement = insert(bodyfat_table).values(
                date=row.date,
                fat=row.fat,
                logid=row.logId,
                source=row.source,
                time=row.time
            )
            try:
                session.execute(insert_statement)
                session.commit()
            except IntegrityError:  # record already exists
                pass

        session.close()
示例#5
0
def get_avg_steps_over_last_week(period='7d'):
    database = Database('fitbit', 'activity')
    end_date = datetime.today()
    start_date = end_date - timedelta(days=period)
    database = Database('fitbit', 'activity')
    connection = database.engine.connect()
    response = connection.execute(f"""
SELECT date, SUM(STEPS)
	FROM activity.steps_intraday
	WHERE DATE between '{start_date}' and '{end_date}'
	GROUP BY date
	ORDER BY date DESC
        """).fetchall()
    steps = []
    for i in response:
        steps.append(i[1])
    print(sum(steps))
    return
示例#6
0
    def get_total_calories_df(self, show=True):
        """
        Sums calories for all days in heart_daily_table.
        :param show: if True, displays the dataframe in addition to returning it.
        :return:
        """
        from fitnick.database.database import Database
        from pyspark.sql import functions as F

        database = Database(self.config['database'], schema='heart')
        database.create_spark_session()
        df = database.get_df_from_db('daily')
        agg_df = (df.groupBy(F.col('date')).agg(
            F.sum('calories')).alias('calories')).orderBy('date')

        if show:
            agg_df.show()

        return agg_df
示例#7
0
def test_insert_steps_intraday():
    activity = Activity(
        config={'database': 'fitbit_test',
                'table': 'calories',
                'sum_column': 'total',
                'base_date': '2020-12-26'
                }
    )
    database = Database('fitbit_test', 'activity')
    response = activity.insert_steps_intraday(database)
示例#8
0
def test_insert_intraday_steps():
    database = Database('fitbit_test', 'activity')
    connection = database.engine.connect()

    connection.execute(steps_intraday_table.delete())
    activity = Activity(
        config={'database': 'fitbit_test',
                'base_date': '2020-10-01'}
    )
    rows = activity.insert_log_data(database, EXPECTED_DAILY_ACTIVITY_ROWS)
    assert len(rows) == 5
示例#9
0
文件: main.py 项目: kcinnick/fitnick
def get_heart_rate_zone_rows(heart_rate_zone):
    statement = heart_daily_table.select().where(
        heart_daily_table.columns.date == str(date.today()))
    rows = [
        i for i in Database(database='fitbit', schema='heart').engine.execute(
            statement)
    ]
    #  retrieve rows for today already in database, if there are none then get rows via fitnick
    if len(rows) == 0:
        rows = heart_rate_zone.get_heart_rate_zone_for_day(database='fitbit')

    return rows
示例#10
0
def batch_load_steps(start_date='2020-01-01', end_date='2021-01-01'):
    start_date = date(2021, 1, 1)  # start date
    database = Database('fitbit', 'activity')
    # end_date = set_batch_end_date(database, start_date)
    end_date = date(2021, 1, 6)  # end date
    delta = end_date - start_date  # as timedelta
    activity_api = Activity(config={'base_date': ''})

    for i in tqdm(list(reversed(range(delta.days + 1)))):
        day = start_date + timedelta(days=i)
        activity_api.config['base_date'] = day
        response = activity_api.insert_steps_intraday(database)
        print(response)
示例#11
0
def test_backfill_calories():
    database = Database('fitbit_test', 'activity')
    connection = database.engine.connect()
    activity = Activity(
        config={'database': 'fitbit_test'}
    )

    connection.execute(calories_table.delete())
    rows = [i for i in connection.execute(calories_table.select())]
    assert len(rows) == 0

    activity.backfill_calories(3)
    assert len([i for i in connection.execute(calories_table.select())]) == 3
示例#12
0
def test_query_sleep_data():
    database = Database('fitbit_test', 'sleep')
    connection = database.engine.connect()

    connection.execute(sleep_summary_table.delete())

    sleep_data = SleepTimeSeries(
        config={
            'database': 'fitbit_test',
            'base_date': '2020-09-05',
            'end_date': '2020-09-05'
        }).batch_query_sleep_data()

    assert sleep_data == EXPECTED_API_RESPONSE
示例#13
0
    def backfill(self, period: int = 90):
        """
        Backfills a database from the current day.
        Example: if run on 2020-09-06 with period=90, the database will populate for 2020-06-08 - 2020-09-06
        :param period: Number of days to look backward.
        :return:
        """
        self.config['base_date'] = (
            date.today() - timedelta(days=period)).strftime('%Y-%m-%d')
        self.config['end_date'] = date.today().strftime('%Y-%m-%d')

        database = Database(database=self.config['database'],
                            schema=self.config['schema'])
        self.insert_data(database=database, table=self.config['table'])
示例#14
0
def test_insert_calorie_data():
    database = Database('fitbit_test', 'activity')
    connection = database.engine.connect()

    connection.execute(calories_table.delete())
    activity = Activity(
        config={'database': 'fitbit_test',
                'base_date': '2020-10-01'}
    )
    raw_data = activity.query_calorie_summary()
    row = activity.parse_calorie_summary('2020-10-01', raw_data)
    inserted_row = activity.insert_calorie_data(database, row)

    assert inserted_row == Calories(date='2020-10-01', total=3116, calories_bmr=1838, activity_calories=1467)
示例#15
0
def test_check_for_duplicates():
    """
    Useful for asserting that there aren't duplicates in the database, which *should* be avoided in the code.
    """
    database = Database('fitbit_test', 'heart')
    connection = database.engine.connect()

    HeartRateTimeSeries(config={
        'base_date': '2020-09-02',
        'period': '1d',
        'database': 'fitbit_test'
    }).insert_data(database, heart_daily_table)

    results = connection.execute(heart_daily_table.select().where(
        heart_daily_table.columns.date == '2020-09-02'))

    assert len([result for result in results]) == 4
    connection.close()
示例#16
0
    def get_calories_for_day(self, day='2020-10-22'):
        """
        Given a YYYY-MM-DD formatted string, retrieves calorie data from the FitBit API
        and inserts it into the database specified by the config.
        :param day: str, day to get calorie data for
        :return:
        """
        from fitnick.database.database import Database

        self.config.update({'base_date': day})

        raw_calorie_summary = self.query_calorie_summary()
        row = self.parse_calorie_summary(self.config['base_date'],
                                         raw_calorie_summary)
        database = Database(self.config['database'], 'activity')
        self.insert_calorie_data(database, row)

        return row
示例#17
0
def test_insert_weight_data():
    from fitnick.body.models.weight import weight_table

    database = Database('fitbit_test', 'weight')
    connection = database.engine.connect()

    connection.execute(weight_table.delete())

    WeightTimeSeries(config={
        'database': 'fitbit_test',
        'base_date': '2020-09-05',
        'period': '1d'
    }).insert_data(database, weight_table)

    rows = [row for row in connection.execute(weight_table.select())]
    connection.close()

    assert sorted(rows) == sorted(EXPECTED_WEIGHT_DATA)
示例#18
0
def test_insert_sleep():
    """
    Deletes & re-inserts data, then asserts the data was inserted as expected.
    :return:
    """
    database = Database('fitbit_test', 'sleep')
    connection = database.engine.connect()

    connection.execute(sleep_summary_table.delete())

    SleepTimeSeries(
        config={
            'database': 'fitbit_test',
            'base_date': '2020-09-05',
            'end_date': '2020-09-10'
        }).insert_data(database)

    rows = [row for row in connection.execute(sleep_summary_table.select())]
    assert len(rows) == 6
示例#19
0
def test_insert_bodyfat():
    """
    Deletes & re-inserts data, then asserts the data was inserted as expected.
    :return:
    """
    database = Database('fitbit_test', 'bodyfat')
    connection = database.engine.connect()

    connection.execute(bodyfat_table.delete())

    BodyFat(
        config={
            'database': 'fitbit_test',
            'base_date': '2020-09-05',
            'period': '1d',
            'table': 'daily'
        }).insert_data()

    rows = [row for row in connection.execute(bodyfat_table.select())]
    assert len(rows) == 1
示例#20
0
    def insert_intraday_data(self):
        """
        Extracts, transforms & loads the intraday data specified by the self.config dict.
        :return:
        """

        data = self.query()
        parsed_rows = self.parse_intraday_response(
            date=self.config['base_date'], intraday_response=data)
        db = Database(self.config['database'], schema=self.config['schema'])

        # create a session connected to the database in config
        session = sessionmaker(bind=db.engine)()

        for row in tqdm(parsed_rows):
            session.add(row)
            session.commit()

        session.close()

        return parsed_rows