在宅中に休憩提案（ミッション）を課してくるLINE botを作ってみた（GAS&Make）

## 在宅ワークで有意義な休憩が取れていますか？
皆さんは在宅ワークをしていますか？？
私は今年度から部署が変わり在宅勤務が多くなりました。在宅ワーク中、休憩のタイミングを失ってしまったり、休憩中にSNSをみてしまってなかなか仕事に戻れなくなってしまったり。。。今回は適度なタイミングで休憩を提案してくれるアプリが欲しいと思い作成をしました。このアプリを使うことで休憩をより有意義にそしてちょっぴり楽しく過ごせればなと思います。

## LINEにミッションが送られてくる
あらかじめ、スプレッドシートに休憩中にしたいことを記載しておくことで指定した時間になると、その中からランダムにしたいこと取得をしてメッセージを作成します。
そして、作成したメッセージをLINEに通知をします。
あなたはこのメッセージの通りにミッションをこなすことで適度な休憩と達成感が得られ、最高のコンディションで仕事をすることができます。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">在宅ワークの休憩のタイミング難しい問題を解決するために、一定時間ごとに10分くらいで出来るミッションを与えてくるLINE botを作成しました！<br><br>これから、コンビニに行ってガムを買ってこいとのミッションが与えられたのでこれからガムを買ってきます！<a href="https://twitter.com/hashtag/protoout?src=hash&amp;ref_src=twsrc%5Etfw">#protoout</a><a href="https://twitter.com/hashtag/LINE?src=hash&amp;ref_src=twsrc%5Etfw">#LINE</a><a href="https://twitter.com/hashtag/%E5%9C%A8%E5%AE%85%E3%83%AF%E3%83%BC%E3%82%AF?src=hash&amp;ref_src=twsrc%5Etfw">#在宅ワーク</a> <a href="https://t.co/nPKRx4OSw8">pic.twitter.com/nPKRx4OSw8</a></p>&mdash; kosuke🪴植物とおしゃべりするアプリを作成中🪴 (@kosuke_Xedge) <a href="https://twitter.com/kosuke_Xedge/status/1538391156379500544?ref_src=twsrc%5Etfw">June 19, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 作成手順

### <1> スプレッドシートにやることを記入
まずはスプレッドシートを新規で作成をして、休憩時間にしたいことを記入していきます。
今回の場合は休憩時間を10分だと仮定をしていますのでそのくらいでできることを書いています。
- カテゴリー列には例のようにコンビニに行くや掃除をするのようにやることを記載していきます。
- 詳細列にはカテゴリーの内容をより詳しく書いてください
- 文末には詳細列の内容に繋がるような文言を書いてください

**例）下のようなLINEを送信したい場合**
1.カテゴリー列からランダムに取得
2.更に詳細列からランダムに取得
3.カテゴリーと同じ行の文末を取得
という流れでLINEのメッセージを作成しています。
![IMG_53252.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618860/a484c61b-c459-eb89-d8fd-0a6e85bbae79.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618860/52c395ee-59ad-b8a4-6880-bd3557074afd.png)

### <2> GASでコードを記載
これから、GASにコードを書いていきますので先ほどのスプレッドシートの拡張機能からGASを開いてください。

### <2.1> スプレッドシートを読み込む
下記のソースコードの記載してあるように、先ほど作成したスプレッドシートを読み込みランダムにカテゴリー、詳細、文末を取得していきます。ここで、カテゴリー数やカテゴリーごとの詳細数はスプレッドシートに書かれた数によって変わりますので注意が必要です。
</details><details><summary>スプレッドシートの読み込み</summary>

