はじめてのGASアプリ – 天気予報SlackBot

## はじめに
Google Apps Scriptをやってみますか？
ここでは、0からGASでSlackに天気予報を投稿するBotの作成方法を共有していきます。
基本的には、他のブログから学び、初めてのGASの作成の模様を自分用メモとして書きました。

## 0.作業環境を用意する
僕の環境は以下の通りです。
1) Windows 10 Pro 64 bit
2) Google Chrome
3) 自分用のGoogleアカウント
4) 管理権限を持っているSlackアカウント

## 1.Slackアプリを作成する
[【初心者向けGAS×Slack】はじめてのSlackアプリを作成しよう](https://tonari-it.com/gas-slack-create-app/)
そんなに難しくない、手順通りで大丈夫と思います。

## 2.Incoming Webhooksを導入する
[【初心者向けGAS】Slackにメッセージを投稿するIncoming Webhooksの最初の一歩](https://tonari-it.com/gas-slack-incoming-webhook/)
生成した**Webhook URL**のメモが必要です。後ほど、postMessageに使います。

## 3.Google Apps Scriptを新規作成する
1) Googleドライブは、Googleトップページ右上のアプリ一覧から開き、「ドライブ」をクリックする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1109922/5b41d3dc-726f-3a2b-e684-9177e33ae85e.png)

2) Googleドライブの左上の[:heavy_plus_sign: 新規]から[その他]→[Google Apps Script]の順に進みます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1109922/1d817dd9-c644-12a1-019c-b5e4fda30a14.png)

3) 「無題のプロジェクト」を新規作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1109922/316e361a-d547-1b95-229b-7856c20ab31e.png)

