洗濯物は放置しているとカビ臭くなるよね
自分の部屋から洗濯機までが離れているので、洗濯終了のビープ音が聞こえないのです。
これは自室でゲームに集中しているとなおさらです。
最新の洗濯機にはスマホ連携でスマホに通知が飛んでくるそうですが、うちのオンボロ洗濯機にはそんな機能はないのです。
この課題を解決するには、そう、ゲーマーのお供のDiscordに通知を飛んでくるようにしようと思ったわけです。
作ったもの
まずは洗濯機にSwitchBot Plug Miniを接続します。
Plug Miniは基本的には遠隔からコンセントのON/OFFを切り替えるものですが、実は電流や電圧をモニタリングすることもできます。
無料でサクッと運用できそうだなと、Cloudflare Workers + Honoで3分おきにSwitchBot APIを叩いてデバイス状態を取得し、消費ワット数(=電圧×電流)が変わったら、Discord Webhookを叩いて通知するという仕組みです。
1日でパパっと作って、これで臭い洗濯物とおさらばと思っていました。
429 Too Many Requests
ところが実際に動かしてみると、DiscordのWebhookを叩くと「429 Too Many Requests」というエラーが返ってくるではありませんか。
3分おきにポーリングし、Cloudeflare のKVに現在の状態を保存して、ON/OFFが切り替わったときにしかWebhookをコールしていません。これでToo Many Requests…???
色々調べてみると、どうもCloudflareからのアクセスがDiscordのレートリミットに厳しく制限されているためらしいです。
Cloudflare Developersのフォーラムでも同様の事例が報告されていました。
あるユーザーはCloudflare WorkersでDiscord通知ワーカーをホストしていた際、WebhookへのPOSTで 「429 - error code: 1015」エラーを受け取ったと報告しており、このエラーはDiscordからではなくCloudflareからのものであるように見えたとのこと。
この問題に対し、別のユーザーからは「DiscordはCloudflareを利用しており、Cloudflareのレートリミットを適用しているため、Cloudflare WorkersのIPアドレスに対してレートリミットが厳しすぎるという問題は以前から知られている」との指摘がありました。この状況を打開するにはリトライが必要であるとも述べられています。
429エラーが発生した場合、レスポンスヘッダーに含まれる「Retry-After」の値を取得し、指定された秒数だけ待機してから再試行するロジックを実装してみました。しかし、例えばリトライ時間が3000秒といった非常に長い待機時間となる場合が多々あり、フォーラムの投稿者も「リトライ関数を組み込んだが効果がなく、ワーカーが一日中ブロックされているようだった」と述べているように、これでは実用的なシステムとして使い物になりません。
このレートリミットを回避するために、仕方なくCloudflare Workersからは直接DiscordのWebhookを叩かず、AWS Lambda URLsをWebhookプロキシとして利用する構成に変更しました。これにより、Cloudflare WorkersはAWS Lambda URLsにリクエストを送信し、LambdaがDiscordへの通知を代行する形になりました。
パパっと作るつもりが、3日も悩んでなんだか複雑な構成です。
403 Forbidden
AWS LambdaのPythonの関数からDiscordのWebhookを叩くと、今度は「403 Forbidden」エラー が発生しました。
いやいや、さっきまでは(エラーだったけど)呼べてたし、curlから叩いたら正常に動作しますよ。なんなんだ。
また2日ほど悩みましたが、同じ現象になっている人の記事がありました。
Pythonでurllib.requestライブラリを使用してDiscord Webhookにメッセージを送る場合は User-Agentヘッダーを設定しようね ってなにそれ。
具体的には、urllibはUser-Agentを設定しない場合、デフォルトで「Python-urllib」というUser-Agentを設定します。そして、Discordはこの「Python-urllib」からのリクエストに対して403を返す仕様になっているとのこと。
理由はわからなかったのですが、多分カジュアルにPytonからWebhookを叩かれるとDiscord側の負荷が問題になるのかもしれません。
まとめ
今回、はじめてDiscordのWebhookを触ってみましたが、色んな人が使うから制限が厳しいのかもしれないなと感じました。
Discordのドキュメントにこの辺がまとまってないので、Webhookを利用する際には、こうした細かい仕様や制限に気をつけないとハマるので要注意っすね。
無事にDiscordに通知が飛んできたので、これで安心して洗濯機のことは気にせず、『ホロウナイト: シルクソング』でボスに何度でも再チャレンジできるようになりました!(問題は何も解決していない…)
作ったものはこちら↓

