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。
我有一些 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。