Mit replace_ios zusammenführen

This commit is contained in:
2019-08-26 13:19:13 +02:00
17 changed files with 297 additions and 236 deletions

View File

@@ -3,6 +3,7 @@ autoreload = 1
autoreloaddelay = 5 autoreloaddelay = 5
autostart = 1 autostart = 1
plcworkdir = /var/lib/revpipyload plcworkdir = /var/lib/revpipyload
plcworkdir_set_uid = 0
plcprogram = program.py plcprogram = program.py
plcarguments = plcarguments =
plcuid = 1000 plcuid = 1000

View File

@@ -31,9 +31,6 @@ Functions</h3>
</tr><tr> </tr><tr>
<td><a style="color:#0000FF" href="#refullmatch">refullmatch</a></td> <td><a style="color:#0000FF" href="#refullmatch">refullmatch</a></td>
<td>re.fullmatch wegen alter python version aus wheezy nachgebaut.</td> <td>re.fullmatch wegen alter python version aus wheezy nachgebaut.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#revpimodio_replaceio">revpimodio_replaceio</a></td>
<td>Importiert und ersetzt IOs in RevPiModIO.</td>
</tr> </tr>
</table> </table>
<hr /><hr /> <hr /><hr />
@@ -83,26 +80,5 @@ True, wenn komplett passt sonst False
</dd> </dd>
</dl> </dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div> <div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /><hr />
<a NAME="revpimodio_replaceio" ID="revpimodio_replaceio"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">revpimodio_replaceio</h2>
<b>revpimodio_replaceio</b>(<i>revpi, filename</i>)
<p>
Importiert und ersetzt IOs in RevPiModIO.
</p><dl>
<dt><i>revpi</i></dt>
<dd>
RevPiModIO Instanz
</dd><dt><i>filename</i></dt>
<dd>
Dateiname der Ersetzungsdatei
</dd>
</dl><dl>
<dt>Returns:</dt>
<dd>
True, wenn alle IOs ersetzt werden konnten
</dd>
</dl>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr /> <hr />
</body></html> </body></html>

View File

@@ -12,7 +12,7 @@ Modul fuer die Verwaltung der PLC-Slave Funktionen.
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3> Global Attributes</h3>
<table> <table>
<tr><td>__author__</td></tr><tr><td>__copyright__</td></tr><tr><td>__license__</td></tr> <tr><td>HASH_FAIL</td></tr><tr><td>HASH_NULL</td></tr><tr><td>HASH_PICT</td></tr><tr><td>HASH_RPIO</td></tr><tr><td>__author__</td></tr><tr><td>__copyright__</td></tr><tr><td>__license__</td></tr>
</table> </table>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3> Classes</h3>
@@ -66,6 +66,12 @@ Methods</h3>
<td><a style="color:#0000FF" href="#RevPiSlave.check_connectedacl">check_connectedacl</a></td> <td><a style="color:#0000FF" href="#RevPiSlave.check_connectedacl">check_connectedacl</a></td>
<td>Prueft bei neuen ACLs bestehende Verbindungen.</td> <td>Prueft bei neuen ACLs bestehende Verbindungen.</td>
</tr><tr> </tr><tr>
<td><a style="color:#0000FF" href="#RevPiSlave.disconnect_all">disconnect_all</a></td>
<td>Close all device connection.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiSlave.disconnect_replace_ios">disconnect_replace_ios</a></td>
<td>Close all device with loaded replace_ios file.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiSlave.newlogfile">newlogfile</a></td> <td><a style="color:#0000FF" href="#RevPiSlave.newlogfile">newlogfile</a></td>
<td>Konfiguriert die FileHandler auf neue Logdatei.</td> <td>Konfiguriert die FileHandler auf neue Logdatei.</td>
</tr><tr> </tr><tr>
@@ -104,6 +110,18 @@ RevPiSlave.check_connectedacl</h3>
<b>check_connectedacl</b>(<i></i>) <b>check_connectedacl</b>(<i></i>)
<p> <p>
Prueft bei neuen ACLs bestehende Verbindungen. Prueft bei neuen ACLs bestehende Verbindungen.
</p><a NAME="RevPiSlave.disconnect_all" ID="RevPiSlave.disconnect_all"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiSlave.disconnect_all</h3>
<b>disconnect_all</b>(<i></i>)
<p>
Close all device connection.
</p><a NAME="RevPiSlave.disconnect_replace_ios" ID="RevPiSlave.disconnect_replace_ios"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiSlave.disconnect_replace_ios</h3>
<b>disconnect_replace_ios</b>(<i></i>)
<p>
Close all device with loaded replace_ios file.
</p><a NAME="RevPiSlave.newlogfile" ID="RevPiSlave.newlogfile"></a> </p><a NAME="RevPiSlave.newlogfile" ID="RevPiSlave.newlogfile"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiSlave.newlogfile</h3> RevPiSlave.newlogfile</h3>

View File

