新しいものづくりがわかるメディア

RSS


fabcrossスマートフォンアプリのダウンロードはこちら

「土日で完成! 趣味のラズパイ」

土日で完成! 趣味のラズパイ ChatGPTで遊ぼう——ラズパイで作ったデジタル時計に天気情報も表示させる

2月の掲載からちょっと間が空いてしまいましたが、宿題であった「電子時計に天気予報も表示する」に取り組んでいきましょう。

前回作った電子時計。ここに天気予報も追加したい 前回作った電子時計。ここに天気予報も追加したい

早速ChatGPTに問いかけてみます。


問い
これに天気予報を加えてください



これに対する答えは以下のようなものでした(用字用語はChatGPTが答えたままにしています)。


天気予報をデジタル時計に加えるには、外部の天気予報APIを利用する必要があります。一般的に利用されるのはOpenWeatherMap APIですが、これを使用するにはAPIキーが必要です。APIキーはOpenWeatherMapのウェブサイトで無料で取得できます。

以下の手順では、OpenWeatherMap APIを使用して現在の天気情報を取得し、それをOLEDディスプレイに表示する方法を示します。このコードは前の時計と曜日を表示するコードに基づいています。

### 必要なライブラリのインストール
- 天気情報を取得するために`requests`ライブラリを使用します。このライブラリがまだインストールされていない場合は、インストールしてください。

pip3 install requests

### OpenWeatherMap APIの設定
1. OpenWeatherMapの[公式サイト](https://openweathermap.org/)にアクセスしてアカウントを作成し、APIキーを取得します。
2. 取得したAPIキーをコード内で使用します。

### Pythonプログラムの更新
以下のコードスニペットを既存の時計表示コードに組み込んで、天気予報を表示します。このコードは現在の天気と気温を取得し、ディスプレイに表示します。

import requests

# OpenWeatherMap APIの設定
API_KEY = 'あなたのAPIキー'  # ここにあなたのOpenWeatherMap APIキーを入力
CITY = 'あなたの都市名'  # 例: 'Tokyo,JP'
URL = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric"

def get_weather():
    try:
        response = requests.get(URL)
        data = response.json()
        # 天気と気温を取得
        weather = data['weather'][0]['main']
        temp = round(data['main']['temp'])
        return f"{weather}, {temp}°C"
    except Exception as e:
        print(f"Error fetching weather data: {e}")
        return "No Weather Data"

# 以前のコードに続いて、無限ループ内で天気情報を取得し表示するコードを追加
while True:
    # 省略: 時刻と曜日の取得、表示のコード

    # 天気情報を取得
    weather_info = get_weather()

    # 天気情報を表示
    weather_width, weather_height = draw.textsize(weather_info, font=day_font)
    weather_x = (oled.width - weather_width) // 2
    weather_y = day_y + day_height + 5  # 曜日の下に少し間隔を開ける
    draw.text((weather_x, weather_y), weather_info, font=day_font, fill=255)

    # 画像をOLEDディスプレイに表示
    oled.image(image)
    oled.show()

    # 1秒間隔で更新
    time.sleep(60)  # 天気情報は頻繁に更新する必要がないため、更新間隔を長くしています

### 注意点
- APIキーは秘密にしてください。公開された場所にアップロードしないように注意してください。
- OpenWeatherMap APIの無料プランには呼び出し回数の制限があります。APIの使用制限を超えないようにしてください。
- 天気情報の更新間隔は長めに設定しています。これはAPIの呼び出し回数を節約するためです。必要に応じて間隔を調整してください。
- 天気情報を取得する関数`get_weather`は、APIからのレスポンスに基づいて天気と気温を文字列として返します。この情報はOLEDディスプレイに表示されます。



どうやら「OpenWeatherMap」にアクセスしてAPIキーをもらえばよさそうです。OpenWeatherMapは、Webやモバイルアプリケーションの開発者に、現在の天候や予報履歴を含む各種気象データのAPIを提供するオンラインサービスです。無料で利用する場合は3時間ごとの天気予報を向こう5日間分、取得できます。また、1分間に60回までAPIを呼び出せます。

早速OpenWeatherMapにアクセスしてみましょう。アカウントを持っていない場合は右上の「Sign in」から「Create an Account」でアカウントを作成します。

OpenWeatherMapにアクセスして「Sign in」をクリック OpenWeatherMapにアクセスして「Sign in」をクリック
「Sign in」からアカウントを作成する 「Sign in」からアカウントを作成する
自分のページが表示された。登録したメールアドレス宛に認証メールが届いているので、こちらを認証しておこう 自分のページが表示された。登録したメールアドレス宛に認証メールが届いているので、こちらを認証しておこう

自分のページが表示されたら、リストの「API Keys」をクリックしてAPIキーを発行します。ページの中にある「Key」の文字列をコピーしておきます。

メニューの「API keys」をクリックすると「Key」の欄にAPIキーが表示される メニューの「API keys」をクリックすると「Key」の欄にAPIキーが表示される

では以前作成したプログラムに、天気予報のプログラムを追加しましょう。「ここにあなたのOpenWeatherMap APIキーを入力」の所には、発行したAPIキーを入力します。

import time
import board
import busio
import requests
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# I2C接続設定
i2c = busio.I2C(board.SCL, board.SDA)
oled = SSD1306_I2C(128, 64, i2c)  # OLEDディスプレイの解像度とI2C接続を設定

# 画像と描画オブジェクトを作成
image = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image)

