mirror of
https://github.com/naruxde/revpipyload.git
synced 2025-11-08 23:23:52 +01:00
first checkin
This commit is contained in:
3
MANIFEST.in
Normal file
3
MANIFEST.in
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
recursive-include data *
|
||||||
|
recursive-include revpipyload *
|
||||||
|
global-exclude *.pyc
|
||||||
7
data/etc/default/revpipyload
Normal file
7
data/etc/default/revpipyload
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# RevPiPyLoader
|
||||||
|
#
|
||||||
|
# Verbose logging add a -v or -vv
|
||||||
|
DAEMON_ARGS="-d"
|
||||||
|
|
||||||
|
# Codepage of files
|
||||||
|
export LANG=C.UTF-8
|
||||||
128
data/etc/init.d/revpipyload
Executable file
128
data/etc/init.d/revpipyload
Executable file
@@ -0,0 +1,128 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: revpipyload
|
||||||
|
# Required-Start: $remote_fs $syslog $piControl
|
||||||
|
# Required-Stop: $remote_fs $syslog $piControl
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: Start RevPiPyLoad to execute python plc program
|
||||||
|
# Description: This file starts the RevPiPyLoad on system
|
||||||
|
# boot. The Loader starts your python plc program and
|
||||||
|
# check whether it is running.
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
# Author: Akira Naru Takizawa <akira@narux.de>
|
||||||
|
|
||||||
|
PATH=/sbin:/usr/sbin:/bin:/usr/bin
|
||||||
|
DESC="RevPiPyLoad to run plc program"
|
||||||
|
NAME=revpipyload
|
||||||
|
DAEMON=/usr/local/share/revpipyload/revpipyload.py
|
||||||
|
DAEMON_ARGS="-d"
|
||||||
|
PIDFILE=/var/run/$NAME.pid
|
||||||
|
SCRIPTNAME=/etc/init.d/$NAME
|
||||||
|
|
||||||
|
# Exit if the package is not installed
|
||||||
|
[ -x "$DAEMON" ] || exit 0
|
||||||
|
|
||||||
|
# Read configuration variable file if it is present
|
||||||
|
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
|
||||||
|
|
||||||
|
# Load the VERBOSE setting and other rcS variables
|
||||||
|
. /lib/init/vars.sh
|
||||||
|
|
||||||
|
# Define LSB log_* functions.
|
||||||
|
# Depend on lsb-base (>= 3.2-14) to ensure that this file is present
|
||||||
|
# and status_of_proc is working.
|
||||||
|
. /lib/lsb/init-functions
|
||||||
|
|
||||||
|
#
|
||||||
|
# Function that starts the daemon/service
|
||||||
|
#
|
||||||
|
do_start()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon has been started
|
||||||
|
# 1 if daemon was already running
|
||||||
|
# 2 if daemon could not be started
|
||||||
|
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
|
||||||
|
|| return 1
|
||||||
|
start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
|
||||||
|
$DAEMON_ARGS \
|
||||||
|
|| return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Function that stops the daemon/service
|
||||||
|
#
|
||||||
|
do_stop()
|
||||||
|
{
|
||||||
|
# Return
|
||||||
|
# 0 if daemon has been stopped
|
||||||
|
# 1 if daemon was already stopped
|
||||||
|
# 2 if daemon could not be stopped
|
||||||
|
# other if a failure occurred
|
||||||
|
start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME.py
|
||||||
|
RETVAL="$?"
|
||||||
|
[ "$RETVAL" = 2 ] && return 2
|
||||||
|
start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
|
||||||
|
[ "$?" = 2 ] && return 2
|
||||||
|
rm -f $PIDFILE
|
||||||
|
return "$RETVAL"
|
||||||
|
}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Function that sends a SIGHUP to the daemon/service
|
||||||
|
#
|
||||||
|
do_reload() {
|
||||||
|
start-stop-daemon --stop --signal 1 --quiet --pidfile $PIDFILE --name $NAME.py
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
|
||||||
|
do_start
|
||||||
|
case "$?" in
|
||||||
|
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||||
|
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
|
||||||
|
do_stop
|
||||||
|
case "$?" in
|
||||||
|
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
|
||||||
|
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
status)
|
||||||
|
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
|
||||||
|
;;
|
||||||
|
reload)
|
||||||
|
log_daemon_msg "Reloading $DESC" "$NAME"
|
||||||
|
do_reload
|
||||||
|
log_end_msg $?
|
||||||
|
;;
|
||||||
|
restart)
|
||||||
|
log_daemon_msg "Restarting $DESC" "$NAME"
|
||||||
|
do_stop
|
||||||
|
case "$?" in
|
||||||
|
0|1)
|
||||||
|
do_start
|
||||||
|
case "$?" in
|
||||||
|
0) log_end_msg 0 ;;
|
||||||
|
1) log_end_msg 1 ;; # Old process is still running
|
||||||
|
*) log_end_msg 1 ;; # Failed to start
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# Failed to stop
|
||||||
|
log_end_msg 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload}" >&2
|
||||||
|
exit 3
|
||||||
|
;;
|
||||||
|
esac
|
||||||
8
data/etc/logrotate.d/revpipyload
Normal file
8
data/etc/logrotate.d/revpipyload
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
/var/log/revpipyload
|
||||||
|
{
|
||||||
|
rotate 6
|
||||||
|
monthly
|
||||||
|
compress
|
||||||
|
missingok
|
||||||
|
notifempty
|
||||||
|
}
|
||||||
7
data/etc/revpipyload/revpipyload.conf
Normal file
7
data/etc/revpipyload/revpipyload.conf
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[DEFAULT]
|
||||||
|
autoreload=1
|
||||||
|
autostart=1
|
||||||
|
plcprogram=test.py
|
||||||
|
xmlrpc=1
|
||||||
|
xmlrpcport=55123
|
||||||
|
zeroonexit=1
|
||||||
3
data/revpipyload
Executable file
3
data/revpipyload
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
exec "/usr/local/share/revpipyload/revpipyload.py" "$@"
|
||||||
119
revpipyload.e4p
Normal file
119
revpipyload.e4p
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
|
||||||
|
<!-- eric project file for project revpipyload -->
|
||||||
|
<!-- Saved: 2017-02-16, 07:47:17 -->
|
||||||
|
<!-- Copyright (C) 2017 Sven Sager, akira@narux.de -->
|
||||||
|
<Project version="5.1">
|
||||||
|
<Language>en_US</Language>
|
||||||
|
<Hash>89ddb4e70b339f832ee277085202b38acc6a125c</Hash>
|
||||||
|
<ProgLanguage mixed="0">Python3</ProgLanguage>
|
||||||
|
<ProjectType>Console</ProjectType>
|
||||||
|
<Description>Dieser Loader wird über das Init-System geladen und führt das angegebene Pythonprogramm aus. Es ist für den RevolutionPi gedacht um automatisch das SPS-Programm zu starten.</Description>
|
||||||
|
<Version>0.1.0</Version>
|
||||||
|
<Author>Sven Sager</Author>
|
||||||
|
<Email>akira@narux.de</Email>
|
||||||
|
<Eol index="-1"/>
|
||||||
|
<Sources>
|
||||||
|
<Source>revpipyload/__init__.py</Source>
|
||||||
|
<Source>revpipyload/proginit.py</Source>
|
||||||
|
<Source>setup.py</Source>
|
||||||
|
<Source>revpipyload/revpipyload.py</Source>
|
||||||
|
</Sources>
|
||||||
|
<Forms/>
|
||||||
|
<Translations/>
|
||||||
|
<Resources/>
|
||||||
|
<Interfaces/>
|
||||||
|
<Others>
|
||||||
|
<Other>data</Other>
|
||||||
|
<Other>MANIFEST.in</Other>
|
||||||
|
</Others>
|
||||||
|
<Vcs>
|
||||||
|
<VcsType>None</VcsType>
|
||||||
|
</Vcs>
|
||||||
|
<FiletypeAssociations>
|
||||||
|
<FiletypeAssociation pattern="*.idl" type="INTERFACES"/>
|
||||||
|
<FiletypeAssociation pattern="*.py" type="SOURCES"/>
|
||||||
|
<FiletypeAssociation pattern="*.py3" type="SOURCES"/>
|
||||||
|
<FiletypeAssociation pattern="*.pyw" type="SOURCES"/>
|
||||||
|
<FiletypeAssociation pattern="*.pyw3" type="SOURCES"/>
|
||||||
|
</FiletypeAssociations>
|
||||||
|
<Checkers>
|
||||||
|
<CheckersParams>
|
||||||
|
<dict>
|
||||||
|
<key>
|
||||||
|
<string>Pep8Checker</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<dict>
|
||||||
|
<key>
|
||||||
|
<string>DocstringType</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<string>pep257</string>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>ExcludeFiles</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<string></string>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>ExcludeMessages</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<string>E123,E226,E24</string>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>FixCodes</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<string></string>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>FixIssues</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<bool>False</bool>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>HangClosing</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<bool>False</bool>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>IncludeMessages</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<string></string>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>MaxLineLength</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<int>80</int>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>NoFixCodes</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<string>E501</string>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>RepeatMessages</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<bool>True</bool>
|
||||||
|
</value>
|
||||||
|
<key>
|
||||||
|
<string>ShowIgnored</string>
|
||||||
|
</key>
|
||||||
|
<value>
|
||||||
|
<bool>False</bool>
|
||||||
|
</value>
|
||||||
|
</dict>
|
||||||
|
</value>
|
||||||
|
</dict>
|
||||||
|
</CheckersParams>
|
||||||
|
</Checkers>
|
||||||
|
</Project>
|
||||||
1
revpipyload/__init__.py
Normal file
1
revpipyload/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"""just init file."""
|
||||||
94
revpipyload/proginit.py
Normal file
94
revpipyload/proginit.py
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Main functions of our program."""
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
from argparse import ArgumentParser
|
||||||
|
from configparser import ConfigParser
|
||||||
|
from os import fork as osfork
|
||||||
|
from os.path import exists as ospexists
|
||||||
|
|
||||||
|
|
||||||
|
class ProgInit():
|
||||||
|
|
||||||
|
"""Programmfunktionen fuer Parameter und Logger."""
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
"""Clean up program."""
|
||||||
|
# Logging beenden
|
||||||
|
logging.shutdown()
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"""Initialize general program functions."""
|
||||||
|
|
||||||
|
# Command arguments
|
||||||
|
parser = ArgumentParser(
|
||||||
|
description="RevolutionPi Python3 Loader"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-d", "--daemon", action="store_true", dest="daemon",
|
||||||
|
help="Run program as a daemon in background"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-c", "--conffile", dest="conffile",
|
||||||
|
default="/etc/revpipyload/revpipyload.conf",
|
||||||
|
help="Application configuration file"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-f", "--logfile", dest="logfile",
|
||||||
|
help="Save log entries to this file"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-v", "--verbose", action="count", dest="verbose",
|
||||||
|
help="Switch on verbose logging"
|
||||||
|
)
|
||||||
|
self.pargs = parser.parse_args()
|
||||||
|
|
||||||
|
# Prüfen ob als Daemon ausgeführt werden soll
|
||||||
|
self.pidfile = "/var/run/revpipyload.pid"
|
||||||
|
self.pid = 0
|
||||||
|
if self.pargs.daemon:
|
||||||
|
# Prüfen ob daemon schon läuft
|
||||||
|
if ospexists(self.pidfile):
|
||||||
|
raise SystemError(
|
||||||
|
"program already running as daemon. check {}".format(
|
||||||
|
self.pidfile
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.pid = osfork()
|
||||||
|
if self.pid > 0:
|
||||||
|
with open(self.pidfile, "w") as f:
|
||||||
|
f.write(str(self.pid))
|
||||||
|
exit(0)
|
||||||
|
|
||||||
|
# Ausgaben umhängen in Logfile
|
||||||
|
sys.stdout = open("/var/log/revpipyload", "a")
|
||||||
|
sys.stderr = sys.stdout
|
||||||
|
|
||||||
|
# Initialize configparser globalconfig
|
||||||
|
self.globalconffile = self.pargs.conffile
|
||||||
|
self.globalconfig = ConfigParser()
|
||||||
|
self.globalconfig.read(self.pargs.conffile)
|
||||||
|
|
||||||
|
# Program logger
|
||||||
|
self.logger = logging.getLogger()
|
||||||
|
logformat = logging.Formatter(
|
||||||
|
"{asctime} [{levelname:8}] {message}",
|
||||||
|
datefmt="%Y-%m-%d %H:%M:%S", style="{"
|
||||||
|
)
|
||||||
|
lhandler = logging.StreamHandler(sys.stdout)
|
||||||
|
lhandler.setFormatter(logformat)
|
||||||
|
self.logger.addHandler(lhandler)
|
||||||
|
if self.pargs.logfile is not None:
|
||||||
|
lhandler = logging.FileHandler(filename=self.pargs.logfile)
|
||||||
|
lhandler.setFormatter(logformat)
|
||||||
|
self.logger.addHandler(lhandler)
|
||||||
|
|
||||||
|
# Loglevel auswerten
|
||||||
|
if self.pargs.verbose is None:
|
||||||
|
loglevel = logging.WARNING
|
||||||
|
elif self.pargs.verbose == 1:
|
||||||
|
loglevel = logging.INFO
|
||||||
|
elif self.pargs.verbose > 1:
|
||||||
|
loglevel = logging.DEBUG
|
||||||
|
self.logger.setLevel(loglevel)
|
||||||
263
revpipyload/revpipyload.py
Executable file
263
revpipyload/revpipyload.py
Executable file
@@ -0,0 +1,263 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
#
|
||||||
|
# (c) Sven Sager, License: GPLv3
|
||||||
|
#
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
import proginit
|
||||||
|
import shlex
|
||||||
|
import signal
|
||||||
|
import subprocess
|
||||||
|
from concurrent import futures
|
||||||
|
from threading import Thread, Event
|
||||||
|
from time import sleep
|
||||||
|
from xmlrpc.server import SimpleXMLRPCServer
|
||||||
|
|
||||||
|
|
||||||
|
class RevPiPlc(Thread):
|
||||||
|
|
||||||
|
def __init__(self, logger, lst_proc):
|
||||||
|
super().__init__()
|
||||||
|
self.autoreload = False
|
||||||
|
self._evt_exit = Event()
|
||||||
|
self.exitcode = 0
|
||||||
|
self._lst_proc = lst_proc
|
||||||
|
self._logger = logger
|
||||||
|
self._procplc = None
|
||||||
|
self.zeroonexit = False
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
# Prozess starten
|
||||||
|
self._logger.info("start plc program")
|
||||||
|
self._procplc = subprocess.Popen(self._lst_proc)
|
||||||
|
|
||||||
|
while not self._evt_exit.is_set():
|
||||||
|
|
||||||
|
# Auswerten
|
||||||
|
self.exitcode = self._procplc.poll()
|
||||||
|
|
||||||
|
if self.exitcode is not None:
|
||||||
|
|
||||||
|
if self.exitcode > 0:
|
||||||
|
self._logger.error(
|
||||||
|
"plc program chrashed - exitcode: {}".format(
|
||||||
|
self.exitcode
|
||||||
|
)
|
||||||
|
)
|
||||||
|
if self.zeroonexit:
|
||||||
|
f = open("/dev/piControl0", "w+b", 0)
|
||||||
|
f.write(bytes(4096))
|
||||||
|
self._logger.warning("set piControl0 to ZERO")
|
||||||
|
else:
|
||||||
|
self._logger.info("plc program did a clean exit")
|
||||||
|
|
||||||
|
if self.autoreload:
|
||||||
|
# Prozess neu starten
|
||||||
|
self._procplc = subprocess.Popen(self._lst_proc)
|
||||||
|
if self.exitcode == 0:
|
||||||
|
self._logger.warning(
|
||||||
|
"restart plc program after clean exit"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self._logger.warning("restart plc program after crash")
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
self._evt_exit.wait(1)
|
||||||
|
|
||||||
|
# Prozess beenden
|
||||||
|
count = 0
|
||||||
|
self._logger.info("term plc program")
|
||||||
|
self._procplc.terminate()
|
||||||
|
while self._procplc.poll() is None and count < 10:
|
||||||
|
count += 1
|
||||||
|
self._logger.debug(
|
||||||
|
"wait term plc program {} seconds".format(count * 0.5)
|
||||||
|
)
|
||||||
|
sleep(0.5)
|
||||||
|
if self._procplc.poll() is None:
|
||||||
|
self._logger.warning("can not term plc program")
|
||||||
|
self._procplc.kill()
|
||||||
|
self._logger.warning("killed plc program")
|
||||||
|
|
||||||
|
self.exitcode = self._procplc.poll()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.evt_exit.set()
|
||||||
|
|
||||||
|
|
||||||
|
class RevPiPyLoad(proginit.ProgInit):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self._exit = True
|
||||||
|
self.evt_loadconfig = Event()
|
||||||
|
|
||||||
|
self.autoreload = None
|
||||||
|
self.plc = None
|
||||||
|
self.plcprog = None
|
||||||
|
self.tpe = None
|
||||||
|
self.xmlrpc = None
|
||||||
|
self.xsrv = None
|
||||||
|
|
||||||
|
# Load config
|
||||||
|
self._loadconfig()
|
||||||
|
|
||||||
|
# Signal events
|
||||||
|
signal.signal(signal.SIGINT, self._sigexit)
|
||||||
|
signal.signal(signal.SIGTERM, self._sigexit)
|
||||||
|
signal.signal(signal.SIGHUP, self._sigloadconfig)
|
||||||
|
|
||||||
|
def _loadconfig(self):
|
||||||
|
"""Load configuration file and setup modul."""
|
||||||
|
self.evt_loadconfig.clear()
|
||||||
|
pauseproc = False
|
||||||
|
if not self._exit:
|
||||||
|
self.logger.info(
|
||||||
|
"shutdown python plc program while getting new config"
|
||||||
|
)
|
||||||
|
self.stop()
|
||||||
|
pauseproc = True
|
||||||
|
|
||||||
|
# Konfigurationsdatei laden
|
||||||
|
self.logger.info(
|
||||||
|
"loading config file: {}".format(self.globalconffile)
|
||||||
|
)
|
||||||
|
self.globalconfig.read(self.globalconffile)
|
||||||
|
|
||||||
|
# Konfiguration verarbeiten
|
||||||
|
self.autoreload = int(self.globalconfig["DEFAULT"].get("autoreload", 1))
|
||||||
|
self.autostart = int(self.globalconfig["DEFAULT"].get("autostart", 0))
|
||||||
|
self.plcprog = self.globalconfig["DEFAULT"].get("plcprogram", None)
|
||||||
|
self.xmlrpc = int(self.globalconfig["DEFAULT"].get("xmlrpc", 1))
|
||||||
|
self.zeroonexit = int(self.globalconfig["DEFAULT"].get("zeroonexit", 1))
|
||||||
|
|
||||||
|
# PLC Thread konfigurieren
|
||||||
|
self.logger.debug("create PLC watcher")
|
||||||
|
self.plc = RevPiPlc(
|
||||||
|
self.logger, shlex.split("/usr/bin/env python3 " + self.plcprog)
|
||||||
|
)
|
||||||
|
self.plc.autoreload = self.autoreload
|
||||||
|
self.plc.zeroonexit = self.zeroonexit
|
||||||
|
self.logger.debug("created PLC watcher")
|
||||||
|
|
||||||
|
# XMLRPC-Server Instantiieren und konfigurieren
|
||||||
|
if self.xmlrpc:
|
||||||
|
self.logger.debug("create xmlrpc server")
|
||||||
|
self.xsrv = SimpleXMLRPCServer(
|
||||||
|
(
|
||||||
|
"",
|
||||||
|
int(self.globalconfig["DEFAULT"].get("xmlrpcport", 55123))
|
||||||
|
),
|
||||||
|
logRequests=False,
|
||||||
|
allow_none=True
|
||||||
|
)
|
||||||
|
self.xsrv.register_introspection_functions()
|
||||||
|
|
||||||
|
self.xsrv.register_function(self.xml_plcexitcode, "plcexitcode")
|
||||||
|
self.xsrv.register_function(self.xml_plcrestart, "plcrestart")
|
||||||
|
self.xsrv.register_function(self.xml_plcrunning, "plcrunning")
|
||||||
|
self.xsrv.register_function(self.xml_plcstart, "plcstart")
|
||||||
|
self.xsrv.register_function(self.xml_plcstop, "plcstop")
|
||||||
|
self.xsrv.register_function(self.xml_reload, "reload")
|
||||||
|
self.logger.debug("created xmlrpc server")
|
||||||
|
|
||||||
|
if pauseproc:
|
||||||
|
self.logger.info(
|
||||||
|
"start python plc program after getting new config"
|
||||||
|
)
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def _sigexit(self, signum, frame):
|
||||||
|
"""Signal handler to clean an exit program."""
|
||||||
|
self.logger.info("got exit signal")
|
||||||
|
self.stop()
|
||||||
|
|
||||||
|
def _sigloadconfig(self, signum, frame):
|
||||||
|
self.logger.info("got reload config signal")
|
||||||
|
self.evt_loadconfig.set()
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
"""Start python program and watching it."""
|
||||||
|
self.logger.info("starting revpipyload")
|
||||||
|
self._exit = False
|
||||||
|
|
||||||
|
if self.xmlrpc:
|
||||||
|
self.logger.info("start xmlrpc-server")
|
||||||
|
self.tpe = futures.ThreadPoolExecutor(max_workers=1)
|
||||||
|
self.tpe.submit(self.xsrv.serve_forever)
|
||||||
|
|
||||||
|
if self.autostart:
|
||||||
|
self.logger.info("starting plc program {}".format(self.plcprog))
|
||||||
|
self.plc.start()
|
||||||
|
|
||||||
|
while not self._exit \
|
||||||
|
and not self.evt_loadconfig.is_set() \
|
||||||
|
and self.plc.is_alive():
|
||||||
|
self.evt_loadconfig.wait(1)
|
||||||
|
|
||||||
|
if not self._exit:
|
||||||
|
self.logger.info("exit python plc program to reload config")
|
||||||
|
self._loadconfig()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
"""Stop python program."""
|
||||||
|
self.logger.info("stopping revpipyload")
|
||||||
|
self._exit = True
|
||||||
|
|
||||||
|
self.logger.info("stopping plc program {}".format(self.plcprog))
|
||||||
|
self.plc.stop()
|
||||||
|
self.plc.join()
|
||||||
|
|
||||||
|
if self.xmlrpc:
|
||||||
|
self.logger.info("shutting down xmlrpc-server")
|
||||||
|
self.xsrv.shutdown()
|
||||||
|
self.tpe.shutdown()
|
||||||
|
self.xsrv.server_close()
|
||||||
|
|
||||||
|
def xml_plcexitcode(self):
|
||||||
|
self.logger.debug("xmlrpc get plcexitcode")
|
||||||
|
return -1 if self.plc.is_alive() else self.plc.exitcode
|
||||||
|
|
||||||
|
def xml_plcrestart(self):
|
||||||
|
self.logger.debug("xmlrpc get plcrestart")
|
||||||
|
self.plc.stop()
|
||||||
|
self.plc.join()
|
||||||
|
exitcode = self.plc.exitcode
|
||||||
|
self.plc = RevPiPlc(
|
||||||
|
self.logger, shlex.split("/usr/bin/env python3 " + self.plcprog)
|
||||||
|
)
|
||||||
|
self.plc.autoreload = self.autoreload
|
||||||
|
self.plc.zeroonexit = self.zeroonexit
|
||||||
|
self.plc.start()
|
||||||
|
return (exitcode, self.plc.exitcode)
|
||||||
|
|
||||||
|
def xml_plcrunning(self):
|
||||||
|
self.logger.debug("xmlrpc get plcrunning")
|
||||||
|
return self.plc.is_alive()
|
||||||
|
|
||||||
|
def xml_plcstart(self):
|
||||||
|
if self.plc.is_alive():
|
||||||
|
return -1
|
||||||
|
else:
|
||||||
|
self.plc = RevPiPlc(
|
||||||
|
self.logger, shlex.split("/usr/bin/env python3 " + self.plcprog)
|
||||||
|
)
|
||||||
|
self.plc.autoreload = self.autoreload
|
||||||
|
self.plc.zeroonexit = self.zeroonexit
|
||||||
|
self.plc.start()
|
||||||
|
return self.plc.exitcode
|
||||||
|
|
||||||
|
def xml_plcstop(self):
|
||||||
|
self.logger.debug("xmlrpc get plcstop")
|
||||||
|
self.plc.stop()
|
||||||
|
self.plc.join()
|
||||||
|
return self.plc.exitcode
|
||||||
|
|
||||||
|
def xml_reload(self):
|
||||||
|
self.logger.info("xmlrpc reload configuration")
|
||||||
|
self.evt_loadconfig.set()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
root = RevPiPyLoad()
|
||||||
|
root.start()
|
||||||
56
setup.py
Normal file
56
setup.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
#! /usr/bin/env python3
|
||||||
|
#
|
||||||
|
# (c) Sven Sager, License: LGPLv3
|
||||||
|
#
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""Setupscript fuer RevPiPyLoad."""
|
||||||
|
import distutils.command.install_egg_info
|
||||||
|
from distutils.core import setup
|
||||||
|
from glob import glob
|
||||||
|
|
||||||
|
|
||||||
|
class MyEggInfo(distutils.command.install_egg_info.install_egg_info):
|
||||||
|
|
||||||
|
u"""Disable egg_info installation, seems pointless for a non-library."""
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
u"""just pass egg_info."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
author="Sven Sager",
|
||||||
|
author_email="akira@narux.de",
|
||||||
|
url="https://revpimodio.org",
|
||||||
|
maintainer="Sven Sager",
|
||||||
|
maintainer_email="akira@revpimodio.org",
|
||||||
|
|
||||||
|
license="LGPLv3",
|
||||||
|
name="revpipyload",
|
||||||
|
version="0.1.0",
|
||||||
|
|
||||||
|
scripts=["data/revpipyload"],
|
||||||
|
|
||||||
|
data_files=[
|
||||||
|
("/etc/default", ["data/etc/default/revpipyload"]),
|
||||||
|
("/etc/init.d", ["data/etc/init.d/revpipyload"]),
|
||||||
|
("/etc/logrotate.d", ["data/etc/logrotate.d/revpipyload"]),
|
||||||
|
("/etc/revpipyload", ["data/etc/revpipyload/revpipyload.conf"]),
|
||||||
|
("share/revpipyload", glob("revpipyload/*.*")),
|
||||||
|
],
|
||||||
|
|
||||||
|
description="PLC Loader für Python-Projekte auf den RevolutionPi",
|
||||||
|
long_description=""
|
||||||
|
"Dieses Programm startet beim Systemstart ein angegebenes Python PLC\n"
|
||||||
|
"Programm. Es überwacht das Programm und startet es im Fehlerfall neu.\n"
|
||||||
|
"Bei Abstruz kann das gesamte /dev/piControl0 auf 0x00 gesettz werden.\n"
|
||||||
|
"Außerdem stellt es einen XML-RPC Server bereit, über den die Software\n"
|
||||||
|
"auf den RevPi geladen werden kann. Das Prozessabbild kann über ein Tool\n"
|
||||||
|
"zur Laufzeit überwacht werden.",
|
||||||
|
|
||||||
|
classifiers=[
|
||||||
|
"License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)",
|
||||||
|
"Operating System :: POSIX :: Linux",
|
||||||
|
],
|
||||||
|
cmdclass={"install_egg_info": MyEggInfo},
|
||||||
|
)
|
||||||
Reference in New Issue
Block a user