2013年9月15日日曜日

Raspberry Piで田無タワー風天気予報ガジェットを作る(ソフトウェア編)

前回(ハードウェア編)から続く...

今回はソフトウェアの実装をまとめていきます。ソフトで実現すべきことは、
  • 天気予報のAPIを叩いて明日の天気を取得する
  • 取得した天気に応じてGPIOでLEDを点灯させる
の二つです。

これらを実現する方法はいくつもあると思いますが、ここではコンパイル不要で再修正も楽なPythonを使ってみることにします。Python用にRaspberry PiのGPIO操作ライブラリRPi.GPIOが提供されているので、ファイルIOで直接叩くよりも比較的シンプルに実装できます。

公式からダウンロードしたRaspbian wheezyのイメージにはデフォルトでRPi.GPIOがインストールされているはずです。もしモジュールのimportに失敗する場合はこちらの手順などを参考にインストールします。

OpenWeatherMap

インターネットで天気予報を提供するAPIのひとつに、OpenWeatherMapというものがあります。OpenWeatherMapは、天気を知りたい場所を指定してHTTPでリクエストを送ると、XMLまたはJSON形式でレスポンスを返してくれます。予報だけでなく、現在の天気を知ることもできます。取得したレスポンスを適当に処理して、天気とか気温とかを取り出します。

まずは、試しにレスポンスを取得してみます。公式のAPIサンプルに、下記のリクエスト例が置いてあります。


これをベースに編集してみましょう。
地名はLondonからTokyoに変更、レスポンス形式はXMLからJSONへ、unitsはそのまま、cntは翌一日分のみで十分ですので1にします。
http://api.openweathermap.org/data/2.5/forecast/daily?q=Tokyo&mode=json&units=metric&cnt=1
こんな感じかな。試しにブラウザのURL欄に入力してみると、、
{"cod":"200","message":0.0176,"city":{"id":1850147,"name":"Tokyo","coord":{"lon":139.691711,"lat":35.689499},"country":"JP","population":8336599},"cnt":1,"list":[{"dt":1378605600,"temp":{"day":25.58,"min":19.64,"max":25.58,"night":19.64,"eve":20.69,"morn":25.58},"pressure":1018.16,"humidity":91,"weather":[{"id":502,"main":"Rain","description":"heavy intensity rain","icon":"10d"}],"speed":1.81,"deg":275,"clouds":92,"rain":16}]}
ってな感じでレスポンスが返ってきました。問題なさそうですね。

では、このリクエストをPythonコードから投げて、レスポンスを取得してみましょう。 適当な作業ディレクトリにPythonファイルを作って編集していきます。 実行してみます。 ブラウザで表示させた時と同様、JSON形式のレスポンスが返ってきたでしょうか?
次に、このJSONレスポンスをスクレイピングして、天気の部分だけを取り出してみます。 これを実行すると、天気の部分のテキストだけが抽出されるはずです。 こんな風に↓

GPIO

続いてLEDを点灯させるためのGPIO操作をPythonプログラムに追加していきます。まずGPIO.setmode()でピン番号の指定方法を銘記します。これに合わせ、あらかじめR、G
、B変数にはRPiボードのP1コネクタ上でのピン番号を入れておきます。続くGPIO.serwarnings()は、GPIOを再操作した時に、既に当該ピンが使用中である旨の警告が出るので、これを抑止するために書いておきます。次にGPIO.setmode()で各ピンを出力に設定。あとは、天気予報に合わせた色をRGBで各ピンに設定するだけです!

さて、天気をどの色で表現するか。ご所望の田無タワーが、どの天気のときにどの色で光るかを調べてみるわけですけどね。。

スカイタワー西東京さん(公式)によれば
曇りは緑雨は水色に決定し、残りの紫が晴れ

Wikipedia先生によれば
晴れ=紫色 曇り=黄緑色 雨=青色

西東京市さんによれば
紫色:晴れ緑色:曇り青色:雨

と、若干矛盾系の殺伐とした雰囲気が感じられるんですが、とりあえずここでは
  • 晴れ:R+Gで紫
  • 曇り:Gで明るい緑
  • 雨:G+Bで水色
ということにしましょう。いずれでもない場合はとりあえず例外ということでだけ光らせておきます。

最終的なPythonコードは下記のようになります。 では実行してみましょうか。 天気予報によって異なる色でLEDが点灯するのを確認できます。

「曇り」のとき
「晴れ」のとき
カメラの露出開けすぎた?なんだか眩しい・・・


(おまけ) Raspbian起動時に実行、定期的に実行

自動化してみたいと思います。
上で作成したPythonファイルを、あらかじめ/usr/local/bin/にインストールしておきます。
それから、/usr/local/bin/getweather.pyの冒頭に次の1行(Shebang)を追加しておきます。 /usr/local/bin/にはPATHが通っているので、こうすることでgetweather.pyとだけコマンドすれば実行できるようになるわけです。

では、まずRPiの電源を入れてSDカードからRaspbianが立ち上がったときに一度実行させる方法。まず/etc/init.d/の下に適当な名前(ここではgetweather)でテキストファイルを作ります。
中身には次のスクリプトを書きます。
スクリプトファイルを実行可能に。
update-rc.dコマンドでスクリプトを登録します。今はinsserv使う方がナウいのかな?

次に、一定時間ごとに更新する方法。OpenWeatherMapの更新間隔というのもあると思いますが、ここでは単純に1時間おきのcronジョブを設定します。
rootのcrontabを編集します。この辺の扱いは諸説あると思いますが(crontab -eは間違えて-rで全消ししそうで危ないとか、直接エディタを使うのは行儀が悪いとか)、まぁ好みの方法でやったらいいと思います。
で、毎時0分に更新が行われるよう、下記の行を追加します。


参考情報

Free weather data API for developers - Open Weather Map
Weather information from openweathermap.org JSON API by Python - Techdoc Blog 
1: Getting Started with Raspberry Pi GPIO and Python - OPENMICROS.org
RPi Low-level peripherals - eLinux.org
How to add a program to run at startup in Ubuntu Linux Server edition - Temp Variable

2 件のコメント:

  1. 最近raspberyPIとPythonをはじめた初心者です

    質問
    weatherと同じようにスクレイピングして最高気温, 最低気温, 湿度を表示させたいのですがどのようにすればよいのでしょうか?

    そもそもスクレイピングの方法は分かりません

    返信削除
    返信
    1. こんにちは。
      返信が遅くなりすみません。

      JSONのレスポンスに最高気温、最低気温、湿度も含まれています。
      上記Pythonコード中で下記のようにすれば取得、表示できます。
      試してみてください。

      # 最高気温
      max_temp = json.loads(line)['list'][0]['temp']['max']
      print max_temp

      # 最低気温
      min_temp = json.loads(line)['list'][0]['temp']['min']
      print min_temp

      # 湿度
      humidity = json.loads(line)['list'][0]['humidity']
      print humidity

      削除