LoginSignup
41
36

More than 5 years have passed since last update.

緊急地震速報をGoogle Homeでアナウンスしてみる(with Slack通知)

Last updated at Posted at 2018-02-28

はじめに

社内のコミュニケーションスペースにGoogle Homeが!その日は突然やってきました。が、ブームはすぐに過ぎ去り、話しかける人はごくわずかに...。後輩から「何かやらないと、使われなくなっちゃいますね」と、何故か圧力をかけられたので、緊急地震速報を流してみることにしました。

処理フロー

緊急地震速報は、緊急地震速報Botから取得することにしました。フォーマットも公開いただいているので、通知処理を自由に構築できます(ありがとうございます)。

また、どうせならSlackへも通知させよう、ということで以下のような処理フローにしました。

ProcessFlow.png

HubotでTwitterのタイムラインを監視し、推定M5.8以上、もしくは震度4以上の場合に通知させることにします。

前提として、Hubotが準備(インストール)できているものとします。Slackとは連携していなくてOKです(え?1)。

どうやったか

準備

まず、Hubotに監視させるTwitterアカウントを準備し、緊急地震速報Botをフォローしておきます。また、Twitter APIを利用するため、Twitter AppsからTwitterアプリを作成(Create New App)し、API KeyやAccess Tokenなどを入手しておきます。

Hubotスクリプト

Twitterの監視

Twitterの監視には、hubot-twitter-userstreamを利用しました。

$ npm install --save hubot-twitter-userstream

Hubotスクリプト(内部の詳細は次項以降に書きます)を作成し、

hubot/scripts/eew-notifier.coffee
module.exports = (robot) ->
  robot.hear /(.*)/i, (msg) ->
    # (1) 緊急地震速報を取得
    ...
    # (2) 閾値判定(推定M5.8以上、もしくは震度4以上)
    ...
    # (3) Slackへ通知
    ...
    # (4) Google Homeで読み上げ
    ...

TwitterアプリのAPI KeyやAccess Tokenなどを環境変数に

$ export HUBOT_TWITTER_KEY="key"
$ export HUBOT_TWITTER_SECRET="secret"
$ export HUBOT_TWITTER_TOKEN="token"
$ export HUBOT_TWITTER_TOKEN_SECRET="secret"

のように設定した状態で

$ ./bin/hubot -a twitter-userstream

と実行すると、TwitterのタイムラインがHubotへ流れてきます。あとはこれを、煮るなり焼くなり...、です。

以下、Hubotスクリプトの詳細になります。

緊急地震速報を取得

hubot/scripts/eew-notifier.coffee
    # (1) 緊急地震速報を取得
    if msg.message.user.name != 'eewbot'
      return

    vals = msg.message.text.split(',')
    if vals.length != 15
      return

    type      = vals[0]  # 電文の種別
    sign      = vals[1]  # 訓練識別符
    announce  = vals[2]  # 発表時刻
    status    = vals[3]  # 発表状況
    number    = vals[4]  # 電文番号 地震IDごとに00-99
    id        = vals[5]  # 地震ID
    time      = vals[6]  # 地震発生時刻
    latitude  = vals[7]  # 震源の北緯
    longitude = vals[8]  # 震源の東経
    place     = vals[9]  # 震央地名
    depth     = vals[10] # 震源の深さ
    magnitude = vals[11] # マグニチュード
    intensity = vals[12] # 最大震度
    flag      = vals[13] # 震源の海陸判定 0:陸 1:海
    alert     = vals[14] # 警報の有無 0:無 1:有

    if sign == '01' # 00:通常 01:訓練
      return

    if status == '0' # 0:通常
      caption = "■■■EEW(第#{number}報)■■■"
    else if status == '8' or status == '9' # 8,9:最終報
      caption = '■■■EEW(最終報)■■■'
    else # 7:キャンセルを誤って発表したとき(地震ID以降の項目は空)
      return

    overview = "#{place}で地震 最大震度 #{intensity}(推定)"

    canceled = false 

    if type == '35' # 35:最大震度のみ Mの推定なし
      details = "[詳細] #{time}発生 深さ#{depth}km"
    else if type == '36' or type == '37' # 36、37:最大震度 Mの推定あり
      details = "[詳細] #{time}発生 M#{magnitude} 深さ#{depth}km"
    else if type == '39' # 39:キャンセル
      caption = '□□□EEW(キャンセル報)□□□'
      canceled = true
    else
      return

    post = caption
    post += '\n' + overview + '\n' + details if !canceled

※「発表状況(status)」が7のデータを見つけられなかったので、とりあえず何もしないようにしました。

閾値判定(推定M5.8以上、もしくは震度4以上)

hubot/scripts/eew-notifier.coffee
    # (2) 閾値判定(推定M5.8以上、もしくは震度4以上)
    filtered = true ;

    result = intensity.match(/[0-9]+[\.]?[0-9]*/)
    if result? and parseFloat( result[0] ) >= 4.0 # 震度4以上
      filtered = false ;
    if type == '36' or type == '37'
      if parseFloat( magnitude ) >= 5.8 # 推定M5.8以上
        filtered = false ;
    if status == '0'
      if number != '1' and number != '5' # 第1、5、最終報
        filtered = true ;

    if !canceled and filtered
      return

※通知の総数を減らすため、「第1、5、最終、キャンセル報のみ」という条件も追加しました。

Slackへ通知

hubot/scripts/eew-notifier.coffee
    # (3) Slackへ通知
    data =
      channel: '#xxxxx'
      username: 'eewbot'
      text: post

    msg.http('https://hooks.slack.com/services/Txxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxxxx')
      .post(JSON.stringify(data)) (err, res, body) ->
        if err or res.statusCode != 200
          console.log 'Unknown error.'

※Slackへの通知には、Incoming WebHooksを利用しました。Webhook URLが必要になりますので、取得についてはSlackのWebhook URL取得手順などをご参照ください。

※実際のSlackへの通知内容はこんな感じになりました。

Slack.png

Google Homeで読み上げ

hubot/scripts/eew-notifier.coffee
    # (4) Google Homeで読み上げ
    @exec = require('child_process').exec
    command = 'sh /home/xxxxx/announce/index.sh '
    if !canceled
      command += '緊急地震速報、' + overview.replace(' ', '、').replace(/\(推定\)/, '') + '、注意してください'
    else
      command += '先ほどの緊急地震速報はキャンセルされました'
    @exec command, (error, stdout, stderr) ->
      if error
        console.log error
      else if stdout
        console.log stdout

※シェルスクリプト経由で実行される別プロジェクトで、Google Home(google-home-notifier)での読み上げを行っています。これは、以前の記事紹介した処理と同じですので、実装はそちらをご参照ください。

※実際の読み上げ内容は「緊急地震速報、東海道南方沖で地震、最大震度 3、注意してください」といった感じになります。

おわりに

「デスクはSlack、コミュニケーションスペースはGoogle Homeでカバー。カンペキ!」と作ってみたのですが、通知(読み上げ)の応答性に不安があり、実用に耐えない可能性が高そうです(え?)。「ケータイで十分なので、こんなのいらないっス」とか言われてしまう前に、Google Homeの活用方法、もう一度考えないと...。


  1. Slack通知のためではなく、Twitterのタイムライン監視目的でHubotを利用しました。将来Twitter Botとしても利用できそうですし...。 

41
36
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
41
36