Emptyのアイコン画像
Empty 2024年09月20日作成 (2024年10月30日更新)
製作品 製作品 閲覧数 112
Empty 2024年09月20日作成 (2024年10月30日更新) 製作品 製作品 閲覧数 112

デジタルサイネージで 一週間の天気予報

使用言語・バージョン

Python 3.9.2
Pygame 1.9.6 文字や画像の配置に使用
requests 2.25.1 天気予報取得APIから情報を取得する際に使用

使用部品

  • RaspberryPi4
  • モニター
  • パソコンとラズパイ接続用のケーブル

概要

RaspberryPi4をパソコンと接続しモニター上に以下の情報を表示

  • 当日の日付・時間
  • 一週間の天気予報
  • 最高・最低気温

イメージ図

イメージ図は以下の通りである
画面イメージ図

詳細

今回使用した 天気予報取得APIのOpen Meteo APIについて

Open-Meteoは、複数の国の気象サービスと提携してデータを提供しており、各地域に最適な気象モデルを選択して信頼性の高い予報を実現している。緯度経度で場所を指定でき、hourlyパラメータの情報は毎時間更新される。このAPIは、ドイツに拠点を置く開発者や技術者のコミュニティによって管理されており、オープンデータに基づいた気象情報を無料で提供し、特定の地域やプロジェクトに合わせたカスタマイズが可能。

システムの動作
パソコンからプログラムを実行させることで実行画面が表示される。画面上部にリアルタイムの時間と日付・曜日、現在の気温が表示される。画面下部には一週間日付と最高気温・最低気温そしてイラストで天気を表示する。リアルタイムで情報を更新する。

実行画面

実行画面

プログラム

sample.py

