Git Product home page Git Product logo

fitly's Introduction

Fit.ly

Web analytics for endurance athletes Image description Image description Image description Image description Image description Image description Image description Image description Image description

Special thanks to Slapdash for helping organize! https://github.com/ned2/slapdash

Installation Methods

Docker (Recommended)

docker create --name=fitly \
    --restart unless-stopped \
    -e MODULE_NAME=src.fitly.app \
    -e VARIABLE_NAME=server \
    -e TZ=America/New_York \
    -e TIMEOUT=1200 \
    -e DASH_DEBUG=true \
    -p 8050:80 \
    -v <local mount path>:/app/config \
    ethanopp/fitly:latest

Python IDE

After cloning/downloading the repository, install Fit.ly into your environment:

$ pip install -e PATH_TO_fitly

Configuring Your App

Edit the config.ini.example file on your local mount path with your settings (more information below) and change the name of the file to config.ini.

Required Data Sources

Strava

Copy your client key and secret into your config.ini file.

In your strava settings (https://www.strava.com/settings/api) set the autorization callback to 127.0.0.1:8050?strava. All other fields you can update as you'd like.

Optional data sources

Some charts will not work unless these data sources are provided, or until new data sources are added that can pull similar data

Oura

The oura connections is currently required to generate the home page.

In addition to the home page, data points from oura will be use to make performance analytics more accurate. If oura data is not provided, performance analytics will rely on statically defined metrics in the athlete table (i.e. resting heartrate)

Create a developer account at https://cloud.ouraring.com/oauth/applications

Copy your client key and secret into your config.ini file.

Set the redirect URI to: http://127.0.0.1:8050/settings?oura

Withings

Sign up for a withings developer account here: https://account.withings.com/partner/dashboard_oauth2

In addition to the home page, data points from withings will be use to make performance analytics more accurate. If withings data is not provided, performance analytics will rely on statically defined metrics in the athlete table (i.e. weight)

Set the redirect URI to: http://127.0.0.1:8050/settings?withings

Copy your client key and secret into your config.ini file.

Stryd

Pull critical power (ftp) from Stryd. Since Stryd does not share their proprietary formula for calculating CP, we just pull the number rather than trying to recalculate it ourselves.

Enter username and password into config.ini file.

Peloton

Fitly does not pull workout data directly from peloton, strava is the main hub for our workout data (so sync peloton directly to strava).

For those working out to peloton classes, but not necessarily recording their data via the peloton device (using stryd pod on tread, using wahoo fitness trainer with peloton digital app, etc.), fitly will match workouts started around the same time to workouts published to strava, and update the titles of the strava workout with the peloton class name.

If using Oura, HRV recommendations can be used to auto-bookmark new classes on your peloton device daily. Class types to be bookmarked can be configured on the settings page (i.e. on days where HRV recommendation is "Low" effort, auto bookmark some new "Running" workouts of the class type "Fun Run", "Endurance Run", "Outdoor Fun Run", and "Outdoor Endurance Run")

Image description

Enter username and password into config.ini file.

Fitbod & Nextcloud

Fitbod allows exporting your data via the mobile app (Log > Settings icon > Export workout data)

Export your fitbod file to a nextcloud location, and provide that nextcloud location in your config.ini for fit.ly to incorporate into the dashboards.

Spotify

The spotify connections is currently required to generate the music page.

Fitly can keep a history of every song you listen to on spotify and analyze your listenind behavior (skipped, fast forwarded, rewound ,etc.) to determine song likeablity. Listening behavior can then be analyzed by activity type and intensity (i.e what music do you listen to during high intensity runs), clustered into music type (K-means cluster on spotify audio features) and playlists can be automatically generated with recommended music for your next recommended workout.

Create a developer account here: https://developer.spotify.com/dashboard/

Set the redirect URI to: http://127.0.0.1:8050/settings?spotify

Copy your client ID and secret into your config.ini file.

Dashboard startup

Navigate to http://127.0.0.1:8050/pages/settings

Enter the password from your config.ini [settings] password

Connect account buttons on top left of screen. Each successful authentication should save your tokens to the api_tokens table in your database.

Click the 'Refresh' button to pull data

Dashboard startup tips for python IDE users

Installing this package into your virtualenv will result into the development executable being installed into your path when the virtualenv is activated. This command invokes your Dash app's run_server method, which in turn uses the Flask development server to run your app. The command is invoked as follows:

$ run-fitly-dev

The script takes a couple of arguments optional parameters, which you can discover with the --help flag. You may need to set the port using the --port parameter. If you need to expose your app outside your local machine, you will want to set --host 0.0.0.0.

Hosting your application externally (docker compose with nginx)

version: '3'
services:
  letsencrypt:
    image: linuxserver/letsencrypt
    container_name: letsencrypt 
    cap_add:
      - NET_ADMIN
    restart: always
    ports:
      - "80:80"
      - "443:443"
    environment:
      - TZ=America/New_York
      - EMAIL=<your email>
      - URL=<website.com>
      - SUBDOMAINS=fit # this would give a website like fit.website.com
    volumes:
      - <host config dir>:/config
  fitly:
    image: ethanopp/fitly:latest
    container_name: fitly
    restart: always
    depends_on:
      - letsencrypt
    ports:
      - "8050:80"
    environment:
      - MODULE_NAME=src.fitly.app
      - VARIABLE_NAME=server
      - TZ=America/New_York
      - TIMEOUT=1200
      - DASH_DEBUG=true
    volumes:
      - <host config dir>:/app/config
      - <path to letsencrypt host config dir>/keys:/app/keys

NGINX (subdomain example)

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name fit.*;

    include /config/nginx/ssl.conf;

    client_max_body_size 0;

    # enable for ldap auth, fill in ldap details in ldap.conf
    #include /config/nginx/ldap.conf;

    location / {
        # enable the next two lines for http auth
        #auth_basic "Restricted";
        #auth_basic_user_file /config/nginx/.htpasswd;

        # enable the next two lines for ldap auth
        #auth_request /auth;
        #error_page 401 =200 /login;

        include /config/nginx/proxy.conf;
        resolver 127.0.0.11 valid=30s;
        set $upstream_fitly fitly;
        proxy_pass http://$upstream_fitly:80;
    }
}

