Azure Functions上のpythonプログラムから、毎朝6時にその日の1時間ごとの天気予報をslackに通知する


はじめに

朝起きた時の晴れ空で、洗濯しようと決意する人は多いはず。ただ、急な雨で後悔をした人も同じくらい多いはず。
かといっていちいち天気予報をググるのも面倒だし、テレビでは時間が合わずちょうどいまって時に教えてくれない。毎朝、いい感じのタイミングに天気予報をスマホに通知してくれないかなぁ、、
そんな希望に応えるために、表題のようなコードを書いてみました。
「「そういうアプリあるでしょう??」」それを言ったらおしまいです。忘れましょう。

やってみたこと

1.TimerTriggerを持つAzure Funcitionsを準備する
2.OpenWeatherMapのAPIをたたき、東京都の1時間ごとの天気予報データをslackに投稿するpythonコードを書く

環境・使用ツール

・windows10
・python3.7.2
OpenWeatherMap
Azure Functions
・Visual Studio Code

Azure Functionsを準備する

ざっくりこんな感じ。ぶっちゃけこれ以上語ることはない。。
強いて言うなら、「Select a template for your project's first function」のところで、HTTP triggerではなくTimer triggerを選んだくらい。
私の私による私のための備忘録なので許してください。
Visual Studio Codeから見えるフォルダの階層関係は、下のような感じになります。

TimerTriggerに加えてHttpTriggerを二つ作っていますが、気にしない。私の本命はTimerTriggerですが、どれか一つあればいいです。

OpenWeatherMap APIをたたくpythonコードをAzure Functionsに追加する

Azure Functionsでは、TimerTrigger配下にある__init__.pyファイルをいじります。以下の写真は、こちらからの抜粋です。
何の手も加えていない状態の__init.py__ファイルには、関数はmainしかありません。さらに関数を追加する場合には、以下のような追記をしてみましょう。
具体的には、新たに関数を一つ作成し(pi_digits_Python)、返り値を得ます(output)。そして、その関数をmain関数の中で実行し、変数に返り値を代入しています。その変数をmain関数の中で活用していますね。

私もこの書き方を参考にし、TimerTriggerの__init.py__に新たな関数を追加しました。

__init__.py
import datetime
import logging

import requests
import json
import slackweb

import azure.functions as func

def weathercast():
    apikey = "xxxxxxxxxxxxxx"

    api = "https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&exclude={part}&appid={key}"

    latitude = xx
    longitude = xx
    exclude = "current"
    output = ""

    url = api.format(lat = latitude, lon = longitude, part = exclude, key = apikey)
    r = requests.get(url)
    data = r.json()
    data = json.loads(r.text)

    for i in range(8):
        weather = data["hourly"][i]["weather"][0]["main"]
        weather_detail = data["hourly"][i]["weather"][0]["description"]

        k = lambda x : x - 273.15
        l = k(data["hourly"][i]["temp"])
        temp = round(l,1)

        output += "天気:" + weather + ("\n") + "天気詳細:" + weather_detail + ("\n") + "気温:" + str(temp)  + ("\n") + ("\n")
    output += "zura"
    return output

def main(mytimer: func.TimerRequest) -> None:
    utc_timestamp = datetime.datetime.utcnow().replace(
        tzinfo=datetime.timezone.utc).isoformat()

    if mytimer.past_due:
        logging.info('The timer is past due!')

    logging.info('Python timer trigger function ran at %s', utc_timestamp)

    weathercast_zura = weathercast()

    slack = slackweb.Slack(url="xxx")
    slack.notify(text=weathercast_zura, urfurl_links = 'true')

必要なモジュールをimportし、新たにweathercastという関数を追加、この関数から得た返り値outputをmain関数に追加しています。それをそのままslackに投げています。

weathercast関数の中身は、これとかこれとかを参考に。まあ基本はOpenWeatherMap APIのドキュメントを読みました。slackに飛ばすのは、こちらの記事を参考に。

その他注意事項

importするモジュールは、「requirement.txt」にバージョン情報と共に記述する必要があります。こんな感じ。今回は、requestモジュールとjsonモジュールを追加でimportしているので、importしたいバージョンと共に記載してあげましょう。
ちなみに、import datetimeとimport loggingは__init__.pyにもともと記載されていたものなので、気にしない。

azure-functions
slackweb==1.0.5
requests==2.22.0

余談

lambdaに初めて触った

lambdaってなんだかおもしろい形ですね。

lambda 引数:返り値

を基本形として、ここから得られた返り値を別の変数に代入してあげるのかな。

k = lambda x : x - 273.15
l = k(293.15)

とかってやったら、変数lには20が入っているはず。いちいちdefで関数を作成するより楽ですね。参考にしたのはこちら

時差を考慮して

TimerTrigger配下のfunction.jsonでは、TimerTriggerが発動する時間が設定されております。基本的には冒頭の「Azure Functionsを準備する」のフェーズで設定しますが、後々変更したいときはこのファイルをいじります。
__init__.pyを見ている感じ、timezoneがutcのように見受けられるので、時差を意識した記述としています。

{
  "scriptFile": "__init__.py",
  "bindings": [
    {
      "name": "mytimer",
      "type": "timerTrigger",
      "direction": "in",
      "schedule": "0 0 21 * * 0-6"
    }
  ]
}

とてつもない反省

このページのようにcmdをたたかないと、コードは動きませんよね。。
Azure Functionsに乗っける前に普通にローカルで確認していましたが、

__init__.py

としか打っておらず「全然動かねぇ!!!」ってなっていました。もう二度と間違えん。衆目に晒すのは恥でしかありませんが、まぁ備忘録なので。

結果

想定通り、翌朝6時に写真のように時間ごとの天気予報、ついでに気温がslackに届きました。

最後に

ここから派生して、slackに「東京」と打ち込んだら東京の1日の天気を返してくれるようなBotを作りたいのですが、大体の記事が一バージョン前??のやつっぽくてよくわからないですね、、、
ぼちぼち試してみますが、知見のある方の記事を待つ、です。

参考

OpenWeatherMap
Azure Functions
クイック スタート:Visual Studio Code を使用して Azure で関数を作成する
6: 2 つ目の Python 関数を Azure Functions に追加する
無料天気予報APIのOpenWeatherMapを使ってみる
pythonでopenweathermapのAPIを叩こう
Weather API
Python3でslackに投稿する
Pythonのlambdaって分かりやすい