# カスタムフォントサイズの設定
# ビルトインフォントを使用しますが、より大きなサイズやカスタムフォントを使用する場合は、
# 適切な.ttfファイルを指定してください。

FONT_PATH = "/usr/share/fonts/truetype/noto/NotoSans-Regular.ttf"
font_size = 20
font = ImageFont.truetype(FONT_PATH, font_size, encoding = 'unic')

# 曜日の表示に使用するフォントサイズ
day_font_size = 14
day_font = ImageFont.truetype(FONT_PATH, day_font_size, encoding = 'unic')

# OpenWeatherMap APIの設定
API_KEY = '(API_Keyを入れる)  # ここにあなたのOpenWeatherMap APIキーを入力
CITY = 'Tokyo,JP'  # 例: 'Tokyo,JP'
URL = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric"

def get_weather():
    try:
        response = requests.get(URL)
        data = response.json()
        # 天気と気温を取得
        weather = data['weather'][0]['main']
        temp = round(data['main']['temp'])
        return f"{weather}, {temp}°C"
    except Exception as e:
        print(f"Error fetching weather data: {e}")
        return "No Weather Data"

while True:
    # 現在の時刻と曜日を取得
    current_time = time.strftime("%H:%M")
    current_day = time.strftime("%A")  # 曜日を取得

    # 画面をクリア
    draw.rectangle((0, 0, oled.width, oled.height), outline=0, fill=0)

    # 時刻を画面上部に描画
    time_width, time_height = draw.textsize(current_time, font=font)
    time_x = (oled.width - time_width) // 2
    time_y = 2
    draw.text((time_x, time_y), current_time, font=font, fill=255)

    # 曜日を時刻の下に描画
    day_width, day_height = draw.textsize(current_day, font=day_font)
    day_x = (oled.width - day_width) // 2
    day_y = time_y + time_height + 2  # 時刻の下に少し間隔を開ける
    draw.text((day_x, day_y), current_day, font=day_font, fill=255)

    # 天気情報を取得
    weather_info = get_weather()

    # 天気情報を表示
    weather_width, weather_height = draw.textsize(weather_info, font=day_font)
    weather_x = (oled.width - weather_width) // 2
    weather_y = day_y + day_height  # 曜日の下に少し間隔を開ける
    draw.text((weather_x, weather_y), weather_info, font=day_font, fill=255)

    # 画像をOLEDディスプレイに表示
    oled.image(image)
    oled.show()

    # 1秒間隔で更新
    time.sleep(60)  # 天気情報は頻繁に更新する必要がないため、更新間隔を長くしています

