Skip to content

Commit

Permalink
Add weight API
Browse files Browse the repository at this point in the history
  • Loading branch information
Knio committed Jan 5, 2020
1 parent f99d6ca commit 91b03a1
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 110 deletions.
2 changes: 1 addition & 1 deletion myfitbit/_version.py
@@ -1 +1 @@
__version__ = version = '0.6.0'
__version__ = version = '0.7.0'
6 changes: 6 additions & 0 deletions myfitbit/client.py
Expand Up @@ -62,5 +62,11 @@ def get_activities(self, date):
r.raise_for_status()
return json.loads(r.text)

def get_weight_range(self, date_start, date_end):
r = self.session.get('https://api.fitbit.com/1/user/-/body/log/weight/date/{}/{}.json'
.format(str(date_start), str(date_end)))
r.raise_for_status()
return json.loads(r.text)['weight']

def get_steps(self):
raise NotImplementedError
230 changes: 122 additions & 108 deletions myfitbit/datastore.py
@@ -1,108 +1,122 @@
import os
import json
import logging
from datetime import date, time, timedelta

log = logging.getLogger(__name__)

class FitbitDatastore(object):
'''
Local data store of Fitbit json objects.
'''
def __init__(self, root):
self.root = os.path.abspath(root)

def filename(self, *args):
return os.path.join(self.root, *args)

@staticmethod
def write(filename, data):
dirname = os.path.dirname(filename)
os.makedirs(dirname, exist_ok=True)
with open(filename, 'w') as f:
f.write(json.dumps(data, indent=2, sort_keys=True))

@staticmethod
def read(filename):
return json.load(open(filename))

def day_filenames(self, name):
# TODO use profile['memberSince']
start = date(2017, 1, 1)
days = 0
while 1:
day = start + timedelta(days=days)
days += 1
if day == date.today():
return

filename = self.filename(
name,
'{:04d}'.format(day.year),
'{}.{:04d}.{:02d}.{:02d}.json'.format(
name,
day.year,
day.month,
day.day
))
yield day, filename

def get_proile(self):
return self.read(self.filename('profile.json'))

def get_sleep(self):
'''
Return sleep data from the local store.
Returns: [{sleep_data}, ...]
where `sleep_data` is the inner dict from
https://dev.fitbit.com/build/reference/web-api/sleep/
'''
for dir, dirs, files in os.walk(self.filename('sleep')):
for file in files:
filename = os.path.join(dir, file)
data = self.read(filename)
yield from data

def get_activities(self):
'''
Return activities data from the local store.
Yeilds: (day, {activities_data})
where `activities_data` is the inner dict from
https://dev.fitbit.com/build/reference/web-api/activity/
'''
for day, filename in self.day_filenames('activities'):
if not os.path.isfile(filename):
continue
data = self.read(filename)
yield day, data

def get_heartrate_intraday(self):
'''
Return heartrate intraday data from the local store.
Returns: [{hr_data}, ...]
where `hr_data` is:
{
"date": "2016-07-08",
"minutes": [int, ...]
}
minutes is an array of 1440 minutes in the day and the HR during that minute
'''

def compress(data):
minutes = [None] * 24 * 60
for o in data:
h, m, s = map(int, o['time'].split(':'))
i = h * 60 + m
minutes[i] = o['value']
return minutes

for d, filename in self.day_filenames('heartrate_intraday'):
if not os.path.isfile(filename):
continue
data = self.read(filename)
if not data:
continue
yield {
'date': d.isoformat(),
'minutes': compress(data),
}
import os
import json
import logging
from datetime import date, time, timedelta

log = logging.getLogger(__name__)

class FitbitDatastore(object):
'''
Local data store of Fitbit json objects.
'''
def __init__(self, root):
self.root = os.path.abspath(root)

def filename(self, *args):
return os.path.join(self.root, *args)

@staticmethod
def write(filename, data):
dirname = os.path.dirname(filename)
os.makedirs(dirname, exist_ok=True)
with open(filename, 'w') as f:
f.write(json.dumps(data, indent=2, sort_keys=True))

@staticmethod
def read(filename):
return json.load(open(filename))

def day_filenames(self, name):
# TODO use profile['memberSince']
start = date(2017, 1, 1)
days = 0
while 1:
day = start + timedelta(days=days)
days += 1
if day == date.today():
return

filename = self.filename(
name,
'{:04d}'.format(day.year),
'{}.{:04d}.{:02d}.{:02d}.json'.format(
name,
day.year,
day.month,
day.day
))
yield day, filename

def get_proile(self):
return self.read(self.filename('profile.json'))

def get_sleep(self):
'''
Return sleep data from the local store.
Yeilds: {sleep_data}, ...
where `sleep_data` is the inner dict from
https://dev.fitbit.com/build/reference/web-api/sleep/
'''
for dir, dirs, files in os.walk(self.filename('sleep')):
for file in files:
filename = os.path.join(dir, file)
data = self.read(filename)
yield from data

def get_activities(self):
'''
Return activities data from the local store.
Yeilds: (day, {activities_data})
where `activities_data` is the inner dict from
https://dev.fitbit.com/build/reference/web-api/activity/
'''
for day, filename in self.day_filenames('activities'):
if not os.path.isfile(filename):
continue
data = self.read(filename)
yield day, data

def get_weight(self):
'''
Return weight logs from the local store.
Yeilds: {weight_data}, ...
where `weight_data` is the inner dict from
https://dev.fitbit.com/build/reference/web-api/body/#weight
'''
for dir, dirs, files in os.walk(self.filename('weight')):
for file in files:
filename = os.path.join(dir, file)
data = self.read(filename)
yield from data


def get_heartrate_intraday(self):
'''
Return heartrate intraday data from the local store.
Returns: [{hr_data}, ...]
where `hr_data` is:
{
"date": "2016-07-08",
"minutes": [int, ...]
}
minutes is an array of 1440 minutes in the day and the HR during that minute
'''

def compress(data):
minutes = [None] * 24 * 60
for o in data:
h, m, s = map(int, o['time'].split(':'))
i = h * 60 + m
minutes[i] = o['value']
return minutes

for d, filename in self.day_filenames('heartrate_intraday'):
if not os.path.isfile(filename):
continue
data = self.read(filename)
if not data:
continue
yield {
'date': d.isoformat(),
'minutes': compress(data),
}
4 changes: 4 additions & 0 deletions myfitbit/sync.py
Expand Up @@ -18,6 +18,7 @@ def sync(self):
self.sync_profile()
self.sync_sleep()
self.sync_heartrate()
self.sync_weight()
self.sync_heartrate_intraday()
self.sync_activities()

Expand Down Expand Up @@ -75,6 +76,9 @@ def sync_sleep(self):
def sync_heartrate(self):
self.sync_ranged_data('heartrate', self.client.get_heartrate_range)

def sync_weight(self):
self.sync_ranged_data('weight', self.client.get_weight_range)

def sync_intraday_data(self, name, client_fn):
'''
Downloads intraday data from the FitBit API
Expand Down
2 changes: 1 addition & 1 deletion tests/test_myfitbit.py
Expand Up @@ -2,5 +2,5 @@
def test_import():
import myfitbit
print(myfitbit)
assert myfitbit.__version__ == '0.6.0'
assert myfitbit.__version__ == '0.7.0'
assert myfitbit.FitbitClient

0 comments on commit 91b03a1

Please sign in to comment.