LINE API × GASで猛暑日クーポンを自動投稿＆設定機能をつくる

![1624593122625.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1552742/39252c0e-515d-f031-04cc-a80bc13b5ef8.png)



# 概要
前回おこなった [雨の日セール](https://qiita.com/mkpa602/items/cdcce8839960f6c6a31e) の第二弾。
前回と同じく気象庁のデータをGASで取得し、対象地域の翌日の最高気温が30℃以上なら、LINE公式アカウント（旧LINE＠）で猛暑日クーポンを投稿する。といった流れ。更に今回は投稿の基準となる"しきい値"を設定できるようにする。

# 前回より
前回の [雨の日セール](https://qiita.com/mkpa602/items/cdcce8839960f6c6a31e) をテスト運用中、「しきい値を変更できたら有難い」という声を頂いたので、設定機能をつくることに。といっても1からUIをつくる時間も技術も無いのと、GASを使用している事もありスプレッドシートを採用し、しきい値を設定できるようにするのと、ついでに自動投稿を一旦中止する仕組みをつくる。

# 使用したもの
・LINE Messaging API
・Google Apps Script (GAS)
・気象庁ホームページ
・Google SpreadSheet ←new!

# 気象データの取得について
取得する方法は前回の [雨の日セール](https://qiita.com/mkpa602/items/cdcce8839960f6c6a31e) と同じ。

```url:url
https://www.jma.go.jp/bosai/forecast/data/forecast/(area_code).json
```
(area_code)の所に取得したい地域のコードを入れるとjsonでデータが表示される。

 各地域のコード … [気象庁 天気予報](http://www.jma.go.jp/bosai/forecast/)より都道府県を指定し遷移後のURL末端にある6ケタの数字

前回と同様に山口県の気象データを取得する。

```javascript:getForcastData()
  const response = UrlFetchApp.fetch(`https://www.jma.go.jp/bosai/forecast/data/forecast/350000.json`)
  const data = JSON.parse(response)
```
# 最高気温30℃以上の判定
元データの[サイト](http://www.jma.go.jp/bosai/forecast/#area_type=offices&area_code=350000)を見ると、複数の地域の値があるので前回と同じく中部のデータのみ取得。

上記で取得したデータのうち中部の最高気温の値はここに格納されている。

```javascript:getForcastData()
data[0].timeSeries[1].areas[1].temps
```

取得する時間によって格納される値の数が変動する（今日の過ぎた時間帯の値は入らない）ので、今回は格納されている数によって取得する値を変える方法を採用。

```javascript:getForcastData()
  var maxtemp = getMaxtemp(data); //下の関数を使用

  function getMaxtemp(data){
    var tempArray = data[0].timeSeries[2].areas[1].temps
    if(tempArray.length==4){
      return data[0].timeSeries[2].areas[1].temps[3]
    }else if(tempArray.length ==3){
      return data[0].timeSeries[2].areas[1].temps[2]
    }else if(tempArray.length == 2){
      return data[0].timeSeries[2].areas[1].temps[1]
    }
  }

```

本題の判定へ。
最高気温が30℃以上なら投稿処理を実行。
下で使っている変数(hotLine)には後で設定するしきい値を格納する。

```javascript:getForcastData()
/*中略*/
var hotLine = "30" //ここに後述する設定値を格納する

if(maxtemp >= hotLine){
    var tomorrow = new Date();
    tomorrow.setDate(tomorrow.getDate() + 1);
    var tomorrowformat = Utilities.formatDate(tomorrow, 'Asia/Tokyo', 'M/d');
    var title = '【明日は最高気温' + maxtemp + '℃の予報☀ 限定クーポン配信】';
    var header = 'こんばんは\uDBC0\uDC02\n\n'
    var msg = title + '\n\n' + header + '明日' + tomorrowformat + 'の山口は最高気温が' + maxtemp + '℃の予報となっています。お体にお気をつけ下さいませ。\n\n↓猛暑限定クーポンお知らせ↓';
    var imageURL = '販促画像リンク';
    var postData = {
      'messages': [{
      'type': 'text',
      'text': msg
      },{
        "type": "flex",
        "altText": title,
        "contents": {
          "type": "bubble",
          "hero": {
            "type": "image",
            "url": imageURL,
            "size": "full",
            "aspectRatio": "1:1.035",
            "aspectMode": "cover"
          }
        }
      }],
    };
    broadcast_fetch_data(postData);
 }
```

```javascript:broadcast_fetch_data()
function broadcast_fetch_data(postData) {
  var options = {
    "method": "post",
    "headers": {
      "Content-Type": "application/json",
      "Authorization": "Bearer " + "LINEのアクセストークン"
    },
    "payload": JSON.stringify(postData)
  };
  UrlFetchApp.fetch("https://api.line.me/v2/bot/message/broadcast", options);
}
```

あとはGASのトリガーで毎日一定時間に作動させれば無事完了。

# 設定機能をつくる
前述したようにスプレッドシートでしきい値を設定できるようにするのと、ついでに自動投稿を一旦中止する仕組みをつくる。

仕組みは単純で、
　・スプレッドシートにしきい値を入力するセルを作成。
　・GASにてセルの値を取得し、しきい値として使用する。
　・セルが空白の場合は投稿を中止するようにする。


スプレッドシートに以下の形で作成。
![SharedScreenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1552742/4053a130-2fb3-5c2c-bb8a-84e804ec3d8f.jpeg)

あと共有して使用するため、値以外のセルは保護＆余計な値を入れないよう入力規則を設定。
![SharedScreenshot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1552742/b4a27cb8-1602-6ccd-c415-f3fea4543007.jpeg)

念のため（？）100℃まで入力可能に。

# しきい値を取得する

GASにてスプレッドシートの値を読み込む。
他の機能の設定値も取得したいので、汎用的な関数を作成。


```javascript:GetSettingValue()
//値を取得したい項目名を引数に入れる
function GetSettingValue(target) {
  var spreadsheet = SpreadsheetApp.openById("スプレッドシートのId");
  var sheet = spreadsheet.getSheetByName("設定"); //シート名
  var textFinder = sheet.createTextFinder("^" + target + "$").useRegularExpression(true); //検索メソッド。ここでは正規表現で完全一致の条件を指定。
  var ranges = textFinder.findAll();
  
  if(ranges.length >0){
    for (var i = 0; i < ranges.length; i++) {
      // 念のため一致した項目がA列にあるか判定
      if(ranges[i].getColumn() == "1"){
        var index = ranges[i].getRowIndex();
        // セルが空白の場合はnullを返す
        if(sheet.getRange(index, 2).isBlank()) return null
        // セルが空白ではない場合は値を返す
        return sheet.getRange(index, 2).getValue();
      }
    }
  }
}
```

で、先述した処理に組み込むと以下の形に。
しきい値が空欄の時にはnullを返すので、if文に条件を追加し投稿処理から除外させる。

```javascript:getForcastData()
/*中略*/
  var hotLine = GetSettingValue("最高気温条件値");

  //明日の最高気温がしきい値以上かつnull以外のとき
  if((maxtemp >= hotLine)&&(hotLine != null)){
    /*前述の投稿処理*/
  }
```


# 備考
データの置き場所兼UIとしてスプレッドシートを採用したものの、
最終的には
・UI->LINEのトーク画面（一応完成済）
・データの置き場所-> Firebase
が最適なのかなと日々模索中・・。