オフィスを出る前に外が雨かを知れるシステムを作ってみた。

この記事は「オフィス上空の天気予報を通知してみた。」シリーズの第1回です。

「オフィス上空の天気予報を通知してみた。」シリーズ(全4回)

はじめに

TOWNのオフィスは外に出るまでの経路に外が見える窓がなく、外の天気を確認しづらい環境にあるため、「お昼休みに外へ出たら雨が降っていた…。」なんてことがよくあります。1階まで降りたのにわざわざ傘を取りにオフィスへ戻るのは面倒くさいですよね。だからといって毎回エレベーター横の扉を開けて天気を確認するのもそれはそれで面倒…。

→じゃあ外に出ずに簡単に外の天気を知れるシステムがあればいいよねっ!!

というわけで作ってみました。

構成

  1. YOLP(Yahoo! Open Local Platform)の気象情報APIからTOWNのオフィス上空の降雨情報を取得

  2. 通知メッセージの作成

  3. slackに現在の天気と降雨予報を送信

今回は降雨情報の取得にYahoo!が提供しているYOLPの気象情報APIを利用しました。

Yahoo! Open Local Platform(YOLP)は、Yahoo! JAPANがデベロッパー向けに提供する地図・地域情報のAPI・SDKです。

仕様

TOWNの営業時間内にのみ、10分毎に降雨情報を取得しslackのメッセージを更新します。

どのくらいの雨で傘を差すかという基準には個人差があると思います。絶対に濡れたくないから少しでも降っていれば傘を差すという人がいる一方で多少の雨なら気にならない人もいると思います。

そこで今回は降雨量の閾値を以下のように定めました。

0.0mm : 雨は降っていない

0.0mm ~ 1.0mm : 小雨

1.0mm ~ : 雨

事前に準備するもの

コード

  • test_rain
import json
from slackclient import SlackClient


### YOLP ###
APP_ID = "XXXXXXXXXXXXXXX"
BASE_URL = "http://weather.olp.yahooapis.jp/v1/place"
COORDINATES = "XXXXXXXXXXXXXXX"   # [経度],[緯度]
OUTPUT="json"

YOLP_URL = BASE_URL + "?appid=%s&coordinates=%s&output=%s" % (APP_ID,COORDINATES,OUTPUT)
Weather_PARAMS = {
    "appid" : APP_ID,
    "coordinates" : COORDINATES,
    "output" : OUTPUT,
    "past" : 1
}

### SLACK ###
slack_token = "XXXXXXXXXXXXXXX"
slack_client = SlackClient(slack_token)

### channel_id for 降雨情報 ###
channel_id="XXXXXXXXXXXXXXX"
ts_num="XXXXXXXXXXXXXXX"   # メッセージのタイムスタンプ
message = ""