@@ -63,6 +63,9 @@ Methods</h3>
<td><a style="color:#0000FF" href="#ProcimgServer.__init__">ProcimgServer</a></td> <td><a style="color:#0000FF" href="#ProcimgServer.__init__">ProcimgServer</a></td>
<td>Instantiiert RevPiCheckServer()-Klasse.</td> <td>Instantiiert RevPiCheckServer()-Klasse.</td>
</tr><tr> </tr><tr>
<td><a style="color:#0000FF" href="#ProcimgServer.__del__">__del__</a></td>
<td>Clean up RevPiModIO.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#ProcimgServer.devices">devices</a></td> <td><a style="color:#0000FF" href="#ProcimgServer.devices">devices</a></td>
<td>Generiert Deviceliste mit Position und Namen.</td> <td>Generiert Deviceliste mit Position und Namen.</td>
</tr><tr> </tr><tr>
@@ -104,7 +107,13 @@ XML-RPC Server
<dd> <dd>
Replace IOs of RevPiModIO Replace IOs of RevPiModIO
</dd> </dd>
</dl><a NAME="ProcimgServer.devices" ID="ProcimgServer.devices"></a> </dl><a NAME="ProcimgServer.__del__" ID="ProcimgServer.__del__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
ProcimgServer.__del__</h3>
<b>__del__</b>(<i></i>)
<p>
Clean up RevPiModIO.
</p><a NAME="ProcimgServer.devices" ID="ProcimgServer.devices"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
ProcimgServer.devices</h3> ProcimgServer.devices</h3>
<b>devices</b>(<i></i>) <b>devices</b>(<i></i>)

View File

@@ -12,7 +12,7 @@ Main functions of our program.
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3> Global Attributes</h3>
<table> <table>
<tr><td>__author__</td></tr><tr><td>__copyright__</td></tr><tr><td>__license__</td></tr><tr><td>forked</td></tr><tr><td>globalconffile</td></tr><tr><td>logapp</td></tr><tr><td>logger</td></tr><tr><td>logplc</td></tr><tr><td>pargs</td></tr><tr><td>picontrolreset</td></tr><tr><td>rapcatalog</td></tr><tr><td>startdir</td></tr> <tr><td>__author__</td></tr><tr><td>__copyright__</td></tr><tr><td>__license__</td></tr><tr><td>conf</td></tr><tr><td>forked</td></tr><tr><td>globalconffile</td></tr><tr><td>logapp</td></tr><tr><td>logger</td></tr><tr><td>logplc</td></tr><tr><td>pargs</td></tr><tr><td>picontrolreset</td></tr><tr><td>rapcatalog</td></tr><tr><td>startdir</td></tr>
</table> </table>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3> Classes</h3>

View File

@@ -110,6 +110,12 @@ Methods</h3>
<td><a style="color:#0000FF" href="#RevPiPyLoad._signewlogfile">_signewlogfile</a></td> <td><a style="color:#0000FF" href="#RevPiPyLoad._signewlogfile">_signewlogfile</a></td>
<td>Signal handler to start new logfile.</td> <td>Signal handler to start new logfile.</td>
</tr><tr> </tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.check_pictory_changed">check_pictory_changed</a></td>
<td>Prueft ob sich die piCtory Datei veraendert hat.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.check_replace_ios_changed">check_replace_ios_changed</a></td>
<td>Prueft ob sich die replace_ios.conf Datei veraendert hat (oder del).</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.packapp">packapp</a></td> <td><a style="color:#0000FF" href="#RevPiPyLoad.packapp">packapp</a></td>
<td>Erzeugt aus dem PLC-Programm ein TAR/Zip-File.</td> <td>Erzeugt aus dem PLC-Programm ein TAR/Zip-File.</td>
</tr><tr> </tr><tr>
@@ -299,7 +305,29 @@ RevPiPyLoad._signewlogfile</h3>
<b>_signewlogfile</b>(<i>signum, frame</i>) <b>_signewlogfile</b>(<i>signum, frame</i>)
<p> <p>
Signal handler to start new logfile. Signal handler to start new logfile.
</p><a NAME="RevPiPyLoad.packapp" ID="RevPiPyLoad.packapp"></a> </p><a NAME="RevPiPyLoad.check_pictory_changed" ID="RevPiPyLoad.check_pictory_changed"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.check_pictory_changed</h3>
<b>check_pictory_changed</b>(<i></i>)
<p>
Prueft ob sich die piCtory Datei veraendert hat.
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn veraendert wurde
</dd>
</dl><a NAME="RevPiPyLoad.check_replace_ios_changed" ID="RevPiPyLoad.check_replace_ios_changed"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.check_replace_ios_changed</h3>
<b>check_replace_ios_changed</b>(<i></i>)
<p>
Prueft ob sich die replace_ios.conf Datei veraendert hat (oder del).
</p><dl>
<dt>Returns:</dt>
<dd>
True, wenn veraendert wurde
</dd>
</dl><a NAME="RevPiPyLoad.packapp" ID="RevPiPyLoad.packapp"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000"> <h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.packapp</h3> RevPiPyLoad.packapp</h3>
<b>packapp</b>(<i>mode="tar", pictory=False</i>) <b>packapp</b>(<i>mode="tar", pictory=False</i>)

View File

