Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Visualisation, Stress and Heart rate #19

Open
wants to merge 37 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ad84e8f
Started with a visualisation script, generating graphs with chart.js
aquatix Aug 15, 2017
b99e726
Generate data for the wellness summary graphs
aquatix Aug 16, 2017
2768bbc
Renamed to specific template
aquatix Aug 17, 2017
c1520be
Generate coloured steps graphs
aquatix Aug 17, 2017
4d788ee
Also catch 'generic' and 'none' activity levels
aquatix Aug 17, 2017
0a410fa
Reorder sleeping so it's at the beginning
aquatix Aug 17, 2017
657295c
Reverse sort: latest day at top
aquatix Aug 17, 2017
ad38d30
Show steps and floors stats
aquatix Aug 17, 2017
1fd24d9
More stats, nice glyphs (Foundation webfont)
aquatix Aug 19, 2017
19505e7
More stats
aquatix Aug 19, 2017
ff28eea
More Calories, disable animation, slight tweaks
aquatix Aug 20, 2017
e243c18
Brighter colours in the bars
aquatix Aug 20, 2017
cf4d333
Only show heart rate stats when available
aquatix Aug 20, 2017
2d3780f
Be quiet
aquatix Aug 20, 2017
b3454bf
Better alignment of the icons and text
aquatix Aug 20, 2017
69d2378
Use Font Awesome for most icons, but they don't have Feet...
aquatix Aug 20, 2017
0446e54
More Font Awesome
aquatix Aug 20, 2017
edcb77d
Documentation about Wellness data, and visualising it
aquatix Aug 20, 2017
23cb3ae
Small text fixes
aquatix Aug 20, 2017
2c7038d
Accessible icons, changed some icons
aquatix Aug 21, 2017
6c51b19
Updated chart.js, added Step Goal as line
aquatix Nov 3, 2017
7b5cfac
Whitespace fixes
aquatix Nov 11, 2017
b4fc874
Download stress level stats
aquatix Nov 11, 2017
658fd05
Download heart rate data
aquatix Nov 12, 2017
17da414
Start visualising stress and heart rate
aquatix Nov 12, 2017
624a71a
Call to parse heart rate
aquatix Nov 13, 2017
01def29
Tiny fix for import grouping/sorting
aquatix Nov 13, 2017
ed6f952
Parse and show heart rate and stress levels where availabe
aquatix Nov 13, 2017
4011cce
Stress and heart rate have their own time scale; larger graphs
aquatix Nov 13, 2017
a4d991f
Better rendering for the busy lines
aquatix Nov 13, 2017
c204cb7
Download sleep stats
aquatix Nov 13, 2017
3682aa1
Better error messages
aquatix Nov 13, 2017
8ac7ebf
Adjust GMT-based timestamps; support for sleep data
aquatix Nov 13, 2017
83d3082
Visualise sleep, needs a bit more work
aquatix Nov 13, 2017
75e601d
Lets put it in the right order
aquatix Nov 13, 2017
2179ac7
Use the GMT timestamps, seem more accurate; do not show sleep start
aquatix Nov 14, 2017
30e9243
Hide the stress chart by default (looks less busy)
aquatix Nov 14, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,22 @@ To download all your Garmin workouts in TCX format (basically XML), perform the

Again, you should see activities downloading in a few seconds.

To download wellness data (e.g., step count, calories burned, floors ascended and descended), use the download script as follows:

```
python download.py -c garmin_login.csv --start-date 2017-08-18 --end-date 2017-08-20 --displayname 1abcde23-f45a-678b-cdef-90123a45bcd
```

Start date and end date can be the same date to only download one day. Displayname is the part of the url if you go to Activities > Steps on Garmin Connect and look at the part: ../daily-summary/[displayname]/2017-08-20/steps

To visualise the downloaded wellness information, use `visualisation.py`, for example like:

```
python visualisation.py -i /home/youruser/garmin/Results/[email protected]/Wellness -o /home/youruser/www/garmin
```

This creates a file called wellness.html with graphs and statistics. Just open it with your browser, or upload it to your website.

If you run into any problems, please create a ticket!

Packages
Expand All @@ -48,3 +64,5 @@ If any of the following packages require dependencies, they will be listed. To i
- **download.py**: A script for downloading all Garmin Connect data as TCX files for offline parsing. *Dependencies: mechanize*

