rcmdnk's blog
Last update

20201006_withingsapi_200_200

Withingsの体重計や睡眠計測のSleepを使ってますが、 Withingsではそういった情報をクラウドで保存していて、 APIを使ってアクセスできる様になっています。

自分で情報を扱える所に置くことができれば色々とできることもあるだろう、ということで Google Apps Script(GAS)を使ってGoogle Spreadsheetsに情報を保存できるようにしてみました。

Withings

Withingsは体重計や睡眠計、スマートウォッチなどの健康関連製品を作っていますが、 これらはIoT化されていてインターネットに繋いであれば情報はWithingsのサーバー上に保存されます。

通常はそれをアプリを通して見れるようになっています。

PCからでもマイページ からグラフなどを見ることが出来ます。

また、このマイページを通じてWithingsではない体重計で測った以前の体重などをアップロードしたり、 今までWithingsの機器での計測をCSV形式でダウンロードすることも出来ます。

他のサービスだとデータが特定のアプリやウェブサイトからしか見れなかったり データがダウンロードできなかったりして、 さらにはサービス自体が終わってしまうとどうしようもなくなったりする場合もあります。

今の所体重計関連でデータに自由にアクセスできるクラウドサービスを持っているのは Withingsだけだと思います(少なくとも日本から利用できるものに関しては。)

Withings API

そんなわけで、単にデータを取り出したいだけであればマイページから行えば良いのですが、 せっかくのIoTなので色々と他と連携させたり自分でデータを直接弄ったりしてみたくなります。

そんなときにはAPI。

Withings API

他のIoT製品もそうですが、色々やっていくと自分で直接データに触りたくなってくることもあるので、 今後選ぶ際にはAPIの充実してるかどうか、というのも重要だな、と思う今日このごろ。

WithingsのAPIは体重などの計測情報を取ってくることに加え、 データを入力することも出来たりユーザー管理も出来たりと 恐らくアプリやウェブで操作できる一通りのことができる様です。

なので、 意味があるかどうかは置いておいて、 自作でWithingsのアプリ的なものを作ることも可能だと思います。

OAuth 2.0認証の準備

Withings APIはOAuth 2.0の認証を使って利用できます。

まず、Withingsのアカウントが必要なので 作ってない場合にはアカウントを作成:

アカウントの作成

その次に、Withings API partnerとして登録する必要があります。

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

みたいな感じ。

これをブラウザで開くと

20201006_withingsapi.jpg

こんなページに行くので許可してあげます。

許可すると、上の場合だとコールバックURIをlocalhostにしてるので、ローカルホストでWebサーバーを立ててなければ接続拒否になりますが、その際、ブラウザのURLを見ると

https://localhost/?code=dcd53fb4a37a44aa24e16079935f28041067a5a8&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>のところを先程取得したものに変更すれば値が取得できるはずです。

startdateenddateはUNIX時間表記ですが、上のものは2020/10/01 00:00:00から2020/10/05/ 00:00:00までになっています。

meastypeで上のページにあるようにほしい値を取ってこれます。1は体重、6なら体脂肪率、みたいな。 複数欲しい場合には、meastypeの代わりにmeastypes=1,4,5のようにmeastypesを使って必要なものを,でつないでわたします。

category1なら実際の計測値、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で、 体重を求めるにはvalueunitを使って、

value * 10^(unit)

の様な計算をします。

つまり、上の場合は、12345 * 10^(-3) = 12.345が体重(kg)になります。

他の体脂肪率とかもこんな感じでvalueunitを組み合わせて値を算出します。

ここのtypeはどのmeastypeか、を示しています(1なので体重)。

それら以外にalgofmfwという値があったりなかったりしますが、これらは 以前使われていたもので今は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

を記入して追加。 追加するとバージョンが未選択状態になってるので最新のものを選んで起きます。

20201006_library.jpg

ちなみにメニューの方はライブラリとカタカナになってますが、 ポップアップの方は機械翻訳を直せてないのかライブラリが図書館と訳されています。。。

これでOAuth 2.0の認証が色々と簡単にできます。

上のレポジトリにも samples がたくさんあって、GitHubやLINE、またGoogleのサービスに関する例もあります。

残念ながらここにWithingsの例がないので、 ここにある例に従ってsampleを作ってみました。

ここにあるWithings.gs をコピペしてGoogle Apps Scriptのプロジェクト内のファイルに貼り付けて、 CLIENT_IDCLIENT_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 or sleepSummary
  • デプロ時に実行: Headまたはバージョンを作っててそれを指定したいならそれ
  • イベントソース: 時間主導型
  • 時間ベースのトリガータイプ: 日付のタイマー
  • 時刻を選択: 午前0時~1時

の様な感じ。 これで毎日Withings APIを確認してSpreadsheetsをアップデートします。

取得してくる期間ですが、 params.gs の中でデフォルトでbodysleepSummaryも10年間分取るようにしています 2

10年とすると基本的には最初から、ということを意図していて、 全部を取得するようにしています。

毎日アップデートするので、最初に一度全部同期したら、毎日の実行では1ヶ月だけ、とか 短くしても良いんですが、 体重測るのは1日多くて数回だし、10年分取ってきても大した量じゃないので 1日1回するジョブであれば全部取ってきても問題ないだろう、ということでそのようにしています。

Pythonで取得

Pythonを使ってAPIを使いたい場合には Withings公式がOAuth 2.0に関する使用例を作ってくれています。

ユーザーが登録しているデバイス一覧を返すexampleがあるので、 その辺を参考にして体重とかも取ってこれるかと。

Sponsored Links
  1. 色々使いたい場合にはこれを使い回すことになるので、 コールバックURIとかに関してはちょっと面倒かも。

  2. 秒で指定するので、60*60*24*(365*10+4)で365日x10年+4日です。4日、はうるう年が最大限あった場合、ということを考慮して適当に。

Sponsored Links

« Google Apps ScriptをGitHubで管理する 時系列データをGoogle Apps ScriptからSpreadsheetsに良い感じに書き込む »