@@ -4,7 +4,6 @@ helper.__license__?9
helper._setuprt?5(pid, evt_exit) helper._setuprt?5(pid, evt_exit)
helper._zeroprocimg?5() helper._zeroprocimg?5()
helper.refullmatch?4(regex, string) helper.refullmatch?4(regex, string)
helper.revpimodio_replaceio?4(revpi, filename)
logsystem.LogReader.closeall?4() logsystem.LogReader.closeall?4()
logsystem.LogReader.load_applog?4(start, count) logsystem.LogReader.load_applog?4(start, count)
logsystem.LogReader.load_plclog?4(start, count) logsystem.LogReader.load_plclog?4(start, count)
@@ -33,7 +32,13 @@ mqttserver.MqttServer?1(basetopic, sendinterval, broker_address, port=1883, tls_
mqttserver.__author__?9 mqttserver.__author__?9
mqttserver.__copyright__?9 mqttserver.__copyright__?9
mqttserver.__license__?9 mqttserver.__license__?9
picontrolserver.HASH_FAIL?7
picontrolserver.HASH_NULL?7
picontrolserver.HASH_PICT?7
picontrolserver.HASH_RPIO?7
picontrolserver.RevPiSlave.check_connectedacl?4() picontrolserver.RevPiSlave.check_connectedacl?4()
picontrolserver.RevPiSlave.disconnect_all?4()
picontrolserver.RevPiSlave.disconnect_replace_ios?4()
picontrolserver.RevPiSlave.newlogfile?4() picontrolserver.RevPiSlave.newlogfile?4()
picontrolserver.RevPiSlave.run?4() picontrolserver.RevPiSlave.run?4()
picontrolserver.RevPiSlave.stop?4() picontrolserver.RevPiSlave.stop?4()
@@ -57,6 +62,7 @@ plcsystem.RevPiPlc?1(program, arguments, pversion)
plcsystem.__author__?9 plcsystem.__author__?9
plcsystem.__copyright__?9 plcsystem.__copyright__?9
plcsystem.__license__?9 plcsystem.__license__?9
procimgserver.ProcimgServer.__del__?6()
procimgserver.ProcimgServer.devices?4() procimgserver.ProcimgServer.devices?4()
procimgserver.ProcimgServer.ios?4(iotype) procimgserver.ProcimgServer.ios?4(iotype)
procimgserver.ProcimgServer.loadrevpimodio?4() procimgserver.ProcimgServer.loadrevpimodio?4()
@@ -72,6 +78,7 @@ proginit.__author__?9
proginit.__copyright__?9 proginit.__copyright__?9
proginit.__license__?9 proginit.__license__?9
proginit.cleanup?4() proginit.cleanup?4()
proginit.conf?7
proginit.configure?4() proginit.configure?4()
proginit.forked?7 proginit.forked?7
proginit.globalconffile?7 proginit.globalconffile?7
@@ -92,6 +99,8 @@ revpipyload.RevPiPyLoad._plcthread?5()
revpipyload.RevPiPyLoad._sigexit?5(signum, frame) revpipyload.RevPiPyLoad._sigexit?5(signum, frame)
revpipyload.RevPiPyLoad._sigloadconfig?5(signum, frame) revpipyload.RevPiPyLoad._sigloadconfig?5(signum, frame)
revpipyload.RevPiPyLoad._signewlogfile?5(signum, frame) revpipyload.RevPiPyLoad._signewlogfile?5(signum, frame)
revpipyload.RevPiPyLoad.check_pictory_changed?4()
revpipyload.RevPiPyLoad.check_replace_ios_changed?4()
revpipyload.RevPiPyLoad.packapp?4(mode="tar", pictory=False) revpipyload.RevPiPyLoad.packapp?4(mode="tar", pictory=False)
revpipyload.RevPiPyLoad.start?4() revpipyload.RevPiPyLoad.start?4()
revpipyload.RevPiPyLoad.stop?4() revpipyload.RevPiPyLoad.stop?4()

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-5.1.dtd"> <!DOCTYPE Project SYSTEM "Project-5.1.dtd">
<!-- eric project file for project revpipyload --> <!-- eric project file for project revpipyload -->
<!-- Saved: 2019-06-16, 15:47:42 --> <!-- Saved: 2019-08-26, 13:17:52 -->
<!-- Copyright (C) 2019 Sven Sager, akira@narux.de --> <!-- Copyright (C) 2019 Sven Sager, akira@narux.de -->
<Project version="5.1"> <Project version="5.1">
<Language>en_US</Language> <Language>en_US</Language>
@@ -9,7 +9,7 @@
<ProgLanguage mixed="0">Python3</ProgLanguage> <ProgLanguage mixed="0">Python3</ProgLanguage>
<ProjectType>Console</ProjectType> <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> <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.7.6</Version> <Version>0.8.0</Version>
<Author>Sven Sager</Author> <Author>Sven Sager</Author>
<Email>akira@narux.de</Email> <Email>akira@narux.de</Email>
<Eol index="1"/> <Eol index="1"/>

View File

@@ -5,7 +5,6 @@ __copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "GPLv3" __license__ = "GPLv3"
import os import os
import proginit import proginit
from configparser import ConfigParser
from re import match as rematch from re import match as rematch
from subprocess import Popen, PIPE from subprocess import Popen, PIPE
@@ -118,115 +117,6 @@ def _zeroprocimg():
) )
def revpimodio_replaceio(revpi, filename):
"""Importiert und ersetzt IOs in RevPiModIO.
@param revpi RevPiModIO Instanz
@param filename Dateiname der Ersetzungsdatei
@return True, wenn alle IOs ersetzt werden konnten
"""
cp = ConfigParser()
try:
with open(filename, "r") as fh:
cp.read_file(fh)
except Exception as e:
proginit.logger.error(
"could not read replace_io file '{0}' | {1}".format(filename, e)
)
return False
# Pre-check
lst_replace = []
rc = True
for io in cp:
if io == "DEFAULT":
continue
dict_replace = {
"replace": cp[io].get("replace", ""),
"frm": cp[io].get("frm"),
"bmk": cp[io].get("bmk", ""),
"byteorder": cp[io].get("byteorder", "little"),
}
if dict_replace["replace"] in revpi.io:
# Byteorder prüfen
if not (dict_replace["byteorder"] == "little" or
dict_replace["byteorder"] == "big"):
proginit.logger.error(
"byteorder of '{0}' must be 'little' or 'big'".format(io)
)
rc = False
continue
if dict_replace["frm"] == "?":
# Convert defaultvalue from config file
try:
dict_replace["default"] = cp[io].getboolean("defaultvalue")
except Exception:
proginit.logger.error(
"could not convert '{0}' defaultvalue '{1}' to boolean"
"".format(io, cp[io].get("defaultvalue"))
)
rc = False
continue
# Get bitaddress
try:
dict_replace["bitaddress"] = cp[io].getint("bitaddress", 0)
except Exception:
proginit.logger.error(
"could not convert '{0}' bitaddress '{1}' to integer"
"".format(io, cp[io].get("bitaddress"))
)
rc = False
continue
else:
# Convert defaultvalue from config file
try:
dict_replace["default"] = cp[io].getint("defaultvalue")
except Exception:
proginit.logger.error(
"could not convert '{0}' defaultvalue '{1}' to integer"
"".format(io, cp[io].get("defaultvalue"))
)
rc = False
continue
else:
proginit.logger.error(
"can not find io '{0}' to replace with '{1}'"
"".format(dict_replace["replace"], io)
)
rc = False
continue
# Replace_IO übernehmen
lst_replace.append(dict_replace)
if not rc:
# Abbrechen, wenn IO-Verarbeitung einen Fehler hatte
return False
# Replace IOs
for dict_replace in lst_replace:
# FIXME: Hier können Fehler auftreten !!!
revpi.io[dict_replace["replace"]].replace_io(
io,
frm=dict_replace["frm"],
bmk=dict_replace["bmk"],
bit=dict_replace["bitaddress"],
byteorder=dict_replace["byteorder"],
defaultvalue=dict_replace["default"]
)
def refullmatch(regex, string): def refullmatch(regex, string):
"""re.fullmatch wegen alter python version aus wheezy nachgebaut. """re.fullmatch wegen alter python version aus wheezy nachgebaut.