def lambda_handler(event, context):
    sun = 5
    rain = 5
    light_rain = 5

    ### 降雨情報取得 ###
    weather = requests.get(YOLP_URL,params=Weather_PARAMS).json()['Feature'][0]['Property']['WeatherList']['Weather']

    ### 通知メッセージ作成 ###
    for var in range(5,13):
        date = weather[var]['Date']
        rainfall = weather[var]['Rainfall']

        if(var == 6):
            before_words = "現在、"

            if(rainfall == 0.0):
                if(var == rain):
                    message = before_words + "雨が止みました。" + ":sunny:"
                    sun += 2
                elif(var == light_rain):
                    message = before_words + "小雨が止みました。" + ":sunny:"
                    sun += 2
                else:
                    message = before_words + "雨は降っていません。" + ":sunny:"
                    sun += 1
            elif(rainfall >= 1.0):
                if(var == sun):
                    message = before_words + "雨が降り始めました。" + " :umbrella_with_rain_drops:"
                    rain += 2
                elif(var == light_rain):
                    message = before_words + "小雨から雨になりました。" + ":umbrella_with_rain_drops:"
                    rain += 2
                else:
                    message = before_words + "雨が降っています。" + ":umbrella_with_rain_drops:"
                    rain += 1
            else:
                if(var == sun):
                    message = before_words + "小雨が降り始めました。" + ":closed_umbrella:"
                    light_rain += 2
                elif(var == rain):
                    message = before_words + "雨から小雨になりました。" + ":closed_umbrella:"
                    light_rain += 2
                else:
                    message = before_words + "小雨が降っています。" + ":closed_umbrella:"
                    light_rain += 1

        elif(var > 6):
            before_words = "分後、"
            time = (var-6) * 10
            if(rainfall == 0.0):
                if(var == rain):
                    message += "\n" + str(time) + before_words + "雨が止むでしょう。"
                elif(var == light_rain):
                    message += "\n" + str(time) + before_words + "小雨が止むでしょう。"
                else:
                    sun += 1
            elif(rainfall >= 1.0):
                if(var == sun):
                    message += "\n" + str(time) + before_words + "%の確率で雨が降り出すでしょう。"
                elif(var == light_rain):
                    message += "\n" + str(time) + before_words + "小雨から雨に変わるでしょう。"
                else:
                    rain += 1
            else:
                if(var == sun):
                    message += "\n" + str(time) + before_words + "小雨が降り出すでしょう。"
                elif(var ==rain):
                    message += "\n" + str(time) + before_words + "雨から小雨に変わるでしょう。"
                #else:
                light_rain += 1

        elif(var == 5):
                if(rainfall == 0.0):
                    sun += 1
                elif(rainfall >= 1.0):
                    rain += 1
                else:
                    light_rain += 1

    ### 降雨情報以外のメッセージを削除 ###
    for history in get_history(slack_client,channel_id)["messages"]:
        ts=history["ts"]
        if ts != ts_num:
            response=delete_message(slack_client,channel_id,str(ts))

    ### Slackにメッセージを送信 ###
    slack_response = update_message(slack_client, channel_id, message, ts_num)

    return slack_response


def channel_list(client):
    response = client.api_call("channels.list")
    if channels['ok']:
        return channels['channels']
    else:
        return response


def send_message(client, channel_id, message):
    response = client.api_call(
        "chat.postMessage",
        channel=channel_id,
        username="Weather",
        text=message,
        icon_emoji=":rainbow:"
    )
    return response

def update_message(client, channel_id, message,ts):
    response = client.api_call(
        "chat.update",
        channel=channel_id,
        text=message,
        ts=ts
    )
    return response

def delete_message(client,channel_id,ts):
    response = client.api_call(
        "chat.delete",
        channel=channel_id,
        ts=ts
    )
    return response

def get_history(client,channel_id):
    response = client.api_call(
        "channels.history",
        channel=channel_id,
    )
    return response


ちなみに…

Lambdaで書いた上の関数を実行しようとしたら以下のエラーで躓いた話を「lambdaに外部モジュールを読み込ませる」の記事で紹介しています。同様のエラーが起こった方はこの記事を参考にしてください。

Unable to import module 'lambda_function': No module named 'requests'

トリガーの設定

今回は営業日である平日の9時〜19時の時間帯で10分毎に実行するようにしたいのでCloudwatchEventsをトリガーにしてtest_rain関数を実行するようにスケジュール式を設定します。トリガーの設定方法については以下の記事を参考にしてください。

Lambdaで夜間にec2インスタンスを止める

  • cron式
cron(0/10 0-10 ? * MON-FRI *)

動作確認

実際に使ってみました。

晴れの時

雨が降った時

雨が振り始めたという通知があったので確認してみました。

上の画像からは確認が難しいですが…

本格的な雨ではありませんでしたが、霧のような雨を確認しました。雲の様子を見ると限りなく雨が降りそうです。これから雨が降るのかと思っていたら数分後、下のような通知が来ました。

再び外の様子を確認したところ雨は止んでいました!!

さいごに

これで(※外出前にslackを確認すれば)傘を取りに戻る心配がなくなりましたね。

まだ未完成ですが、今後は降雨量のログを残しておき、予報がどのくらいの確率で当たるのかも通知できるようにしたいと思います。また、slackだけでなく他のツールも用いてより簡単に天気を知ることができるような素敵システムにするために改良を重ねていきたいと思います。

追記

降雨予報と共に的中確率も通知してくれる機能を追加しました。詳細は次の記事で紹介していきたいと思います。

「オフィス上空の天気予報を通知してみた。」シリーズ(全4回)