桜前線の訪れをSlackに通知してみる🌸

3月も下旬にさしかかり、うららかな陽気に心躍る季節となりました

いよいよ桜の開花も近づいてきましたね。
今回はそんなワクワク桜の開花予報をSlackへ通知してみようと思います🌸

## 完成イメージ
sustenでは毎朝天気などともに始業をお知らせしてくれる "sustenくん" というSlackBotがいます。
こちらに桜の開花予報通知機能（赤枠部分）を追加してみることにします。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14082/9327ba23-0661-0a82-a69a-6d611c95555c.png)

こんな通知が毎朝通知がくれば ~~陰鬱な始業時間でも~~ 朝からワクワクが止まらないことこの上なしですね！！


## どうやって予測するのか

桜の開花に関する法則で「桜の開花600度の法則」という有名な法則があります。
これは、2月1日から毎日の最高気温を足していき、その累積が600度になったときに桜が開花するというものです。



今回はこの法則に従って2月以降の累積温度を計算し桜開花600度まであとどのくらいかSlackに通知することにします。

## 実装の流れ
お手軽に定時実行を行いたかったため GoogleAppsScript を利用した実装を行います。

0. 気象庁のページから2/1から前日までの最高気温を取得（初回のみ）
1. 気象庁のページから前日の最高気温を取得（デイリー）
1. 取得した気温に当日の最高気温（予想）を足し合わせる
1. 桜開花の進捗をSlackへ通知




### 前日の最高気温を取得する処理

気象庁のページでは気象に関する様々な情報を提供してくれています。
これらのデータは毎日5時、11時、17時の発表に基づいて更新されます。
今回はGASのParserというライブラリを用いて東京都の過去天気ページをクロールし、前日の最高気温を取得することにします。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14082/6ab8fe47-7177-38b1-2bde-fdf435de9301.png)



```Javascript
/*
 * 気象庁のページから前日の最高気温を取得する
 */
function _getYesterdayMaxTemperature() {
  const now = new Date();
  const year = now.getFullYear();
  const month = now.getMonth() + 1;
  const TARGET_URL = `https://www.data.jma.go.jp/obd/stats/etrn/view/daily_s1.php?prec_no=44&block_no=47662&year=${year}&month=${month}&day=&view=p1`;
  // 指定したURLからコンテンツを取得
  const html = UrlFetchApp.fetch(TARGET_URL).getContentText();
  // 取得したコンテンツデータから気象情報をフィルタする
  const rows = Parser.data(html)
    .from(
      '<tr class="mtx" style="text-align:right;">'
    )
    .to("</tr>")
    .iterate();

  // テーブル内の最高気温(8列目のデータ)をすべて抜き出して数値が入っているものだけ抜き出す
  const maxTemps = rows.map(row => row.split("</td>")[7].split('">')[1]).filter(data => data !== "");

  // 一番最後のものが直近（昨日のデータのはず）なので返却する
  return maxTemps.slice(-1)[0];
}
```

このような処理で前日の最高気温を取得してスプレッドシートに記録を行っており、累積気温はスプレッドシート側で計算させています。
~~かなり雑なコードですが社内用なので大目に見てください🙈~~


|![スクリーンショット 2024-03-25 17.42.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14082/ec97f204-b6ed-c39c-7e02-fb026c204b89.png)|
|---|

スプレッドシートには記録せずにreduceで足し合わせてもよいのですが、月またぎの処理が面倒くさそうだったので今回はスプレッドシードに記録する方法を採用しました。

### 桜開花の進捗をSlackへ通知

次にSlackへの通知部分を実装してきましょう！

```Javascript
/*
 * 桜開花状況をSlackへ通知する
 */
function notifyCherryTreeBloom() {
  const MAX = 600;
  const sheet = SpreadsheetApp.openById("xxxxxxxxxxxxxx").getSheetByName("cherry_blossom");
  // シートから累積気温（実績）を取得
  const total = sheet.getRange("B1").getValue();
  // シートから今日の気温（予測）を取得
  const today = sheet.getRange("D1").getValue();

  //　Slackに投稿するメッセージの組み立て
  const percent = Math.floor(((today + total) / MAX) * 100);
  const remain = Math.floor(((MAX - (today + total)) * 10) / 10);
  const cumulativeTemperature = Math.floor((today + total) * 10) / 10;
  const graph = [...Array(100 / 5)].map((_, i) =>
    (i + 1) * 5 <= percent ? "▓" : "▒"
  );
  let message = "";
  message += `2/1からの累積温度は ${cumulativeTemperature} ℃ :chart-up:\n`;

  // 累積気温が600度を超えていたら開花宣言
  if (MAX <= cumulativeTemperature) {
    message +=
      ":cherry_blossom::cherry_blossom: さくらは開花しています！！ :cherry_blossom::cherry_blossom:";
  } else {
    message += `さくらの開花まであと ${remain} ℃ :exclamation:\n`;
    message += `:seedling: 0 ℃ [` + graph.join("") + "] 600 ℃:cherry_blossom:";
  }

  return message;
}

```


# まとめ

記録したデータを基に日々の気温と累積気温をグラフにしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14082/84e49447-5c55-de37-451b-f2fc03b20c35.png)

東京では3月18日に600度を超えてますが、この記事を書いている2024/03/26時点でまだ開花の発表はありません。
見事に外れてますが人生そんなもんです。

# 参考
- [桜の「600℃の法則」とは？開花時期の目安は簡単に計算できるんです \| ハフポスト NEWS](https://www.huffingtonpost.jp/entry/story_jp_65e7c000e4b0d2a2475b0267)
- [気象庁 Japan Meteorological Agency](https://www.jma.go.jp/jma/index.html)