🚀

体力ゲージをSlack連携する ~Garmin&Slack~

2022/02/12に公開

モチベーション

同僚がスマートウォッチを使いこなしていてかっこよかったので、昨年末にGarminの VENU SQ (以後、SQ)というスマートウォッチを購入しました。
SQをはじめとしたGarmin製品には Body Battery (以後、BB)という、身体の電池残量がわかる機能があります。私をはじめとした頑張りすぎちゃう日本人はつい無理してしまうところがあります。しかしBBのような指標があれば、自分のことを客観的に見ることができ、適切に休むなどしてQOL向上につなげることができます。
BBは非常に便利な機能ですが、自分で数値を確認しないと値がわからないようです(pull型情報)。しかしSQにはwebhook連携などがあるようで、頑張ればBBが〇〇%切ったら通知するようなこと(push型情報)もできるかと思いチャレンジしてみます。

登場人物

  • Garming VENU SQ
  • Garmin Connect
  • IFTTT (途中退場)
  • Amazon Lamda
  • Puppeteer
  • Slack

開発環境

エディタ:Visual Studio Code
Node.js: v14.15.5

やったこと

完成イメージの作成

以下のような流れの仕組みを作ろうと計画しました↓↓

スマートウォッチからBBの値を取得し、
IFTTTのwebhook経由でlambdaにリクエストを飛ばし、
Slackへ通知するという仕組みです

同じことをしている人がいないか調査

こんな感じのキーワードで検索しました。

venu sq 
ifttt
webhook
body battery
イベント発火

そして以下の記事を見つけました↓↓
https://garmin.space/?p=139

おお、webhookを飛ばしてIFTTTでキャッチして後処理するという例ですね。
ということで進めていくのですが、早速壁にぶち当たりました。

上記記事の GARMINにwebhooksをインストール をしようとしたところ、Garminウィジェットストアにwebhooksが見つかりません。
どうやら、現在時点だと配信されていないようです。。 orz..
ということで別の方法を探ります。

別の手法調査

以下の記事で APICALL というツールがwebhookっぽい動きをしていたので試してみます↓↓
https://note.com/senhor/n/nf35bfe212594

こちらの記事では、garminと例でSesamiを連携する例が紹介されていました。

なるほど、UIを毎回操作する方式ですが、リクエストさえ飛ばせればslack通知までできそうです。
ということで記事に沿って進めていって、無事に立てておいたlambdaに対してUI操作でリクエストを飛ばすことに成功しました。
そしてあることに気が付きます。
BBの値、どうやって取んねん...

ということでStoreで調べてみました。
https://apps.garmin.com/ja-JP/apps/ac9a81ab-a52d-41b3-8c14-940a9de37544

権限
 このアプリは次の情報にアクセスする必要があります:
  インターネットとの情報の送受信

APICALLはGETリクエストはもちろん、予め設定されたBODYをPOSTリクエストすることはできますが、SQの値へのアクセスは許可されていなかったのです。。ちーん。。

SQへの値へアクセスができる方法の模索

既存アプリがダメなのであれば、Garminシリーズに対して純正のAPIがあるか調査をしてみました。
Garminの公式APIは以下の2種類がありました。

Garmin Health API
全データ取得可能かつ無料ですが,企業向けのため利用不可
https://developer.garmin.com/gc-developer-program/health-api/
Garmin Connect API
個人利用可ですが,有料($5,000)
https://developer.garmin.com/garmin-connect-api/overview/

無料でどうにかしたかったので、上記は断念しました。。

そもそものゴール像の見直し

SQから値を取るのが難しいのでwebhook飛ばす路線は難しいと思いはじめ、別の手法を探し始めました。
その中で、以下の記事を見つけました↓↓
https://blog.sushi.money/entry/2020/03/07/192506

まさに目から鱗の構成でした。
GarminシリーズはGarmin Connectという管理画面があり、GarminデバイスからBluetooth接続されたデバイスに向けて都度値が同期されています。
上記の記事ではそれを利用して、管理画面に自動でログインし、必要な値を取得するという方法を取っていました。

ということで、新規の構成は以下で考えます。

まずは puppeteer をlambdaで動かしてみる

そもそもlambda上でpuppeteerが動かせるか試すために先人の記事を探します。

以下の例では、lambda上でpuppeteerを動かす例があったので試します。
https://dev.classmethod.jp/articles/run-headless-chrome-puppeteer-on-aws-lambda/

WSLだとzipコマンドがなかったので以下コマンドでインストールしまいた。

$ apt install -y zip

また、chromiumのモジュールはNode14.xでは動かないらしく、Node12.xに下げることで実行できました。結構ハマりポイントでした。
https://stackoverflow.com/questions/66214552/tmp-chromium-error-while-loading-shared-libraries-libnss3-so-cannot-open-sha

紆余曲折ありつつ、何とかlambda上でpuppeteerの動作させることができました!
あとはこのプログラムを追加編集します。

先人のコードを元に改修

さて、上記のチュートリアルから改修を進めると、なぜかページ遷移しないバグに出会いました。
launchに dumpio: true をついかするとログが見れるので見てみます。
https://github.com/alixaxel/chrome-aws-lambda/issues/90#issuecomment-571060937

Refused to display 'https://sso.garmin.com/sso/signin?...' in a frame because it set 'X-Frame-Options' to 'sameorigin'.", source: https://connect.garmin.com/signin/ (0)

どうやら、chromiumのクロスサイト設定で引っかかっているようでした。
え、、web上でやろうとするのがそもそも無理??

ということで、ローカルで定時実行することにします。。

記事の例だと、Slackのステータス変更のためにトークンを取得する必要がありましたが、今回はSlackのChannelに投稿するのみなので、Incoming Webhookを利用します。

そして完成したデモ投稿がこちらです↓↓

今回の変更したコードは以下になります。

(TODO: Githubのリンクを貼る)

変更ポイント

  • 環境変数を .env から読み込めるように変更
  • Incoming Webhook 追加

まとめ

当初の意図とは異なる形ですが、なんとか目的は達成できました。
ローカル実行だとPCを閉じると動かなくなるので、何とか別の方法がないか模索してみます。
今後もQOLをあげる施策をゆるゆると続けていきます。

Discussion