このプログラムを「clock4.py」などの名前で保存します。保存したら起動してみましょう。

$ python clock4.py

以下の画像のように表示されればOKです。

時刻と曜日、天気、気温が表示された 時刻と曜日、天気、気温が表示された

さて、このままでもよいのですが、時計なので秒表示もさせたいところです。そこで今度は以下のようなプロンプトを作成して、プログラムを変更します。


問い
時刻を1秒更新、天気を1時間更新にできませんか



これに対するChatGPTの返答は以下のようなものでした。


時刻を1秒ごとに更新しつつ、天気予報を1時間ごとに更新するには、時刻更新と天気情報更新のロジックを分離し、それぞれ異なる更新間隔で動作するようにする必要があります。これを実現する一つの方法は、天気情報の更新を制御するために別のタイマーを使用することです。

以下の更新されたプログラムでは、時刻の表示を1秒ごとに、天気情報の更新を1時間ごとに行います。

import time
import requests
import board
import busio
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# OpenWeatherMap APIの設定
API_KEY = 'あなたのAPIキー'
CITY = 'あなたの都市名'
URL = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric" 

def get_weather():
    try:
        response = requests.get(URL)
        data = response.json()
        weather = data['weather'][0]['main']
        temp = round(data['main']['temp'])
        return f"{weather}, {temp}°C"
    except Exception as e:
        print(f"Error fetching weather data: {e}")
        return "No Weather Data"

# I2C接続設定
i2c = busio.I2C(board.SCL, board.SDA)
oled = SSD1306_I2C(128, 64, i2c)

# 画像と描画オブジェクトを作成
image = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image)

# フォントの設定
font_size = 20
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size)
day_font_size = 14
day_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", day_font_size)

# 天気情報の更新間隔 (秒)
weather_update_interval = 3600  # 1時間
last_weather_update = time.time() - weather_update_interval  # 初期値を設定して最初のループで天気を更新

weather_info = "Loading..."

while True:
    current_time = time.strftime("%H:%M:%S")
    current_day = time.strftime("%A")

    # 天気情報の更新
    if time.time() - last_weather_update > weather_update_interval:
        weather_info = get_weather()
        last_weather_update = time.time()

    # 画面をクリア
    draw.rectangle((0, 0, oled.width, oled.height), outline=0, fill=0)

    # 時刻と曜日の表示
    draw.text((5, 5), current_time, font=font, fill=255)
    draw.text((5, 30), current_day, font=day_font, fill=255)

    # 天気情報の表示
    draw.text((5, 50), weather_info, font=day_font, fill=255)

    # 画像をOLEDディスプレイに表示
    oled.image(image)
    oled.show()

    # 1秒間隔でループ
    time.sleep(1)

このコードでは、`last_weather_update` 変数を使用して最後に天気情報を更新した時刻を記録し、現在時刻がこの時刻から指定した更新間隔を超えたかどうかを確認します。超えていた場合、天気情報を更新します。時刻表示は毎秒更新され続けますが、天気情報の更新は1時間ごとにのみ行われます。



ではこのプログラムを「clock5.py」などとして保存し、実行します。

$ python clock5.py

すると今度は秒も表示されて更新されます。

秒を含めた時刻と曜日、天気、気温が表示された 秒を含めた時刻と曜日、天気、気温が表示された

さて、このプログラムのままでもよいのですが、表示を日本語にしたいですね。そこで今度は日本語の表示にするように変更させます。


問い
このプログラムで表示される曜日と天気を日本語にしてください。またフォントは日本語のフォントにしてください



これに対するChatGPTの返答は以下のものでした。


コード全体を日本語化するために、曜日を日本語で表示し、フォントも日本語フォントに設定しましょう。また、天気情報も日本語に変換する必要があります。

以下が変更後のコードです:

