Raspberry Piにはプログラムを自動起動する方法がいろいろありますが、今回は、「/etc/rc.local」を使ってRaspberry Piのプログラムを自動起動します。Raspberry PiのOSは、「2018-04-18-raspbian-stretch」を使用します。
/etc/rc.localを使った自動起動(基本的な説明)
「/etc/rc.local」を使ってプログラムを起動するには、次のviコマンドでroot権限で「/etc/rc.local」を開き、すでに記述されている「exit 0」の前に、プログラムを実行するコマンドをフルパスで記述します。
$ sudo vi /etc/rc.local
コマンドにより記述が終了すると再起動します。これにより記述されたプログラムがroot権限を持って起動されます。うまくプログラムが起動しない時は、次のチェックを行います。
- プログラムはフルパスで記述します。
- ファイルのアクセスについてもプルパスで行います。
- ファイルのアクセス権限をroot権限でもアクセスできるようにします。
「sudo raspi-config」した上で”Wait for Network at Boot” -> ” Slow Wait for network connection before completing boot”をチェックすると、システムの起動の際、ネットワークに接続されるまで待機するようになります。ただし起動が遅くなります。
ソケット通信を行うPythonスクリプトを自動起動(自動起動実施例)
自動起動用のPythonスクリプト「testserver.py」を次の仕様で作成し、「/etc/rc.local」に登録して自動起動します。
- TCPポート「50000」を使ってソケット通信を行うサーバプログラムを作成します。
- クライアントからデータを受け取ると、折り返しそのデータをクライアントに送信します。
- 起動時に現在時刻をログ「log/text.txt」に出力する。また、クライアントからのアクセスがあると、クライアントのアドレスと受信したデータをログ「log/text.txt」に出力します。
- syslog.syslogメソッドを利用して、「/var/log/syslog」にログを出力する。
作成した「testserver.py」を次に示します。
#!/usr/bin/env python3 # socket サーバを作成 import socket import datetime import syslog f = open('/home/pi/startuptest/log/text.txt', mode='a') # 書き込みモードで開く f.write(datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")+"\n") # シーケンスが引数。 f.close() syslog.syslog('syslog test:'+datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S")+"\n") # AF = IPv4 という意味 # TCP/IP の場合は、SOCK_STREAM を使う with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: # IPアドレスとポートを指定 s.bind(('192.168.10.6', 50000)) # 1 接続 s.listen(1) # connection するまで待つ while True: # 誰かがアクセスしてきたら、コネクションとアドレスを入れる conn, addr = s.accept() with conn: while True: # データを受け取る data = conn.recv(1024) if not data: break f = open('/home/pi/startuptest/log/text.txt', mode='a') # 書き込みモードで開く f.write("data : {}, addr: {}".format(data, addr)+"\n") # シーケンスが引数。 f.close() conn.sendall(b'Received: ' + data)
クライアント側のPythonスクリプト「testclient.py」を次に示します。
# クライアントを作成 import socket with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: # サーバを指定 s.connect(('192.168.10.6', 50000)) # サーバにメッセージを送る s.sendall(b'hello') # ネットワークのバッファサイズは1024。サーバからの文字列を取得する data = s.recv(1024) # print(repr(data))
「/etc/rc.local」の内容を次に示します。python3による「testserver.py」の起動コマンドを記述しています。「echo “I do nothing.”」により、「I do nothing.」が、起動時に「/var/log/boot.log」に出力されます。
$ cat /etc/rc.local #!/bin/sh -e # # rc.local # # This script is executed at the end of each multiuser runlevel. # Make sure that the script will "exit 0" on success or any other # value on error. # # In order to enable or disable this script just change the execution # bits. # # By default this script does nothing. # Print the IP address _IP=$(hostname -I) || true if [ "$_IP" ]; then printf "My IP address is %s\n" "$_IP" fi echo "I do nothing." /usr/bin/python3 /home/pi/startuptest/testserver.py & exit 0
各プログラムとログフォルダのパーミッションと所有者を次に示します。
$ ls -all 合計 20 drwxr-xr-x 3 pi pi 4096 7月 22 19:01 . drwxr-xr-x 29 pi pi 4096 7月 22 19:05 .. drwxrwxrwx 2 pi pi 4096 7月 22 19:05 log -rw-r--r-- 1 pi pi 404 7月 22 19:01 testclient.py -rw-r--r-- 1 pi pi 1177 7月 22 19:01 testserver.py
ログフォルダ内のパーミッションと所有者を次に示します。ログファイル「text.txt」の所有者がrootになっています。
$ ls -all 合計 12 drwxrwxrwx 2 pi pi 4096 7月 22 19:05 . drwxr-xr-x 3 pi pi 4096 7月 22 19:01 .. -rw-r--r-- 1 root root 67 7月 22 19:07 text.txt
次のコマンドでTCPポート「50000」のサーバが立ち上がっているかを確認します。
$ sudo lsof -i ・・・ python3 517 root 3u IPv4 13584 0t0 TCP 192.168.10.6:50000 (LISTEN) ・・・ ・・・
次のコマンドでプロセスを確認します。
$ ps -aux ・・・ root 510 0.3 0.8 11632 8048 ? S 17:36 0:00 /usr/bin/python3 /home/pi/startuptest/testserver.py ・・・ ・・・
次のコマンドであらかじめ作成したクライアントスクリプト「testclient.py」を実行します。クライアントから送信したデータがエコーバックされています。
$ python3 testclient.py b'Received: hello'
ログファイル「text.txt」を確認します。
2018/07/22 19:05:55 data : b’hello’, addr: (‘192.168.10.6′, 54912) data : b’hello’, addr: (‘192.168.10.6′, 54914) 2018/07/22 20:13:31 data : b’hello’, addr: (‘192.168.10.6’, 42674) 2018/07/23 11:31:02
「/var/log/syslog」には次の内容がログされています。
・・・ Jul 23 18:27:29 raspberrypi /testserver.py: syslog test:2018/07/23 18:27:29 ・・・ ・・・