2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

余ったラズパイで時計と天気を表示するデジタルサイネージ作成の備忘録

Last updated at Posted at 2024-08-21

余ったラズパイで時計と天気を表示するデジタルサイネージっぽいものを作った。

使用したもの

  • Raspberry Pi 3 ModelB+
  • LEDディスプレイ
  • HDMI
  • マウス
  • キーボード

時計と天気を表示するPythonアプリの作成

時計と天気はTkinterで表示する。天気はOpenWetherAPIで特定の場所の天気を取得する。

Tkinterをインストール

pip3 install pytk

下記時計と天気情報を表示するプログラム

import tkinter as tk
from tkinter import font
import time
import requests
import math

# OpenWeatherMap API
api_key = '**************************'  # ここにAPIキーを入力してください
city_name = 'Tokyo'  # 表示したい都市名

def get_weather():
    url = f"http://api.openweathermap.org/data/2.5/weather?q={city_name}&appid={api_key}&units=metric"
    response = requests.get(url)
    weather_data = response.json()
    
    if weather_data['cod'] == 200:
        temp = weather_data['main']['temp']
        weather_desc = weather_data['weather'][0]['description']
        return f"{city_name}: {temp}°C, {weather_desc.capitalize()}"
    else:
        return "Weather data not available"

def update_clock():
    current_time = time.strftime('%H:%M:%S')
    time_label.config(text=current_time)
    time_label.after(1000, update_clock)  # 1秒ごとに更新

def update_weather():
    weather = get_weather()
    weather_label.config(text=weather)
    weather_label.after(600000, update_weather)  # 10分ごとに更新

def draw_hand(canvas, length, angle, width, color, tag):
    angle = math.radians(angle)
    x = center_x + length * math.sin(angle)
    y = center_y - length * math.cos(angle)
    canvas.create_line(center_x, center_y, x, y, width=width, fill=color, tags=tag)

def update_analog_clock():
    # 既存の針を削除
    canvas.delete('hands')
    
    # 現在時刻を取得
    now = time.localtime()
    hour = now.tm_hour % 12
    minute = now.tm_min
    second = now.tm_sec
    
    # 角度計算
    hour_angle = (hour + minute / 60) * 30  # 1時間=30度
    minute_angle = (minute + second / 60) * 6  # 1分=6度
    second_angle = second * 6  # 1秒=6度
    
    # 時計の針を描画(タグ付き)
    draw_hand(canvas, clock_radius * 0.5, hour_angle, 8, 'white', 'hands')  # 時針
    draw_hand(canvas, clock_radius * 0.7, minute_angle, 6, 'white', 'hands')  # 分針
    draw_hand(canvas, clock_radius * 0.9, second_angle, 2, 'red', 'hands')  # 秒針
    
    canvas.after(1000, update_analog_clock)

# GUI Setup
root = tk.Tk()
root.title("Digital Signage")
root.attributes("-fullscreen", True)  # フルスクリーンモード
root.configure(background='black')
root.attributes('-fullscreen', True)

# フォント設定
time_font = font.Font(family='Helvetica', size=30, weight='bold')
weather_font = font.Font(family='Helvetica', size=20, weight='bold')

# 時計の中心と半径
center_x, center_y = 200, 180
clock_radius = 150

# キャンバス(アナログ時計表示用)
canvas = tk.Canvas(root, width=400, height=400, bg='black', highlightthickness=0)
canvas.pack(anchor='center', pady=0)

# デジタル時計表示ラベル
time_label = tk.Label(root, font=time_font, bg='black', fg='white')
time_label.pack(anchor='n', pady=0)

# 天気表示ラベル
weather_label = tk.Label(root, font=weather_font, bg='black', fg='white')
weather_label.pack(anchor='s', pady=20)

# アナログ時計の盤面を描画
for i in range(12):
    angle = math.radians(i * 30)
    x = center_x + clock_radius * 0.9 * math.sin(angle)
    y = center_y - clock_radius * 0.9 * math.cos(angle)
    canvas.create_text(x, y, text=str(i if i > 0 else 12), fill="white", font=("Helvetica", 24))

# 時刻と天気情報の更新
update_clock()
update_weather()
update_analog_clock()

# 終了するにはEscキーを押す
root.bind("<Escape>", lambda e: root.destroy())

root.mainloop()

実行すると下記のような画面が表示される。
2024-08-21-103117_1920x1080_scrot-1.png

ラズパイ起動時に自動実行

意外とここに時間がかかった。

サービスデーモンを作成するときに気を付けること

  1. コマンドはフルパスで記載
  2. 実行ユーザーを指定する
  3. 失敗したときの再実行を定義する
sudo emacs /etc/systemd/system/run_uvicorn.service
sudo systemctl daemon-reload
sudo systemctl stop run_uvicorn.service
sudo systemctl start run_uvicorn.service
[Unit]
Description = run uvicorn daemon
After=network.target

[Service]
User=ec2-user
Group=ec2-user
ExecStart = /home/ec2-user/run_uvicorn.sh
WorkingDirectory=/var/www/html/myapp
RemainAfterExit=yes
Restart=always
RestartSec=20

 [Install]
WantedBy = multi-user.target
run_uvicorn.sh
#!/bin/sh 
PATH=$PATH:$HOME/.local/bin:$HOME/bin
export PATH

echo `date` >> /home/ec2-user/run_uvicorn.log

# Fast API Server Auto Boot 
alias mycommand='/usr/bin/nohup uvicorn main:app --host localhost --port 8000  --workers 1  --timeout-keep-alive 30 &'
mycommand

#find /tmp/ -type f -mtime +7 -exec rm -f {} \; 

起動時の自動実行は、systemctl serviceを使用する。

  1. 上記Pythonコードを実行するシェルスクリプトを作成する。
/home/pi/autoexec.sh
#!/bin/sh

export DISPLAY=:0.0
exec python3 /home/pi/auroexec.py

DISPLAY=:**の数字はecho $DISPLAYで確認してください

  1. serviceファイルを作成する
    vi /etc/systemdl/system/autoexec.service
  2. 下記を記載する
    /etc/systemdl/system/autoexec.service
    [Unit]
    Desription=My Tkinter Script
    After=network-online.target
    #Wants=graphical.target
    
    [Service]
    User=pi
    Group=pi
    Environment=DISPLAY=:0.0
    #Environment=XAUTHOITY=/home/pi/.Xauthority
    ExecStart=/bin/bash /home/pi/autoexec.sh
    Restart=always
    RestartSec=5
    Type=forking
    RemainAfterExit=yes
    RuntimeMaxSec=7d
    
    [Install]
    WantedBy=multi-user.target
    
  3. systemctl daemon-reload
  4. systemctl start autoexec.service
    これで正常にPythonプログラムが実行されるか確認する。
  5. systemctl enable autoexec.service
  6. sudo reboot

参考リンク

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?