GoogleAppsScript(GAS)を使って，「おはよう」と「おやすみ」を言うと睡眠時間を教えてくれる人を作る！

#目次
[1.はじめに](#はじめに)
[2.LINE botを作る](#line-botを作る)
　　[2.1.Webhook](#webhook)
[3.GoogleAppsScriptを使ってLINE botに機能をつけよう](#googleappsscriptを使ってline-botに機能をつけよう)
　　[3.1睡眠時間をお知らせするコードを書こう](#睡眠時間をお知らせするコードを書こう)
　　[3.2.簡単にコード解説](#簡単にコード解説)
　　[3.3.Webhookを使ってLINE botと連携させる](#webhookを使ってline-botと連携させる)
[4.動作確認](#動作確認)
[5.まとめ](#まとめ)

#はじめに
LINEで「おはよう」と「おやすみ」を送ると，睡眠時間をお知らせしてくれる便利な人はいないのか・・・？
いるわけがない．しかしいないなら作ればいい！！

ということで，今回は**GoogleAppsScript**を使用してLINEで「おはよう」と「おやすみ」を言うだけで，睡眠時間をお知らせしてくれるLINE botを作っていこうと思います．

先に言っておきますが，GASもLINE APIに関しても初めて触れたので，間違い表記があるかもしれません...
まぁ，何はともあれ作っていきましょう！！

#LINE botを作る
まずはじめに，LINE botを作っていきます．
でもどうやってコメントに反応するLINE botなんて作るのか？

実はLINE bot自体を作るのはそんなに難しいことじゃないんですよね～
LINEには**LINE Developer**というものがあって，ここにLINEアカウントでログインしてチャネルというものを作成すると，簡単にbotを作成できちゃうんです！！

[**LINE Developer**](https://developers.line.biz/ja/)

上記のサイトにアクセスして，LINEアカウントでログインしてみましょう．その後左上のコンソールをクリックすると，こんな画面になると思います．

![414755b1-e000-43ac-486b-51a29f53e158.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/d8465356-7bed-707b-d1b0-5eaef2cf947a.png)


LINE botのチャネルを作成するために，まずは適当にプロバイダーを作成します．
プロバイダーを作成したら，**Messaging API**を選択し，チャネルを作成します．このときのチャネル名，チャネルのアイコンはbotを作ったときにそのまま表示されます．ほかの入力必須項目は適当に入力しちゃってください．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/c25ead01-02fc-b01c-e4a1-312799c9f0a1.png)

登録出来たらMessaging API設定にいき，**応答メッセージ**と**あいさつメッセージ**を無効にしておきます．
ちなみに**応答メッセージ**は自動応答機能，**あいさつメッセージ**はbotをLINEで友達登録した時に文章を送る機能です．今回は個人的な用途なので無効にしますが，そういう機能ってことは知っておきましょう．

次に作成したチャネルのチャネルアクセストークンを取得しておきます．これはGoogleAppsScriptで作成するコード内で使用します．
Messaging API設定を一番下まで行くと，チャネルアクセストークンが発行できるので，ロングタームを作成しましょう．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/79721391-f0b2-519f-8a3b-cf7e83fc1d23.png)


ここまできて，自動応答機能を無効にしてbotが作れるのかい？，と思ってるでしょう．
大丈夫です．**Webhook**という機能を使用すると，自分の力でbotに自動応答機能を搭載することができます！
##Webhook
じゃあWebhookってなんだって話なんですが...
>[Webhookとは？-Qiita](https://qiita.com/soarflat/items/ed970f6dc59b2ab76169)

Webhookという機能について詳しくは知らないので，知りたい方は上記の記事を参考にしてください．
簡単に説明すると，「ユーザが投稿などをしたときに，どういった動作をするか指定する機能」みたいです．

先ほどのMessaging API設定の中にWebhook設定があり，WebhookのURLが登録できるようになっています．その下にWebhookの利用という項目があるので，そこをONにしてください．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/a49f7cc4-5c09-62d6-7e5e-18b19be98fde.png)
この部分にbotの動きを指定したプロジェクトのURLを登録することで，botがその通りに動くようになるわけです！
そして今回は，このbotの動きを**GoogleAppsScript**を使って作ろうということです！

ここまででLINE bot自体は作れたので，次は**GoogleAppsScript**でプロジェクトを作成してLINE botに機能をつけていきましょう!

#GoogleAppsScriptを使ってLINE botに機能をつけよう
GoogleAppsScriptとはgoogleが提供するスクリプトエディタです．
これを使ってプロジェクトを作成し，そのプロジェクトを使ってLINE botを動かしていきます．

これを使うためにはgoogle driveでGoogleAppsScriptをインストールする必要があるので，あらかじめインストールしておきましょう．
google driveにアクセスしたら，[新規]→[その他]→[アプリを追加]からGoogleAppsScriptをインストールできます．

ここまでで下準備完了です．ここからはガリガリとコーディングしていきます！

今回はユーザIDと就寝時間をスプレッドシートに保存するので，まずスプレッドシートを開きます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/508dadc8-6cff-c240-d9bf-da99225de64f.png)

そしたら[ツール]→[スクリプトエディタ]を開きます．
このスクリプトエディタにコードを書いていくわけです.

##睡眠時間をお知らせするコードを書こう

まずコードを載せて，部分的に解説していきます.
コード見るのは面倒という方は飛ばして大丈夫です．

```js:sample_bot.gs
function doPost(e) {
  /*受信したトークの情報読み込み*/
  var json = JSON.parse(e.postData.contents);        　　//jsonの呼び出し
  var message = json.events[0].message.text;             //送られたメッセージ内容
  var time_send = json.events[0].timestamp;              //メッセージが送られた時間
  var message_userId = json.events[0].source.userId;     //送信者のID
  var morning_variety = ['おはよう','おはようございます'];
  var night_variety = ['おやすみ','おやすみなさい']; 
  
  /*送信するためのトークン取得*/
  var reply_token= json.events[0].replyToken;
  if (typeof reply_token === 'undefined') {
    return;
  }
  
  /*スプレッドシートの読み込み*/
  const ss = SpreadsheetApp.getActiveSpreadsheet();                           //スプレッドシート読み込み
  const sheet = ss.getSheetByName('シート1');                                  //スプレッドシート内の1つのシートを読み込み
  const lastRow = sheet.getLastRow();                                         //シートの行数を読み込み
  const row_Id = 1;                                                           //Idが書かれている列
  const row_sleep = 2;                                                        //睡眠開始時刻が書かれている列
  const userLineNum = searchLineNum(message_userId, row_Id, lastRow, sheet);  //userIdに対応する行
  /*送信するトークの情報*/
  var reply_message;                                  //返信内容
  var do_reply=0;        　　　　　　　　　　　　　　　　 //返信するなら1, しないなら0

  /*発言が「おはよう」のときの処理*/
  if(isSame(message,morning_variety)){
    reply_message = 'おはようございます。';
    do_reply=1;
    
    //シートの情報から睡眠時間を計算
    var time_sleep;        //単位はミリ秒
    if(userLineNum !== -1) time_sleep = time_send-sheet.getRange(userLineNum, row_sleep).getValue();
    else time_sleep=-1;
    
    if(time_sleep !== -1){
      time_sleep=time_sleep/1000;        　　　　　　　//単位を秒に変換
      var hour=Math.floor(time_sleep/(60*60));       //時間を計算
      time_sleep=time_sleep%(60*60);     
      var minute=Math.floor(time_sleep/(60));        //分を計算

      if(hour >= 1){
        if(minute !== 0) reply_message += '\n'+Math.floor(hour)+'時間'+Math.floor(minute)+'分寝ましたね。';
        else reply_message += '\n'+Math.floor(hour)+'時間寝ましたね。\n'
      }else{
        if(minute !== 0) reply_message += '\n'+Math.floor(minute)+'分寝ましたね。';
        else reply_message = '今寝たばっかりですよ。';
      }
    }else if(time_sleep === -1){
      reply_message += '\nおやすみを言っていないので、時間がわかりません。';
    }
  }
  
  /*発言が「おやすみ」のときの処理*/
  if(isSame(message,night_variety)){
    reply_message = 'おやすみなさい。';
    do_reply=1;
    //発言した時刻をスプレッドシートに書き込む
    if(userLineNum !== -1) sheet.getRange(userLineNum, row_sleep).setValue(time_send);
    else{
      sheet.getRange(lastRow+1, row_Id).setValue(message_userId);
      sheet.getRange(lastRow+1, row_sleep).setValue(time_send);
    }
  }
  
  /*メッセージを返信*/   
  if(do_reply === 1){
    sendReplyMessage(reply_token, reply_message);
  }
  return ContentService.createTextOutput(JSON.stringify({'content': 'post ok'})).setMimeType(ContentService.MimeType.JSON);
}

//文字列とリストで一致するかを判定
function isSame(str,str_list){
  for(var i=0;i<str_list.length;i++){
    if(str===str_list[i]){
      return true;
    }
  }
}

//Idからシート内の対応する行数を返す，Idが見つからなければ-1を返す
function searchLineNum(userId, row_Id, lastRow, sheet){
  for(let i=1; i<=lastRow; i++){
    if(userId === sheet.getRange(i, row_Id).getValue()) return i;
  }
  return -1;
}

//メッセージ送信部分
function sendReplyMessage(reply_token, reply_message){
  var CHANNEL_ACCESS_TOKEN = 'チャネルのアクセストークン'; 
  var line_endpoint = 'https://api.line.me/v2/bot/message/reply';
  UrlFetchApp.fetch(line_endpoint, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': reply_message,
      }],
    }),
  });
}
```

コードはこんな感じになります.

##簡単にコード解説
先ほどあげたコードを簡単に解説していきます．

###トーク取得

``` js:sample.gs
  /*受信したトークの情報読み込み*/
  var json = JSON.parse(e.postData.contents);        　　//jsonの呼び出し
  var message = json.events[0].message.text;             //送られたメッセージ内容
  var time_send = json.events[0].timestamp;              //メッセージが送られた時間
  var message_userId = json.events[0].source.userId;     //送信者のID
```

この部分は送信されたトーク情報を読み込んでいます.
JSONという機能を使用することで，LINEから送られてきたメッセージの内容やUserIDなどを読み込めます．なかなに汎用性が高そうですね・・・！

>[Messaging APIリファレンス](https://developers.line.biz/ja/reference/messaging-api/)

詳しくはこのサイトに載っているので，ぜひ見てみてください！

###送信先のトークン取得
```js:sample.gs
  /*送信するためのトークン取得*/
  var reply_token= json.events[0].replyToken;
  if (typeof reply_token === 'undefined') {
    return;
  }
```
この部分では送信先のアカウントのトークンを取得しています．これをしないとどこに送信したらいいのかがわからないので重要です．
この部分では取得できない場合には動作を終了していますね．

###スプレッドシート取得

```js:sample.gs
  /*スプレッドシートの読み込み*/
  const ss = SpreadsheetApp.getActiveSpreadsheet();                           //スプレッドシート読み込み
  const sheet = ss.getSheetByName('シート1');                                  //スプレッドシート内の1つのシートを読み込み
  const lastRow = sheet.getLastRow();                                         //シートの行数を読み込み
  const row_Id = 1;                                                           //Idが書かれている列
  const row_sleep = 2;                                                        //睡眠開始時刻が書かれている列
```

ここではスプレッドシートの内容を読み込んでいます．
重要な部分は上2つで，
SpreadsheetApp.getActiveSpreadsheet() : 連携しているスプレッドシートを取得
(スプレッドシートオブジェクト).getSheetByName('シート名') : スプレッドシート内の1つのシートを取得(この場合はシート1)
という感じでスプレッドシートの内容を取得することができます．
また今回は睡眠開始時刻をこの様に保存しているので，IDが書かれている列は1，睡眠開始時刻が書かれている列は2に設定しています．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/51c660b1-096c-73ca-ea78-b6a8da40c37b.png)


lastRowはシートの最後の行を取得できるので，上の場合は2が取得できます．
スプレッドシートに対応させることができるなんて，これまた汎用性が高そうですね...！

###メッセージ送信
最後にメッセージの送信部分についてです.

```js:sample.gs
//メッセージ送信部分
function sendReplyMessage(reply_token, reply_message){
  var CHANNEL_ACCESS_TOKEN = 'チャネルアクセストークン'; 
  var line_endpoint = 'https://api.line.me/v2/bot/message/reply';
  UrlFetchApp.fetch(line_endpoint, {
    'headers': {
      'Content-Type': 'application/json; charset=UTF-8',
      'Authorization': 'Bearer ' + CHANNEL_ACCESS_TOKEN,
    },
    'method': 'post',
    'payload': JSON.stringify({
      'replyToken': reply_token,
      'messages': [{
        'type': 'text',
        'text': reply_message,
      }],
    }),
  });
}
```

まず'チャネルアクセストークン'の場所には，先ほど作成したチャネルアクセストークンを入力します．ここが間違えているとうまく動きません．

メッセージ送信部分が関数になっていますが，関数である必要はないです．
いろいろと書いてありますが，この部分で行っていることは，
「lineのbotの自動返信機能を使って，連携しているチャネルから返信させる」
ということだけです．ちなみに今回使用しているUrlFetchAppの使い方は外部のAPIを使用して操作を行いたいときにしようします．使い方は以下のようです．

UrlFetchApp.fetch(URL, [パラメータ])
URL部分には通信先のURLを書き，パラメータの部分でデータの形式を指定してあげます．

この場合だと，URL部分では https://api.line.me/v2/bot/message/reply との通信を指定し，パラメータ部分は文字コードやらチャネルやらを指定しています．
APIについてもっと詳しく知りたい方はこちらを見てみてください．

>[【初心者向けGAS】Google Apps ScriptでWeb APIを活用するための基礎知識](https://tonari-it.com/gas-web-api-http-urlfetch/)

##Webhookを使ってLINE botと連携させる
せっせとコードを書き終えたところで，最後にLINE botとGoogleAppsScriptの連携を行います．
これを行えば，無事に睡眠時間をお知らせするbotが完成です！

やり方は簡単です．
まずスプレッドシートからスクリプトエディタを開き，[公開]→[ウェブアプリケーションとして導入]を選択します．そうしたらこのように設定し，Deployします．
更新時にもproject versionは常にnewにする必要があるそうなので注意が必要です．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/7178da82-322f-4d49-ec89-f41f8d603778.png)

Deployが出来たらURL部分をコピーします．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/06127630-171d-5c2b-afd3-d82449d9f451.png)

そうしたらLINE DeveloperのチャネルのMessaging API設定を開き，Webhook URL部分に貼り付けます．
貼り付けが終われば，睡眠時間をお知らせるするbotの完成です！！！

#動作確認
やっとのことで作り終えたので，動作確認です．
今回はbotに以下の機能を付けました．
「おやすみ」:
おやすみを返し，おやすみを言った時刻をスプレッドシートに記入．

「おはよう」:
    1.スプレッドシートに時刻が記入してあれば，睡眠時間をお知らせする．
    2.スプレッドシートに時刻が記入してなければ，お知らせしない．
    3.睡眠時間が0分だったら，寝たばっかりのことを伝える．

実際にやってみましょう!
「おやすみ」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/195e353f-4914-aebb-ae4b-5f8b4ab61f5c.png)

「おはよう」
1.「おやすみ」を言っていた場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/1fc2db54-2273-c70a-279e-31be523b488a.png)

2.「おやすみ」を言っていない場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/a01c5e0d-5afd-0c8a-09b9-de0eb4484efb.png)

3.睡眠時間が0分の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/9399033c-5eab-dcc1-af6a-4ff0a4b74f3b.png)

なんだか愛着が湧いてきますね．スプレッドシートにはこんな感じで記入されました．
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/626406/28c6b979-7e60-037d-3d09-6e1a66e67762.png)

うまくいってますね！
プログラムを見るとわかりますが，実は「おはようございます」か「おやすみなさい」でも動くように作っています．
またuserIDと睡眠開始時間を紐づけしているので，賢いことに個人を判別しています．そのためどっかのグループに入れてみんなで使っても大丈夫です！

#まとめ
GASを使ってLINE botに機能をつけることが出来ました．
pythonを使ってLINE Notifyから通知を送る，ということはやったことあったのですが，それよりもかなり汎用性が高いと感じました．

このbotさえ作れば，簡単に機能を拡張できますね．例えば睡眠時間の平均時間をだすとか...
このbotを使っていい機能を実装出来たらまた記事を投稿しようと思います！！

それでは，お疲れさまでした！