Raspberry Pi PicoでAPIから天気予報を取得し表示する

電子工作

皆さんこんにちは、ITAです。
今回はRaspberry Pi Pico Wを使ってAPIから天気予報を取得し、OLEDディスプレイに表示するということをやっていきたいと思います。OLEDディスプレイで日本語を表示できないのため、天気予報は英語のOpenWeatherMap APIから取得します。

はじめに

このプロジェクトではWi-Fi接続APIからのデータ取得、そしてOLEDへの表示という3つの要素を組み合わせています。初心者の方でも取り組みやすい内容なので、Raspberry Pi Picoの活用例としてぜひ挑戦してみてください。


Wi-Fi接続に関しては以前に扱わせていただいた記事をご参照いただくとよろしいかと思います。
Wi-Fi接続の方法について

また、OLEDディスプレイへの表示に関しましても以前に扱わせていただいた記事をご参照いただくとよろしいかと思います。
OLEDディスプレイに表示する方法

Open Weather Mapの使い方

OpenWeatherMapは世界中の天気情報を取得できる便利なAPIサービスです。無料プランでも現在の天気や気温、湿度などの基本情報を取得できます。

アカウント登録とAPIキー取得

OpenWeatherMapを使うには、まず公式サイトhttps://openweathermap.org/でアカウント登録を行い、APIキーを取得する必要があります。このAPIキーは、天気情報を取得するための認証コードとして使われます。APIキーを取得できたら次に行きましょう。

OLED接続

OLEDディスプレイの詳細に関しては、こちらのOLEDディスプレイの使い方をご参照ください。

使用部品

  • Raspberry Pi Pico W (Wi-Fiが使えるもの!
  • OLEDディスプレイ(128×64、I2C接続、SSD1306)
  • ジャンパーワイヤー

配線方法(例)

OLED端子Picoピン番号説明
VCC3V3 (Pin 36)電源
GNDGND (Pin 38)グラウンド
SCLGP15 (Pin 21)クロック線
SDAGP14 (Pin 19)データ線

I2Cのピン番号はプログラム内でも指定する必要があります。この例ではSCLにGP15、SDAにGP14を接続しています。

ソフトウェアとコード解説

Raspberry Pi Pico Wで天気予報を取得してOLEDディスプレイに表示するプログラムについて、段階的に解説します。

必要なライブラリ

以下のライブラリを使います:

  • network:Wi-Fi接続に使用
  • urequests:APIにHTTPリクエストを送るために使用
  • ujson:JSON形式のデータを扱うために使用
  • ssd1306:OLEDディスプレイの制御に使用
  • machine/time:I2C通信や待機処理に使用

urequestsとssd1306は別途インストールする必要がありますので注意してください。

APIからデータ取得

OpenWeatherMapのAPIを使って、都市名に対応する現在の天気データを取得します。

def get_weather():
    url = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric"
    try:
        response = urequests.get(url)
        data = response.json()
        response.close()
        return data
    except:
        return None

JSONから必要なデータを抽出

取得したJSON形式のデータから、天気、気温、湿度などの情報を取り出します。例は、天気、気温、湿度です。

weather_main = data["weather"][0]["main"]
temp = data["main"]["temp"]
humidity = data["main"]["humidity"]

その他に取得できるデータとパスは以下のようになっています。さらに詳しい内容はこちら(openweathermap公式)をご覧ください。

JSONキーのパス意味
name都市名“Tokyo”
weather[0].main天気(簡潔)“Clear”, “Clouds”, “Rain” など
weather[0].description天気(詳細)“light rain”, “overcast clouds”
main.temp気温(摂氏)26.7
main.humidity湿度(%)65
main.pressure気圧(hPa)1013
wind.speed風速(m/s)2.1
wind.deg風向(度)180
clouds.all雲量(%)75
rain.1h または rain.3h降水量(mm)0.5
dtデータ取得時刻(UNIX時間)例: 1650000000

OLEDへ表示

先ほど取り出した、データをOLEDディスプレイに表示させます。データが来なかった場合は、failed!と表示されます。

def display_weather(data):
    oled.fill(0)
    if data is None:
        oled.text("Weather fetch", 0, 0)
        oled.text("failed!", 0, 10)
        oled.show()
        return

    city = data.get("name", "N/A")
    weather_main = data["weather"][0]["main"]
    temp = data["main"]["temp"]
    humidity = data["main"]["humidity"]

    oled.text(city, 0, 0)
    oled.text("Weather: {}".format(weather_main), 0, 16)
    oled.text("Temp: {:.1f}C".format(temp), 0, 32)
    oled.text("Humidity: {}%".format(humidity), 0, 48)
    oled.show()

やってみた(実行結果と表示例)

こちらが全体のコードです。

from machine import Pin, I2C
import ssd1306
import network
import time
import urequests
import ujson

# WiFi接続設定
SSID = 'あなたのSSID'
PASSWORD = 'あなたのWi-Fiパスワード'

# OpenWeatherMap設定
API_KEY = 'あなたのAPIキー'
CITY = 'Tokyo,jp' #ご自分に合わせて

# OLED初期化(I2C)
i2c = I2C(1, scl=Pin(15), sda=Pin(14)) #ご自分のものに合わせて
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(128, 64, i2c)

def connect_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    if not wlan.isconnected():
        print('Connecting to network...')
        wlan.connect(SSID, PASSWORD)
        while not wlan.isconnected():
            pass
    print('Network config:', wlan.ifconfig())

def get_weather():
    url = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric&lang=en"
    try:
        response = urequests.get(url)
        data = response.json()
        response.close()
        return data
    except:
        return None

def display_weather(data):
    oled.fill(0)
    if data is None:
        oled.text("Weather fetch", 0, 0)
        oled.text("failed!", 0, 10)
        oled.show()
        return

    city = data.get("name", "N/A")
    weather_main = data["weather"][0]["main"]
    temp = data["main"]["temp"]
    humidity = data["main"]["humidity"]

    oled.text(city, 0, 0)
    oled.text("Weather: {}".format(weather_main), 0, 16)
    oled.text("Temp: {:.1f}C".format(temp), 0, 32)
    oled.text("Humidity: {}%".format(humidity), 0, 48)
    oled.show()



def main():
    connect_wifi()
    while True:
        weather_data = get_weather()
        print(weather_data) 
        display_weather(weather_data)
        time.sleep(600)  # 例:10分に一回更新

if __name__ == "__main__":
    main()

こちらが実際に表示した例です。

まとめ

やってみてわかったこと・注意点

  • Open Weather Map の無料プランでは、API の呼び出し回数に制限(例:1時間あたり60回など)があります。頻繁にアクセスしすぎると一時的にアクセス制限されることがあるため、更新間隔(例:10分おきなど)を適切に設定しましょう。
  • 取得できるデータは多いですが、表示領域が限られているため、見せたい情報をうまく取捨選択する必要があります。
  • エラー処理は非常に大切です。APIキーの間違いやWi-Fiの接続失敗があると表示ができなくなるため、しっかり対策しておくと安心です。

今後の発展

今後の発展としては、天気の種類に応じたシンプルなアイコン(太陽、雲、雨マークなど)をOLEDディスプレイに表示することで、視覚的によりわかりやすくしてみたいです。また、現在の天気だけでなく、3時間ごとの予報や翌日の天気なども表示できるようにするなどいったことをすると、より実用的な天気表示システムになるのではないかと思いました。
今回はAPIから天気予報を取得しましたが、他にもたくさん取得できるものはあるので挑戦していきたいと思います。

コメント

タイトルとURLをコピーしました