Edited at

オフィスから出る前に Slack で雨雲レーダーを確認しよう ⛈️


そろそろ梅雨明けですが・・

そろそろ今年も、ほぼ全ての地域が梅雨明けしそうな頃合い1ですが、いかがお過ごしでしょうか?

先日、Twitter でこちらの投稿を見かけまして、確かにこれは便利な Slack 連携だと思いました。

「東京アメッシュをSlackに流す的なのがうらやましかった」と書かれているので、すでにそのような Slack アプリをつくって普段から利用されている方がいらっしゃるのでしょう。素晴らしい Slack API の活用例ですね! :thumbsup:


試しにつくってみた

アニメーション GIF になるバージョンをつくってみました。雨雲レーダーってこれから雨が降りそうかを正確に判断できるだけでなく、ずっと見ていられる感じもあって、眺めているのも楽しかったりしますよね :smiley:

スラッシュコマンドからのリクエストの処理には Slack が最近公開した Bolt ⚡️ という新しいフレームワークを利用して実装しています。Bolt については、以下の日本語の情報をご覧ください。

実装したアプリは以下の GitHub リポジトリで公開しています。

https://github.com/seratch/slack-weather-radar-map

git.io/amesh という短縮 URL もつくっておいたので、他の人に教えるときはぜひそちらで!


今回対応してみた三つの機能

まず、この Slack アプリがどのように動くものなのか、完成形を見てみましょう。この Slack アプリの基本的な挙動は、スラッシュコマンドで呼び出すと Slack アプリが Yahoo! JAPAN の API から日時をスライドしながら複数枚の画像を取得して、それを一つのアニメーション GIF として応答するというものです。


デフォルトの表示 - /amesh {prefecture}

デフィルトでは、アルファベットの都道府県名(例: tokyo, osaka, aichi)を受け取ると、今の雨雲レーダーから少し先の予測までをアニメーション GIF で表示します。引数指定なしは東京都(tokyo)で動作します。


今の状況だけを表示 - /amesh {prefecture} now

アニメーション GIF ではなく、今時点での雨雲レーダーだけを表示したい場合は now をつけます。画像一枚だけの取得ですし、応答がはやくなります。


直近一日分を表示 - /amesh {prefecture} today

三つ目のオプションは、直近一日の雨雲の流れを見るための today オプションです。これはこれから雨が降るかどうか知りたいというよりは、大雨の日などにどの時間帯が一番ピークだったか、後から振り返るときなどに使うとよさそうですね。


コードを変えずにカスタマイズ

私が作ったこのアプリのコードを変えることなく、カスタマイズしたい場合、以下の二点を変更することができます。


スラッシュコマンド名

デフォルトは /amesh ですが、SLASH_COMMAND_NAME という環境変数に別の名前を指定して Slack アプリの設定側でも同じ名前を指定すれば、変更することができます。


マップの表示モード

デフォルトは map という設定ですが、Yahoo! JAPAN の API には以下のようなオプションがあります。変更する場合は YAHOO_JAPAN_API_MAP_MODE という環境変数に設定してください。



  • map - 通常の地図


  • photo - 航空写真


  • map-b1 - 地下街


  • hd - ハイビジョン地図


  • hybrid - ハイブリッド地図


  • blankmap - 白地図


  • osm - Open Street Map

例えば、以下は hybrid で設定した場合の表示例です。


ローカルで動かしてみよう

事前に Slack アプリの設定が必要です。まだ作成していない場合は https://api.slack.com/apps にアクセスして「Create New App」ボタンから新しい Slack アプリを作ってください。


Slack アプリの設定

Slack アプリをつくったら、アプリの設定画面で以下の設定や情報の取得を行います。


スラッシュコマンドを追加する

左メニューの「Features > Slash Commands」から設定できます。

デフォルトの設定で OK なら /amesh という名前でコマンドを追加、Request URL はデプロイ予定の URL を入力します。まだ URL が決まっていない場合はダミーで入れておいてあとで変更することもできます。


ボットユーザーを追加する

左メニューの「Features > Bot Users」から設定できます。

名前はなんでも OK です。


必要な権限(scope)を設定する

左メニューの「Features > OAuth & Permissions」から設定できます。

この手順でやっていれば、すでに commandsbot は付いていると思いますので、追加で files:write:user を指定します。


アプリをワークスペースにインストールする

左メニューの「Settings > Install App」から実行できます。

インストールが終わったら、発行された「Bot User OAuth Access Token」を SLACK_BOT_TOKEN の環境変数の値として使います。また左メニューの「Settings > Basic Information > App Credentials」の「Signing Secret」を SLACK_SIGNING_SECRET の値として使用します。


Yahoo! デベロッパーネットワークの設定

Yahoo! デベロッパーネットワークにアクセスして、Yahoo! JAPAN の Web API を活用するアプリケーションの設定を行います。追加手順はこちらで確認することができます。

「サーバーサイド(Yahoo! ID連携 v2)」のアプリケーションを作成して、発行された「Client ID」を YAHOO_JAPAN_API_CLIENT_ID として使用します。


ローカルで動作確認する

Node.js を使った開発に慣れていれば、ローカルで動かしてみてください。Bolt はこの記事時点で Node 10.13.0 以上で動作するので、サポートされている Node.js をインストールしておいてください。そして必要な環境変数は _env というファイルにサンプルがあるのでそれらを指定してください。

nvm use 10.13.0 # Bolt runs on Node 10.13+

cp -p _env .env
vi .env
source .env

その上で必要な npm モジュールをインストールして、アプリを起動してみてください。

npm i

npm run local

上記でアプリが正常に起動しましたか? この Node アプリは http://localhost:3000/slack/events で Slack からのリクエストを処理するよう設定されています。