1. 曜日を日本語に変換
2. 天気情報を日本語に変換
3. 日本語フォントを使用

import time
import requests
import board
import busio
from adafruit_ssd1306 import SSD1306_I2C
from PIL import Image, ImageDraw, ImageFont

# OpenWeatherMap APIの設定
API_KEY = 'あなたのAPIキー'
CITY = 'あなたの都市名'
URL = f"http://api.openweathermap.org/data/2.5/weather?q={CITY}&appid={API_KEY}&units=metric"

def get_weather():
    try:
        response = requests.get(URL)
        data = response.json()
        weather = data['weather'][0]['main']
        temp = round(data['main']['temp'])
        weather_dict = {
            'Clear': '晴れ',
            'Clouds': '曇り',
            'Rain': '雨',
            'Snow': '雪',
            'Drizzle': '霧雨',
            'Thunderstorm': '雷雨',
            'Mist': '霧'
        }
        weather_jp = weather_dict.get(weather, '不明')
        return f"{weather_jp}, {temp}°C"
    except Exception as e:
        print(f"Error fetching weather data: {e}")
        return "天気情報なし"

# I2C接続設定
i2c = busio.I2C(board.SCL, board.SDA)
oled = SSD1306_I2C(128, 64, i2c)

# 画像と描画オブジェクトを作成
image = Image.new("1", (oled.width, oled.height))
draw = ImageDraw.Draw(image)

# フォントの設定
font_size = 20
font = ImageFont.truetype("/usr/share/fonts/truetype/fonts-japanese-gothic.ttf", font_size)
day_font_size = 14
day_font = ImageFont.truetype("/usr/share/fonts/truetype/fonts-japanese-gothic.ttf", day_font_size)

# 日本語の曜日
days_jp = {
    'Monday': '月曜日',
    'Tuesday': '火曜日',
    'Wednesday': '水曜日',
    'Thursday': '木曜日',
    'Friday': '金曜日',
    'Saturday': '土曜日',
    'Sunday': '日曜日'
}

# 天気情報の更新間隔 (秒)
weather_update_interval = 3600  # 1時間
last_weather_update = time.time() - weather_update_interval  # 初期値を設定して最初のループで天気を更新

weather_info = "読み込み中..."

while True:
    current_time = time.strftime("%H:%M:%S")
    current_day = time.strftime("%A")
    current_day_jp = days_jp.get(current_day, '不明')

    # 天気情報の更新
    if time.time() - last_weather_update > weather_update_interval:
        weather_info = get_weather()
        last_weather_update = time.time()

    # 画面をクリア
    draw.rectangle((0, 0, oled.width, oled.height), outline=0, fill=0)

    # 時刻と曜日の表示
    draw.text((5, 5), current_time, font=font, fill=255)
    draw.text((5, 30), current_day_jp, font=day_font, fill=255)

    # 天気情報の表示
    draw.text((5, 50), weather_info, font=day_font, fill=255)

    # 画像をOLEDディスプレイに表示
    oled.image(image)
    oled.show()

    # 1秒間隔でループ
    time.sleep(1)

このコードでは、日本語の曜日と天気情報を表示するために以下の変更を加えました:

1. `days_jp`辞書を使用して英語の曜日を日本語に変換。
2. 天気情報を日本語に変換するための`weather_dict`辞書を追加。
3. 日本語フォント(`fonts-japanese-gothic.ttf`)を使用。

これにより、曜日と天気情報が日本語で表示されるようになります。



ではこれを「clock6.py」などのファイル名で保存して実行しましょう。

$ python clock6.py

これで日本語表示になりました。以下のように表示されればOKです。

表示が日本語になった 表示が日本語になった

ここまでChatGPTでOLEDに時刻や曜日、天気を表示させる仕組みを作り上げてみました。意外と簡単にプログラムができることがお分かりいただけたかと思います。自分のやってみたいことを、ChatGPTでいろいろと実行してみてはいかがでしょうか。