DIYで作る電子ペーパー額縁に表示する内容を外から変える(cgi編)
DIYで作る電子ペーパー額縁の作り方(ハード編)、DIYで作る電子ペーパー額縁の作り方(ソフト編) のつづき。
表示している画像を外から変更できるようにします。
Webサーバを動かしてcgiで画像を変えられるようにすることで外部からhttpアクセスで画像を変更できるようにします。
簡単なのはCGI自体で電子ペーパーを書き換えてしまう形ですが、ちょっとこの後の展開上の必要もあって間にjsonファイルを挟む形にします。
図で書くとこんな感じ。
jsonファイルのフォーマット
中間のjsonファイルのフォーマットには白黒用、赤用の画像ファイル名を格納しておきます。
画像ファイル自体はラズパイのディレクトリにあらかじめ入れておきます。
{
"BnWImage":"白黒画像ファイル名",
"RedImage":"赤画像ファイル名"
}
Webサーバとcgi
Webサーバには軽量Webサーバのlighttpdを使います。
sudo apt install lighttpd
cgiを有効にします。
/etc/lighttpd/conf-available/cat 10-cgi.conf
# /usr/share/doc/lighttpd/cgi.txt
server.modules += ( "mod_cgi" )
$HTTP["url"] =~ "^/cgi-bin/" {
cgi.assign = ( "" => "" )
alias.url += ( "/cgi-bin/" => "/cgiファイルのあるディレクトリ/cgi-bin/" )
}
そしてcgiです。
以下は、入力値チェックなどを省いた最低限の処理ですので必要に応じて入力チェックの追加やアクセス制限を必ず追加してください。
#!/usr/bin/python
import cgi
import json
image_pattern = [
{
"BnWImage":"白黒画像ファイル名①",
"RedImage":"赤画像ファイル名①"
},
{
"BnWImage":"白黒画像ファイル名②",
"RedImage":"赤画像ファイル名②"
},
{
"BnWImage":"白黒画像ファイル名③",
"RedImage":"赤画像ファイル名③"
},
]
try:
form = cgi.FieldStorage()
imageno = int(form.getvalue('no',''))
with open("jsonファイル名", "wt") as f:
json.dump(image_pattern[imageno], f)
print("OK")
except Exception as e:
print("NG")
常駐アプリ
次に常駐アプリ側です。ファイル名はsignplate.py とします。
ここだけの話、すでに初期バージョンが残ってないので記憶を頼りに書いてます。動かなかったらごめんない。
from PIL import Image, ImageDraw, ImageFont
from waveshare_epd import epd7in5b_V2
epd = epd7in5b_V2.EPD()
last_images = []
def display_image(loop):
global last_images
with open('jsonファイル名') as f:
images = json.load(f)
if images["BnWImage"] != last_image["BnWImage"] or images["RedImage"] != last_image["RedImage"]:
# 前回と表示画像ファイル名が異なる時のみ電子ペーパーに描画する。
Himage_bnw = Image.new('1', (epd.width, epd.height), 255)
Himage_red = Image.new('1', (epd.width, epd.height), 255)
Himage_bnw.paste(Image.open(images['BnWImage']), (0,0))
Himage_red.paste(Image.open(images['RedImage']), (0,0))
epd.init()
epd.display(epd.getbuffer(Himage_bnw), epd.getbuffer(Himage_red))
epd.sleep()
last_images = images
# 5秒に1回チェック
loop.call_later(5, check_calendar, loop)
# メインループ
loop = asyncio.get_event_loop()
loop.call_soon(display_image, loop)
常駐させたいので、ユーザ権限でsystemdのサービスとして動かします。
ユーザー権限で systemd のサービスを稼働させる方法 – pyopyopyo – Linuxとかプログラミングの覚え書き –
起動したいユーザのホームディレクトリ下にユニットファイルを作成します。~/.config/systemd/user/signplate.service
内容は以下のイメージ。
[Unit]
Description=signplate
[Service]
# 起動コマンド(ExecStart)はイメージで書いています。実際にはシェルスクリプトを指定しています。
ExecStart=python signplate.py
# kill で落とす場合は、必要であれば python のプログラム側でもSIGTERMを受けて終了処理をするなど書いておきます。
ExecStop=/usr/bin/pkill -f 'python signplate.py'
Restart=always
[Install]
WantedBy=default.target
サービスに登録。
systemctl --user enable signplate
systemctl --user start signplate
OS起動時にユーザサービスを自動起動するためにはrootで以下の操作が必要。
sudo loginctl enable-linger ユーザー名
systemctl から起動されたプロセスの出力は、journalctl で見ることができます。
journalctl --user-unit signplate
使い方
あとは、cgi叩くときに画像ファイルの番号を指定して呼び出せば、あらかじめ登録されていた画像ファイルが表示されます。
http://192.168.x.x/cgi-bin/signplate-cgi.py?no=1
最後に
とりあえずこれでラズパイの外から変更できるようにはなりましたが、ラズパイと同一ネットワーク内からでないと変更できません。
できればSwitchBotとかと連動できるようにインターネット側から変更したい。
今のままでも ngrok などのサービスを使ってインターネットからのアクセスをラズパイに呼び込めばできないこともないですがインターネットから呼び込むなんて怖い怖い。
せめてIPアドレス制限とかできればと思いましたが、ngrok ソースIP制限とか有償プランじゃないとできないみたいなのですよねー。
てことで少し別のアプローチを取ることにしました。それは別の機会にー。