さらに、もう一つ Terminal ウィンドウを開きます。ngrok という開発用プロキシを使って、この Node アプリが Slack プラットフォームからのリクエストを受け付けられるようにします。

ngrok http 3000

表示された URL を Slack アプリの設定画面の「Features > Slash Commands」に設定したスラッシュコマンドの「Request URL」に設定します。

npm run local はコードが変更されると自動的に反映されるように設定されているので、コードをいじっては /amesh コマンドで呼び出すというサイクルで試行錯誤ができます。色々と試してみてください。

例えば Yahoo! API の z パラメータを変更すれば、より広域な地図に変更して日本全体の雨雲の流れを表示してみたりもできます。

もう少し実用的にするために、会社のオフィスの緯度・経度を基準点に指定して、パラメータを指定しなくても簡単にオフィスの近辺での情報を表示するように変更して運用するとよいかと思います。

また、スラッシュコマンドではなく bot メンションや、キーワードへの反応に変更するなどのカスタマイズも Bolt なら簡単にできるでしょう。メンションされたときの動作は app.event('app_mention', ...)、キーワードへの反応は app.message('雨雲レーダー見せて', ...) のように実装できると思います。

再掲となりますが、以下のドキュメントも参考にしてみてください。


デプロイしよう

通常の Bolt アプリであれば、どのような環境にも非常に簡単にデプロイが可能です。Heroku だけでなく、AWS API Gateway + Lambda や Google Cloud Functions (Cloud Functions for Firebase も同様)など、様々な環境で Bolt は簡単に動作させることができます。2

しかし、今回のサンプルに限っては node-canvas に依存している事情から AWS Lambda で動かすのはなかなか手間がかかります(詳細は注釈参照)3。この手のアプリは Docker image を作って別の仕組みでで動かすのがよさそうです。

また、Google Cloud Functions / Cloud Functions for Firebase については AWS Lambda のようにネイティブ npm モジュールについての制限は特になく、簡単に動作はさせられますが、今回のように外部 URL への HTTP リクエストを複数投げてアニメーション GIF をつくるような処理はあまり相性がよくないようで、どうしても応答までに長く時間がかかってしまうようでした。そのため、今回、以下に示す例は一枚のみの天気図を表示するサンプルとしました。

ということで、今回のサンプルをそのまま動かすなら Heroku が最も簡単かと思います。


Heroku にデプロイする

https://github.com/seratch/slack-weather-radar-map

この GitHub リポジトリは Deploy to Heroku ボタンが設置されています。Heroku のアカウントをお持ちなら、今すぐにでも簡単に Heroku にデプロイすることができます。

いかがでしたか?簡単に動作させることができたのではないかと思います。


FaaS にデプロイする

Heroku に比べるとシンプルなサンプルとなりますが FaaS へのデプロイについても紹介しておきます。


Cloud Functions for Firebase

Google Cloud に関しては Cloud Functions fore Firebase のサンプルを紹介しています。若干の違いはありますが4 Google Cloud Functions でも同様にデプロイできるはずです。


AWS API Gateway + Lambda

AWS API Gateway + Lambda のサンプルServerless Framework を使ったサンプルです。

AWS のサンプルは以下の二つの問題に対処するために少し工夫をしています。


  • 同期的に処理をすると特にコールドスタート時に 3 秒以内に応答できずにタイムアウトしてしまう

  • Lambda の handler が応答を返した後にまだ処理中の Promise での非同期処理が打ち切られてしまう

以下は Lambda functions の定義からの抜粋です。API Gateway 経由で Internet facing な frontend と内部からのみ呼び出される backend の二つの Lambda を定義しています。

functions:

# frontend: Slack からのリクエストを受け付けて backend を起動し 3 秒以内に 200 OK を返す
frontend:
handler: handler.frontend
events:
- http:
method: post
path: /slack/events

# backend: frontend 関数によって非同期実行され、時間がかかる処理を行う
# エラーが発生したら Slack からもらった response_url に通知する
backend:
handler: handler.backend

frontend は Slack Platform からのリクエストを受け付けます。frontendは、無事 backend を非同期で起動できたら HTTP リクエストに対して 200 OK を返して終了します。

backend は処理を実行し、エラーが発生した場合には response_url を使ってエラーを通知します。 スラッシュコマンドでの response_url についてはこちらのドキュメントを参照してください。


まとめ

このように Yahoo! JAPAN さんが公開している API を利用すれば、非常に簡単に雨雲レーダーを反映した地図画像を取得することができます。この記事ではそれを複数枚つなぎ合わせてアニメーション GIF をつくり、さらにそれを Slack にファイルとしてアップロードするサンプルをご紹介しました。

https://github.com/seratch/slack-weather-radar-map

そして、その実装は Bolt を活用しました。Bolt を使うと Slack アプリ固有の処理をするコードを最小化して、本質的な実装だけに集中することができるようになります。日本語に翻訳されていますので、入門ガイドを読んでみてください。

ぜひ皆さんの職場やコミュニティのワークスペースでこのスラッシュコマンドを有効にして活用してみてください :raised_hand:





  1. tenki.jp で例年の梅雨明けの時期を確認しました。 



  2. いくつか個人的にサンプルを書いたりもしているので、見てみてください。  



  3. 興味のある方は node-canvas の AWS Lambda に関するドキュメント関連する GitHub issueを見てみてください。簡単に説明すると、今回の場合、 macOS などでパッケージングした zip パッケージは Lambda 上で動作しないため AWS の EC2 環境などで sls deploy する必要があります。が、それを行っても、なお libuuid.so.1 が Lambda 環境だと存在しなくて動作しないため、Lambda Layers を使って対応しなければならないようです。 



  4. 関数を export するときに functions.https.onRequest を呼ぶかなどの軽微な違いです。