```javascript:Todo
function Todo() {
  //■テーマ■
  //休憩時間にやることをLINEで通知

  //アクティブなシートを取得
  const sheet = SpreadsheetApp.getActiveSheet();

  //初期値
  //カテゴリー数
  const cat_len = 4;
  //カテゴリー数ごとの詳細数
  const detail_len = [5,5,6,1];

  // やることのカテゴリーをランダムにスプレッドシートから取得
  const random_num1 = Math.floor(Math.random()*cat_len)
  //カテゴリーを取得
  let message01 = sheet.getRange(random_num1*10+2,1).getValue();
  console.log("カテゴリー:",message01);

  // やることの詳細をスプレッドシートから取得 
  const random_num2 = Math.floor(Math.random()*detail_len[random_num1])
  //やることの詳細名前を取得
  let message02 = sheet.getRange(random_num1*10+random_num2+2,2).getValue();
  console.log("詳細:",message02);

  // 文末をスプレッドシートから取得 
  let message03 = sheet.getRange(random_num1*10+2,3).getValue();
  console.log("(random_num1*10+1,3):",random_num1*10+2)
  console.log("文末:",message03);

  message = "\n休憩時間になりました。\n\n＜やること＞\n"+message01 +"\n<詳細>\n"+ message02 + message03;

  // LINEをつかってメッセージを送信
  sendLine(message);
}
```
</details>

### <2.2> 平日&指定した時間に通知が来るようにしたい
今回はLINEに休憩時間でやることが送られてくるのですが、休みの日や仕事前や後に送られてくると鬱陶しいですよね。
ですので、平日の設定をした時間にしか送信されないように設定をします。
↓に参考にした記事を載せておきます。

https://dev.classmethod.jp/articles/202001-workday-only-gas/

</details><details><summary>平日のみ通知</summary>

```javascript:isWorkday
// 指定された日が営業日か（営業日 = 「土日でない」「祝日カレンダーに予定がない」）
// 営業日 = true
function isWorkday (targetDate) {

  // targetDate の曜日を確認、週末は休む (false)
  var rest_or_work = ["REST","mon","tue","wed","thu","fri","REST"]; // 日〜土
  if ( rest_or_work [targetDate.getDay ()] == "REST" ) {
    return false;
  }; 

  // 祝日カレンダーを確認する
  var calJpHolidayUrl = "ja.japanese#holiday@group.v.calendar.google.com";
  var calJpHoliday = CalendarApp.getCalendarById (calJpHolidayUrl);
  if (calJpHoliday.getEventsForDay (targetDate).length != 0) {
    // その日に予定がなにか入っている = 祝祭日 = 営業日じゃない (false)
    return false;
  } ;

  // 全て当てはまらなければ営業日 (True)
  return true;
}
```
</details>
</details><details><summary>指定した時刻に通知</summary>

```javascript:isWorktime
// 指定された時刻が休憩時間内か
function isWorktime (targetTime){

  //現在の時間と分を取得
  let target_hour = String(targetTime.getHours());
  let target_min = String(targetTime.getMinutes());

  //アクティブなシートを取得
  const sheet = SpreadsheetApp.getActiveSheet();
  //最終行
  const lastRow = 5;

  // targetTime の時刻を確認、休憩時間外は (false)
  for(let i=2;i<=lastRow;i++){ 
    let rest_time = sheet.getRange(i,4).getValue();
    let rest_hour = String(rest_time.getHours());
    let rest_min = String(rest_time.getMinutes());
    if ( target_hour+target_min == rest_hour+rest_min ) {
      console.log("休憩時間です。")
      return true;
    }
  }; 
  return false;
}
```
</details>

時刻の指定についてはスプレッドシートのD列にあらかじめ休憩時刻を記入しておくことで、設定をした時刻に送信をすることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618860/127c2efe-4a82-a72b-8058-5fb9637ff5c0.png)

### <2.3> Makeにリクエストを送る。
ここでは、Webhookを用いてMakeにHTTPリクエストを送ります。
Webhookについては↓のサイトがわかりやすいのでおすすめです！

https://kintone-blog.cybozu.co.jp/developer/000283.html

</details><details><summary>LINEを送信</summary>

```javascript:sendLine
function sendLine(message){
  //makeのwebhookのURL設定
  const url = "";

  //送信完了をmakeを使ってLINEに通知
  const sendMessage = message;
  console.log(sendMessage);
  UrlFetchApp.fetch(url + encodeURIComponent(sendMessage));
}
```
</details>

### <3> MakeでLINEに通知
MakeにログインをしてWebhookの作成とLINEと連携を行います。
ここで、SCHEDULINGを『ON』にして、Run scenarioを『Immediately』に設定をすることでGASからのWebhookを常時受け取ることができるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618860/9ce90f59-f3c7-95ed-77c7-5249668d39a2.png)

