Withingsの体重計や睡眠計測のSleepを使ってますが、 Withingsではそういった情報をクラウドで保存していて、 APIを使ってアクセスできる様になっています。
自分で情報を扱える所に置くことができれば色々とできることもあるだろう、ということで Google Apps Script(GAS)を使ってGoogle Spreadsheetsに情報を保存できるようにしてみました。
- Withings
- Withings API
- OAuth 2.0認証の準備
- ブラウザとターミナルを使って取得してみる
- Google Apps Scriptで取得する
- 取得した値をGoogle Spreadsheetsに保存する
- Pythonで取得
Withings
Withingsは体重計や睡眠計、スマートウォッチなどの健康関連製品を作っていますが、 これらはIoT化されていてインターネットに繋いであれば情報はWithingsのサーバー上に保存されます。
通常はそれをアプリを通して見れるようになっています。
PCからでもマイページ からグラフなどを見ることが出来ます。
また、このマイページを通じてWithingsではない体重計で測った以前の体重などをアップロードしたり、 今までWithingsの機器での計測をCSV形式でダウンロードすることも出来ます。
他のサービスだとデータが特定のアプリやウェブサイトからしか見れなかったり データがダウンロードできなかったりして、 さらにはサービス自体が終わってしまうとどうしようもなくなったりする場合もあります。
今の所体重計関連でデータに自由にアクセスできるクラウドサービスを持っているのは Withingsだけだと思います(少なくとも日本から利用できるものに関しては。)
Withings API
そんなわけで、単にデータを取り出したいだけであればマイページから行えば良いのですが、 せっかくのIoTなので色々と他と連携させたり自分でデータを直接弄ったりしてみたくなります。
そんなときにはAPI。
他のIoT製品もそうですが、色々やっていくと自分で直接データに触りたくなってくることもあるので、 今後選ぶ際にはAPIの充実してるかどうか、というのも重要だな、と思う今日このごろ。
WithingsのAPIは体重などの計測情報を取ってくることに加え、 データを入力することも出来たりユーザー管理も出来たりと 恐らくアプリやウェブで操作できる一通りのことができる様です。
なので、 意味があるかどうかは置いておいて、 自作でWithingsのアプリ的なものを作ることも可能だと思います。
OAuth 2.0認証の準備
Withings APIはOAuth 2.0の認証を使って利用できます。
まず、Withingsのアカウントが必要なので 作ってない場合にはアカウントを作成:
その次に、Withings API partnerとして登録する必要があります。
上記のページで、
- Description: 適当な説明
- メールアドレス: 適当なメールアドレス
- 会社: 個人利用になりますが必須なので適当にGitHubのアカウントでも
- コールバックURI: きちんとしたものが決まってなければとりあえず
https://localhost
で - Environment:
dev
。他の値でも良いけど後で使うURLでstate
の値に設定するもの。
な感じで登録すると
- クライアントID
- コンシューマーシークレット
を取得することが出来ます。 他に複製のしようがないので、現状一つのアカウントで作れるアプリは一つだけっぽいです 1。
ブラウザとターミナルを使って取得してみる
まずは簡単にブラウザとターミナルを使ってWithingsの情報を取得してみます。
まず、認証を行い認証コードを取得します。
https://account.withings.com/oauth2_user/authorize2?response_type=code&client_id=<クライアントID>&scope=<scope>&redirect_uri=<コールバックURI>&state=<Environment>
上のURLで<クライアントID>
を上で取得したもの、<コールバックURI>
、<Enviroment>
のところを自分で設定したものに変更します。
また、<scope>
に関してはWithings API listから必要なものを。
体重計とかの情報はuser.metrics
、SleepやWatchの情報はuser.activity
とかです。複数の場合は,
で並べてscope=user.metrics,user.activity
の様な感じに。
https://account.withings.com/oauth2_user/authorize2?response_type=code&client_id=XXXXXXXXXXXXXXXXXXXXXXXXX&scope=user.metrics,user.activity&redirect_uri=https://localhost&state=dev
みたいな感じ。
これをブラウザで開くと
こんなページに行くので許可してあげます。
許可すると、上の場合だとコールバックURIをlocalhostにしてるので、ローカルホストでWebサーバーを立ててなければ接続拒否になりますが、その際、ブラウザのURLを見ると
https://localhost/?code=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX&state=dev
みたいになっているはずです。このcode=
の後ろの文字列が認証コードになるのでこれをコピーします。
次に、ターミナルから以下のcurlコマンドを実行します。
$ curl --data 'grant_type=authorization_code&client_id=<クライアントID>&client_secret=<コンシューマーシークレット>&redirect_uri=<コールバックURI>&code=<認証コード>' 'https://account.withings.com/oauth2/token'
<クライアントID>
、<コンシューマーシークレット>
は先程取得したもの、<コールバックURI>
は上で指定したもの、<認証コード>
は今取得したもの、に書き換えます。
ただし、この認証コードの有効期限はたったの30秒になっています。
なので、先に上のコマンドをターミナル上で認証コードの部分以外書いておいて、 ブラウザで取得後すぐに貼り付けて実行、みたいにする必要があります。
時間が経ってしまうと、
{"errors":[{"message":"invalid_grant: Invalid Params"}]}
みたいなエラーがかえってきます。
うまく行けば
{"access_token":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","expires_in":10800,"token_type":"Bearer","scope":"user.metrics,user.activity","refresh_token":"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","userid":"XXXXXXXX"}
みたいな感じの内容が返ってきます。
このaccess_token
をメモしておきます。
これを使って体重の計測値を取得したければ、
$ curl 'https://wbsapi.withings.net/measure?action=getmeas&access_token=<access_token>&meastype=1&category=1&startdate=1601478000&enddate=1601823600'
などとします。
ここでは MeasureのGetmeas というAPIを使っています。
<access_token>
のところを先程取得したものに変更すれば値が取得できるはずです。
startdate
、enddate
はUNIX時間表記ですが、上のものは2020/10/01 00:00:00から2020/10/05/ 00:00:00までになっています。
meastype
で上のページにあるようにほしい値を取ってこれます。1
は体重、6
なら体脂肪率、みたいな。
複数欲しい場合には、meastype
の代わりにmeastypes=1,4,5
のようにmeastypes
を使って必要なものを,
でつないでわたします。
category
は1
なら実際の計測値、2
ならユーザーが設定した目標値になります。
多分体重くらいしかないはずです。
コマンドがうまく行けば
{
"status": 0,
"body": {
"updatetime": XXXXXXXXXX,
"timezone": "Asia/Tokyo",
"measuregrps": [
{
"grpid": XXXXXXXXXX,
"attrib": 0,
"date": XXXXXXXXXX,
"created": XXXXXXXXXX,
"category": 1,
"deviceid": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"hash_deviceid": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"measures": [
{
"value": 12345,
"type": 1,
"unit": -3,
"algo": 3,
"fm": 133
}
],
"comment": null
},
...
]
}
}
みたいなJSON形式の情報が取得できます(実際には整形されてないので上のはjqコマンドで整形したもの。)
body.measuregrps
という配列があって、その中に計測がありますが、
重要なのはその中のmeasures
で、
体重を求めるにはvalue
とunit
を使って、
value * 10^(unit)
の様な計算をします。
つまり、上の場合は、12345 * 10^(-3) = 12.345
が体重(kg)になります。
他の体脂肪率とかもこんな感じでvalue
とunit
を組み合わせて値を算出します。
ここのtype
はどのmeastype
か、を示しています(1
なので体重)。
それら以外にalgo
、fm
、fw
という値があったりなかったりしますが、これらは
以前使われていたもので今はdeprecatedなものなので無視してください。
Google Apps Scriptで取得する
上の様にコマンドラインベースでアプリを作ることも可能ですが、 今回はGoogle Spreadsheetsに保存したいので、 そうであればGoogle Apps Scriptでやるのが一番便利です。
Google Apps Scriptには apps-script-oauth2 という OAuth 2.0用のライブラリが用意されているのでこれを使います。
適当なGoogle Apps Scriptのプロジェクトを作成
したら、リソースライブラリに行って、
Add a library
の欄に
1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF
を記入して追加。 追加するとバージョンが未選択状態になってるので最新のものを選んで起きます。
ちなみにメニューの方はライブラリとカタカナになってますが、 ポップアップの方は機械翻訳を直せてないのかライブラリが図書館と訳されています。。。
これでOAuth 2.0の認証が色々と簡単にできます。
上のレポジトリにも samples がたくさんあって、GitHubやLINE、またGoogleのサービスに関する例もあります。
残念ながらここにWithingsの例がないので、 ここにある例に従ってsampleを作ってみました。
ここにあるWithings.gs
をコピペしてGoogle Apps Scriptのプロジェクト内のファイルに貼り付けて、
CLIENT_ID
とCLIENT_SECRET
の値を設定してください。
さらに、GASでWithings APIを使う際には Withings API partner のページで コールバックURIを
https://script.google.com/macros/d/<SCRIPT_ID>/usercallback
の様に設定し直す必要があります。
このSCRIPT_ID
はメニューのファイルプロジェクトのプロパティから取得することが出来ますし、プロジェクトを開いているURLにもhttps://script.google.com/d/<SCRIPT_ID>/...
の様になっているのでそこからとっても良いです。
コールバックURIの設定をして、CLIENT_ID/CLIENT_SECRETをスクリプトで設定したら、
run
関数を選んで実行します。
そうすると一回目は認証のプロセスになります。
認証が終わって、もう一度実行すると値が取得できるはずです。
取得した値は表示ログに出てきます。 (ログが表示されるまでちょっと(数十秒から1,2分)かかります。)
デフォルトではMEASTYPES
で1(体重)と6(体脂肪率)、DAYS
で30を指定して過去一ヶ月分のデータを取得する様になっています。
取得した値をGoogle Spreadsheetsに保存する
上のライブラリを使って実際に運用しているものがこちら
Sleepの情報も取ってくるようにしています。
ただ、Sleepに関してはここで取得しているのは一晩の全体の概要だけです。 実際には睡眠中、ノンレム睡眠になったりレム睡眠になった毎に期間を分けたを細かいデータがあるのですが、 そこまでどう扱うか考えられてないので。
で、Spreadsheetsに保存する際にも色々工夫があるのですが、長くなりそうなので別に書きたいと思います。
このレポジトリのものは、 Google Apps Script のページから作った新規プロジェクトではなく、 Google Spreadsheetsのツールスクリプトエディタから作成するプロジェクトを使います。 それによってSpreadsheetsのIDとかを直接書く必要がなくなるので。
このレポジトリのものも、Withings-gas-example同様にCLIENT_ID/SECRETを設定して、 コールバックURIをこのプロジェクトのものに設定すれば簡単に使えると思います。
このプロジェクトを作ってbody
などの関数がちゃんと動くのを確認したら、編集現在のプロジェクトのトリガー
へ行きトリガーを追加から新たな時間主導型のトリガーを追加します。
- 実行する関数を選択:
body
orsleepSummary
- デプロ時に実行:
Head
またはバージョンを作っててそれを指定したいならそれ - イベントソース:
時間主導型
- 時間ベースのトリガータイプ:
日付のタイマー
- 時刻を選択:
午前0時~1時
の様な感じ。 これで毎日Withings APIを確認してSpreadsheetsをアップデートします。
取得してくる期間ですが、
params.gs
の中でデフォルトでbody
もsleepSummary
も10年間分取るようにしています
2。
10年とすると基本的には最初から、ということを意図していて、 全部を取得するようにしています。
毎日アップデートするので、最初に一度全部同期したら、毎日の実行では1ヶ月だけ、とか 短くしても良いんですが、 体重測るのは1日多くて数回だし、10年分取ってきても大した量じゃないので 1日1回するジョブであれば全部取ってきても問題ないだろう、ということでそのようにしています。
Pythonで取得
Pythonを使ってAPIを使いたい場合には Withings公式がOAuth 2.0に関する使用例を作ってくれています。
ユーザーが登録しているデバイス一覧を返すexampleがあるので、 その辺を参考にして体重とかも取ってこれるかと。