fitly's People

Contributors

ethanopp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fitly's Issues

Trouble connecting oura

Hi, was having trouble trying to connect my oura account. I hit the 'connect oura' button on the setting page, I was redirected to the oura page to grant access to the app, I accept the grant, andwas redirected back the settings page, with the 'connect oura' button still there. In the debug output I see:

Exception on /_dash-update-component [POST]
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functionsrule.endpoint
File "/usr/local/lib/python3.7/site-packages/dash/dash.py", line 1076, in dispatch
response.set_data(func(*args, outputs_list=outputs_list))
File "/usr/local/lib/python3.7/site-packages/dash/dash.py", line 1007, in add_context
output_value = func(*args, **kwargs) # %% callback invoked %%
File "/app/src/fitly/pages/settings.py", line 1093, in update_tokens
oura_auth_client.fetch_access_token(parse_qs(query_params.query)['code'][0])
KeyError: 'code'

Turns out the callback url to fitly contained an additional "?" (after /settings?oura) and converting the second "?" to an "&" then re-submitting the callback url connected the oura account.

Not sure if there's anything you can do about it, but might help someone else if they see this.

Where do we use df_samples?

I want to import all my strava data into the tool (1500+ activities since 2007) so I'm trying to import a csv extract from http://flink.run

In the datapull.refresh_database function, I replace the strava API call:

activities = client.get_activities(after=after, limit=0)

By this snippet:

if strava_connected():
                            athlete_id = 1  # TODO: Make this dynamic if ever expanding to more users
                            client = get_strava_client()
                            after = config.get('strava', 'activities_after_date')

                            activities = []

                            with open('strava.csv', newline='') as strava_csv:
                                reader = csv.DictReader(strava_csv)
                                for row in reader:
                                    act = stravalib.model.Activity(
                                        name=row['name'],
                                        distance=float(row['distance']) if row['distance'] else 0,
                                        moving_time=timedelta(int(row['moving_time'])) if row['moving_time'] else 0,
                                        elapsed_time=int(row['elapsed_time']) if row['elapsed_time'] else 0,
                                        total_elevation_gain=float(row['total_elevation_gain']) if row['total_elevation_gain'] else 0,
                                        type=row['type'],
                                        workout_type=row['workout_type'],
                                        id=row['id'],
                                        ...etc...
                                        activities.append(act)

Now the problem is downstream, the df_samples make an API call to get the streams of activity. I'm still not clear of what these df_samples are used for. Can someone post a screenshot of where they are used in the UI?

I'm trying to think of ways I can import archive data without blowing up the API calls rate limit (100 per 15min). What am I loosing if I don't have any df_samples in the tool? What are they used for in terms of KPIs?

I believe the strength of any charting tool resides in the ability to draw models on past data.

Cycling Distance on Performance page fails to render

Hi!

On the Performance page, the lower right display fails to render any of the cycling options. Each one I select (distance, duration, HrSS, etc) results in the following being logged:

Exception on /_dash-update-component [POST] Traceback (most recent call last): File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app response = self.full_dispatch_request() File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request rv = self.handle_user_exception(e) File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception reraise(exc_type, exc_value, tb) File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise raise value File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request rv = self.dispatch_request() File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/usr/local/lib/python3.7/site-packages/dash/dash.py", line 1076, in dispatch response.set_data(func(*args, outputs_list=outputs_list)) File "/usr/local/lib/python3.7/site-packages/dash/dash.py", line 1007, in add_context output_value = func(*args, **kwargs) # %% callback invoked %% File "/app/src/fitly/pages/performance.py", line 3429, in update_yoy_chart figure, hoverData = create_yoy_chart(sport=sport, metric=metric) File "/app/src/fitly/pages/performance.py", line 1870, in create_yoy_chart line={'shape': 'spline', 'color': colors[index]}, IndexError: list index out of range
As always, happy to provide any additional info. Thanks!

sqlalchemy.exc.StatementError: (builtins.TypeError) SQLite Date type only accepts Python date objects as input.

Hello,

I think the commit 67bef5cbd62218a50a4bcb2e5af8c80b329deb3f breaks the build. When I deploy this version locally (run-fitly-dev) I cannot update the Birthday in settings anymore and get a callback error in the UI.

Steps to reproduce the issue:

(env) pierre@pierre-thinkpad:~/Workspace/fitly(master)$ rm config/fitness.db 
(env) pierre@pierre-thinkpad:~/Workspace/fitly(master)$ git checkout 67bef5cbd62218a50a4bcb2e5af8c80b329deb3f .
(env) pierre@pierre-thinkpad:~/Workspace/fitly(master)$ run-fitly-dev

I delete the db to make sure I'm using clean data, and that everything I'm as a first time user in the app works.

Go to settings and enter my birthday, click ok.
image
image

I also can reproduce this issue by cloning the repo again from scratch and deploying the app.

ImportError: cannot import name 'db_connect'

I think 6ca2f5463889c6ad09fda41c46d437863acfea9b leads to the below issue.

(env) pierre@pierre-thinkpad:~/Workspace/fitly(master)$ run-fitly-dev 
Traceback (most recent call last):
  File "/home/pierre/Workspace/fitly/env/bin/run-fitly-dev", line 11, in <module>
    load_entry_point('Fit.ly', 'console_scripts', 'run-fitly-dev')()
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/pkg_resources/__init__.py", line 480, in load_entry_point
    return get_distribution(dist).load_entry_point(group, name)
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2693, in load_entry_point
    return ep.load()
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2324, in load
    return self.resolve()
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/pkg_resources/__init__.py", line 2330, in resolve
    module = __import__(self.module_name, fromlist=['__name__'], level=0)
  File "/home/pierre/Workspace/fitly/src/fitly/dev_cli.py", line 5, in <module>
    from .app import app
  File "/home/pierre/Workspace/fitly/src/fitly/app.py", line 32, in <module>
    from . import index
  File "/home/pierre/Workspace/fitly/src/fitly/index.py", line 5, in <module>
    from .pages import home, lifting, performance, power, settings
  File "/home/pierre/Workspace/fitly/src/fitly/pages/settings.py", line 8, in <module>
    from ..api.ouraAPI import oura_connected, connect_oura_link, save_oura_token
  File "/home/pierre/Workspace/fitly/src/fitly/api/ouraAPI.py", line 2, in <module>
    from ..api.sqlalchemy_declarative import db_connect, db_insert, ouraReadinessSummary, ouraActivitySummary, \
ImportError: cannot import name 'db_connect'

error

Tried to run the docker container from Windows and from Linux both get this error. Any insight?

Checking for script in /app/prestart.sh

Running script /app/prestart.sh

Running inside /app/prestart.sh, you could add migrations to this file, e.g.:

#! /usr/bin/env bash

Let the DB start

sleep 10;

Run migrations

alembic upgrade head

{"loglevel": "info", "workers": 16, "bind": "0.0.0.0:80", "workers_per_core": 2.0, "host": "0.0.0.0", "port": "80"}

Traceback (most recent call last):

File "/usr/local/bin/gunicorn", line 8, in

sys.exit(run())

File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 58, in run

WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()

File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 228, in run

super().run()

File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 72, in run

Arbiter(self).run()

File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 58, in init

self.setup(app)

File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 118, in setup

self.app.wsgi()

File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi

self.callable = self.load()

File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 49, in load

return self.load_wsgiapp()

File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp

return util.import_app(self.app_uri)

File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 358, in import_app

mod = importlib.import_module(module)

File "/usr/local/lib/python3.7/importlib/init.py", line 127, in import_module

return _bootstrap._gcd_import(name[level:], package, level)

File "", line 1006, in _gcd_import

File "", line 983, in _find_and_load

File "", line 953, in _find_and_load_unlocked

File "", line 219, in _call_with_frames_removed

File "", line 1006, in _gcd_import

File "", line 983, in _find_and_load

File "", line 967, in _find_and_load_unlocked

File "", line 677, in _load_unlocked

File "", line 728, in exec_module

File "", line 219, in _call_with_frames_removed

File "/app/src/fitly/init.py", line 5, in

from .utils import get_dash_args_from_flask_config

File "/app/src/fitly/utils.py", line 167, in

local_tz = pytz.timezone(config.get('timezone', 'timezone'))

File "/usr/local/lib/python3.7/configparser.py", line 780, in get

d = self._unify_values(section, vars)

File "/usr/local/lib/python3.7/configparser.py", line 1146, in _unify_values

raise NoSectionError(section) from None

configparser.NoSectionError: No section: 'timezone'

Peloton Credentials Required? (error 401 on pelotonApi.get_class_type)

Are the peloton credentials required to use all the features of the app?
Either way, for some reason, the below exception in pelotonApi._create_api_session(cls) is never raised. I don't have any login/pwd for peloton in the config.

if cls.peloton_username is None or cls.peloton_password is None:
            raise PelotonClientError("The Peloton Client Library requires a `username` and `password` be set in "
                                     "`/.config/peloton, under section `peloton`")

Not sure how the "is None" is supposed to work but print(cls.peloton_username) outputs 2 spaces.

This leads to receiving an error 401 when making the API call for pelotonApi.get_class_types.

image

sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread

I use fitly with Oura & Strava credentials only.
When I do Settings > Truncate All I see what seems to be multithreading issues during the Strava import?

New Workout found: London
Exception during reset or similar
Traceback (most recent call last):
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/werkzeug/local.py", line 72, in __getattr__
    return self.__storage__[self.__ident_func__()][name]
KeyError: 139767122663168

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/sqlalchemy/pool/base.py", line 697, in _finalize_fairy
    fairy._reset(pool)
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/sqlalchemy/pool/base.py", line 893, in _reset
    pool._dialect.do_rollback(self)
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 543, in do_rollback
    dbapi_connection.rollback()
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 139767150724864 and this is thread id 139767122663168.
Exception closing connection <sqlite3.Connection object at 0x7f1e10b7dc70>
Traceback (most recent call last):
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/werkzeug/local.py", line 72, in __getattr__
    return self.__storage__[self.__ident_func__()][name]
KeyError: 139767122663168

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/sqlalchemy/pool/base.py", line 697, in _finalize_fairy
    fairy._reset(pool)
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/sqlalchemy/pool/base.py", line 893, in _reset
    pool._dialect.do_rollback(self)
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 543, in do_rollback
    dbapi_connection.rollback()
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 139767150724864 and this is thread id 139767122663168.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/sqlalchemy/pool/base.py", line 270, in _close_connection
    self._dialect.do_close(connection)
  File "/home/pierre/Workspace/fitly/env/lib/python3.6/site-packages/sqlalchemy/engine/default.py", line 549, in do_close
    dbapi_connection.close()
sqlite3.ProgrammingError: SQLite objects created in a thread can only be used in that same thread. The object was created in thread id 139767150724864 and this is thread id 139767122663168.
Inserting records into db_refresh...
Refresh Complete

It doesn't happen every time though.

Rolling window of strava activities?

Hi,

Curious if there's a way to configure a "rolling window" of strava activities, like optionally only keeping the past 13 months, as an example.

Thanks!

Dockerhub Image Plans

Hello,

Thanks for the great project! I was wondering if there are plans to push a finished image to docker hub to make running everything a lot easier?

Database refresh not refreshing

Hi! Having trouble refreshing the database. So far, I don't believe I've been able to import any data from any of the connected apps (strava, oura, or withings) I did pull the docker image tonight, so I'm on the latest code for this report

At first, when trying to refresh the database, I was getting a message to the effect that my athlete data was incomplete (that was a few days ago, so I don't have the precise errors). When saving each item of athlete data, all seemed well, except for 'recovery metric'. Each time I saved that setting, no matter the chosen value, I was seeing something close to this in the output:

Error resetting hrv workout plan: unsupported operand type(s) for +: 'NoneType' and 'datetime.timedelta'
or
Error resetting hrv workout plan: 'NoneType' object has no attribute 'date'

The chosen recovery metric value always updates as expected though. There was, and still is, a red outline around the athlete box, so maybe that's a clue?

At some point, the athlete data error went away when refreshing, and now attempting to refresh data launches the Database Refresh in Progress modal, but it just sits there spinning away, never going away on it's own. None of the dashboards are populating, so I'm presuming it's not actually pulling data. The only errors I see logged when refreshing are the above hrv workout plan errors, so not sure where to go from here.

Again, happy to provide any additional info.

Thanks!

Review oauth dance

Currently search params in redirect uri (set on remote apps) to allow callback in dash to parse url and determine which service to save tokens for. (details in readme)

If someone has a better way to do this, please let me know prior to us adding new ones :)

Issues connecting to Strava

I set up a new app in Strava and filled in user_id and secret in settings.ini but I have a hard time pulling Strava data. Docker logs show that the connection is indeed established, I can see API requests on Strava app's page, but Fitly doesn't display any info from Strava. Some of the logs:

fitly  | Unable to set attribute nickname on entity <Shoe id=g5815688 name='Whitin trail Barefoot'>
fitly  | Unable to set attribute retired on entity <Shoe id=g5815688 name='Whitin trail Barefoot' resource_state=2>
fitly  | Unable to set attribute converted_distance on entity <Shoe id=g5815688 name='Whitin trail Barefoot' resource_state=2>
fitly  | Strava connected
fitly  | 'NoneType' object has no attribute 'tokens'
fitly  | Spotify not connected
fitly  | Error in https://api.spotify.com/v1/me/top/tracks?time_range=medium_term&limit=10&offset=0:
fitly  | 401: Invalid access token

The app looks gorgeous on the screenshots, but when deployed the main page simply says "Provide oura credentials" and nothing else. I do not own oura, I just want Strava data.
I wonder if Strava has changed their API access rules since the last commit made to this app. Looking forward to using it.

Error pulling oura data: Unknown string format: 2019-01-07T03:

First, great work on the project, it's really good and exactly the kind of thing I'm looking for!

I deployed fitly locally on ubuntu 18.04 using run-fitly-dev. After entering my Oura keys and athlete information I can pull the oura data for the dashboard but it keeps failing in ouraAPI.py in the function pull_activity_data(oura, days_back=7).

def pull_activity_data(oura, days_back=7):
...
        df_activity_summary['day_end_local'] = pd.to_datetime(df_activity_summary['day_end'].apply(lambda x: x[:-6]))
...

Everytime I attempt the refresh the data I receive the following error:

Error pulling oura data: Unknown string format: 2019-01-07T03:

I'll keep digging and revert back with my findings.

Also, I'm interested in knowing if anyone manages to use ptvsd for debugging and how. At the moment I'm using print() everywhere and it makes me sad to not use an actual debugger.

errors running in docker

Exception on /_dash-update-component [POST]

Traceback (most recent call last):

File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app

response = self.full_dispatch_request()

File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request

rv = self.handle_user_exception(e)

File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception

reraise(exc_type, exc_value, tb)

File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise

raise value

File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request

rv = self.dispatch_request()

File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request

return self.view_functions[rule.endpoint](**req.view_args)

File "/usr/local/lib/python3.7/site-packages/dash/dash.py", line 1078, in dispatch

response.set_data(func(*args, outputs_list=outputs_list))

File "/usr/local/lib/python3.7/site-packages/dash/dash.py", line 1009, in add_context

output_value = func(*args, **kwargs)  # %% callback invoked %%

File "/app/src/fitly/pages/power.py", line 1110, in update_power_curve

figure = power_curve(activity_type, power_unit)

File "/app/src/fitly/pages/power.py", line 416, in power_curve

interval_lengths += [i for i in range(1230, (int(math.floor(max_interval / 10.0)) * 10) + 1, 30)]

TypeError: unsupported operand type(s) for /: 'NoneType' and 'float'

Oura import wont work when API returns multiple readiness entries for the same day

I suspect Oura to record incomplete datasets for sleep data when the ring runs out of battery. For example, in my case, the pull_sleep_data() import blows up when the oura API returns a set of data without all the columns such as 'rmssd_5min' or 'hr_5min'.

Incomplete dataset:

{'midpoint_time': 19020, 'score_total': 96, 'score_alignment': 100, 'total': 30420, 'awake': 5100, 'score_disturbances': 69, 'is_longest': 1, 'light': 9420, 'score_latency': 52, 'bedtime_end': '2016-11-02T07:24:58-05:00', 'hypnogram_5min': '44444444433334433333333333333224322223322333333333332333332333222211222222233223333333322223333333333344233333323333344', 'breath_average': 16, 'efficiency': 86, 'hr_average': 68.125, 'score_efficiency': 86, 'rem': 20550, 'period_id': 0, 'duration': 35520, 'bedtime_start': '2016-11-01T21:32:58-05:00', 'score': 79, 'score_rem': 100, 'deep': 450, 'score_deep': 8, 'timezone': -300, 'onset_latency': 2610, 'summary_date': '2016-11-01', 'restless': 40}

The above leads to a KeyError on '5min_hr'.

The one below is a "valid" record:

{'awake': 3120, 'bedtime_end': '2020-08-06T06:32:30-07:00', 'bedtime_end_delta': 23550, 'bedtime_start': '2020-08-05T22:32:30-07:00', 'bedtime_start_delta': -5250, 'breath_average': 15.75, 'deep': 2790, 'duration': 28800, 'efficiency': 89, 'hr_5min': [0, 0, 62, 62, 59, 59, 59, 59, 60, 61, 61, 61, 62, 62, 63, 62, 62, 62, 62, 63, 63, 61, 61, 60, 60, 61, 62, 66, 65, 68, 69, 61, 64, 65, 63, 60, 60, 58, 62, 61, 62, 61, 62, 60, 58, 57, 58, 58, 57, 58, 58, 58, 56, 54, 54, 54, 55, 54, 54, 54, 52, 53, 53, 53, 54, 57, 56, 54, 51, 50, 50, 50, 50, 51, 51, 51, 52, 52, 52, 52, 52, 52, 53, 53, 56, 56, 54, 53, 51, 51, 50, 51, 51, 52, 52, 50, 52], 'hr_average': 57.12, 'hr_lowest': 50, 'hypnogram_5min': '442222211111133222211222233333443322223322222222222222222222222233322222222222223333322222222224', 'is_longest': 1, 'light': 18420, 'midpoint_at_delta': 9390, 'midpoint_time': 14640, 'onset_latency': 690, 'period_id': 1, 'rem': 4470, 'restless': 35, 'rmssd': 48, 'rmssd_5min': [0, 0, 41, 34, 46, 45, 31, 28, 25, 21, 21, 27, 18, 15, 18, 41, 31, 45, 36, 31, 31, 50, 36, 39, 34, 48, 35, 29, 33, 25, 24, 44, 29, 42, 53, 54, 48, 55, 45, 54, 42, 42, 33, 32, 45, 45, 31, 31, 42, 50, 34, 40, 74, 69, 46, 60, 47, 51, 45, 61, 69, 87, 62, 74, 53, 61, 68, 75, 74, 57, 49, 59, 67, 50, 46, 51, 40, 61, 44, 42, 72, 58, 72, 83, 76, 55, 72, 60, 77, 81, 73, 61, 60, 54, 63, 74, 66], 'score': 76, 'score_alignment': 100, 'score_deep': 49, 'score_disturbances': 63, 'score_efficiency': 93, 'score_latency': 91, 'score_rem': 64, 'score_total': 76, 'summary_date': '2020-08-05', 'temperature_delta': -0.24, 'temperature_deviation': -0.24, 'temperature_trend_deviation': 0.02, 'timezone': -420, 'total': 25680}

I'm reviewing the import methodology in ouraAPI.pull_sleep_data(oura, days_back=7)

Strava OAuth Issues - redirect uri invalid

Hello,
I setup fitly with the image from dockerhub and a compose config, did all the necessary steps of filling in the details in the config.ini but when I click the button to connect to strava I get a "bad request - redirect uri invalid"

I run the service on a host in the network on 192.168.8.102 so I replaced all the 127.0.0.1 with that IP. However, when I do that I get an error message from strava as follows.

{"message":"Bad Request","errors":[{"resource":"Application","field":"redirect_uri","code":"invalid"}]}
If I use the default 127.0.0.1 strava is not complaining and I can select the OAuth permissions but of course the subsequent redirect goes to the wrong IP.

config.ini
redirect_uri = http://192.168.8.102:8050/settings?strava

Strava My API Application
192.168.8.102:8050?strava

Oura is working without any problems. Any ideas on what might be wrong or how to fix it? I can provide more info if necessary. I am just not sure what else might help.

peloton_auto_bookmark_metric is an invalid keyword argument for athlete

Hi! Having some trouble getting started. I've pulled the latest image from dockerhub, but the container is crashing:

~/$ docker run -e MODULE_NAME=src.fitly.app -e VARIABLE_NAME=server -p 8050:80 -v /home/me/fitly:/app/config ethanopp/fitly:latest

Checking for script in /app/prestart.sh
Running script /app/prestart.sh
Running inside /app/prestart.sh, you could add migrations to this file, e.g.:

#! /usr/bin/env bash

Let the DB start

sleep 10;

Run migrations

alembic upgrade head

{"loglevel": "info", "workers": 8, "bind": "0.0.0.0:80", "workers_per_core": 2.0, "host": "0.0.0.0", "port": "80"}
Traceback (most recent call last):
File "/usr/local/bin/gunicorn", line 8, in
sys.exit(run())
File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 58, in run
WSGIApplication("%(prog)s [OPTIONS] [APP_MODULE]").run()
File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 228, in run
super().run()
File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 72, in run
Arbiter(self).run()
File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 58, in init
self.setup(app)
File "/usr/local/lib/python3.7/site-packages/gunicorn/arbiter.py", line 118, in setup
self.app.wsgi()
File "/usr/local/lib/python3.7/site-packages/gunicorn/app/base.py", line 67, in wsgi
self.callable = self.load()
File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
return self.load_wsgiapp()
File "/usr/local/lib/python3.7/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
return util.import_app(self.app_uri)
File "/usr/local/lib/python3.7/site-packages/gunicorn/util.py", line 358, in import_app
mod = importlib.import_module(module)
File "/usr/local/lib/python3.7/importlib/init.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "", line 1006, in _gcd_import
File "", line 983, in _find_and_load
File "", line 967, in _find_and_load_unlocked
File "", line 677, in _load_unlocked
File "", line 728, in exec_module
File "", line 219, in _call_with_frames_removed
File "/app/src/fitly/app.py", line 13, in
db_startup(app)
File "/app/src/fitly/init.py", line 86, in db_startup
peloton_auto_bookmark_metric='readiness'
File "", line 4, in init
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/state.py", line 433, in initialize_instance
manager.dispatch.init_failure(self, args, kwargs)
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/langhelpers.py", line 70, in exit
with_traceback=exc_tb,
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/util/compat.py", line 182, in raise

raise exception
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/state.py", line 430, in _initialize_instance
return manager.original_init(*mixed[1:], **kwargs)
File "/usr/local/lib/python3.7/site-packages/sqlalchemy/ext/declarative/base.py", line 840, in declarative_constructor
"%r is an invalid keyword argument for %s" % (k, cls
.name)
TypeError: 'peloton_auto_bookmark_metric' is an invalid keyword argument for athlete

I was previous getting some configuration errors, but I worked through those, and I'm now at this error. Happy to provide any additional info/ Thanks!

Odd PMC Scaling

Hello! I am having fun with this tool (and will bring a PR with some minor tweaks to the Withings API in the next little while) - but I'm getting a view of the PMC that is weirdly compressed relative to the view the demo screenshots show. I've explored performance.py but haven't located the values that might be controlling this. Can you point me in the right direction?

Screenshot at 2022-11-29 10-09-07

Performance view not rendering

Hi! After successfully refreshing my data, when attempting to view the performance view, the page does not render and the following is logged:

{"loglevel": "info", "workers": 8, "bind": "0.0.0.0:80", "workers_per_core": 2.0, "host": "0.0.0.0", "port": "80"}
Exception on /_dash-update-component [POST]
Traceback (most recent call last):
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/usr/local/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/usr/local/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functionsrule.endpoint
File "/usr/local/lib/python3.7/site-packages/dash/dash.py", line 1076, in dispatch
response.set_data(func(*args, outputs_list=outputs_list))
File "/usr/local/lib/python3.7/site-packages/dash/dash.py", line 1007, in add_context
output_value = func(*args, **kwargs) # %% callback invoked %%
File "/app/src/fitly/utils.py", line 87, in router_callback
layout = page(**kwargs)
File "/app/src/fitly/pages/performance.py", line 46, in get_layout
pmc_switch_settings = json.loads(athlete_info.pmc_switch_settings)
File "/usr/local/lib/python3.7/json/init.py", line 341, in loads
raise TypeError(f'the JSON object must be str, bytes or bytearray, '
TypeError: the JSON object must be str, bytes or bytearray, not NoneType

As far as I can tell, the other views I'd want to use (Home, Power) seem to be working as expected.

Appreciate the assistance to date, and as always, happy to provide any additional details.

Thanks!

Strava activity stream has not attribute 'keys' - Cannot generate df_samples

First thing - I'm trying to understand the strava data scraping while I'm having issues with the below code.

def build_df_samples(self):
        seconds = 1
        streams = get_strava_client().get_activity_streams(self.id, types=types)
        self.df_samples = pd.DataFrame(columns=types)
        # Write each row to a dataframe
        for item in types:
            if item in streams.keys():
                self.df_samples[item] = pd.Series(streams[item].data, index=None)

Which will return a "...has no attribute keys()" error when pulling strava data.
I can add a "if streams..." before the for loop as a workaround but then the df_sample is empty and the below line fails:

self.df_samples = self.df_samples.resample(str(seconds) + 'S').mean()

Throwing:
Error pulling strava data: Only valid with DatetimeIndex, TimedeltaIndex or PeriodIndex, but got an instance of 'Float64Index'

I'll keep digging and will revert back with my findings. I haven't finished investigating but it seems to be happening on all activities.

Second thing - As a side note, I have old data only with time and nothing else. That might trigger a problem down the line. Example:
image

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.