BLOG

ブログ

【ラズパイ】デジタルサイネージを作ってみた

こんにちは、タロウです。

モバイルモニターがある。
使ってないラズパイがある。
寂しそうにしている壁もある。

そんなデジタルサイネージを作ってみました。

いきなり完成

ブラウザを使わずに画面を作ってみたい欲があり、
Python(pygame)で時計と天気予報を配置してシンプルなデジタルサイネージを作成しました。

(写真は自分で撮ったやつだぜ。長秒露光ガンバった。)

使用言語・バージョン

Python3.9
pygame2.1.2文字や画像を手軽に配置できそうなライブラリを探していたところ、
Pythonのゲーム開発ライブラリにたどり着きました。
requests2.28.1天気予報取得APIを叩く時に使用します。

機材

  • Raspberry Pi 2 model B
  • モバイルモニター

以降、ポイントと作成した手順です!

まずはPygameを使って画面を表示する

Pythonはほぼ初見ですが、
まず画面が出ないことには始められないので何か表示するところから始めます。
(もっと効率の良い書き方などなどあるかもしれません。お目汚し失礼いたします!)

必要な初期設定、画面サイズ、フォントの設定を行います。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import pygame
from pygame.locals import *

# GUI Setting from here------
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]))

# フルサイズ
screen = pygame.display.set_mode(size, pygame.FULLSCREEN)

### フォント ###
# タイトル
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'), 48)

ラズパイに接続しているモニターで画面いっぱいに表示させたいので、
フルサイズとなるようディスプレイ設定をします。

フォントは大きさ別に3種類準備しました。

次に、背景画像の設定処理を書きます。

# 背景画像の表示
def screen_home():
    background_image = pygame.image.load("images/illumination.jpg")
    background_image = pygame.transform.scale(background_image,(size[0], size[1]))
    screen.blit(background_image, (0, 0))

背景画像は、実行ソースと同じレイヤのimages内に画像を配置し読み込みます。
表示サイズもディスプレイ設定と同様にフルサイズとなるよう設定します。

最後に起動したら実行し続ける処理へ、作成した設定処理の呼び出しを書きます。

if __name__ == '__main__':
    while True:
        for event in pygame.event.get():
            # 背景設定
            screen_home()

            # 画面表示
            pygame.display.update()

            # フレームレート設定
            fpsclock.tick(1000)

            #ensure there is always a safe way to end the program if the touch screen fails
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

ループ内で、背景設定処理、表示処理を書きます。
※次の時計表示のためにフレームレートは1秒で設定します。
※1秒ごとに時間を差し替えないと行けないので毎回背景から設定し直しています。

日本語フォントが入っていない場合

下記コマンドでフォントをインストールします。

sudo apt install fonts-ipaexfont

時計を表示する

現在時刻を取得し表示用にフォーマットを決めます。
カッコ内に曜日も合わせて表示します。

import datetime
import time

~~~~~~~ 略 ~~~~~~~

def update_time():
    # 日時の取得
    _now = datetime.datetime.now()
    today = _now.strftime("%m / %d")
    nowtime = _now.strftime("%H:%M:%S")
    weelday = _now.strftime('%a')

    time = title_font.render(today + " " + nowtime + " (" + weelday + ")", True, (255,255,255))
    screen.blit(time, (50,100))

フレームレートを1秒にしているので、
毎回現在日付を取得して正確な秒数を表示します!

天気予報を表示する

今回は「Open-Meteo」の天気予報APIを使用しました。
緯度経度で天気を取得することができるので割と正確に把握することができそうです!

起動時に1度だけ取得するようにし、

// 20221206104836
// https://api.open-meteo.com/v1/forecast?latitude=43.068064&longitude=141.346432&daily=temperature_2m_max,temperature_2m_min,weathercode&timezone=Asia%2FTokyo

{
  "latitude": 43.05,
  "longitude": 141.375,
  "generationtime_ms": 0.5159378051757812,
  "utc_offset_seconds": 32400,
  "timezone": "Asia/Tokyo",
  "timezone_abbreviation": "JST",
  "elevation": 19.0,
  "daily_units": {
    "time": "iso8601",
    "temperature_2m_max": "°C",
    "temperature_2m_min": "°C",
    "weathercode": "wmo code"
  },
  "daily": {
    "time": [
      "2022-12-05",
      "2022-12-06",
      "2022-12-07",
      "2022-12-08",
      "2022-12-09",
      "2022-12-10",
      "2022-12-11"
    ],
    "temperature_2m_max": [
      -2.6,
      2.2,
      2.5,
      0.0,
      0.7,
      0.5,
      -1.0
    ],
    "temperature_2m_min": [
      -6.9,
      -5.5,
      -3.0,
      -2.3,
      -6.4,
      -6.0,
      -5.6
    ],
    "weathercode": [
      3,
      3,
      3,
      85,
      2,
      3,
      3
    ]
  }
}

このようにパラメータで返却値を絞ることができるので、
必要なデータだけ取得することができました。

※1週間の天気、最高気温・最低気温を取得しています。

ハマったところ

switchが使えなかった

Pythonにはswitchが無いらしく、同様のロジックをmatchを使い表現できるようでした。
(バージョン3.10以降のみ)

が、動作環境が3.9だったので動かすことができず、下のように表現しました。

### イケてなさすぎる
# 天気コードとイラストの紐付けデータ
whether_images = {
    0 : pygame.image.load("images/sun.png"),
    1 : pygame.image.load("images/cloud.png"),
    2 : pygame.image.load("images/cloud.png"),
    3 : pygame.image.load("images/cloud.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")
}
# numでKey指定して画像イメージを取り出す
whether_images.get(daily["weathercode"][num]

### 本当はこうしたかった
# お天気マーク
# whether_image = ""
# match daily["weathercode"][num]:
#     case 0
#         # 快晴
#         whether_image = pygame.image.load("images/sun.png"),
#     case 1 | 2 | 3
#         # おおむね晴れ、ときどき曇り
#         whether_image = pygame.image.load("images/cloud.jpg")
#     case 61 | 62 | 63 | 66 | 67
#         # 雨
#         whether_image = pygame.image.load("images/rain.jpg")
#     case 85 | 86
#         # 雪
#         whether_image = pygame.image.load("images/snow.jpg")

さいごに

Python初心者でしたがなんとか表示できるものが出来上がりました。

何かを表示する基礎部分ができたので、
運行情報など必要な情報をとってカスタマイズしていきたいと思います!

ちょうど一年前に作成したドアセンサーとも連携できる気がしています。

これと連携できそう・・

また進展したらその様子を紹介させてください!

RELATED ARTICLE