【Oura Ring】自分の体調をSlackプロフィールに同期した話【GAS】

はじめに

こんにちは。@0meo です。

「あー、今日ぜんぜん寝てないわ〜〜。体調悪いわ〜〜〜(チラッチラッ」

ってなるときありませんか? 僕はあります。

そこで自分の体調をアッピールしていくための自動スクリプトを作成しました。

今回作成した自動スクリプトでは、Oura Ringで計測したコンディションスコアをSlackのプロフィール横に表示される絵文字に同期します。スクリプトOSSとして公開しており、誰でも使うことができます。

github.com

使用している要素は以下の通りです。

作り方

1. Google Apps Script APIを有効にする

https://script.google.com/home/usersettings からGoogle Apps Script APIを有効にします。

2. 環境を整える

ソースコードをクローンします。

$ git clone https://github.com/meokz/oura-ring-for-slack-status.git

開発ツールをインストールし、使用するグーグルアカウントでログインします。

$ npm install -g @google/clasp
$ clasp login

プロジェクトを初期化します。

$clasp create --title OuraRingForSlackStatus --type sheets

3. デプロイする

以下のコマンドでソースコードをデプロイすることができます。

$ clasp push

デプロイが終わったことを確認したら、GASで開きましょう。

$ clasp open

このような画面を開くことができたらOKです。

Oura Ringからのデータ取得はこんな感じ

function getDailyReadiness(): DailyReadiness {
  const host = "https://api.ouraring.com/v2";
  const start_date = Utilities.formatDate(new Date(), "Asia/Tokyo", "yyyy-MM-dd");
  const end_date = Utilities.formatDate(getTomorrow(), "Asia/Tokyo", "yyyy-MM-dd");
  const url = host + `/usercollection/daily_readiness?start_date=${start_date}&end_date=${end_date}`;

  const params: GoogleAppsScript.URL_Fetch.URLFetchRequestOptions = {
    method: "get",
    contentType: "application/json",
    headers: { Authorization: `Bearer ${props.OURA_RING_TOKEN}` },
  };

  const contents = UrlFetchApp.fetch(url, params).getContentText();
  const dailyReadiness = JSON.parse(contents) as DailyReadiness;
  return dailyReadiness;
}

Slackへのステータス反映はこんな感じです。

function updateSlackStatus(emoji: string, text: string) {
  const url = "https://slack.com/api/users.profile.set";
  const payload = {
    profile: {
      status_emoji: emoji,
      status_text: text,
    },
  };

  const params: GoogleAppsScript.URL_Fetch.URLFetchRequestOptions = {
    method: "post",
    contentType: "application/json",
    headers: { Authorization: `Bearer ${props.SLACK_USER_OAUTH_TOKEN}` },
    payload: JSON.stringify(payload),
  };

  UrlFetchApp.fetch(url, params);
}

emojiの切り替えには雑にスコアをしきい値処理します。ここは自分好みに値を変えても良いです。

function getIconNo(data: DailyReadinessData): number {
  if (data.score >= 85) {
    return 1;
  } else if (data.score >= 75) {
    return 2;
  } else if (data.score >= 65) {
    return 3;
  } else if (data.score >= 55) {
    return 4;
  } else {
    return 5;
  }
}

3. Slackの設定をする

3.a. 絵文字を追加する

Slackに絵文字を追加します。今回使う自動スクリプトでは、スコアに対して5段階の絵文字に変換します。 1を最も良い状態、5に行くほど悪い状態だと定義したときに、それぞれ対応する絵文字を

  • :condition_1:, :condition_2:, :condition_3:, :condition_4:, :condition_5:

として追加してください。

3.b. Botを作る

続いて、https://api.slack.com/ を開いて「Create an app」を選択します。

「From scratch」を選びましょう。

「App Name」に好きな文字列を入力し、導入したいワークステーションを選択してください。

「Settings」→「Basic infomation」→「Display Information」を埋めて、「Save Changes」で保存します。

「Features」→「App Home」の「Your App’s Presence in Slack」に移動し、「Edit」を押します。

適当に埋めて、「Add」を押しましょう。

3.c. Webhook URLを発行する

「Features」→「Incoming Webhooks」を開き、「Activate Incoming Webhooks」をONにします。

すると、下に「Webhook URLs for Your Workspace」というセクションが生えるので、「Add new Webhook to Workspace」を選択します。

チャンネルを選ぶ画面が出てくるので、好きなチャンネルを選びましょう。

以下の画面に出てくるWebhook URLを後で SLACK_WEBHOOK_URL の枠にペーストします。

3.d. User OAuth Tokenを発行する

「Features」→「OAuth & Permissions」を開き、「User Token Scopes」から「Add an OAuth Scope」を選びます。

「users.profile:write」を与えましょう。

この時点でアプリの再インストールが求められるので、ボタンを押してインストールし直しましょう。

「OAuth Tokens for Your Workspace」セクションにある「User OAuth Token」の値を控えます(「Bot User OAuth Token」ではない)。 これを後で SLACK_USER_OAUTH_TOKEN の枠にペーストします。

4. Oura Ringのトークンを取得する

https://cloud.ouraring.com/personal-access-tokens にアクセスし、「Create New Personal Access Token」を押してアクセストークンを発行します。名前は分かりやすいように「Slack Status」とでもしましょう。

発行されたトークンをコピーし、後で OURA_RING_TOKEN の枠にペーストします。

5. 環境変数を設定し、デプロイする

GASの環境変数を設定します。「設定」→「スクリプト プロパティ」から「スクリプト プロパティを追加」を選択します。

ここでは先ほどのセクションで生成した3つの環境変数を設定します。

  • SLACK_WEBHOOK_URL: Slack通知のWeb hook用URL
  • SLACK_USER_OAUTH_TOKEN: SlackのUser OAuthトーク
  • OURA_RING_TOKEN: Oura Ringのトーク

続いてAPIとして公開します。「デプロイ」→「新しいデプロイ」として、「種類の選択」で「ウェブアプリ」を選んでください。その際、アクセスできるユーザーを「全員」にします。

URLが発行されるのでコピーしましょう。 このURLを叩くことでGASスクリプトが発火され、Oura Ring APIからのデータ取得 → GASで判定ロジックが発火 → Slack APIを更新という流れが実行されます。

5. iOSでオートメーションを組む

さて、これでSlackの状態を更新できるようになりましたが、どのタイミングでAPIを叩けば良いでしょうか。 GASでスケジュールを組んで定期的にAPIを叩くことが考えられます。 しかし、ここではiOSのオートメーションで組んでみようと思います。

Oura Ring APIは、Oura Ringのモバイルアプリを開いたときに同期されます。 つまり、Oura Ringのモバイルアプリを閉じたとき、Oura Ring APIの値は最新になっているはずなのです。

「ショートカット」アプリを開き、「オートメーション」タブを開きます。そして「個人用オートメーションを作成」を押しましょう。

「新規オートメーション」から「App」を選択します。

「App」に「Oura」をセットし、「閉じている」にチェックボックスを入れます。

アクションを設定する画面になるので、「アクションを追加」します。

「URLの内容を取得」を選びます。

このようにアクションをセットできました。

URLの部分をタップして、先ほど発行したAPIのURLをペーストします。

最後に、「実行の前に尋ねる」をオフにしましょう。「実行時に通知」もオフで良いでしょう。完了を押せば設定は終わりです。

これでOuraアプリを開きデータが更新された後、アプリをバックグラウンドに移すとAPIが発火されSlackが更新されます。

使ってみる

Oura Ringのモバイルアプリを開いた後、閉じるとSlackに通知が来ているはずです。