View File

@@ -74,7 +74,6 @@ class MqttServer(Thread):
self._reloadmodio = False self._reloadmodio = False
self._replace_ios = replace_ios self._replace_ios = replace_ios
self._rpi = None self._rpi = None
self._rpi_write = None
self._send_events = send_events self._send_events = send_events
self._sendinterval = sendinterval self._sendinterval = sendinterval
self._write_outputs = write_outputs self._write_outputs = write_outputs
@@ -130,26 +129,18 @@ class MqttServer(Thread):
# RevPiModIO-Modul Instantiieren # RevPiModIO-Modul Instantiieren
if self._rpi is not None: if self._rpi is not None:
self._rpi.cleanup() self._rpi.cleanup()
if self._rpi_write is not None:
self._rpi_write.cleanup()
proginit.logger.debug("create revpimodio2 object for MQTT") proginit.logger.debug("create revpimodio2 object for MQTT")
try: try:
# Lesend und Eventüberwachung # Vollzugriff und Eventüberwachung
self._rpi = revpimodio2.RevPiModIO( self._rpi = revpimodio2.RevPiModIO(
autorefresh=self._send_events, autorefresh=self._send_events,
monitoring=True, monitoring=not self._write_outputs,
configrsc=proginit.pargs.configrsc, configrsc=proginit.pargs.configrsc,
procimg=proginit.pargs.procimg, procimg=proginit.pargs.procimg,
replace_io_file=self._replace_ios replace_io_file=self._replace_ios,
direct_output=True,
) )
# Schreibenen Zugriff
if self._write_outputs:
self._rpi_write = revpimodio2.RevPiModIO(
configrsc=proginit.pargs.configrsc,
procimg=proginit.pargs.procimg,
replace_io_file=self._replace_ios
)
if self._replace_ios: if self._replace_ios:
proginit.logger.info("loaded replace_ios to MQTT") proginit.logger.info("loaded replace_ios to MQTT")
@@ -159,16 +150,11 @@ class MqttServer(Thread):
# Lesend und Eventüberwachung # Lesend und Eventüberwachung
self._rpi = revpimodio2.RevPiModIO( self._rpi = revpimodio2.RevPiModIO(
autorefresh=self._send_events, autorefresh=self._send_events,
monitoring=True, monitoring=not self._write_outputs,
configrsc=proginit.pargs.configrsc, configrsc=proginit.pargs.configrsc,
procimg=proginit.pargs.procimg procimg=proginit.pargs.procimg,
direct_output=True,
) )
# Schreibenen Zugriff
if self._write_outputs:
self._rpi_write = revpimodio2.RevPiModIO(
configrsc=proginit.pargs.configrsc,
procimg=proginit.pargs.procimg
)
proginit.logger.warning( proginit.logger.warning(
"replace_ios_file not loadable for MQTT - using " "replace_ios_file not loadable for MQTT - using "
"defaults now | {0}".format(e) "defaults now | {0}".format(e)
@@ -176,7 +162,6 @@ class MqttServer(Thread):
except Exception: except Exception:
self._rpi = None self._rpi = None
self._rpi_write = None
proginit.logger.error( proginit.logger.error(
"piCtory configuration not loadable for MQTT" "piCtory configuration not loadable for MQTT"
) )
@@ -280,11 +265,11 @@ class MqttServer(Thread):
# IO holen # IO holen
if coreio: if coreio:
coreio = ioname.split(".")[-1] coreio = ioname.split(".")[-1]
io = getattr(self._rpi_write.core, coreio) io = getattr(self._rpi.core, coreio)
if not isinstance(io, revpimodio2.io.IOBase): if not isinstance(io, revpimodio2.io.IOBase):
raise RuntimeError() raise RuntimeError()
else: else:
io = self._rpi_write.io[ioname] io = self._rpi.io[ioname]
io_needbytes = type(io.value) == bytes io_needbytes = type(io.value) == bytes
except Exception: except Exception:
proginit.logger.error( proginit.logger.error(
@@ -300,10 +285,8 @@ class MqttServer(Thread):
) )
elif ioget: elif ioget:
# Daten je nach IO Type aus Prozessabbild laden # Werte laden, wenn nicht autorefresh
if io.type == revpimodio2.OUT: if not self._send_events:
io._parentdevice.syncoutputs()
else:
io._parentdevice.readprocimg() io._parentdevice.readprocimg()
# Publish Wert von IO # Publish Wert von IO
@@ -344,7 +327,6 @@ class MqttServer(Thread):
return return
# Write Value to RevPi # Write Value to RevPi
io._parentdevice.syncoutputs()
try: try:
io.value = value io.value = value
except Exception: except Exception:
@@ -352,8 +334,6 @@ class MqttServer(Thread):
"could not write '{0}' to Output '{1}'" "could not write '{0}' to Output '{1}'"
"".format(value, ioname) "".format(value, ioname)
) )
else:
io._parentdevice.writeprocimg()
elif ioreset: elif ioreset:
# Counter zurücksetzen # Counter zurücksetzen

View File

@@ -10,8 +10,13 @@ from shared.ipaclmanager import IpAclManager
from threading import Event, Thread from threading import Event, Thread
from timeit import default_timer from timeit import default_timer
# Hashvalues
HASH_NULL = b'\x00' * 16
HASH_FAIL = b'\xff' * 16
HASH_PICT = HASH_FAIL
HASH_RPIO = HASH_NULL
# NOTE: Sollte dies als Process ausgeführt werden?
class RevPiSlave(Thread): class RevPiSlave(Thread):
"""RevPi PLC-Server. """RevPi PLC-Server.
@@ -70,6 +75,19 @@ class RevPiSlave(Thread):
) )
dev._acl = level dev._acl = level
def disconnect_all(self):
"""Close all device connection."""
# Alle Threads beenden
for th in self._th_dev:
th.stop()
def disconnect_replace_ios(self):
"""Close all device with loaded replace_ios file."""
# Alle Threads beenden die Replace_IOs emfpangen haben
for th in self._th_dev:
if th.got_replace_ios:
th.stop()
def newlogfile(self): def newlogfile(self):
"""Konfiguriert die FileHandler auf neue Logdatei.""" """Konfiguriert die FileHandler auf neue Logdatei."""
pass pass
@@ -80,6 +98,7 @@ class RevPiSlave(Thread):
# Socket öffnen und konfigurieren bis Erfolg oder Ende # Socket öffnen und konfigurieren bis Erfolg oder Ende
self.so = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.so = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.so.settimeout(2)
while not self._evt_exit.is_set(): while not self._evt_exit.is_set():
try: try:
self.so.bind((self._bindip, self._port)) self.so.bind((self._bindip, self._port))
@@ -97,9 +116,11 @@ class RevPiSlave(Thread):
self.exitcode = -1 self.exitcode = -1
# Verbindung annehmen # Verbindung annehmen
proginit.logger.info("accept new connection for revpinetio")
try: try:
tup_sock = self.so.accept() tup_sock = self.so.accept()
proginit.logger.info("accepted new connection for revpinetio")
except socket.timeout:
continue
except Exception: except Exception:
if not self._evt_exit.is_set(): if not self._evt_exit.is_set():
proginit.logger.exception("accept exception") proginit.logger.exception("accept exception")
@@ -174,6 +195,7 @@ class RevPiSlaveDev(Thread):
self._deadtime = None self._deadtime = None
self._devcon, self._addr = devcon self._devcon, self._addr = devcon
self._evt_exit = Event() self._evt_exit = Event()
self.got_replace_ios = False
self._writeerror = False self._writeerror = False
# Sicherheitsbytes # Sicherheitsbytes
@@ -381,10 +403,47 @@ class RevPiSlaveDev(Thread):
) )
break break
else: else:
continue
finally:
# End-of-Transmission character immer senden # End-of-Transmission character immer senden
self._devcon.send(b'\x04') self._devcon.send(b'\x04')
continue
elif cmd == b'PH':
# piCtory md5 Hashwert senden (16 Byte)
proginit.logger.debug(
"send pictory hashvalue: {0}".format(HASH_PICT)
)
self._devcon.sendall(HASH_PICT)
elif cmd == b'RP':
# Replace_IOs Konfiguration senden, wenn hash existiert
proginit.logger.debug(
"transfair replace_io configuration: {0}"
"".format(proginit.pargs.configrsc)
)
replace_ios = proginit.conf["DEFAULT"].get("replace_ios", "")
try:
if HASH_RPIO != HASH_NULL and replace_ios:
with open(replace_ios, "rb") as fh:
# Komplette replace_io Datei senden
self._devcon.sendall(fh.read())
except Exception as e:
proginit.logger.error(
"error on replace_io transfair: {0}".format(e)
)
break
else:
# End-of-Transmission character immer senden
self._devcon.send(b'\x04')
continue
elif cmd == b'RH':
# Replace_IOs md5 Hashwert senden (16 Byte)
self.got_replace_ios = True
proginit.logger.debug(
"send replace_ios hashvalue: {0}".format(HASH_RPIO)
)
self._devcon.sendall(HASH_RPIO)
elif cmd == b'EX': elif cmd == b'EX':
# Sauber Verbindung verlassen # Sauber Verbindung verlassen
@@ -416,6 +475,7 @@ class RevPiSlaveDev(Thread):
) )
else: else:
# Simulation # Simulation
# TODO: IOCTL für Dateien implementieren
proginit.logger.warning( proginit.logger.warning(
"ioctl {0} with {1} simulated".format(request, arg) "ioctl {0} with {1} simulated".format(request, arg)
) )

View File

@@ -54,6 +54,11 @@ class ProcimgServer():
proginit.logger.debug("leave ProcimgServer.__init__()") proginit.logger.debug("leave ProcimgServer.__init__()")
def __del__(self):
"""Clean up RevPiModIO."""
if self.rpi is not None:
self.rpi.cleanup()
def devices(self): def devices(self):
"""Generiert Deviceliste mit Position und Namen. """Generiert Deviceliste mit Position und Namen.
@return list() mit Tuple (pos, name)""" @return list() mit Tuple (pos, name)"""
@@ -99,7 +104,8 @@ class ProcimgServer():
self.rpi = revpimodio2.RevPiModIO( self.rpi = revpimodio2.RevPiModIO(
configrsc=proginit.pargs.configrsc, configrsc=proginit.pargs.configrsc,
procimg=proginit.pargs.procimg, procimg=proginit.pargs.procimg,
replace_io_file=self.replace_ios replace_io_file=self.replace_ios,
direct_output=True,
) )
if self.replace_ios: if self.replace_ios:
@@ -110,6 +116,7 @@ class ProcimgServer():
self.rpi = revpimodio2.RevPiModIO( self.rpi = revpimodio2.RevPiModIO(
configrsc=proginit.pargs.configrsc, configrsc=proginit.pargs.configrsc,
procimg=proginit.pargs.procimg, procimg=proginit.pargs.procimg,
direct_output=True,
) )
proginit.logger.warning( proginit.logger.warning(
"replace_ios_file not loadable for ProcimgServer - using " "replace_ios_file not loadable for ProcimgServer - using "
@@ -122,9 +129,6 @@ class ProcimgServer():
) )
return e return e
# NOTE: Warum das?
self.rpi.syncoutputs(device=0)
proginit.logger.debug("created revpimodio2 object") proginit.logger.debug("created revpimodio2 object")
def setvalue(self, device, io, value): def setvalue(self, device, io, value):
@@ -140,8 +144,6 @@ class ProcimgServer():
if type(value) == Binary: if type(value) == Binary:
value = value.data value = value.data
self.rpi.syncoutputs(device=device)
try: try:
# Neuen Wert übernehmen # Neuen Wert übernehmen
if type(value) == bytes or type(value) == bool: if type(value) == bytes or type(value) == bool:
@@ -156,13 +158,12 @@ class ProcimgServer():
except Exception as e: except Exception as e:
return [device, io, False, str(e)] return [device, io, False, str(e)]
self.rpi.writeprocimg(device=device)
return [device, io, True, ""] return [device, io, True, ""]
def values(self): def values(self):
"""Liefert Prozessabbild an Client. """Liefert Prozessabbild an Client.
@return Binary() bytes or None""" @return Binary() bytes or None"""
if self.rpi.readprocimg() and self.rpi.syncoutputs(): if self.rpi.readprocimg():
bytebuff = bytearray() bytebuff = bytearray()
for dev in self.rpi.device: for dev in self.rpi.device:
bytebuff += bytes(dev) bytebuff += bytes(dev)

View File

@@ -7,7 +7,9 @@ import logging
import os import os
import sys import sys
from argparse import ArgumentParser from argparse import ArgumentParser
from configparser import ConfigParser
conf = ConfigParser()
forked = False forked = False
globalconffile = None globalconffile = None
logapp = "revpipyloadapp.log" logapp = "revpipyloadapp.log"

View File