import pygame import time import datetime import os import sys import requests # API呼び出し用 from pygame.locals import * # MeteoAPIの設定 API_KEY = 'your_meteo_api_key' # 取得したAPIキーを設定してください LATITUDE = 33.5597 # 高知県の緯度 LONGITUDE = 133.5311 # 高知県の経度 WEATHER_API_URL = f"https://api.open-meteo.com/v1/forecast?latitude={LATITUDE}&longitude={LONGITUDE}&current_weather=true&daily=temperature_2m_max,temperature_2m_min,weathercode&timezone=Asia/Tokyo" # 定数 WIDTH = 1600 # 幅 HEIGHT = 900 # 高さ # モジュール初期化 pygame.init() pygame.mouse.set_visible(0) # サイズ設定 size = (pygame.display.Info().current_w, pygame.display.Info().current_h) print("Framebuffer size: %d x %d" % (size[0], size[1])) # 画面設定 surface = pygame.display.set_mode((WIDTH, HEIGHT)) # フォント設定 title_font = pygame.font.Font(os.path.join('/usr/share/fonts/truetype/fonts-japanese-gothic.ttf'), 120) body_font = pygame.font.Font(os.path.join('/usr/share/fonts/truetype/fonts-japanese-gothic.ttf'), 70) info_font = pygame.font.Font(os.path.join('/usr/share/fonts/truetype/fonts-japanese-gothic.ttf'), 25) # 天気コードに対応する画像のロード whether_images = { 0: pygame.image.load("images/sun.png"), 1: pygame.image.load("images/sun.png"), 2: pygame.image.load("images/sun.png"), 3: pygame.image.load("images/sun.png"), 4: pygame.image.load("images/sun.png"), 5: pygame.image.load("images/sun.png"), 6: pygame.image.load("images/sun.png"), 7: pygame.image.load("images/sun.png"), 8: pygame.image.load("images/sun.png"), 9: pygame.image.load("images/sun.png"), 10: pygame.image.load("images/sun.png"), 11: pygame.image.load("images/cloud.png"), 12: pygame.image.load("images/cloud.png"), 13: pygame.image.load("images/cloud.png"), 14: pygame.image.load("images/cloud.png"), 15: pygame.image.load("images/cloud.png"), 16: pygame.image.load("images/cloud.png"), 17: pygame.image.load("images/cloud.png"), 18: pygame.image.load("images/cloud.png"), 19: pygame.image.load("images/cloud.png"), 20: pygame.image.load("images/cloud.png"), 21: pygame.image.load("images/cloud.png"), 50: pygame.image.load("images/rain.png"), 51: pygame.image.load("images/rain.png"), 52: pygame.image.load("images/rain.png"), 53: pygame.image.load("images/rain.png"), 54: pygame.image.load("images/rain.png"), 55: pygame.image.load("images/rain.png"), 56: pygame.image.load("images/rain.png"), 57: pygame.image.load("images/rain.png"), 58: pygame.image.load("images/rain.png"), 59: pygame.image.load("images/rain.png"), 60: pygame.image.load("images/rain.png"), 61: pygame.image.load("images/rain.png"), 62: pygame.image.load("images/rain.png"), 63: pygame.image.load("images/rain.png"), 66: pygame.image.load("images/rain.png"), 67: pygame.image.load("images/rain.png"), 71: pygame.image.load("images/rain.png"), 72: pygame.image.load("images/rain.png"), 73: pygame.image.load("images/rain.png"), 85: pygame.image.load("images/snow.png"), 86: pygame.image.load("images/snow.png") } # MeteoAPIを使って天気データを取得 def fetch_weather_data(): try: response = requests.get(WEATHER_API_URL) response.raise_for_status() weather_data = response.json() return weather_data # 現在の天気と日次の天気データを返す except requests.exceptions.RequestException as e: print(f"API request failed: {e}") return None # 背景画像の表示 def screen_home(): background_image = pygame.image.load("images/haikei.png") background_image = pygame.transform.scale(background_image, (size[0], size[1])) surface.blit(background_image, (0, 0)) # 現在時刻の表示 def update_time(): _now = datetime.datetime.now() today = _now.strftime("%m / %d") nowtime = _now.strftime("%H:%M:%S") weekday = _now.strftime('%a') time_text = title_font.render(today + " " + nowtime + " (" + weekday + ")", True, (255, 255, 255)) surface.blit(time_text, (50, 100)) # 現在の気温の表示 def display_current_temperature(current_weather): current_temp = current_weather['temperature'] # 現在の気温を取得 temp_text = body_font.render(f"現在の気温: {current_temp}°C", True, (255, 255, 255)) surface.blit(temp_text, (50, 250)) # 時刻の下に表示 # 一週間の天気を下部にまとめて表示 def display_weekly_weather(daily_weather): # 表示するX座標の初期値 start_x = 50 start_y = HEIGHT - 500 # 画面の下部に配置 for i in range(len(daily_weather['time'])): day = daily_weather['time'][i] max_temp = daily_weather['temperature_2m_max'][i] min_temp = daily_weather['temperature_2m_min'][i] weather_code = daily_weather['weathercode'][i] # 天気アイコンの取得とリサイズ weather_image = whether_images.get(weather_code) if weather_image: # 天気アイコンのサイズを変更 (例: 100x100ピクセルにリサイズ) weather_image_resized = pygame.transform.scale(weather_image, (100, 100)) surface.blit(weather_image_resized, (start_x, start_y)) # 日付を表示 date_text = info_font.render(day, True, (255, 255, 255)) surface.blit(date_text, (start_x, start_y + 110)) # アイコンの下に日付を表示 # 最高気温と最低気温を表示(改行するように調整) max_temp_text = info_font.render(f"最高気温: {max_temp}°C", True, (255, 255, 255)) min_temp_text = info_font.render(f"最低気温: {min_temp}°C", True, (255, 255, 255)) # 最高気温と最低気温を改行して表示 surface.blit(max_temp_text, (start_x, start_y + 160)) surface.blit(min_temp_text, (start_x, start_y + 210)) # 次の天気データを表示する位置にずらす start_x += 220 # 横に220pxずつずらす if __name__ == '__main__': fpsclock = pygame.time.Clock() # リアルタイムで天気データを取得 weather_data = fetch_weather_data() if weather_data is None: print("Failed to fetch weather data.") sys.exit() current_weather = weather_data['current_weather'] # 現在の天気データ daily_weather = weather_data['daily'] # 7日間の天気データ while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() # 背景画像の表示 screen_home() # 現在時刻の表示 update_time() # 現在の気温の表示 display_current_temperature(current_weather) # 一週間の天気を画面下部にまとめて表示 display_weekly_weather(daily_weather) # 画面更新 pygame.display.update() # フレームレート制御 fpsclock.tick(60)

工夫した点

Pythoではswitch文が使えなかったため、match文を変わりに使用しました。初めてmatch文を触ったので手探りながら完成させた点が工夫した点です。

まとめ

初めに想定していた、一週間の天気など最低限の機能は実装できた。しかし、中央部に追加情報を加える予定だったが時間がなくあきらめた。Open Meteo APIでは、降水量、日の出、日の入りの時間、最大風速、突風、太陽放射量、など様々な機能を追加出来るため、発展性は高い。

参考文献

Weather Forecast API

https://open meteo.com/

API キーもログインも不要!完全無料で使える天気予報 API 「 Open Meteo 」を使ってみた!

https://paiza.hatenablog.com/entry/2021/11/04/130000

ログインしてコメントを投稿する