This post builds on a previous experiment where I made a remote control app for my outlets with a Raspberry Pi, Python/Flask and AngularJS. For the backend to be really useful, I want to make it behave as a service in Linux. It should start automatically after a reboot and there should be some control mechanism for manually starting, stopping and viewing the status of the service. There should also be a proper logging in place.
Services in Raspbian
Handling services in Raspbian/Debian requires a few commands: service, update-rc.d and systemctl. To display the status of all registred services, you can use the service command:
service --status-all
It will show a list like:
[ + ] alsa-utils [ + ] avahi-daemon [ + ] bluetooth [ - ] bootlogs [ - ] bootmisc.sh [ - ] checkfs.sh [ - ] checkroot-bootclean.sh [ - ] checkroot.sh [ + ] console-setup ...
The prefixes mean:
[+] - the service is running [-] - the service is not running
And for checking a specific service:
service [ServiceName] status
A service can be started, stopped or restarted with the appropriate switches:
sudo service [ServiceName] start sudo service [ServiceName] stop sudo service [ServiceName] restart
Creating a new service in Raspbian
An application can be started as a daemon process with the start-stop-daemon command. But as this command has a rather intricate argument list, it is better to create a bash script that simplify the usage (this will also allow auto start when booting). For example, to start a daemon process we want to specify the program (with possible arguments) to run, what user that should run the process and create a PID file so that the process can be tracked, the full argument list would look something like this:
start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS
Not something that you would like to type many times.
Instead, you can use a bash file as described by Stephen C Phillips in this excellent tutorial:
http://blog.scphillips.com/posts/2013/07/getting-a-python-script-to-run-in-the-background-as-a-service-on-boot/
The init file for my Flask application would look something like this:
#!/bin/sh | |
# from http://blog.scphillips.com/posts/2013/07/getting-a-python-script-to-run-in-the-background-as-a-service-on-boot/ | |
### BEGIN INIT INFO | |
# Provides: remotecontrol | |
# Required-Start: $remote_fs $syslog | |
# Required-Stop: $remote_fs $syslog | |
# Default-Start: 2 3 4 5 | |
# Default-Stop: 0 1 6 | |
# Short-Description: A service for a web server that handles remote controlled outles | |
# Description: The service runs a Flask application that exposes a web api and an AngularJS app | |
### END INIT INFO | |
DIR=/home/[USER]/HomeAutomation/RemoteControlApp | |
DAEMON=$DIR/remotecontrol.py | |
DAEMON_NAME=remotecontrol | |
DAEMON_OPTS="" | |
# Root is needed to use the GPIO pins on the Raspberry | |
DAEMON_USER=root | |
PIDFILE=/var/run/$DAEMON_NAME.pid | |
. /lib/lsb/init-functions | |
do_start () { | |
log_daemon_msg "Starting system $DAEMON_NAME daemon" | |
start-stop-daemon –start –background –pidfile $PIDFILE –make-pidfile –user $DAEMON_USER –chuid $DAEMON_USER –startas $DAEMON — $DAEMON_OPTS | |
log_end_msg $? | |
} | |
do_stop () { | |
log_daemon_msg "Stopping system $DAEMON_NAME daemon" | |
start-stop-daemon –stop –pidfile $PIDFILE –retry 10 | |
log_end_msg $? | |
} | |
case "$1" in | |
start|stop) | |
do_${1} | |
;; | |
restart|reload|force-reload) | |
do_stop | |
do_start | |
;; | |
status) | |
status_of_proc "$DAEMON_NAME" "$DAEMON" && exit 0 || exit $? | |
;; | |
*) | |
echo "Usage: /etc/init.d/$DAEMON_NAME {start|stop|restart|status}" | |
exit 1 | |
;; | |
esac | |
exit 0 |
Note: to get the Python script started with this bash file, you need to add execution rights on the Python file and also on the bash script file. In my case:
chmod 777 remotecontrol.py sudo chmod 777 /etc/init.d/remotecontrol.sh
If you put the bash script in the /etc/init.d/ folder you can use the update-rc.d command to add the service for autostart when booting. For example:
sudo update-rc.d remotecontrol.sh defaults
This will add make the application run at the default run level (see https://wiki.debian.org/RunLevel).
To remove the service from autostart:
sudo update-rc.d -f remotecontrol.sh remove
If you change the bash script, you can reload it with the systemctl command:
sudo systemctl daemon-reload
Logging
As the application now runs in the background, we can not see any messages that are printed out. Stephen C Phillips has made a very useful logging example in his blog post:
It uses the Python Logging library and is easily adapted for any Python application.
I have updated the code for my Remote Outlet application so that it uses a similar logger. With the Python script now running as a background service, the tracing and any other output are routed to the log file in /tmp/remotecontrol.log.
The GitHub repository has been updated with the new code that includes service handling and logging:
https://github.com/LarsBergqvist/RemoteControlled_Outlets
Hi!
I had a similar problem to solve and i made this package here: https://github.com/bithon/python-daemon-set-sunrise/releases
I hope its ok to “advertise” it here, but i hope some people could find it useful.
Best regards,
Oliver
LikeLiked by 1 person