Fitbit

Collect Your Own Fitbit Data with Python という解説に従って,自分の Fitbit のデータを取得する。基本的には fitbit ライブラリを使う。このライブラリの GitHub リポジトリは こちら,ドキュメントは こちら にある。

まず Fitbit の 開発者サイト にログインし,Manage → Register An App でアプリケーションを登録する。方法は上の解説に詳しく書かれている(アプリ名と組織名に fitbit という文字列を含めることはできない)。おそらくGDPRの影響か,Terms Of Service Url,Privacy Policy Url が追加されている。OAuth 2.0 Client ID と Client Secret をメモしておく。

ライブラリ自体は pip install fitbit で入る。後で cherrypy も必要になる。リポジトリ にある gather_keys_oauth2.py を同じディレクトリに置いて作業する。

import fitbit
import gather_keys_oauth2 as Oauth2
import pandas as pd 
import datetime

CLIENT_ID = '......'
CLIENT_SECRET = '................................'

server = Oauth2.OAuth2Server(CLIENT_ID, CLIENT_SECRET)
server.browser_authorize()
ACCESS_TOKEN = str(server.fitbit.client.session.token['access_token'])
REFRESH_TOKEN = str(server.fitbit.client.session.token['refresh_token'])

これを実行すると,ブラウザが開き,アクセス機能を求める画面が出る。「すべて許可する」をチェックして「許可」ボタンを押すと,「You are now authorized to access the Fitbit API! You can close this window」と出る。次からはログイン画面だけになる。これらを使ってクライアントを作る:

auth2_client = fitbit.Fitbit(CLIENT_ID, CLIENT_SECRET, oauth2=True,
                             access_token=ACCESS_TOKEN, refresh_token=REFRESH_TOKEN)

アクセストークンの有効期限はデフォルト1日である。

例として昨日の心拍数を取得してみる:

yesterday = str((datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y%m%d"))
yesterday2 = str((datetime.datetime.now() - datetime.timedelta(days=1)).strftime("%Y-%m-%d"))
today = str(datetime.datetime.now().strftime("%Y%m%d"))

fit_statsHR = auth2_client.intraday_time_series('activities/heart',
                                                base_date=yesterday2,
                                                detail_level='1sec')

fit_statsHR にデータが入る。最初の10個くらいを眺めてみる:

In [ ]: fit_statsHR['activities-heart-intraday']['dataset'][:10]
Out[ ]: 
[{'time': '08:40:10', 'value': 70},
 {'time': '08:40:25', 'value': 70},
 {'time': '08:40:35', 'value': 79},
 {'time': '08:40:50', 'value': 95},
 {'time': '08:40:55', 'value': 115},
 {'time': '08:41:00', 'value': 104},
 {'time': '08:41:05', 'value': 105},
 {'time': '08:41:10', 'value': 113},
 {'time': '08:41:15', 'value': 122},
 {'time': '08:41:20', 'value': 124}]

だいたい5〜15秒ごとのデータが取れているようである。このままでは扱いにくいので,pandas の DataFrame に直す:

date = fit_statsHR['activities-heart'][0]['dateTime']
t = [pd.to_datetime(date + ' ' + x['time'])
     for x in fit_statsHR['activities-heart-intraday']['dataset']]
v = [x['value'] for x in fit_statsHR['activities-heart-intraday']['dataset']]
df = pd.DataFrame({'Heart Rate':v}, index=t)

日付入りのファイル名で CSV に保存する:

df.to_csv('heart' + yesterday + '.csv')

読むには次のようにする:

df = pd.read_csv("heart20190718.csv", index_col=0, parse_dates=[0])

簡単なプロット:

df.plot(figsize=(10,5))
心拍数

もうちょっと軸を読みやすくするには,次のようにする:

import matplotlib.dates as mdates

locator = mdates.AutoDateLocator()
formatter = mdates.ConciseDateFormatter(locator)
ax = plt.gca()  # または ax = plt.subplot(1,1,1)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
ax.plot(df)

さらに点ごとに色を付けてみる:

cm = plt.get_cmap('jet')
locator = mdates.AutoDateLocator()
formatter = mdates.ConciseDateFormatter(locator)
plt.gca().xaxis.set_major_locator(locator)
plt.gca().xaxis.set_major_formatter(formatter)
for i, v in df.iterrows():
    plt.plot(i, v[0], ".", color=cm((v[0] - 50) / 100))
plt.ylim(50, 170)

Seaborn を使ってみる:

import seaborn as sns

pd.plotting.register_matplotlib_converters()
cm = plt.get_cmap('jet')
locator = mdates.AutoDateLocator()
formatter = mdates.ConciseDateFormatter(locator)
ax = sns.scatterplot(df.index, df['Heart Rate'], hue=df['Heart Rate'],
                     palette=cm, hue_norm=(60,150))
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
plt.xlim(min(df.index), max(df.index))
plt.ylim(50, 170)
心拍数

Last modified: