PLC-Program up- and download
This commit is contained in:
2017-03-06 09:26:25 +01:00
parent 96a3bacadf
commit 52353e4a5a
3 changed files with 86 additions and 17 deletions

View File

@@ -0,0 +1,6 @@
syntax: glob
*.tar.gz
test/*
.*
build/*
*.pyc

View File

@@ -1,3 +1,4 @@
recursive-include data * recursive-include data *
recursive-include revpipyload * recursive-include revpipyload *
global-exclude test/*
global-exclude *.pyc global-exclude *.pyc

View File

@@ -1,7 +1,7 @@
#!/usr/bin/python3 #!/usr/bin/python3
# #
# RevPiPyLoad # RevPiPyLoad
# Version: 0.2.2 # Version: see global var plcverion
# #
# Webpage: https://revpimodio.org/revpipyplc/ # Webpage: https://revpimodio.org/revpipyplc/
# (c) Sven Sager, License: LGPLv3 # (c) Sven Sager, License: LGPLv3
@@ -12,12 +12,19 @@ import os
import shlex import shlex
import signal import signal
import subprocess import subprocess
import tarfile
from concurrent import futures from concurrent import futures
from shutil import rmtree
from tempfile import mktemp
from threading import Thread, Event from threading import Thread, Event
from time import sleep, asctime from time import sleep, asctime
from xmlrpc.client import Binary
from xmlrpc.server import SimpleXMLRPCServer from xmlrpc.server import SimpleXMLRPCServer
pyloadverion = "0.2.2"
class LogReader(): class LogReader():
"""Ermoeglicht den Zugriff auf die Logdateien. """Ermoeglicht den Zugriff auf die Logdateien.
@@ -58,7 +65,7 @@ class LogReader():
self.fhapp.seek(self.posapp) self.fhapp.seek(self.posapp)
break break
proginit.debug("got {} new log lines".format(len(lst_new))) proginit.logger.debug("got {} new app log lines".format(len(lst_new)))
return lst_new return lst_new
def get_applog(self): def get_applog(self):
@@ -97,7 +104,7 @@ class LogReader():
self.fhplc.seek(self.posplc) self.fhplc.seek(self.posplc)
break break
proginit.debug("got {} new log lines".format(len(lst_new))) proginit.logger.debug("got {} new pyloader log lines".format(len(lst_new)))
return lst_new return lst_new
def get_plclog(self): def get_plclog(self):
@@ -130,14 +137,14 @@ class RevPiPlc(Thread):
def _zeroprocimg(self): def _zeroprocimg(self):
"""Setzt Prozessabbild auf NULL.""" """Setzt Prozessabbild auf NULL."""
if os.exists("/dev/piControl0"): if os.path.exists("/dev/piControl0"):
f = open("/dev/piControl0", "w+b", 0) f = open("/dev/piControl0", "w+b", 0)
f.write(bytes(4096)) f.write(bytes(4096))
proginit.logger.warning("set piControl0 to ZERO") proginit.logger.warning("set piControl0 to ZERO")
def run(self): def run(self):
"""Fuehrt PLC-Programm aus und ueberwacht es.""" """Fuehrt PLC-Programm aus und ueberwacht es."""
lst_proc = shlex.split("/usr/bin/env python3 -u " + self.program) lst_proc = shlex.split("/usr/bin/env python3 -u " + self._program)
# Ausgaben konfigurieren und ggf. umleiten # Ausgaben konfigurieren und ggf. umleiten
fh = None fh = None
@@ -154,7 +161,7 @@ class RevPiPlc(Thread):
fh.flush() fh.flush()
# Prozess erstellen # Prozess erstellen
proginit.logger.info("start plc program {}".format(self.program)) proginit.logger.info("start plc program {}".format(self._program))
self._procplc = subprocess.Popen( self._procplc = subprocess.Popen(
lst_proc, bufsize=1, stdout=fh, stderr=subprocess.STDOUT lst_proc, bufsize=1, stdout=fh, stderr=subprocess.STDOUT
) )
@@ -203,7 +210,7 @@ class RevPiPlc(Thread):
# Prozess beenden # Prozess beenden
count = 0 count = 0
proginit.logger.info("term plc program {}".format(self.program)) proginit.logger.info("term plc program {}".format(self._program))
self._procplc.terminate() self._procplc.terminate()
while self._procplc.poll() is None and count < 10: while self._procplc.poll() is None and count < 10:
count += 1 count += 1
@@ -213,7 +220,7 @@ class RevPiPlc(Thread):
sleep(0.5) sleep(0.5)
if self._procplc.poll() is None: if self._procplc.poll() is None:
proginit.logger.warning( proginit.logger.warning(
"can not term plc program {}".format(self.program) "can not term plc program {}".format(self._program)
) )
self._procplc.kill() self._procplc.kill()
proginit.logger.warning("killed plc program") proginit.logger.warning("killed plc program")
@@ -239,6 +246,7 @@ class RevPiPyLoad(proginit.ProgInit):
self.logr = LogReader() self.logr = LogReader()
self.plc = None self.plc = None
self.tfile = {}
self.tpe = None self.tpe = None
self.xsrv = None self.xsrv = None
@@ -284,6 +292,9 @@ class RevPiPyLoad(proginit.ProgInit):
self.globalconfig["DEFAULT"].get("zeroonexit", 1) self.globalconfig["DEFAULT"].get("zeroonexit", 1)
) )
# Workdirectory wechseln
os.chdir(self.plcworkdir)
# PLC Thread konfigurieren # PLC Thread konfigurieren
self.plc = self._plcthread() self.plc = self._plcthread()
@@ -310,7 +321,9 @@ class RevPiPyLoad(proginit.ProgInit):
self.xsrv.register_function(self.xml_plcstart, "plcstart") self.xsrv.register_function(self.xml_plcstart, "plcstart")
self.xsrv.register_function(self.xml_plcstop, "plcstop") self.xsrv.register_function(self.xml_plcstop, "plcstop")
self.xsrv.register_function(self.xml_plcupload, "plcupload") self.xsrv.register_function(self.xml_plcupload, "plcupload")
self.xsrv.register_function(self.xml_plcuploadclean, "plcuploadclean")
self.xsrv.register_function(self.xml_reload, "reload") self.xsrv.register_function(self.xml_reload, "reload")
self.xsrv.register_function(lambda: pyloadverion, "version")
proginit.logger.debug("created xmlrpc server") proginit.logger.debug("created xmlrpc server")
if pauseproc: if pauseproc:
@@ -324,8 +337,10 @@ class RevPiPyLoad(proginit.ProgInit):
@returns: PLC-Thread Object or None""" @returns: PLC-Thread Object or None"""
# Prüfen ob Programm existiert # Prüfen ob Programm existiert
if not os.exists(os.path.join(self.plcworkdir, self.plcprog)): if not os.path.exists(os.path.join(self.plcworkdir, self.plcprog)):
proginit.logger.error("plc file does not exists {}") proginit.logger.error("plc file does not exists {}".format(
os.path.join(self.plcworkdir, self.plcprog)
))
return return
proginit.logger.debug("create PLC watcher") proginit.logger.debug("create PLC watcher")
@@ -346,6 +361,17 @@ class RevPiPyLoad(proginit.ProgInit):
proginit.logger.debug("got reload config signal") proginit.logger.debug("got reload config signal")
self.evt_loadconfig.set() self.evt_loadconfig.set()
def packplc(self):
"""Erzeugt aus dem PLC-Programm ein TAR-File."""
filename = mktemp(suffix=".tar.gz", prefix="plc")
try:
fh_tar = tarfile.TarFile.open(name=filename, mode="w:gz")
fh_tar.add(".")
fh_tar.close()
except:
return ""
return filename
def start(self): def start(self):
"""Start plcload and PLC python program.""" """Start plcload and PLC python program."""
proginit.logger.info("starting revpipyload") proginit.logger.info("starting revpipyload")
@@ -374,9 +400,10 @@ class RevPiPyLoad(proginit.ProgInit):
proginit.logger.info("stopping revpipyload") proginit.logger.info("stopping revpipyload")
self._exit = True self._exit = True
proginit.logger.debug("stopping revpiplc-thread") if self.plc is not None:
self.plc.stop() proginit.logger.debug("stopping revpiplc-thread")
self.plc.join() self.plc.stop()
self.plc.join()
if self.xmlrpc: if self.xmlrpc:
proginit.logger.info("shutting down xmlrpc-server") proginit.logger.info("shutting down xmlrpc-server")
@@ -384,8 +411,16 @@ class RevPiPyLoad(proginit.ProgInit):
self.tpe.shutdown() self.tpe.shutdown()
self.xsrv.server_close() self.xsrv.server_close()
def xml_plcdownload(self): def xml_plcdownload(self, file=None):
pass # TODO: Daten blockweise übertragen
if file is None:
return self.packplc()
elif os.path.exists(file):
fh = open(file, "rb")
xmldata = Binary(fh.read())
fh.close()
os.remove(file)
return xmldata
def xml_plcexitcode(self): def xml_plcexitcode(self):
proginit.logger.debug("xmlrpc call plcexitcode") proginit.logger.debug("xmlrpc call plcexitcode")
@@ -413,8 +448,35 @@ class RevPiPyLoad(proginit.ProgInit):
self.plc.join() self.plc.join()
return self.plc.exitcode return self.plc.exitcode
def xml_plcupload(self, path=None, file=None, clear=False): def xml_plcupload(self, filedata):
pass # TODO: Daten blockweise annehmen
if filedata is None:
return False
filename = mktemp(prefix="upl")
# Daten in tmp-file schreiben
fh = open(filename, "wb")
fh.write(filedata.data)
fh.close()
if tarfile.is_tarfile(filename):
# Archiv auspacken
fh_tar = tarfile.open(filename)
fh_tar.extractall()
fh_tar.close()
os.remove(filename)
else:
# Kein Archiv
os.remove(filename)
return False
def xml_plcuploadclean(self):
try:
rmtree(".", ignore_errors=True)
except:
return False
return True
def xml_reload(self): def xml_reload(self):
proginit.logger.debug("xmlrpc call reload") proginit.logger.debug("xmlrpc call reload")