@@ -28,7 +28,7 @@ begrenzt werden!
__author__ = "Sven Sager" __author__ = "Sven Sager"
__copyright__ = "Copyright (C) 2018 Sven Sager" __copyright__ = "Copyright (C) 2018 Sven Sager"
__license__ = "GPLv3" __license__ = "GPLv3"
__version__ = "0.7.6" __version__ = "0.8.0"
import gzip import gzip
import logsystem import logsystem
import picontrolserver import picontrolserver
@@ -39,6 +39,7 @@ import signal
import tarfile import tarfile
import zipfile import zipfile
from configparser import ConfigParser from configparser import ConfigParser
from hashlib import md5
from helper import refullmatch from helper import refullmatch
from json import loads as jloads from json import loads as jloads
from shared.ipaclmanager import IpAclManager from shared.ipaclmanager import IpAclManager
@@ -49,7 +50,7 @@ from time import asctime
from xmlrpc.client import Binary from xmlrpc.client import Binary
from xrpcserver import SaveXMLRPCServer from xrpcserver import SaveXMLRPCServer
min_revpimodio = "2.3.3" min_revpimodio = "2.4.1"
class RevPiPyLoad(): class RevPiPyLoad():
@@ -67,14 +68,18 @@ class RevPiPyLoad():
# Klassenattribute # Klassenattribute
self._exit = True self._exit = True
self.pictorymtime = os.path.getmtime(proginit.pargs.configrsc)
self.replaceiosmtime = 0
self.evt_loadconfig = Event() self.evt_loadconfig = Event()
self.globalconfig = ConfigParser() self.globalconfig = ConfigParser()
proginit.conf = self.globalconfig
self.logr = logsystem.LogReader() self.logr = logsystem.LogReader()
self.xsrv = None self.xsrv = None
self.xml_ps = None self.xml_ps = None
# Dateimerker
self.pictorymtime = 0
self.replaceiosmtime = 0
self.replaceiofail = False
# Berechtigungsmanger # Berechtigungsmanger
if proginit.pargs.developermode: if proginit.pargs.developermode:
self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=9) self.plcslaveacl = IpAclManager(minlevel=0, maxlevel=9)
@@ -194,6 +199,7 @@ class RevPiPyLoad():
"loading config file: {0}".format(proginit.globalconffile) "loading config file: {0}".format(proginit.globalconffile)
) )
self.globalconfig.read(proginit.globalconffile) self.globalconfig.read(proginit.globalconffile)
proginit.conf = self.globalconfig
# Merker für Subsystem-Neustart nach laden, vor setzen # Merker für Subsystem-Neustart nach laden, vor setzen
restart_plcmqtt = self._check_mustrestart_mqtt() restart_plcmqtt = self._check_mustrestart_mqtt()
@@ -213,6 +219,8 @@ class RevPiPyLoad():
self.globalconfig["DEFAULT"].get("plcprogram", "none.py") self.globalconfig["DEFAULT"].get("plcprogram", "none.py")
self.plcarguments = \ self.plcarguments = \
self.globalconfig["DEFAULT"].get("plcarguments", "") self.globalconfig["DEFAULT"].get("plcarguments", "")
self.plcworkdir_set_uid = self.globalconfig["DEFAULT"].getboolean(
"plcworkdir_set_uid", False)
self.plcuid = \ self.plcuid = \
self.globalconfig["DEFAULT"].getint("plcuid", 65534) self.globalconfig["DEFAULT"].getint("plcuid", 65534)
self.plcgid = \ self.plcgid = \
@@ -228,23 +236,17 @@ class RevPiPyLoad():
self.zeroonexit = \ self.zeroonexit = \
self.globalconfig["DEFAULT"].getboolean("zeroonexit", True) self.globalconfig["DEFAULT"].getboolean("zeroonexit", True)
# MTime für replace io übernehmen # Dateiveränderungen prüfen
mtime = 0 file_changed = False
if self.replace_ios_config: # Beide Funktionen müssen einmal aufgerufen werden
if os.access(self.replace_ios_config, os.R_OK | os.W_OK): if self.check_pictory_changed():
mtime = os.path.getmtime(self.replace_ios_config) file_changed = True
else: if self.check_replace_ios_changed():
proginit.logger.error( file_changed = True
"can not access (r/w) the replace_ios file '{0}' " if file_changed:
"using defaults".format(self.replace_ios_config)
)
self.replace_ios_config = ""
if self.replaceiosmtime != mtime:
# MQTT reload erforderlich
restart_plcmqtt = True restart_plcmqtt = True
restart_plcslave = True
self.replaceiosmtime = mtime restart_plcprogram = True
# Konfiguration verarbeiten [MQTT] # Konfiguration verarbeiten [MQTT]
self.mqtt = 0 self.mqtt = 0
@@ -328,6 +330,10 @@ class RevPiPyLoad():
) )
os.chdir(self.plcworkdir) os.chdir(self.plcworkdir)
# Workdirectory owner setzen
if self.plcworkdir_set_uid:
os.chown(self.plcworkdir, self.plcuid, -1)
# MQTT konfigurieren # MQTT konfigurieren
if restart_plcmqtt: if restart_plcmqtt:
self.stop_plcmqtt() self.stop_plcmqtt()
@@ -419,17 +425,18 @@ class RevPiPyLoad():
"revpimodio2: 'apt-get install python3-revpimodio2'" "revpimodio2: 'apt-get install python3-revpimodio2'"
"".format(min_revpimodio) "".format(min_revpimodio)
) )
try: else:
self.xml_ps = procimgserver.ProcimgServer( try:
self.xsrv, self.xml_ps = procimgserver.ProcimgServer(
None if not self.replace_ios_config self.xsrv,
else self.replace_ios_config, None if not self.replace_ios_config
) else self.replace_ios_config,
self.xsrv.register_function(1, self.xml_psstart, "psstart") )
self.xsrv.register_function(1, self.xml_psstop, "psstop") self.xsrv.register_function(1, self.xml_psstart, "psstart")
except Exception as e: self.xsrv.register_function(1, self.xml_psstop, "psstop")
self.xml_ps = None except Exception as e:
proginit.logger.error(e) self.xml_ps = None
proginit.logger.error(e)
# XML Modus 2 Einstellungen lesen und Programm herunterladen # XML Modus 2 Einstellungen lesen und Programm herunterladen
self.xsrv.register_function( self.xsrv.register_function(
@@ -592,6 +599,67 @@ class RevPiPyLoad():
proginit.logger.debug("leave RevPiPyLoad._signewlogfile()") proginit.logger.debug("leave RevPiPyLoad._signewlogfile()")
def check_pictory_changed(self):
"""Prueft ob sich die piCtory Datei veraendert hat.
@return True, wenn veraendert wurde"""
mtime = os.path.getmtime(proginit.pargs.configrsc)
if self.pictorymtime == mtime:
return False
self.pictorymtime = mtime
# TODO: Nur "Devices" list vergleich
with open(proginit.pargs.configrsc, "rb") as fh:
file_hash = md5(fh.read()).digest()
if picontrolserver.HASH_PICT == file_hash:
return False
picontrolserver.HASH_PICT = file_hash
return True
def check_replace_ios_changed(self):
"""Prueft ob sich die replace_ios.conf Datei veraendert hat (oder del).
@return True, wenn veraendert wurde"""
# Zugriffsrechte prüfen (pre-check für unten)
if self.replace_ios_config \
and not os.access(self.replace_ios_config, os.R_OK):
if not self.replaceiofail:
proginit.logger.error(
"can not access (r/w) the replace_ios file '{0}' "
"using defaults".format(self.replace_ios_config)
)
self.replaceiofail = True
else:
self.replaceiofail = False
if not self.replace_ios_config or self.replaceiofail:
# Dateipfad leer, prüfen ob es vorher einen gab
if self.replaceiosmtime > 0 \
or picontrolserver.HASH_RPIO != picontrolserver.HASH_NULL:
self.replaceiosmtime = 0
picontrolserver.HASH_RPIO = picontrolserver.HASH_NULL
return True
else:
mtime = os.path.getmtime(self.replace_ios_config)
if self.replaceiosmtime == mtime:
return False
self.replaceiosmtime = mtime
# TODO: Instanz von ConfigParser vergleichen
with open(self.replace_ios_config, "rb") as fh:
file_hash = md5(fh.read()).digest()
if picontrolserver.HASH_RPIO == file_hash:
return False
picontrolserver.HASH_RPIO = file_hash
return True
return False
def packapp(self, mode="tar", pictory=False): def packapp(self, mode="tar", pictory=False):
"""Erzeugt aus dem PLC-Programm ein TAR/Zip-File. """Erzeugt aus dem PLC-Programm ein TAR/Zip-File.
@@ -668,12 +736,43 @@ class RevPiPyLoad():
# mainloop # mainloop
while not self._exit: while not self._exit:
file_changed = False
# Neue Konfiguration laden # Neue Konfiguration laden
if self.evt_loadconfig.is_set(): if self.evt_loadconfig.is_set():
proginit.logger.info("got reqeust to reload config") proginit.logger.info("got reqeust to reload config")
self._loadconfig() self._loadconfig()
# Dateiveränderungen prüfen mit beiden Funktionen!
if self.check_pictory_changed():
file_changed = True
# Alle Verbindungen von ProcImgServer trennen
self.th_plcslave.disconnect_all()
proginit.logger.warning("piCtory configuration was changed")
if self.check_replace_ios_changed():
if not file_changed:
# Verbindungen von ProcImgServer trennen mit replace_ios
self.th_plcslave.disconnect_replace_ios()
file_changed = True
proginit.logger.warning("replace ios file was changed")
if file_changed:
# Auf Dateiveränderung reagieren
# MQTT Publisher neu laden
if self.mqtt and self.th_plcmqtt is not None:
self.th_plcmqtt.reload_revpimodio()
# XML Prozessabbildserver neu laden
if self.xml_ps is not None:
self.xml_psstop()
self.xml_ps.loadrevpimodio()
# Kein psstart um Reload im Client zu erzeugen
# MQTT Publisher Thread prüfen # MQTT Publisher Thread prüfen
if self.mqtt and self.th_plcmqtt is not None \ if self.mqtt and self.th_plcmqtt is not None \
and not self.th_plcmqtt.is_alive(): and not self.th_plcmqtt.is_alive():
@@ -687,27 +786,14 @@ class RevPiPyLoad():
# PLC Server Thread prüfen # PLC Server Thread prüfen
if self.plcslave and self.th_plcslave is not None \ if self.plcslave and self.th_plcslave is not None \
and not self.th_plcslave.is_alive(): and not self.th_plcslave.is_alive():
proginit.logger.warning( if not file_changed:
"restart plc slave after thread was not running" proginit.logger.warning(
) "restart plc slave after thread was not running"
)
self.th_plcslave = self._plcslave() self.th_plcslave = self._plcslave()
if self.th_plcslave is not None: if self.th_plcslave is not None:
self.th_plcslave.start() self.th_plcslave.start()
# piCtory auf Veränderung prüfen
if self.pictorymtime != os.path.getmtime(proginit.pargs.configrsc):
proginit.logger.warning("piCtory configuration was changed")
self.pictorymtime = os.path.getmtime(proginit.pargs.configrsc)
# MQTT Publisher neu laden
if self.mqtt and self.th_plcmqtt is not None:
self.th_plcmqtt.reload_revpimodio()
# XML Prozessabbildserver neu laden
if self.xml_ps is not None:
self.xml_psstop()
self.xml_ps.loadrevpimodio()
self.evt_loadconfig.wait(1) self.evt_loadconfig.wait(1)
proginit.logger.info("stopping revpipyload") proginit.logger.info("stopping revpipyload")
@@ -1082,6 +1168,7 @@ class RevPiPyLoad():
# conf-Datei schreiben # conf-Datei schreiben
with open(proginit.globalconffile, "w") as fh: with open(proginit.globalconffile, "w") as fh:
self.globalconfig.write(fh) self.globalconfig.write(fh)
proginit.conf = self.globalconfig
proginit.logger.info( proginit.logger.info(
"got new config and wrote it to {0}" "got new config and wrote it to {0}"
"".format(proginit.globalconffile) "".format(proginit.globalconffile)

View File

@@ -41,7 +41,7 @@ class TestSystem:
rpi = revpimodio2.RevPiModIO( rpi = revpimodio2.RevPiModIO(
configrsc=proginit.pargs.configrsc, configrsc=proginit.pargs.configrsc,
procimg=proginit.pargs.procimg, procimg=proginit.pargs.procimg,
monitoring=False, monitoring=True,
debug=True, debug=True,
replace_io_file=file, replace_io_file=file,
) )

View File

@@ -27,11 +27,11 @@ setup(
license="LGPLv3", license="LGPLv3",
name="revpipyload", name="revpipyload",
version="0.7.6", version="0.8.0",
scripts=["data/revpipyload"], scripts=["data/revpipyload"],
install_requires=["revpimodio2 >= 2.3.3"], install_requires=["revpimodio2 >= 2.4.1"],
python_requires=">=3.2", python_requires=">=3.2",
data_files=[ data_files=[

View File

@@ -1,5 +1,5 @@
[DEFAULT] [DEFAULT]
Debian-Version: 1 Debian-Version: 1
Depends3: python3-revpimodio2 (>= 2.2.5) Depends3: python3-revpimodio2 (>= 2.4.1)
Package: revpipyload Package: revpipyload
Suite: stable Suite: stable