Python – Running daemon involving GPIO on Pi

gpiomonitoringpythonsudo

I have a daemon that monitors various things using the GPIO ports. I have used python to write the code for this using the RPi.GPIO module.

I would like to ensure that the daemon is always running, i.e., restart it after a crash and start it when the system boots (crucially before any user logs in — this Pi runs headless). There is a little flashing LED that tells me its running, but that's not ideal.

I have read about using MONIT for this purpose but I'm having a few issues. My attempts so far have mainly been around this solution:

https://stackoverflow.com/questions/23454344/use-monit-monitor-a-python-program

This is my bash wrapper file, its called /home/pi/UPSalarm/UPSalarm.bash

#!/bin/bash

PIDFILE=/var/run/UPSalarm.pid

case $1 in
    start)
        #source /home
        #Launch script
        sudo python /home/pi/UPSAlarm/UPSalarm.py 2>/dev/null &
        # store PID value
        echo $! > ${PIDFILE}
    ;;
    stop)
        kill `cat ${PIDFILE}`
        # Proccess killed, now remove PID
        rm ${PIDFILE}
    ;;
    *)
        echo "usage: scraper {start|stop}" ;;
esac
exit 0`

This is my monit rule

check process UPSalarm with pidfile /var/run/UPSalarm.pid
   start = "/home/pi/UPSalarm/UPSalarm start"
   stop = "/home/pi/UPSalarm/UPSalarm stop"

I have two problems: firstly, I get the wrong PID number in UPSalarm.pid. I am wondering if I get a PID number for sudo? This is why I have posted the question here; I need sudo because I need access to the GPIO ports. Secondly, it doesn't work. Thirdly, I am not sure what source does in the bash file?

I know monit has great documentation, but a worked example for python really would be helpful, I've been stuck for a good few days.

The following websites were also helpful:
https://www.the-hawkes.de/monitor-your-raspberrypi-with-monit.html (for setting up monit)
https://mmonit.com/monit/documentation/monit.html

And these two questions are related but don't solve my problem:
https://raspberrypi.stackexchange.com/questions/9938/monitoring-a-python-script-running-in-a-screen-session-with-monit
How to restart the Python script automatically if it is killed or dies

Best Answer

That shell wrapper looks like an init script, but apparently it isn't (hence you need to use sudo there; scripts run by init would not require this).

This seems to be a very clumsy way to do this; the shell wrapper does not serve any purpose that could not be better served by the python program itself. Get rid of that; if you want an init script specifically, write a minimal one, but I suggest you move the logic of controlling the daemon from the init script into the daemon (UPSalarm.py) itself.

Since you want only one instance, define a pid file that the process is to use. When UPSalarm.py start is run, it will check for the existence of this file. If it does not exist, it writes its own pid to this file and continues. If it does exist, it gets the pid and then checks with the OS to see if a process with the pid exists and if so, what it is called. This will prove that either UPSalarm.py is already running, or not. If it is, exit with an "Already running" message.

When UPSalarm.py stop is run, a similar sequence is involved -- check for the pid file, if it exists check the pid, if the pid is valid for a process named UPSalarm.py, signal it to stop, presumably with SIGINT. UPSalarm.py itself should implement a signal handler for SIGINT, such that it deletes the pid file before it exits.

I am not a python programmer and this is not a programming site (for that, see Stack Overflow), but I promise all this is easily possible with python.

  • To get the pid of the current process, use os.getpid().
  • For mapping a pid to a process name, read /proc/[pid]/cmdline and do a string search for UPSalarm.py (or better yet, the name of process as invoked, which would be sys.argv[0], see here).
  • For signal handling, start here and here.
  • To send a signal to another process, use os.kill().

It should be easy to then configure monit to handle this daemon. You also then have the option of instead just using cron (or your own script) to call UPSalarm.py start at intervals, say every 5-10 minutes.

Related Question