- **monthly.py**: A script for updating one's Twitter account with monthly statistics. Currently, the statistics and format are identical to those seen on [DailyMile](http://www.dailymile.com) for their weekly statistics. I just thought it'd be neat to have monthly updates, too. *Dependencies: tweepy, mechanize*

- **visualisation.py**: A script to generate graphs and statistics overviews from the Wellness data downloaded with download.py. *Dependencies: jinja2*
60 changes: 56 additions & 4 deletions download.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,18 @@
SSO = "https://sso.garmin.com/sso"
CSS = "https://static.garmincdn.com/com.garmin.connect/ui/css/gauth-custom-v1.2-min.css"
REDIRECT = "https://connect.garmin.com/post-auth/login"

ACTIVITIES = "http://connect.garmin.com/proxy/activity-search-service-1.2/json/activities?start=%s&limit=%s"
WELLNESS = "https://connect.garmin.com/modern/proxy/userstats-service/wellness/daily/%s?fromDate=%s&untilDate=%s"
DAILYSUMMARY = "https://connect.garmin.com/modern/proxy/wellness-service/wellness/dailySummaryChart/%s?date=%s"

STRESS = "https://connect.garmin.com/modern/proxy/wellness-service/wellness/dailyStress/%s"
HEARTRATE = "https://connect.garmin.com/modern/proxy/wellness-service/wellness/dailyHeartRate/%s?date=%s"
SLEEP = "https://connect.garmin.com/modern/proxy/wellness-service/wellness/dailySleep/user/%s?date=%s"

TCX = "https://connect.garmin.com/modern/proxy/download-service/export/tcx/activity/%s"
GPX = "https://connect.garmin.com/modern/proxy/download-service/export/gpx/activity/%s"


def login(agent, username, password):
global BASE_URL, GAUTH, REDIRECT, SSO, CSS

Expand Down Expand Up @@ -153,7 +157,7 @@ def wellness(agent, start_date, end_date, display_name, outdir):
try:
response = agent.open(url)
except:
print('Wrong credentials for user {}. Skipping.'.format(username))
print('Wrong credentials for user {}. Skipping wellness for {}.'.format(username, start_date))
return
content = response.get_data()

Expand All @@ -168,7 +172,7 @@ def dailysummary(agent, date, display_name, outdir):
try:
response = agent.open(url)
except:
print('Wrong credentials for user {}. Skipping.'.format(username))
print('Wrong credentials for user {}. Skipping daily summary for {}.'.format(username, date))
return
content = response.get_data()

Expand All @@ -178,6 +182,51 @@ def dailysummary(agent, date, display_name, outdir):
f.write(content)


def dailystress(agent, date, outdir):
url = STRESS % (date)
try:
response = agent.open(url)
except:
print('Wrong credentials for user {}. Skipping daily stress for {}.'.format(username, date))
return
content = response.get_data()

file_name = '{}_stress.json'.format(date)
file_path = os.path.join(outdir, file_name)
with open(file_path, "w") as f:
f.write(content)


def dailyheartrate(agent, date, display_name, outdir):
url = HEARTRATE % (display_name, date)
try:
response = agent.open(url)
except:
print('Wrong credentials for user {}. Skipping daily heart rate for {}.'.format(username, date))
return
content = response.get_data()

file_name = '{}_heartrate.json'.format(date)
file_path = os.path.join(outdir, file_name)
with open(file_path, "w") as f:
f.write(content)


def dailysleep(agent, date, display_name, outdir):
url = SLEEP % (display_name, date)
try:
response = agent.open(url)
except:
print('Wrong credentials for user {}. Skipping daily sleep for {}.'.format(username, date))
return
content = response.get_data()

file_name = '{}_sleep.json'.format(date)
file_path = os.path.join(outdir, file_name)
with open(file_path, "w") as f:
f.write(content)


def login_user(username, password):
# Create the agent and log in.
agent = me.Browser()
Expand Down Expand Up @@ -208,8 +257,11 @@ def download_wellness_for_user(agent, username, start_date, end_date, display_na

# Scrape all wellness data.
wellness(agent, start_date, end_date, display_name, download_folder)
# Daily summary does not do ranges, only fetch for `startdate`
# Daily summary, stress and heart rate do not do ranges, only fetch for `startdate`
dailysummary(agent, start_date, display_name, download_folder)
dailystress(agent, start_date, download_folder)
dailyheartrate(agent, start_date, display_name, download_folder)
dailysleep(agent, start_date, display_name, download_folder)


if __name__ == "__main__":
Expand Down
Loading