Python 守护进程使用 init-script 正确启动但启动失败

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

我有一些 python 守护进程用于 raspberry pi 应用程序 运行 在启动时使用初始化脚本。

init 脚本从控制台运行良好,正确启动和结束后台进程。

使用 sudo insserv GartenwasserUI 使脚本自动启动

开机启动,LCD背光亮就是证明,但登录后不在进程列表中。使用 sudo service GartenwasserUI start 手动启动会立即生效。

有什么问题吗?

这里是脚本

#!/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 "" in

    start|stop)
        do_
        ;;

    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

以及脚本本身:

#!/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()

我找到了解决方案: 当机器启动时,mosquitto 服务以 S02 启动。由于 python 守护程序初始化脚本没有它们依赖于 mosquitto 的信息,因此它们也作为 S02 启动。

解决问题的更改:

在初始化脚本的 LSB 头中设置依赖项:

# Required-Start:    $remote_fs $syslog mosquitto

之后,两个 python 守护进程都正确执行为 S03。