地震を知らせるDiscordボットを作ったお話

この記事は [防災アプリ開発 Advent Calendar 2023](https://adventar.org/calendars/9301) 11日目、
[Qiita全国学生対抗戦 Advent Calendar 2023](https://qiita.com/advent-calendar/2023/student) 11日目の記事です。

2024/07/15 一部リンク修正
2025/02/22 リンク切れ箇所を修正
2025/05/21 リンク切れ箇所等、一部文章や画像の修正

# はじめに
2年ほど前から Windows向けの地震情報ソフトを製作しています。
昨年はそのソフトに関する[記事](https://qiita.com/Ameuma773/items/db48285f2a38a3e37c99)を書きました。

2023年、この記事では新たに製作したDiscordボットについて書いていこうと思います。

:::note warn
地震情報の基礎知識などについて、できるだけ初見でも理解できるように書いています。
ただし、間違った情報を書いてしまっている可能性もあります。
予めご了承の上、間違いがあった場合はお知らせください。
:::

# ボットの概要
Discord上で **地震情報** やそれに伴う **津波情報** をお知らせするボットです。
この度、一般向けにボットを公開しましたので、ご自身のDiscordサーバーでご利用いただけます。

https://earthquickly.com/discord/

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">地震・津波情報をお知らせする Discordボット<br>「EarthQuickly for Discord」を公開しました。<br>ご自身のDiscordサーバーにて、ぜひお使いください！<a href="https://t.co/MJI7c4PaUo">https://t.co/MJI7c4PaUo</a> <a href="https://t.co/Is0HeMqFi9">pic.twitter.com/Is0HeMqFi9</a></p>&mdash; あめうま (@Ameuma773) <a href="https://twitter.com/Ameuma773/status/1733645202722898355?ref_src=twsrc%5Etfw">December 10, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

このボットの最大の特徴は
『**すべての情報を地図に描画する**』ことです。

地震情報と一概に言っても、たくさんの種類があります。
今回作成したボットで受信できるのは、気象庁が発表する以下の情報です。

## 緊急地震速報
緊迫感のある「あの音」のイメージが強そうな緊急地震速報。
緊急地震速報には、大きく2種類「**予報**」と「**警報**」があり、
一般に想像される、テレビや防災無線などで流れる緊急地震速報は **警報** です。

緊急地震速報（予報）では、
予想されている **震源地・規模・最大震度** などの情報が事細かに取得でき、
予想が更新された場合は、すぐに「続報」が発表されます。
過去には、高度利用者向けの情報が一つの地震に対して70報以上発表されたこともあります。
（例 : 2022/03/16 福島県沖 M7.4 の地震など）

ただしDiscordボットにはレートリミットがあり、緊急地震速報を毎報送信していては、
大地震の際などに制限に引っかかる恐れがあります。

そのため 緊急地震速報（予報）においては、
- **第1報**
- **最大震度が更新されたとき**
- **最終報**

の3つに絞って送信することにしています。
もちろん 緊急地震速報（警報）については、すべての情報を送信します。

表示例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/2c4e9df1-88b5-9398-edd1-624cca91ce8e.png)
[2023年11月30日19時53分発生の地震](https://typhoon.yahoo.co.jp/weather/jp/earthquake/20231130195331.html)における緊急地震速報（予報）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/ac8d51a0-5a3b-8660-172d-f5f33ec5ed0a.png)
[2023年6月11日18時55分発生の地震](https://typhoon.yahoo.co.jp/weather/jp/earthquake/20230611185503.html)における緊急地震速報（警報）
※タイムスタンプ・送信時刻は動作確認時の時刻で、実際の発表とは異なります。

このボットでは 予報と警報、どちらの情報もお知らせできるので、
予報における豊富な予想の情報量と、警報で発表する明示的な警戒地域、
両方の情報を即座に知る事ができます。
 
> 緊急地震速報システムの詳細な解説は省きます。
> **[気象庁｜緊急地震速報｜緊急地震速報とは](https://www.data.jma.go.jp/eew/data/nc/shikumi/whats-eew.html)**

## いわゆる「地震情報」
地震が発生した後、今の地震は震度いくつだったのか？と気になりますよね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/8b5244c6-a24f-074e-ad76-dd04f25c63fe.png)
[2023年11月30日 20時38分発生の地震](https://typhoon.yahoo.co.jp/weather/jp/earthquake/20231130203540.html)における地震情報

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/580459e1-d076-20dd-6e78-6e70fa2a3466.png)
[2023年5月11日 4時11分発生の地震における震度速報](https://typhoon.yahoo.co.jp/weather/jp/earthquake/20230511041647.html)
※タイムスタンプは動作確認時の時刻で、実際の発表時刻とは異なります。

前述の緊急地震速報と同様、震度のアイコンを大きく表示させることで、
パッと見て情報の概要が理解できるようにしています。

## 津波情報
地震と津波は切っても切り離せない関係にあります。
大きな地震があった後は津波の有無を特に気にする方も多いのではないのでしょうか。

津波情報も地図と文字の両方で、分かりやすくお知らせします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/f6805f41-5e41-deb8-03c9-b06f23d5c6c7.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/0a9ed954-f0ec-c5af-6776-c5070a24068f.png)
2023年10月09日 08時24分発表の情報
※お知らせ文のタイムスタンプは動作確認時の時刻で、実際の発表時刻とは異なります。

気象庁の発表する津波情報には、
「**大津波警報**」「**津波警報**」「**津波注意報**」「**津波予報**」があります。

|情報の種類|予想高さの発表値|
|:-:|:-:|
|大津波警報|5m, 10m, 10m超|
|津波警報|3m|
|津波注意報|1m|
|津波予報|0.2m|

一般に「津波の心配がある」とされるのは、**津波注意報以上**が発表されたときです。
APIの問題等もあり、津波注意報以上の情報のみを受信対象としています。

津波注意報の発表範囲が広いと、それだけメッセージも長くなってしまいます。
見にくさが生じる点については、解決すべき課題だと感じています。

スクショを見ればわかる通り、11月に実装していたこの機能ですが、
まさか2週間も経たずに「**本番**」が来るなんて...（後述）

# 受け取りやすくする工夫
このボットでは、受け取る情報をチャンネルごとに設定できます。

そのため、地震情報と緊急地震速報で**チャンネルを分けたり**、
緊急地震速報（警報）などの緊急性の高い情報は**人の多いチャンネルにも流す**など、
情報の重要度に応じた設定を行うことが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/174820f3-6949-85b4-5320-89925760d33b.png)

# 技術的なお話
```tex:使用したフレームワーク・ライブラリ
Node.js v20, Disocrd.js v14, Puppeteer, Leaflet
```

### システム概要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/0665d5eb-e0c1-cc49-fa02-ecd34f03387d.png)

地震情報や津波情報、緊急地震速報を発表するのはもちろん 気象庁 です。
気象庁から直接受信することも『**技術的には可能**』ですが費用面などを踏まえると、
余りにも敷居が高すぎるので、おとなしくAPIに頼ることにします。

### 利用しているAPI
地震情報・津波情報・緊急地震速報（警報）
[P2P地震情報 JSON API v2](https://www.p2pquake.net/develop/json_api_v2/)

緊急地震速報（予報）
[Wolfx API](https://api.wolfx.jp/)

## 地図への描画

開発当初から、『**すべての情報を地図に描画する**』ことを前提にシステムを考えていました。
しかし、サーバーで画像生成というもののハードルの高さに軽く絶望しました。

### 発想の転換

自分が過去に開発したものに、[EarthQuickly for Web](https://ameuma773.github.io/EarthQuicklyForWeb/)というWebサイトがあります。
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/41c06da1-01d6-550c-d1f2-b0d4f3fddd1c.jpeg)

Leafletを用いた地図描画が売りのサイトですが、
地震情報を地図に描画する部分だけ切り抜いて使えるのでは？と考えました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/ad40cac6-80f4-db0f-97d6-edc7a93774dd.png" width = 50%">　地図の部分だけ切り抜いた図

ボットを動かすNode.jsサーバーで、puppeteerのChromiumブラウザを起動しておき、
WebSocket経由で地震情報を受信した際に、すぐにブラウザへ情報の載ったJSONを送ります。

EarthQuickly for Webのサイトで使っている描画する関数を実行し、
処理終了のタイミングで、すぐにスクリーンショットを撮影します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/e35edc43-35f0-94cb-d250-d49bff5f97f7.png)

あとはDiscord.jsで、生成した画像を添付したメッセージを作成し、
指定されたチャンネルへメッセージを送信するだけです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/89169c3b-11cb-7ca5-7b10-7c0448894ee4.png)

思いのほか、良い感じにDiscordの画面にも合ってる感じがして結構好きです。

# 謝辞的な何か
### とあるDiscordサーバーとの出会い
このボットを作るきっかけになった出会いです。

とある日、あるDiscordサーバーに参加させていただきました。
地震や防災に興味のある方が多いこのサーバーでは、
**地震情報**や**気象情報**、火山の**噴火情報**までボットがお知らせしていました。

600を超える人が集まっていたこの場所において、
これらのボットが防災に少しでも寄与するのは間違いのないことでしょう。

そんなボットたちに尊敬の意を抱くとともに、
「**こんなボットを作ってみたい！！**」という憧れも抱きました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/527990dd-5986-e862-8dc6-20134c90ddd9.png)

過去にDiscordのボットの開発した経験は幾ばくかありますが、
どれも中途半端に終わったものばかり。

そのため、作り始めたところで三日坊主に終わるだろうと思うのは自然な話です。
そう思って、なんだかんだと数か月が経過していました。

### 開発チームがあるらしい
例のDiscordサーバーには、
ボットの開発やサイトの制作などを行っている方達のチームがありました。

あのサーバーには、防災情報のボットのみならず様々なボットが生息(?)しています。

他のサーバーで見るような大手のボットはむしろ少なく、
この開発チームの手によって生み出されたボットが多数を占めています。

そんな活発に開発が行われている現場を目の当たりにして、
いわゆる「**開発欲**」が沸々と湧いてくるわけです。

ふと呟きました。
```
私「自分も新しくbot作ろうかな
　地震情報を地図に描画して送信するような」
 
 鯖主「もし作れたら地震情報のチャンネルで使いたいな」
 ```
「**え、使ってくれるの！！！！！**」

鯖主本人からのこの発言、
これが原動力になり、ついに新しい地震ボットの開発がスタートしました。

モチベーションって重要ですよね、という話です。
滅多に着火することのない、やる気の炎が点火しました。

### 数日後
本当に使ってもらえました。
技術力を認められたような気がして嬉しかったですね。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/73ce899e-b579-5bcf-4f7c-058a0c4b8c2a.png" width="80%">

開発チームの方々には、フィードバックの面で大変お世話になりました。
なんといっても、防災にもボットにも精通した有識者だらけなのですから。

これほど心強いことはありません。本当にありがとうございます。

# 実例
記事を書いていた矢先、[フィリピン付近でM7.7の大地震](https://typhoon.yahoo.co.jp/weather/jp/earthquake/20231202234048.html)が発生。
日本の太平洋側には、広い範囲に津波注意報が発表されました。

11月に実装していた津波情報の機能は、この津波情報にも問題なく対応してくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/062134dc-ee2f-5dfa-87be-156e53032317.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/d8b2496e-029f-b08e-fa31-f0fdb80eed3a.png)
※発表地域が長すぎるため、カットしています。

### 生成した画像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/dac5cc77-ef0d-51cc-2b97-dec751795a5e.png)

やはりメッセージが長くなる問題はあるものの、すべての動作が予定通りに動きました。
問題なく情報が描画できている様子を見て、少しほっとしました。

このような防災系のプロダクトは、いざという時に動いてこそ意味がある物なので、
こういう時に動かなかったら大問題ですからね。

もちろん、翌朝の津波注意報解除も問題なくお知らせすることができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/b1a17f4d-07ec-24a9-3e9a-41c0cfd1b9d5.png)

# 最後に
久しぶりのDiscordボット開発にはなりましたが、とても良い経験になったと思います。
そしてこれからもボットの維持・管理・改善を続けていきますので、
少しでも開発を応援していただけると幸いです。

最後までお読みいただき、ありがとうございました。

> 開発に携わり、助言を下さったすべての方に改めて感謝申し上げます。
> 本当にありがとうございました。これからもよろしくお願いいたします。

![スクリーンショット 2024-12-03 000152.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2359589/2f860c20-388d-43da-b86b-3da3a6527f49.png)