Pythonプログラムをデーモン起動する(Raspbian)

Pythonで実装したプログラムを、Raspberry Pi(Raspbian)でデーモン起動させるときのメモ。

python-daemonのインストール

python-daemonは、Pythonプログラムをdaemon化できるパッケージである。

sudo apt-get install python-daemon

デーモンプログラム

Pythonプログラムはこんな感じ。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
 
import serial
import time
 
from daemon import DaemonContext
from daemon.pidlockfile import PIDLockFile
 
if __name__ == '__main__':
        # 以下がデーモンプロセスとして実行される
        # pidfileが/tmpにないと、動作しないらしい
        with DaemonContext(pidfile=PIDLockFile('/tmp/serial-arduino.pid')):
                main()

起動スクリプト

サービス起動させるための起動デーモンは以下の通り。

$ sudo vi /etc/init.d/hoged
 
#!/bin/sh
 
### BEGIN INIT INFO
# Provides:        hoged
# Required-Start:  $local_fs $remote_fs $syslog
# Required-Stop:   $remote_fs
# Default-Start:   2 3 4 5
# Default-Stop: 
# Short-Description: Start hoged daemon
### END INIT INFO
 
PATH=/sbin:/bin:/usr/sbin:/usr/bin
# Source function library.
. /lib/lsb/init-functions
 
# Path to the script
DAEMON=/usr/local/sbin/python-hoge.py
PROG=serial-arduino
PIDFILE=/tmp/hoged.pid
LOCKFILE=/tmp/hoged.pid.lock
 
test -f $DAEMON || exit 0
 
lock_hoged() {
        if [ -x /usr/bin/lockfile-create ]; then
                lockfile-create $LOCKFILE
                lockfile-touch $LOCKFILE &
                LOCKTOUCHPID="$!"
        fi
}
 
unlock_hoged() {
        if [ -x /usr/bin/lockfile-create ] ; then
                kill $LOCKTOUCHPID
                lockfile-remove $LOCKFILE
        fi
}
 
case "$1" in
    start)
        log_daemon_msg "Starting $PROG server" "$PROG"
        lock_hoged
        start-stop-daemon --start --quiet --oknodo --pidfile $PIDFILE --startas $DAEMON -- -p $PIDFILE
        status=$?
        unlock_hoged
        log_end_msg $status
        ;;
    stop)
        log_daemon_msg "Stopping $PROG server" "$PROG"
        start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
        log_end_msg $?
        rm -f $PIDFILE
        ;;
    status)
        status_of_proc -p $PIDFILE $DAEMON $PROG
        ;;
    restart)
        stop
            start
        ;;
    *)
        echo "Usage: $PROG {start|stop|status|restart}"
        exit 1
        ;;
esac

最後に変更を反映。

sudo update-rc.d hoged defaults

Raspberry Pi – Arduino間でシリアル通信を行う

シリアル通信を行うことが可能なscreenコマンドと、
Pythonでシリアル通信を行うことが可能なpython-serialモジュールを
apt-getを利用してRaspberry Piにインストールする

sudo apt-get install screen
sudo apt-get install python-serial

次に、Pythonでシリアル通信スクリプトを作成する

vi serial-arduino.py

このときにファイル名をserial.pyとかいう名前にしてしまうと、
Pythonのserialモジュールと名前が重複してしまい、

AttributeError: ‘module’ object has no attribute ‘Serial’

というエラーがでてしまうので、他の名前にするのが良い。

USBでRaspberry PiとArduinoを接続し、
なんというデバイス名称で認識されているか確認する

dmesg
lsusb

シリアル通信でArduinoから定期的に送られてくるデータをもとに、
JSONファイルを作成するサンプルは以下の通り。

  • カンマ区切りデータの場合
import serial

    def main():
            # デバイス名: /dev/ttyACM0 通信速度: 9600bps
            con=serial.Serial('/dev/ttyACM0', 9600)
            # デバイス名を出力する
            print con.portstr
            while 1:
                    # 1行ごとにデータを取得する
                    str=con.readline()
                    # ファイルに書き込み
                    f = open('/tmp/data.json', 'w')
                    f.write("[{\"data_1\":" + str + "}]")
                    f.close()

    if __name__ == '__main__':
            main()
  • JSON形式の場合
import serial
    import json

    def main():
            # デバイス名: /dev/ttyACM0 通信速度: 9600bps
            con=serial.Serial('/dev/ttyACM0', 9600)
            # デバイス名を出力する
            print con.portstr
            while 1:
                    try:
                            # strという変数名は使用できない
                            strs=con.readline()
                            dec=json.loads(strs)

                            f = open('/tmp/data.json', 'w')
                            f.write(strs)
                            f.close()
                    except KeyError:
                            print "KeyError"
                    except ValueError:
                            print "ValueError"
                    except NameError:
                            print "NameError"

    if __name__ == '__main__':
                    main() 

実行してJSONが吐き出されるか確認する

python serial-arduino.py