pythondaemonraspberry-pi2start-stop-daemon

Python daemon starts correctly with init-script but fails on startup


I have some python daemons for raspberry pi applications running on startup with init-scripts.

The init script runs fine from the console, starts and ends the background process correctly.

The script was made autostart with sudo insserv GartenwasserUI

It starts on startup, which is proof by having the LCD backlight on, but is not in the process list after logon. A manual start with sudo service GartenwasserUI start works immediately.

What could be wrong?

Here the script

#!/bin/sh

### BEGIN INIT INFO
# Provides:          GartenwasserUI
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: GartenwasserUI acts as a mqtt client for LCD displaying and switching gpio through mqtt
# Description:       Put a long description of the service here
### END INIT INFO

# Change the next 3 lines to suit where you install your script and what you want to call it
DIR=/usr/local/bin/Gartenwasser
DAEMON=$DIR/GartenwasserUI.py
DAEMON_NAME=GartenwasserUI

# Add any command line options for your daemon here
DAEMON_OPTS=""

# This next line determines what user the script runs as.
# Root generally not recommended but necessary if you are using the Raspberry Pi GPIO from Python.
DAEMON_USER=root

# The process ID of the script when it runs is stored here:
PIDFILE=/var/run/$DAEMON_NAME.pid

. /lib/lsb/init-functions

do_start () {
    log_daemon_msg "Starting system $DAEMON_NAME daemon"
    cd $DIR
    #python ./$DAEMON_NAME.py &
    start-stop-daemon --start --background --pidfile $PIDFILE --make-pidfile --user $DAEMON_USER --chuid $DAEMON_USER --startas $DAEMON -- $DAEMON_OPTS  --verbose -stdout /var/log/GartenwasserUI.log
    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

And the script itself:

#!/usr/bin/env python

__author__ = "Bernd Gewehr"

# import python libraries
import os
import signal
import sys
import time

# import libraries
import lib_mqtt as MQTT
from Adafruit_CharLCDPlate import Adafruit_CharLCDPlate

#DEBUG = False
DEBUG = True

MQTT_TOPIC_IN = "/Gartenwasser/#"
MQTT_TOPIC = "/Gartenwasser"
MQTT_QOS = 0

VALVE_STATE = [0, 0, 0, 0, 0]

def on_message(mosq, obj, msg):
    """
    Handle incoming messages
    """
    topicparts = msg.topic.split("/")

    if DEBUG:
       print msg.topic
       print topicparts
       for i in range(0,len(topicparts)):
           print i, topicparts[i]
       print msg.payload

    pin = int('0' + topicparts[len(topicparts) - 1])
    value = int(msg.payload)

    if topicparts[2] == "in":
        if pin == 29:
            VALVE_STATE[0] = value
        if pin == 31:
            VALVE_STATE[1] = value
        if pin == 33:
            VALVE_STATE[2] = value
        if pin == 35:
            VALVE_STATE[3] = value

    Message = 'V1: ' + str(VALVE_STATE[0]) + ' V2: ' + str(VALVE_STATE[1]) + '\nV3: ' + str(VALVE_STATE[2]) + ' V4: ' + str(VALVE_STATE[3])
    lcd.clear()
    lcd.message(Message)


# End of MQTT callbacks


def cleanup(signum, frame):
    """
    Signal handler to ensure we disconnect cleanly
    in the event of a SIGTERM or SIGINT.
    """
    # Cleanup  modules
    MQTT.cleanup()
    lcd.stop()

    # Exit from application
    sys.exit(signum)


def loop():
    """
    The main loop in which we mow the lawn.
    """
    while True:
        time.sleep(0.08)
        buttonState = lcd.buttons()
        for b in btn:
            if (buttonState & (1 << b[0])) != 0:
                if DEBUG: print 'Button pressed for GPIO ' + str(b[1])
                if b[1] > 0: MQTT.mqttc.publish(MQTT_TOPIC + '/in/' + str(b[1]), abs(VALVE_STATE[b[2]]-1), qos=0, retain=True)
                time.sleep(.5)
                break



# Use the signal module to handle signals
for sig in [signal.SIGTERM, signal.SIGINT, signal.SIGHUP, signal.SIGQUIT]:
    signal.signal(sig, cleanup)

# Initialise our libraries
lcd = Adafruit_CharLCDPlate()
lcd.backlight(True)

MQTT.init()
MQTT.mqttc.on_message = on_message
MQTT.mqttc.subscribe(MQTT_TOPIC_IN, qos=MQTT_QOS)

# Clear display and show greeting, pause 1 sec
lcd.clear()
lcd.message("Gartenwasser\nstartet...")
time.sleep(1)
Message = 'V1: ' + str(VALVE_STATE[0]) + ' V2: ' + str(VALVE_STATE[1]) + '\nV3: ' + str(VALVE_STATE[2]) + ' V4: ' + str(VALVE_STATE[3])
lcd.clear()
lcd.message(Message)

# Cycle through backlight colors
#col = (lcd.RED, lcd.YELLOW, lcd.GREEN, lcd.TEAL,
#       lcd.BLUE, lcd.VIOLET, lcd.WHITE, lcd.OFF)
#for c in col:
#    lcd.ledRGB(c)
#   sleep(.5)

# assign GPIO & Status index of VALVA_STATUS

btn = ((lcd.LEFT, 29, 0),
       (lcd.UP, 31, 1),
       (lcd.DOWN, 33, 2),
       (lcd.RIGHT, 35, 3),
       (lcd.SELECT, 0, 4))

# start main procedure
loop()

Solution

  • I found the solution: When the machine starts up, the mosquitto service starts withs S02. Since the python daemons init scripts had no info that they depend on mosquitto, they were started as S02 also.

    The change that solved the problem:

    Set the dependencies in the LSB header of the init script:

    # Required-Start:    $remote_fs $syslog mosquitto
    

    After that, both python daemons were executed correctly as S03.