### <4> GASでトリガーの設定を行う
↓のようにGASのトリガーで1分ごとにmainメソッドを呼び出すことで定期実行が可能になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2618860/e84505b3-a023-39ff-fd5a-08ebb06733cf.png)

## おわりに
今回初めてGASとMakeを使いましたが、数時間で問題解決のためのプロトタイプを作成することができるのかと感動をしました。今後も身の回りの問題や課題を解決していけるようなプロトタイプの作成をしていきたいと思います。

## ソースコード

</details><details><summary>完成版</summary>

```javascript:完成版
function Todo() {
  //■テーマ■
  //休憩時間にやることをLINEで通知

  //アクティブなシートを取得
  const sheet = SpreadsheetApp.getActiveSheet();

  //初期値
  //カテゴリー数
  const cat_len = 4;
  //カテゴリー数ごとの詳細数
  const detail_len = [5,5,6,1];

  // やることのカテゴリーをランダムにスプレッドシートから取得
  const random_num1 = Math.floor(Math.random()*cat_len)
  //カテゴリーを取得
  let message01 = sheet.getRange(random_num1*10+2,1).getValue();
  console.log("カテゴリー:",message01);

  // やることの詳細をスプレッドシートから取得 
  const random_num2 = Math.floor(Math.random()*detail_len[random_num1])
  //やることの詳細名前を取得
  let message02 = sheet.getRange(random_num1*10+random_num2+2,2).getValue();
  console.log("詳細:",message02);

  // 文末をスプレッドシートから取得 
  let message03 = sheet.getRange(random_num1*10+2,3).getValue();
  console.log("(random_num1*10+1,3):",random_num1*10+2)
  console.log("文末:",message03);

  message = "\n休憩時間になりました。\n\n＜やること＞\n"+message01 +"\n<詳細>\n"+ message02 + message03;

  // LINEをつかってメッセージを送信
  sendLine(message);
}

function sendLine(message){
  //makeのwebhookのURL設定
  const url = "";

  //送信完了をmakeを使ってLINEに通知
  const sendMessage = message;
  console.log(sendMessage);
  UrlFetchApp.fetch(url + encodeURIComponent(sendMessage));
}

// 指定された日が営業日か（営業日 = 「土日でない」「祝日カレンダーに予定がない」）
// 営業日 = true
function isWorkday (targetDate) {

  // targetDate の曜日を確認、週末は休む (false)
  var rest_or_work = ["REST","mon","tue","wed","thu","fri","REST"]; // 日〜土
  if ( rest_or_work [targetDate.getDay ()] == "REST" ) {
    return false;
  }; 

  // 祝日カレンダーを確認する
  var calJpHolidayUrl = "ja.japanese#holiday@group.v.calendar.google.com";
  var calJpHoliday = CalendarApp.getCalendarById (calJpHolidayUrl);
  if (calJpHoliday.getEventsForDay (targetDate).length != 0) {
    // その日に予定がなにか入っている = 祝祭日 = 営業日じゃない (false)
    return false;
  } ;

  // 全て当てはまらなければ営業日 (True)
  return true;
}

// 指定された時刻が休憩時間内か
function isWorktime (targetTime){

  //現在の時間と分を取得
  let target_hour = String(targetTime.getHours());
  let target_min = String(targetTime.getMinutes());

  //アクティブなシートを取得
  const sheet = SpreadsheetApp.getActiveSheet();
  //最終行
  const lastRow = 5;

  // targetTime の時刻を確認、休憩時間外は (false)
  for(let i=2;i<=lastRow;i++){ 
    let rest_time = sheet.getRange(i,4).getValue();
    let rest_hour = String(rest_time.getHours());
    let rest_min = String(rest_time.getMinutes());
    if ( target_hour+target_min == rest_hour+rest_min ) {
      console.log("休憩時間です。")
      return true;
    }
  }; 
  return false;
}

function main () {
  var today = new Date ();
  // debug のために任意の日付を仕込む (year,month-1,day,hour,min,sec)
  // today = new Date (2022, 05, 17, 11, 30, 0);

  console.log(today)

  // 営業日であれば実行
  if (isWorkday (today) == true) {
    if(isWorktime (today) == true){
      Todo();
    }
    else{
    console.log("まだ休憩時間ではありません。")
    }
  }
  else{
    console.log("今日はお休みです")
  }
}
```
</details>