2024/01/31(Wed)古のRaspberry Piを使ったお手軽デジタルサイネージ

2024/01/31 0:41 Software::LinuxHardware::Raspberry Pi
安価なLinux箱で、しかもGPIOが載っているということで、ちょうど10年くらい前の2014年にとりあえず買ってみたRaspberry Pi 1B、年単位でバリバリ常時稼働して5-6年は使っていたものの、その後は引退してました。
でも今になって、「大したことはしないけど常時稼働させたいヤツ」が出てきたので、また運用に戻ることに…

余談:これまでのRaspi遍歴

今までこんな用途に使ってました。
SSH踏み台&外部からエアコン操作
赤外線学習は面倒なので、Amazonとかで売られている汎用エアコンリモコンの電源ボタンのパッド取りだし、GPIO経由で制御する仕組み。
結局、つけっぱなし運用でも電気代大して変わらないということでお蔵入り。
アラームシステム
CGI経由でcronを操作して指定した時間にmpg123でアラームをスヌーズ再生する(3.5mm端子に繋いだスピーカーから再生)
これは、アラーム数やスヌーズ回数に上限があるガラケーの目覚ましだけでは起きられなかったことがきっかけで作り、年単位でずっと世話になった(苦笑)目覚ましを止めるためには、起き上がってPCの電源を入れ、ブラウザから止めるしか無いというw(後に、スマホやタブレットでも可能になった)
ゴリゴリの素HTMLとPerlで書かれており、あの頃は若かった…
時々忘れた頃に、デスクトップ(X Window System)を試しては、ああこりゃ遅すぎて駄目だとなり、殆どX無しのFedoraで動かしてました。

今なにをやりたいのか

ズバリ「Webページとかを垂れ流しに刷るサイネージ」で、情報コンテンツは「天気」という平凡な内容です。特段新しい事は、何もありません。
実際、Lチカと同じくらいそういう用途は既にありふれてると思いますし、なんなら今回もその先人のソリューションを借りてお手軽化してます。

天気をわざわざRaspiで表示しなくたって、スマホあるじゃんと思われるかもしれないですが、私、家の中では携帯不携帯で、よく机にほったらかしたままにしてます。明日、天気どうだっけ?知りたい!と思ったときに限って、手元にスマホが無いので、「じゃあ、そこら辺のモニタに垂れ流しにしておけば良いじゃん」という発想です。スマホやタブレットの台数あっても、結局充電箇所に行かないと無いし……(横着)
もちろん、TVやスマートスピーカー等、垂れ流しに出来る他のソリューションも考えられますが、ニュースの特定の時間帯を待ったり、データ放送に切り替えて操作したり、「明日の天気は?」みたいな発話などをするというのは、その一手間がもうダメなんです(爆)困った困った。

電気代?Raspberry Piはモデルにも依りますが、1Bだと約3Wってところなので、我が家の電気代をざっくりと使用量で割った単位量30円/kWhから計算すると、1ヶ月で65円、1年で777円とまあ誤差の範囲内レベルです。
実際には殆どアイドルでしょうから、3Wも食ってないでしょうし。

まあ、ちゃんと買った物をお蔵入りにせず活用するというところが大事、、うん。

お手軽ソリューション Screenly(現Anthias)

ということで、Webページとか動画を単に画面に出すだけのお手軽サイネージを探していたところ、Screenly(現Anthias)というのがヒットしました。
どうやらScreenlyは商用化して、Open sourceはScreenly OSE(Anthias)と名前を変えたようです。特に凝ったこともサポートも要らないので、OSS版で十分ですね。

Anthiasイメージ導入

調べてみると、Raspberry Pi公式のRaspberry Pi Imagerとかを使って、即導入済みの展開イメージを作れるらしく、しかもRaspberry Pi 1用のパッケージもあるとか!手厚いなーと思ってやってみました。

サクッとOther specific-purpose OS > Anthias > Anthias (pi1)が見つかります。しかもまあまあ新しい(2022年12月)
screenly01.png


が、実際にSDカードに焼いて起動してみると、Anthiasのロゴが出たところでフリーズ……
動いているのかもしれませんが、待てど暮らせど一晩放っておいても進んでいる気配が無いので、こりゃだめだと投げました。

Raspberry Pi OS上に構築