## 4.天気予報SlackBotの実装
###4.1.天気予報API「OpenWeatherMap」について
現時点、完全制限なしの天気予報APIがほとんどないので、今回は認証が必要なAPI: [**OpenWeatherMap**](https://openweathermap.org/)を使うことに決めました。

無料版で利用可能な以下の2つをAPIで実行します。
・指定した都市の現在の天気を取得する。(http://api.openweathermap.org/data/2.5/weather?q={city}&appid={key}&lang=ja&units=metric)
・指定した都市の先5日間の3時間ごとの天気を取得する。(http://api.openweathermap.org/data/2.5/forecast?q={city}&appid={key}&lang=ja&units=metric)
**q={city}&appid={key}**を自分の天気を取得したい都市名、APIキーにセットすることが必要です。

###4.2.天気予報APIからのJSONを文字列に変換する

```js:app.gs
function main() {
  // get from > https://home.openweathermap.org/api_keys
  // *current weather api*
  var URL = 'http://api.openweathermap.org/data/2.5/weather?q=Shinagawa-ku,JP&appid={your API key}&lang=ja&units=metric';
  var res = UrlFetchApp.fetch(URL);
  var data = JSON.parse(res.getContentText());

  // *every 3 hours for the last 5 days weather api*
  var futureURL = 'http://api.openweathermap.org/data/2.5/forecast?q=Shinagawa-ku,JP&appid={your API key}&lang=ja&units=metric';
  var futureResponse = UrlFetchApp.fetch(futureURL);
  var futureData = JSON.parse(futureResponse.getContentText());

  // send message text
  var strBody = "";

  if(data.cod == 200 && futureData.cod == 200){
    var city = data.name;

    // current data
    var summary = data.weather[0].description;
    var temp = Math.floor(data.main.temp);
    var date = new Date(data.dt*1000);

    // tomorrow data
    const tomorrowHour = 9;
    var tomorrowData = futureData.list.find(s => new Date(s.dt*1000).getHours() == tomorrowHour);
    var tomorrowSummary = tomorrowData.weather[0].description;
    var tomorrowTemp = Math.floor(tomorrowData.main.temp);
    var tomorrowDate = new Date(tomorrowData.dt*1000);
    var ary = ["日", "月", "火", "水", "木", "金", "土"];
    var week_num = tomorrowDate.getDay();
    var week = "("+ary[week_num]+")";
    var time = Utilities.formatDate(tomorrowDate, "Asia/Tokyo", "M/d");
    var tomorrowDateText = time + week;

    var todayWeather = "*【今日 " + date.getHours() + "時発表の天気予報" + getEmoji(data) + "】*\n> " + city + "：" + summary + " " + temp + "℃";
    var tomorrowWeather = "*【明日 " + tomorrowDateText + " 午前" + String(tomorrowHour) + "時の天気" + getEmoji(tomorrowData) + "】*\n> " + city + "：" + tomorrowSummary + " " + tomorrowTemp + "℃";

    strBody = todayWeather + "\n" + tomorrowWeather;
  }
  else{
    strBody = "データを取得できません。ご確認ください。";
  }

  post(strBody);
}
```

###4.3.Incoming Webhooksの機能を使って、Slackにメッセージを送る

```js:post.gs
function post(text) {
  // *Slack Webhook URL*
  var url = 'your Webhook URL';
  var params = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({text: text}),
  };
  UrlFetchApp.fetch(url, params);
}
```

###4.4.天気に応じた天気アイコンを表示させる

```js:getEmoji.gs
function getEmoji(json) {
  switch (json.weather[0].main){
    case 'Clouds':
    return ":cloud:";
    case 'Snow':
    return ":snowflake:";
    case 'Rain':
    return ":rain_cloud:";
    case 'Clear':
    return ":sun_with_face:";
    case 'Fog':
    case 'Haze':
    return ":fog:";
    case 'Mist':
    return ":barely_sunny:";
    default:
    return ":mostly_sunny:";
  }
}
```

###4.5.天気予報をSlackに送る動作確認
プロジェクト編集画面の「:arrow_forward: 実行」ボタンをクリックして、Incoming Webhooksで設定したチャンネルに以下のように投稿が行われます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1109922/075b2c01-6f18-b6ab-af7e-ec0fd8bda327.png)

###4.6.祝日・休日判定処理の追加（FIX:06/27）
6月27日現時点、出勤日のみメッセージを届けたいので、以下のように祝日・休日判定処理を追加する。
戻り値がTRUEの場合、メッセージ送信を行う。

```js:workday.gs
function workday(date) {
  // check today is working day
  let dateInt = date.getDay();
  if (dateInt == 0 || dateInt == 6) {
    return false;
  }
  // check today is holiday
  let calendarId = "ja.japanese#holiday@group.v.calendar.google.com";
  let calendar = CalendarApp.getCalendarById(calendarId);
  let todayEvents = calendar.getEventsForDay(date);
  if (todayEvents.length > 0) {
    return false;
  }
  return true;
}
```

## 5.デプロイ
1、画面右上にある「デプロイ」ボタン→「新しいデプロイ」で、作成済みのAPPをデプロイする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1109922/56064006-c3ca-5562-a90c-70f9e3651d90.png)
2、Googleアカウントを選択して、データへのアクセスを承認する。
（「アクセスを承認」ボタン→「詳細」リンク→プロジェクト名（安全ではないページ）に移動→「許可」ボタン→「完了」ボタン）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1109922/0ed9f64e-dda1-3cd6-070d-e26d557de4f2.png)

## 6.トリガー
画面左側にある「:alarm_clock: トリガー」メニュー→[:heavy_plus_sign: トリガーを追加]ボタン、APP実行したい時間帯を選択すると、「保存」ボタンをクリックする。
僕の方は、毎日退勤する前、現在の気温とあす朝の天気を知りたい、午後6-7時を選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1109922/27855223-f4fd-47b9-f478-2e16236155f6.png)

## 7.自動的に投稿を実行される
選択した時間帯通りに知りたい情報を投稿しました！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1109922/4205fe96-37d6-26a1-c0f7-9ed7cbe798c8.png)

## 8.Source Code (GitHub)
https://github.com/peepa857/gas-weather-bot

## まとめ
GASの初心者として天気予報Botを作れました。定期ジョブ、デプロイ作業は意外に親しみやすい、マウスを数回クリックするだけです。APIから取得のデータを活用して、投稿内容のカスタマイズを簡単にできます。

## 参照サイト
https://tonari-it.com/google-apps-script-manual/#toc29

https://auto-worker.com/blog/?p=1612#toc_id_1

http://greenkour.hateblo.jp/entry/2018/08/06/093000