GoogleHome + IFTTTで睡眠時間を管理してみる

## はじめに
- 半額で売られていたので思わずGoogleHomeMiniを衝動買い
- が、使いどころがラーメンタイマーくらいしかないことに気づきました
- せっかくなので以前Fitbitで挫折した睡眠時間管理をやってみます

## やりたいこと
1. 「おやすみ」というとスプレッドシートに就寝時間を記録
![キャプチャ.PNG](https://qiita-image-store.s3.amazonaws.com/0/118147/3b80cbd1-c772-6277-6a49-242920499b5c.png)


2. 「おはよう」というとスプレッドシートに起床時間を記録
![goodmorning.PNG](https://qiita-image-store.s3.amazonaws.com/0/118147/c32b16e7-cd49-1118-c84d-5b3cda9b6e53.png)


3. Googleカレンダーに就寝時間 ～ 起床時間の予定を登録
![キャプチャ2.PNG](https://qiita-image-store.s3.amazonaws.com/0/118147/72559793-4a7c-4a08-f4b5-b8871e02eb15.png)

## やったこと

### 1. 「おやすみ」というとスプレッドシートに就寝時間を記録
#### まずIFTTTの「this」の部分を作成
- IFTTTで、GoogleHomeに「おやすみ」というと起動する設定を行います

1. トリガーにGoogle Assistantを選択
1. 最初の選択肢は「Say simple phase」を選択
    - 文字列や数字の変数を使えるらしいですが、今回はキーフレーズのみ
1. 「What do you want to say ?」の部分に「おはよう」と入力
    - ここだけあっていれば動くので他は適当です

    <img src="https://qiita-image-store.s3.amazonaws.com/0/118147/bbbb9755-1110-792a-3aa6-9087f3ba8626.png" width=40%>



#### 次にIFTTTの「that」の部分を作成
- 起動した際にGoogle Sheetに新しい行を追加する設定を行います

1. アクションにGoogle Sheetを選択
1. 選択肢は「Add row to spreadsheet」を選択
1. 「Formatted row」に追加する行の情報を入力
    - パイプ(|)三つでセルの境目を表現できる
    - 今回は「|||bed time」と入力
    - これで一列目は空白で、二列目に「bed time」と入力される
    - 一列目に時間を入力したいけど、IFTTTから直接は出来ないらしいのでGASで対応する
1. 「Spreadsheet name」と「Drive folder path」には記録したいスプレッドシートのパスと名前を入力してください
    - 無い場合には勝手に作ってくれるみたいなので、あまり気にしなくてもいいかも

<img src="https://qiita-image-store.s3.amazonaws.com/0/118147/a92db924-5473-f0c5-fcac-09238d09ba02.png" width=40%>

#### GASを利用して時間を記録
- このままだと時間が入力されないので、GASを利用してシートの値が更新された時間を記録するようにします

1. 対象のスプレッドシートのツール→スクリプトエディタから、GASを開く
2. 以下のスクリプトを記載

    ```js
    function addDate() {
      var lastRow = sheet.getLastRow();
      sheet.getRange(lastRow, 1).setValue(new Date());
    }
    ```

3. トリガーボタンを押下してトリガー編集ダイアログを表示
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/118147/9b29e3ba-77de-3660-7831-e6f02699ad6b.png)

4. 以下のようにトリガーを設定
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/118147/0fe20331-7ca2-2c15-db3f-29f6035d9e3e.png)

5. これで、値が変更されたタイミングで空白にしておいた一列目に時刻が入るようになります
    ![image.png](https://qiita-image-store.s3.amazonaws.com/0/118147/6f960f4c-2d8c-a2e7-79eb-e6dc34e3a213.png)

### 2. 「おはよう」というとスプレッドシートに起床時間を記録
- 就寝の時と基本は同じなので割愛
    - 違うのは起床時間だとわかるように「wakeup time」と記載するくらい

### 3. Googleカレンダーに就寝時間 ～ 起床時間の予定を登録
- ここは全てGASを利用して行います

1. 予定作成イベントを起床時間記録時に同時に発火するよう設定
    - 時間記録時に起床時間記録だった場合にはカレンダー登録メソッドを呼び出すよう追加します
    
        ```js
        function addDate() {
          var lastRow = sheet.getLastRow();
          sheet.getRange(lastRow, 1).setValue(new Date());
          if(isWakeup(lastRow)) {
            createSleepDiary(lastRow, lastRow - 1);
          }
        }
        ```
    - createSleepDiaryの第一引数は起床時間の行、第二引数は就寝時間の行です
    - isWakeupの中はこんな感じ

        ```js
        function isWakeup(row) {
          return sheet.getRange(row, 2).getValue() == "wakeup time" 
        }
        ```
1. 就寝時間と起床時間から睡眠時間を計算
    - createSleepDiary内で就寝時間と起床時間を取得します
        - 時間は一列目に記載されているはずなので、各行から一列目を取得するだけ

        ```js
        function createSleepDiary(wakeupRow, sleepRow) {
           var bedTime = sheet.getRange(sleepRow, 1).getValue();
           var wakeupTime = sheet.getRange(wakeupRow, 1).getValue();
           var sleepingTime = getDiff(bedTime, wakeupTime);
        }
        ```
    - 各時間がとれたらgetDiffに渡して睡眠時間を計算します
        - ここはもっと良い方法がありそう

        ```js
        function getDiff(bedTime, wakeupTime) {
          var millis = wakeupTime.getTime() - bedTime.getTime();
          var hour = Math.floor(millis / HOUR);
          millis = millis - (hour * HOUR);
          var minute = Math.floor(millis / MINUTE);
          return hour + '時間' + minute + '分';
        }
        ```
1. Googleカレンダーに予定を作成
    - まずCalendarApp.getCalendarByIdを利用してカレンダーを取得します
        - この際、引数に登録先のカレンダーIDを指定する必要があります
        - GoogleカレンダーのIDはWeb版の設定画面から見ることが出来ます

        ```js
        function createEvent(bedTime, wakeupTime, sleepingTime){
          var calendar = CalendarApp.getCalendarById(TARGET_GOOGLE_CALENDAR_ID);
        }
        ```
    - カレンダーが取得できたらcalendar.createEventを利用して予定を作成します
        - 第一引数が開始時間、第二引数が終了時間、第三引数はオプションになっています
        - 今回はカレンダーの概要部分に睡眠時間を記載しています

        ```js
        function createEvent(bedTime, wakeupTime, sleepingTime){
          var calendar = CalendarApp.getCalendarById(TARGET_GOOGLE_CALENDAR_ID);
          calendar.createEvent('睡眠記録', new Date(bedTime), new Date(wakeupTime) , {description: sleepingTime}); 
        }
        ```
    - 最後にcreateSleepDiaryからcreateEventを呼び出すようにすれば完成です

        ```js
        function createSleepDiary(wakeupRow, sleepRow) {
           var bedTime = sheet.getRange(sleepRow, 1).getValue();
           var wakeupTime = sheet.getRange(wakeupRow, 1).getValue();
           var sleepingTime = getDiff(bedTime, wakeupTime);
           createEvent(bedTime, wakeupTime, sleepingTime);
        }
        ```

## 実際に動かしてみると
- ちゃんと記録されました
- 寝ぼけた声だとGoogleHomeが認識してくれないことがあるのが悩みです

![カレンダー.PNG](https://qiita-image-store.s3.amazonaws.com/0/118147/ce497425-a2b2-21de-e1b0-5816b1b20708.png)



## おわりに
- GoogleHomeはトリガーの役目しかしてないですね
- でもトリガーさえ叩いてしまえば後ろはなんだって出来そう
- PS4操作とか家電操作とか、夢が広がります
- とりあえず次は睡眠不足の時警告してくれるようにしたいです

## 参考
- [Google Home、IFTTT、Googleスプレッドシートを使って独自音声コマンドでログをとる（ついでにNode.jsやngrokやらも使ってLINEやGoogle Homeに通知する）](https://qiita.com/miso_develop/items/be562d8a823ad2639d94)
- [[GAS][カレンダー]予定を作成するには: 逆引きGoogle Apps Script](http://www.bmoo.net/archives/2012/03/313258.html)