
以前、Googleドライブへ静止画像を定期送信するように組んだRaspberry Pi 定点カメラで、画角調整時にブラウザから直接Raspberry Pi 内の撮影画像を閲覧出来るよう、 Python で簡素な Webサーバ を立ててみました。
SimpleHTTPServer/http.serverをモジュール起動するだけ
Pythonには簡易Webサーバが標準ライブラリとして用意されているので、何も追加インストールすることなく、Pythonスクリプト内でインポートして使ったり、以下の要領でPython起動時にモジュールとして呼び出して使うことが出来ます。
- Python 2.x系ではSimpleHTTPServer :
1 |
$ python2 -m SimpleHTTPServer |
- Python 3.x系ではhttp.server :
1 |
$ python3 -m http.server |
※ドキュメントにも明記されているように、あくまで開発時のデバッグ用などの用途に限定するのが、セキュリティ上好ましいとされています。
ポート番号は省略するとデフォルトで8000番が使われますが、それ以外にしたい場合はどちらのモジュールでもポート番号を続けて記述するだけ。他、ネットワークインターフェイスを指定することも可能ですが、詳細は省きます。
一方で気になったのは公開するルートディレクトリを指定する方法で、次のように -d オプションで指定出来るのは、このオプションが実装されたPython 3.7以降に限られます(以下は /tmp 以下を公開する例)。
1 2 3 4 5 6 7 |
$ python3 --version Python 3.7.3 $ python3 -m http.server -d /tmp Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 192.168.1.199 - - [16/May/2022 21:48:49] "GET / HTTP/1.1" 200 - ^C Keyboard interrupt received, exiting. |
このオプションが使えない場合では、コマンド実行時のパスがそのまま公開フォルダルートと言う仕様なので、実行前に予め移動しておかなければなりません。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
~$ python3 --version Python 3.6.9 ~$ python3 -m http.server -d /tmp usage: server.py [-h] [--cgi] [--bind ADDRESS] [port] server.py: error: argument port: invalid int value: '/tmp' ~$ cd /tmp; python3 -m http.server Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 127.0.0.1 - - [16/May/2022 22:14:06] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [16/May/2022 22:14:06] code 404, message File not found 127.0.0.1 - - [16/May/2022 22:14:06] "GET /favicon.ico HTTP/1.1" 404 - ^C Keyboard interrupt received, exiting. /tmp$ |
Ctrl-C で終了させると、当然のことながら現在のディレクトリは実行前の場所から移動したままになるので、これが時に不便に思うことがあります。
pushd〜popdで挟めば元の場所へ戻れる
このような場合に、元いた場所をスタックに保存してから移動し( pushd )、実行後はスタックからパスを読み出して移動( popd )するのが便利です。
1 2 3 4 5 6 7 8 9 10 |
~$ pushd /tmp; python3 -m http.server; popd /tmp ~ Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 127.0.0.1 - - [16/May/2022 23:39:04] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [16/May/2022 23:39:17] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [16/May/2022 23:39:18] "GET / HTTP/1.1" 200 - ^C Keyboard interrupt received, exiting. ~ ~$ |
このコマンドはLinuxのみならずmacOSやMS-DOSにもあるのですが、全く知りませんでした。
さらに、 pushd では複数のディレクトリを記憶出来ますが、直前のみで良い場合は、 cd - でも戻れますが、こちらはLinuxとmacOSに限定されます。
1 2 3 4 5 6 7 8 |
~$ cd /tmp; python3 -m http.server; cd - Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ... 127.0.0.1 - - [16/May/2022 23:47:34] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [16/May/2022 23:47:37] "GET / HTTP/1.1" 200 - ^C Keyboard interrupt received, exiting. /home/user ~$ |
定点カメラの稼働するRaspberry Piへ実装
PythonのWebサーバの仕様を一通り確認したので、実際に定点カメラが稼働しているRaspberry Piで実行してみます。
実はこの端末はFlightAwareのPiAwareをベースとしていることもあり、現在インストールされているPythonのバージョンも変えたく無いという思いから、ここまでしつこく事前検証していました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
$ uname -a Linux piaware1 4.19.66+ #1253 Thu Aug 15 11:37:30 BST 2019 armv6l GNU/Linux $ lsb_release -a No LSB modules are available. Distributor ID: Raspbian Description: Raspbian GNU/Linux 9.13 (stretch) Release: 9.13 Codename: stretch $ python2 --version Python 2.7.13 $ python3 --version Python 3.5.3 ~ $ pushd /tmp; python3 -m http.server; popd /tmp ~ Serving HTTP on 0.0.0.0 port 8000 ... 192.168.1.136 - - [16/May/2022 15:10:55] "GET / HTTP/1.1" 200 - 192.168.1.136 - - [16/May/2022 15:10:55] code 404, message File not found 192.168.1.136 - - [16/May/2022 15:10:55] "GET /favicon.ico HTTP/1.1" 404 - 192.168.1.136 - - [16/May/2022 15:12:35] "GET /raspicam.jpg HTTP/1.1" 200 - ^C Keyboard interrupt received, exiting. ~ ~ $ |
これにより、実機の横でスマートフォンのブラウザから容易に定点カメラの画角をチェック出来るようになりました。
2023年11月追記:systemdでデーモン化
この定点カメラの撮影した画像をHome Assistant(関連記事はこちら)から参照したくなったので、Python Web Serverをsystemdでデーモン化することにしました。
記述したserviceファイルは次の通り。 WorkingDirectory パラメータを利用して、Webに公開したい /tmp へ移動するので、上述の pushd〜popd は不要です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
[Unit] Description=python simpleHTTPServer, publishing /tmp After=syslog.target network.target [Service] Type=simple WorkingDirectory=/tmp ExecStart=/usr/bin/python3 -m http.server > /dev/null 2>&1 & ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill $MAINPID TimeoutStartSec=0 RestartSec=10 Restart=always KillMode=process [Install] WantedBy=multi-user.target |
非力な初代Raspberry Piで常時稼働させるに際して気にしていた点は2つ。
まず、コマンドラインで動かしていた際、アクセスログが標準出力されていましたが、デーモン化したプロセスではシステムログに書き出されることもなく一安心(SDカードへのI/O低減)。
1 2 3 4 5 6 7 8 9 10 11 12 |
$ tail -f /var/log/syslog Nov 2 10:58:42 piaware1 systemd[1]: pyhttpserver.service: Control process exited, code=exited status=1 Nov 2 10:58:42 piaware1 systemd[1]: pyhttpserver.service: Unit entered failed state. Nov 2 10:58:42 piaware1 systemd[1]: pyhttpserver.service: Failed with result 'exit-code'. Nov 2 10:58:44 piaware1 systemd[1]: Stopped python simpleHTTPServer, publishing /tmp. Nov 2 11:03:39 piaware1 systemd[1]: Reloading. Nov 2 11:03:43 piaware1 systemd[1]: apt-daily.timer: Adding 8h 14min 51.397418s random time. Nov 2 11:03:58 piaware1 systemd[1]: Started python simpleHTTPServer, publishing /tmp. . . (この間にアクセスあるがログには記録されず) . Nov 2 11:08:38 piaware1 wpa_supplicant[337]: wlan0: WPA: Group rekeying completed with ##:##:##:##:##:## [GTK=CCMP] |
もう1つはCPUやメモリリソースの消費です。シングルコアの初代Raspberry Piなので特にCPU負荷が気がかりでしたが、 top でしばらく見守っていても、CPUは 0% のまま、メモリ消費も 3.5% なので動かし続けても問題はなさそう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
top - 11:12:56 up 74 days, 22:11, 1 user, load average: 1.81, 1.58, 1.60 Tasks: 84 total, 2 running, 52 sleeping, 0 stopped, 0 zombie %Cpu(s): 58.6/7.8 66[||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ] KiB Mem : 36.9/378120 [||||||||||||||||||||||||||||||||||||| ] KiB Swap: 10.8/102396 [||||||||||| ] PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 12845 root 20 0 17500 13232 7388 S 0.0 3.5 0:03.41 /usr/bin/python3 -m http.server 3174 fr24 20 0 150244 12156 2852 S 0.0 3.2 353:13.05 /usr/bin/fr24feed 404 dump1090 15 -5 31196 11028 2200 R 53.1 2.9 54363:23 /usr/bin/dump1090-fa --quiet --device-type rtlsdr --device-index 0 --g+ 411 piaware 20 0 22488 8860 5668 S 0.0 2.3 1777:09 /usr/bin/piaware -p /run/piaware/piaware.pid -plainlog -statusfile /ru+ 19773 piaware 20 0 12404 8740 5008 S 3.1 2.3 53:49.37 /usr/lib/piaware/helpers/fa-mlat-client --input-connect localhost:3000+ 12574 root 20 0 38668 6836 5820 S 0.0 1.8 0:00.60 /usr/lib/policykit-1/polkitd --no-debug 71 root 20 0 27956 6584 6360 S 0.0 1.7 20:46.84 /lib/systemd/systemd-journald |