もしかして、重たすぎるX Window Systemをフル初期化しようとして落ちている(でもRaspi 1用にカスタムされているはずなのに?)、あるいは、一応作られているけど実際のデバイスで確認している人は実は居ない(もう10年経ってる古いハードですし)等と考えて、Raspberry Pi OS(Legacy, 32bit)に追加していく方式もテスト。

Raspberry Pi OSを焼き込めば、さくっと立ち上がり(ただしdesktop environmentが入ったものを選ぶと、ものすごくモッサリなので、Raspberry Pi OS (other)からno desktop environmentを選んだ)、その後のインストール
$ bash <(curl -sL https://install-anthias.srly.io)
も小一時間かかりつつ、成功。
ただし、再起動後には何も変化無く、ちょっと検証してみたところでは、↑の導入スクリプトによってインストールされるdockerコマンドが全てSegmentation Faultする。
おそらくdockerが新しすぎて、ARMv6の32bit CPUをうまくサポート出来なくなっている?
まあ、それを直したところで、この非力なCPUとメモリでdockerは無茶すぎるので、これも没に。

どうやったらScreenlyは2024年、Raspberry Pi 1Bで動くか?

2022年の情報ながら、ドンピシャなポストが公式フォーラムにありました。
Does latest Screenly OSE work on 2014 B+ V1.2 Pi? - Anthias Forum

やっぱり、2022年頃から既にdockerがSegmentation Faultする現象は起こっていたようで、結論としては2018年頃のイメージを使えということ。
私もhttps://github.com/Screenly/Anthias/releases/tag/v0.14にある、2018-01-19-Screenly_OSE_4GB.zipをSDカードにポンッと焼いて、無事起動を確認しました。
とりあえずUsageはこんな感じ。適当な32GBのSDカードに焼きましたが、もっと少なくても全然いけますw
$ df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/root        30G  1.6G   27G   6% /
devtmpfs        182M     0  182M   0% /dev
tmpfs           186M     0  186M   0% /dev/shm
tmpfs           186M   21M  166M  11% /run
tmpfs           5.0M  4.0K  5.0M   1% /run/lock
tmpfs           186M     0  186M   0% /sys/fs/cgroup
/dev/mmcblk0p1   41M   21M   21M  51% /boot
tmpfs            38M     0   38M   0% /run/user/1000

追加の設定色々

まずはScreenly自体をセットアップする前に、足回りを整えておく必要があります。

とりあえず起動すれば何か画面に出て、設定画面がHTTPポートでlistenされましたが、Raspberry Pi自体の仕様により、起動時からHDMIを繋いでいないとコンポジットの方に出力が行ってしまうという点と、Screenlyのイメージは素ではSSHが開いていない点をナントカします。

1. 電源をつけてしまっていたら、とりあえず本体にコンソール/キーボードを繋いでシャットダウンさせるか、念じてぶち切った後に、念のためSDカードを再作成しておきます。
2. SDカードを作業PCでマウントし、/boot/config.txtに "hdmi_force_hotplug=1"を追加。
3. 作業PCにはHDMIが無いため、HDMI->VGA変換が動く様に以下を追加。
# VGA変換するとHDMIのEDIDが正しく認識されないので無視
hdmi_ignore_edid=0xa5000080
# 解像度としてXGAになるようにしておく
hdmi_group=2
hdmi_mode=16
4. sudo raspi-configを実行し、5 Interfacing Options > P2 SSH > Yesを選ぶと、再起動時に自動的にSSH Serverが稼働するようになります。


あと、日本語のWebページを表示させたいので、フォントでも入れておくか……とおもむろに実行。
$ sudo apt-get update && sudo install fonts-moto
と思ったら、mirrordirector.raspbian.orgは既に提供を終了しているっぽいので、apt sourceを切り替えます。
aptに限らず、古いディストリイメージを使うと、パッケージシステムのURL切り替えってほぼ必ず必要ですね。まあ、コミュニティの貢献で成り立っているので文句を言う筋合いはないのですが、そのバージョンの最終リリースまでには退役してレガシーサーバーを見に行くURLも登録して置いてもらえると嬉しいですね……。
ということで、早速修正。
$ sudo vi /etc/apt/sources.list
- deb http://mirrordirector.raspbian.org/raspbian/ stretch main contrib non-free rpi
+ deb http://legacy.raspbian.org/raspbian/ stretch main contrib non-free rpi
$ sudo apt-get update && sudo install fonts-moto
再度、実行したところ、fc-cache(フォントキャッシュ)の更新だけで十数分かかります……おぉ、マジか、この遅さ。


で、↑が原因っぽいですが、再起動をして上がってくるときに、一旦Emergency modeに落ちてEnterを押すまでScreenlyが画面に表示されない現象が起こっていたので、/boot/cmdline.txtから"system.unit=kernel-network-なんとか.unit"を削除して事なきを得ました。
元のイメージファイルはそんな指定など無かったので、apt更新がかかったタイミングで何か変更された模様。

やっとEnterを押さずに起動できるようになったものの、今度は最初のようにScreenlyが表示されず、tty1のログインコンソールが出てしまう現象もありました。
tty2がグラフィカルコンソールなので、Ctrl+Alt+F2で切り替えれば良いのですが、再起動したらこれを行うのも面倒なので、以下を実施しました。これで最初からtty2が開かれるようになります。
$ sudo systemctl enable getty@tty2

Screenlyを試す

Screenlyの設定ページは非常に素直で、アセットと呼ばれる出力セットの登録を行うだけ。
基本的にウェブページのURL、表示する期間、表示切り替えのタイミングなどの操作だけなので、特に説明書を読む必要も無く、直感的に操作可能でした。
まずは適当に軽めのGoogleあたりを表示してみて、日本語フォントを含め描画がうまくいかテストするとヨシ。
screenly02.png


お世辞にも爆速とはいえないものの、Start/Endの範囲内が現在に含まれるようにしてOnをクリックすれば、数秒以内位にレンダリングが終わりました。おー、お手軽。


で、それから目的の天気サイト*1をiframeにして定期的にreloadするようにしたweather.htmlというのを読み込ませてみると、ブラウザが古いのかキチンとJavaScriptを解釈していないような挙動で、描画が壊れまくり……うーん、困った。
User-Agentはこんな感じ
Mozilla/5.0 (X11; Linux armv7l) AppleWebKit/538.15 (KHTML, like Gecko) Version/8.0 Safari/538.15
で、"/home/pi/screenly/viewer.py"をちょっと覗いてみると、uzbl-browserというバイナリを起動していることから、uzblという軽量系のブラウザをつかってる見たいです。利用想定環境のブラウザではないでしょうし、2016年頃でリリースが止まっているので、まあ仕方ないですね。

画像化で解決

まあ無理矢理な解決方法ですが、要はレンダー結果が表示出来れば良いので、他のFirefoxとかが動かせるLinux鯖でレンダーした結果を画像に落としておきます。
まあ公衆送信とかするわけでは無いですが、利用規約的にも、そのままの形で画像化して利用するだけなので問題無いでしょう。

みんな大好き、Webブラウザの自動化といえばSeleniumです。適当にサンプルが色々見つかるので、サクッと書いてみました。
ポイントは、
  • 常時稼働のX Windows Systemが動いている環境を用意しておく。
  • async/awaitを使って楽がしたかったので、今回はNode.jsを採用。ディストリから普通にdnf installでもapt-get installでもしておき、さらにselenium-driverのnpm installしておく。(グローバルでもローカルでもお好みで)
  • さらにgeckodriverを展開し、geckodriverというバイナリをPATHに通しておく。Firefoxもインストールしておく。
  • スクリプト中のtarget, output, intervalは適宜環境に合わせて調整
  • headlessで起動しても、ツールバー等の高さ?が出力サイズに影響していると思われるので、コンテンツ部が1920x1080の画像を出力するためには、ブラウザサイズを1920x1196にしておく
  • レンダリング終了は、本来XPathなどで特定の要素が書き終わったことを検知するのがセオリー。ただし、今回はAJAXでバリバリ書かれていく上に、URLによって要素が異なるので、単に5秒待つという横着してます。
  • テスト中はCtrl+CのSIGINTで、systemdから起動する際はSIGTERMを受けた際に、きちんとgeckodriverとfirefoxが連動して終了するように注意する。特にsystemdはきちんとexitコードを返してあげないと、30秒経ってからSIGABRTとなる。
  • systemdには、Type=simple, KillMode=process, Restart=always設定のサービスとして登録しておけばOK。