熱中症アラートをGASからSlackで通知する

最近、37,38度などの猛暑日が続いています。
会社では、出社日が基本的に多いのですが、台風などの災害時には、
`RWでOK`、という方針をチームで決めました。

災害級の猛暑なら、行き倒れても困るし、`RWでOK！`ということに同じようにしよう、ということにしました。
ただし、`熱中症アラートが出た日に限定`。

# 熱中症アラートとは？
気象庁が出しているものですが、暑さ指数というものに準じてだしています。
気温ではありません。
`暑さ指数31以上だと、危険域に入る`とされています。

ので、一旦基準としては、暑さ指数31以上だったら、ということにしました。
しかし、暑さ指数をどこから取れば良いのか。

調べたところ、暑さ指数（WBGT)は、気象庁のサイトでcsvとしてアクセスできるとのこと。

https://www.wbgt.env.go.jp/data_service2.php

> 情報提供期間：2023年4月26日（水）～2023年10月25日（水）

という記載があるので、GASでの通知は年ごとに更新する必要はあるかもしれません。
ここから、CSV情報を引っ張ってくれば良さそうです。

::: note info
2024年に同じスプレッドシートを流用してみましたが、同様に更新されていたので、同じURLを公開しているようです。
:::


# 暑さ指数の実測値取得

実測値の取得を都道府県別、地点別、などで取得できるようになっています。
詳しくは、前項に貼ったリンクのPDFから確認してください。

`岐阜県の暑さ指数実測値URL`
https://www.wbgt.env.go.jp/est15WG/dl/wbgt_gifu_202304.csv

これを紐解くと
```
https://www.wbgt.env.go.jp/est15WG/dl/wbgt_ + 都道府県 _ + 日付.csv
```

というわけです。天気予報のjsonだと都道府県コードになっているので、それより簡単そうです。

`東京の暑さ指数実測値URL`

https://www.wbgt.env.go.jp/est15WG/dl/wbgt_tokyo_202307.csv

こんな感じですね。

# 外部CSVデータをGASで取得・・・しかし
通常、csvのデータ取得は、
```js
var input = 'https://www.wbgt.env.go.jp/est15WG/dl/wbgt_tokyo_202307.csv';
let response = UrlFetchApp.fetch(input, options);
```

で取得できるが、気象庁の暑さ指数のcsvはどういうわけか、UrlFetchAppで取得しようとすると、
`Exception: Address unavailable`が出てしまい、アクセスが不可能。

試しに、spreadsheetで、IMPORTDATA()でデータ取得してみると、取得は可能だった。
ただし、日付や時刻は文字化けしているような感じがある。
少し確認してみると、読み込んだcsvのデータが、自動で表示されているため、適宜日時や時間に治す必要がある。

![スクリーンショット 2023-07-22 14.58.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1026740/39d65417-d79e-78f9-ec44-abad612e6bcc.png)

直してみると正しく表示される。
![スクリーンショット 2023-07-22 14.59.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1026740/bce94a91-dcba-2155-3073-5c8d0dd37ab4.png)


googleか、サイトの権限上の問題がありそうだが、どうにも解決方法が見つからないので、IMPORTDATA()にてシートを介してやりくりする。

## 地域観測点
csvのデータを覗くと、数字のIDが振られている。これは地域観測点。


https://www.jma.go.jp/jma/kishou/know/amedas/ame_master.pdf

気象庁が出しているpdf一覧に記載がある。

> 44132:東京

こちらを採用してみる。

## SpreadSheetで、IMPORTDATA()
GASが読み込むためのシートを用意する。
ただ、さっき引用したのは実測値だったので、当日危険指数31を超えるかどうかは、出勤前には判断ができない。
そのため、見るcsvとしては予測値でなければならない。

`東京の暑さ指数予測値`
https://www.wbgt.env.go.jp/prev15WG/dl/yohou_tokyo.csv

暑さ指数は、通常の暑さ指数に対して10をかけている。

![スクリーンショット 2023-07-22 15.16.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1026740/00195e0b-0142-7c28-304e-05ab3f341749.png)

つまり、310以上になったら、アラートを出せば良い、ということになる。

`202307xx15 -> 7月某日、15時に310以上になるなら、アラートを通知する`
という仕様としてみる。

# スプレッドシートに関数を入れていく
まず結果から

![スクリーンショット 2023-07-22 20.13.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1026740/6cdfb6aa-e8a9-6162-aa94-f7af94202d7f.png)

※テストのために、暑さ指数しきい値を200ってことにして出しています。
`L2に、危険域かどうか、TRUE or FALSEが入ります。`

## XLOOKUPで、該当の時間の暑さ指数を探す
XLOOKUPは、スプレッドシートの関数ですが、交差した場所の検索が可能。
まず、WBGT値を割り出す。

|セル|値|補足|
|--|--|--|
|F1|44132|東京丸の内の地点|
|H1|=today()||
|J1|21|テストのためとりあえず21時|
|L1|=VALUE(CONCATENATE(H1, J1)|
|J2|=XLOOKUP(F1, B4:B14,XLOOKUP(L1, D3:W3,D4:W14))|
|L2|=IF(J2>=200,true,false)|テストのためしきい値を200としておく|

XLOOKUPは、入れ子で呼ぶことで、交差した値を検索することができる。

# GAS側の処理
GAS側はこのシートのTRUE or FALSEを引っ張ってきてトリガー通知するだけ。

```js
// スプレッドシートの読み込み
function loadSpreadSheet(url) {
  var spredId = url.replaceAll("https://docs.google.com/spreadsheets/d/", '');
  Logger.log("id : " + spredId);

  return SpreadsheetApp.openById(spredId);
}

/**
 * メッセージの送信
 */
function sendSlackMessage(message, channel) {
  Logger.log("Send Slack Message");
  var url = "https://slack.com/api/chat.postMessage";
  var bot_token = PropertiesService.getScriptProperties().getProperty("slackbot_token");

  var payload = {
    "token": bot_token,
    "channel": channel,
    "text": message
  };

  var options =
  {
    "method": "post",
    "payload": payload
  };

  UrlFetchApp.fetch(url, options);
}

// 暑さ指数についてアラートを出す
// 気象庁のシートをインポートしているが、コレは公開時期が限定されているので注意
function alertWBGT() {
  // heat_wbgtシート
  var sheet = loadSpreadSheet('シートid');
  var wbgt = sheet.getRange("J2");
  var wbgtValue = wbgt.getValue();
  if (isNaN(wbgtValue)) {
    Logger.log('値とれないっす');
    return;    
  } else {
    Logger.log("WBGT値:" + wbgtValue);
  }

  var alert = sheet.getRange("L2");
  var alertValue = alert.getValue();

  // 暑さ指数が31超えてたら通知する
  if (!isNaN(alertValue) && alertValue) {
    Logger.log("熱中症アラート：" + alertValue);
    var message = ":alert:暑さ指数31を超えてます! :hot_face: 熱中症アラートに注意してください!:alert:"
    sendSlackMessage(message, '通知するCH');
  }
}

```

トリガー設定については割愛。
基本的には、スプレッドシートで暑さ指数と、時間を調整する。

Slackの結果はこんな感じ。
![スクリーンショット 2023-07-22 20.25.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1026740/b39733c3-92d2-beac-03fd-9094f303f07e.png)

補足・・・。
気象庁のCSVじゃなくて、環境庁でした。

実際のしきい値としては、310、時間は12,15時あたりを取ってくるのが良いかと思います。