From a13ba75bee6ecb62fa0df10b56f11a42e65faff5 Mon Sep 17 00:00:00 2001 From: NaruX Date: Mon, 10 Jun 2019 22:50:29 +0200 Subject: [PATCH 1/3] =?UTF-8?q?StructIO=20f=C3=BCr=20export=20erweitert=20?= =?UTF-8?q?Export=20und=20Importfunktionen=20f=C3=BCr=20ersetzte=20IOs=20h?= =?UTF-8?q?inzugef=C3=BCgt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- revpimodio2/io.py | 8 +++++- revpimodio2/modio.py | 65 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 9b62833..9dc7c4a 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -950,7 +950,7 @@ class StructIO(IOBase): """ __slots__ = "__frm", "_parentio_address", "_parentio_defaultvalue", \ - "_parentio_length" + "_parentio_length", "_parentio_name" def __init__(self, parentio, name, frm, **kwargs): """Erstellt einen IO mit struct-Formatierung. @@ -975,6 +975,9 @@ class StructIO(IOBase): raise ValueError("byteorder must be 'little' or 'big'") bofrm = "<" if byteorder == "little" else ">" + # Namen des parent fuer export merken + self._parentio_name = parentio._name + if frm == "?": bitaddress = kwargs.get("bit", 0) max_bits = parentio._length * 8 @@ -995,6 +998,9 @@ class StructIO(IOBase): else: bitaddress = "" bitlength = struct.calcsize(bofrm + frm) * 8 + self._parentio_address = None + self._parentio_defaultvalue = None + self._parentio_length = None # [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress] valuelist = [ diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 55f589a..418847b 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -5,6 +5,7 @@ __copyright__ = "Copyright (C) 2018 Sven Sager" __license__ = "LGPLv3" import warnings +from configparser import ConfigParser from json import load as jload from multiprocessing import cpu_count from os import access, F_OK, R_OK @@ -519,6 +520,36 @@ class RevPiModIO(object): if not self._monitoring: self.writeprocimg(dev) + def export_replaced_ios(self, filename): + """Exportiert ersetzte IOs dieser Instanz. + + Exportiert alle ersetzten IOs, welche mit .replace_io(...) angelegt + wurden. Die Datei kann z.B. fuer RevPiPyLoad verwndet werden um Daten + in den neuen Formaten per MQTT zu uebertragen oder mit RevPiPyControl + anzusehen. + + @param filename Dateiname fuer Exportdatei""" + acheck(str, filename=filename) + + cp = ConfigParser() + for io in self.io: + if isinstance(io, StructIO): + cp.add_section(io.name) + cp[io.name]["parentio_name"] = io._parentio_name + cp[io.name]["frm"] = io.frm + cp[io.name]["bmk"] = io.bmk + cp[io.name]["bitaddress"] = str(io._bitaddress) + cp[io.name]["byteorder"] = io._byteorder + cp[io.name]["defaultvalue"] = str(io.defaultvalue) + try: + with open(filename, "w") as fh: + cp.write(fh) + except Exception as e: + raise RuntimeError( + "could not write export file '{0}' | {1}" + "".format(filename, e) + ) + def get_jconfigrsc(self): """Laedt die piCtory Konfiguration und erstellt ein . @return der piCtory Konfiguration""" @@ -584,6 +615,39 @@ class RevPiModIO(object): signal(SIGINT, self.__evt_exit) signal(SIGTERM, self.__evt_exit) + def import_replaced_ios(self, filename): + """Importiert ersetzte IOs in diese Instanz. + + Importiert ersetzte IOs, welche vorher mit .export_replaced_ios(...) + in eine Datei exportiert worden sind. Diese IOs werden in dieser + Instanz wieder hergestellt. + + @param filename Dateiname der Exportdatei""" + acheck(str, filename=filename) + + cp = ConfigParser() + try: + with open(filename, "r") as fh: + cp.read_file(fh) + except Exception as e: + raise RuntimeError( + "could not read export file '{0}' | {1}" + "".format(filename, e) + ) + + for io in cp: + if io == "DEFAULT": + continue + + self.io[cp[io].get("parentio_name")].replace_io( + io, + frm=cp[io].get("frm"), + bmk=cp[io].get("bmk"), + bit=cp[io].getint("bitaddress"), + byteorder=cp[io].get("byteorder", "little"), + defaultvalue=cp[io].getint("defaultvalue") + ) + def mainloop(self, blocking=True, no_warn=False): """Startet den Mainloop mit Eventueberwachung. @@ -977,5 +1041,6 @@ from . import device as devicemodule from . import helper as helpermodule from . import summary as summarymodule from .io import IOList +from .io import StructIO from .netio import RevPiNetIODriver, RevPiNetIO From 2e802544c978f4f5b5de8f0a0b636d6174bd401a Mon Sep 17 00:00:00 2001 From: NaruX Date: Wed, 12 Jun 2019 17:18:15 +0200 Subject: [PATCH 2/3] Import und Export der Dateien verbessert --- doc/revpimodio2.io.html | 4 ++-- doc/revpimodio2.modio.html | 37 +++++++++++++++++++++++++++++++ eric-revpimodio2.api | 2 ++ revpimodio2.e4p | 4 ++-- revpimodio2/__init__.py | 2 +- revpimodio2/io.py | 5 +++-- revpimodio2/modio.py | 45 +++++++++++++++++++++++++++++++------- setup.py | 2 +- 8 files changed, 85 insertions(+), 16 deletions(-) diff --git a/doc/revpimodio2.io.html b/doc/revpimodio2.io.html index 7398e5f..0637b6f 100644 --- a/doc/revpimodio2.io.html +++ b/doc/revpimodio2.io.html @@ -1045,8 +1045,8 @@ struct formatierung (1 Zeichen) oder 'ANZAHLs' z.B. '8s' Weitere Parameter: - bmk: Bezeichnung fuer IO - bit: Registriert IO als am angegebenen Bit im Byte - - byteorder: Byteorder fuer IO, Standardwert vom ersetzter IO - - defaultvalue: Standardwert fuer IO, Standard vom ersetzter IO + - byteorder: Byteorder fuer IO, Standardwert vom ersetzten IO + - defaultvalue: Standardwert fuer IO, Standard vom ersetzten IO

diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html index fcca538..b7ce297 100644 --- a/doc/revpimodio2.modio.html +++ b/doc/revpimodio2.modio.html @@ -125,12 +125,18 @@ Methods

exit Beendet mainloop() und optional autorefresh. +export_replaced_ios +Exportiert ersetzte IOs dieser Instanz. + get_jconfigrsc Laedt die piCtory Konfiguration und erstellt ein . handlesignalend Signalhandler fuer Programmende verwalten. +import_replaced_ios +Importiert ersetzte IOs in diese Instanz. + mainloop Startet den Mainloop mit Eventueberwachung. @@ -411,6 +417,22 @@ Beendet mainloop() und optional autorefresh.
Entfernt auch alle Devices aus autorefresh
+ +

+RevPiModIO.export_replaced_ios

+export_replaced_ios(filename) +

+Exportiert ersetzte IOs dieser Instanz. +

+ Exportiert alle ersetzten IOs, welche mit .replace_io(...) angelegt + wurden. Die Datei kann z.B. fuer RevPiPyLoad verwndet werden um Daten + in den neuen Formaten per MQTT zu uebertragen oder mit RevPiPyControl + anzusehen. +

+
filename
+
+Dateiname fuer Exportdatei +

RevPiModIO.get_jconfigrsc

@@ -449,6 +471,21 @@ Signalhandler fuer Programmende verwalten. Funktion wird nach dem letzten Lesen der Inputs ausgefuehrt, gefolgt vom letzten Schreiben der Outputs + +

+RevPiModIO.import_replaced_ios

+import_replaced_ios(filename) +

+Importiert ersetzte IOs in diese Instanz. +

+ Importiert ersetzte IOs, welche vorher mit .export_replaced_ios(...) + in eine Datei exportiert worden sind. Diese IOs werden in dieser + Instanz wieder hergestellt. +

+
filename
+
+Dateiname der Exportdatei +

RevPiModIO.mainloop

diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index 98bbf09..b580270 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -159,8 +159,10 @@ revpimodio2.modio.RevPiModIO.configrsc?7 revpimodio2.modio.RevPiModIO.cycleloop?4(func, cycletime=50) revpimodio2.modio.RevPiModIO.cycletime?7 revpimodio2.modio.RevPiModIO.exit?4(full=True) +revpimodio2.modio.RevPiModIO.export_replaced_ios?4(filename) revpimodio2.modio.RevPiModIO.get_jconfigrsc?4() revpimodio2.modio.RevPiModIO.handlesignalend?4(cleanupfunc=None) +revpimodio2.modio.RevPiModIO.import_replaced_ios?4(filename) revpimodio2.modio.RevPiModIO.ioerrors?7 revpimodio2.modio.RevPiModIO.length?7 revpimodio2.modio.RevPiModIO.mainloop?4(blocking=True, no_warn=False) diff --git a/revpimodio2.e4p b/revpimodio2.e4p index 35a99a8..816e923 100644 --- a/revpimodio2.e4p +++ b/revpimodio2.e4p @@ -1,7 +1,7 @@ - + en_US @@ -9,7 +9,7 @@ Python3 Console Das Modul stellt alle Devices und IOs aus der piCtory Konfiguration in Python3 zur Verfügung. Es ermöglicht den direkten Zugriff auf die Werte über deren vergebenen Namen. Lese- und Schreibaktionen mit dem Prozessabbild werden von dem Modul selbst verwaltet, ohne dass sich der Programmierer um Offsets und Adressen kümmern muss. Für die Gatewaymodule wie ModbusTCP oder Profinet sind eigene 'Inputs' und 'Outputs' über einen bestimmten Adressbereich definierbar. Auf diese IOs kann mit Python3 über den Namen direkt auf die Werte zugegriffen werden. - 2.3.2 + 2.3.3 Sven Sager akira@narux.de diff --git a/revpimodio2/__init__.py b/revpimodio2/__init__.py index b435a20..26c7636 100644 --- a/revpimodio2/__init__.py +++ b/revpimodio2/__init__.py @@ -22,7 +22,7 @@ __author__ = "Sven Sager " __copyright__ = "Copyright (C) 2018 Sven Sager" __license__ = "LGPLv3" __name__ = "revpimodio2" -__version__ = "2.3.2" +__version__ = "2.3.3" # Global package values OFF = 0 diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 9dc7c4a..3b0b9ca 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -961,8 +961,8 @@ class StructIO(IOBase): @param kwargs Weitere Parameter: - bmk: Bezeichnung fuer IO - bit: Registriert IO als am angegebenen Bit im Byte - - byteorder: Byteorder fuer IO, Standardwert vom ersetzter IO - - defaultvalue: Standardwert fuer IO, Standard vom ersetzter IO + - byteorder: Byteorder fuer IO, Standardwert vom ersetzten IO + - defaultvalue: Standardwert fuer IO, Standard vom ersetzten IO """ # Structformatierung prüfen @@ -1005,6 +1005,7 @@ class StructIO(IOBase): # [name,default,anzbits,adressbyte,export,adressid,bmk,bitaddress] valuelist = [ name, + # Darf nur bei StructIO None sein, wird nur dann berechnet kwargs.get("defaultvalue", None), bitlength, parentio._slc_address.start, diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 418847b..306f75c 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -534,13 +534,20 @@ class RevPiModIO(object): cp = ConfigParser() for io in self.io: if isinstance(io, StructIO): + + # Required values cp.add_section(io.name) - cp[io.name]["parentio_name"] = io._parentio_name + cp[io.name]["replace"] = io._parentio_name cp[io.name]["frm"] = io.frm - cp[io.name]["bmk"] = io.bmk - cp[io.name]["bitaddress"] = str(io._bitaddress) + + # Optional values + if io._bitaddress >= 0: + cp[io.name]["bitaddress"] = str(io._bitaddress) cp[io.name]["byteorder"] = io._byteorder cp[io.name]["defaultvalue"] = str(io.defaultvalue) + if io.bmk != "": + cp[io.name]["bmk"] = io.bmk + try: with open(filename, "w") as fh: cp.write(fh) @@ -625,6 +632,7 @@ class RevPiModIO(object): @param filename Dateiname der Exportdatei""" acheck(str, filename=filename) + # Load config file cp = ConfigParser() try: with open(filename, "r") as fh: @@ -635,17 +643,38 @@ class RevPiModIO(object): "".format(filename, e) ) + # Pre-check for io in cp: if io == "DEFAULT": continue - self.io[cp[io].get("parentio_name")].replace_io( + do_replace_io = cp[io].get("replace", "") + if do_replace_io not in self.io: + raise RuntimeError( + "can not find io '{0}' to replace".format(do_replace_io) + ) + + # Replace IOs + for io in cp: + if io == "DEFAULT": + continue + + replace_io = cp[io].get("replace", "") + replace_frm = cp[io].get("frm") + + # Convert defaultvalue from config file + if replace_frm == "?": + replace_defaultvalue = cp[io].getboolean("defaultvalue") + else: + replace_defaultvalue = cp[io].getint("defaultvalue") + + self.io[replace_io].replace_io( io, - frm=cp[io].get("frm"), - bmk=cp[io].get("bmk"), - bit=cp[io].getint("bitaddress"), + frm=replace_frm, + bmk=cp[io].get("bmk", ""), + bit=cp[io].getint("bitaddress", 0), byteorder=cp[io].get("byteorder", "little"), - defaultvalue=cp[io].getint("defaultvalue") + defaultvalue=replace_defaultvalue ) def mainloop(self, blocking=True, no_warn=False): diff --git a/setup.py b/setup.py index dae3212..ed4e147 100644 --- a/setup.py +++ b/setup.py @@ -17,7 +17,7 @@ setup( license="LGPLv3", name="revpimodio2", - version="2.3.2", + version="2.3.3", packages=["revpimodio2"], python_requires="~=3.2", From 2dbd37f2e7ce135b2d0abdfeff8e7e810b6e16d2 Mon Sep 17 00:00:00 2001 From: NaruX Date: Sun, 16 Jun 2019 13:44:59 +0200 Subject: [PATCH 3/3] =?UTF-8?q?Parameter=20replace=5Fio=5Ffile=20hinzugef?= =?UTF-8?q?=C3=BCgt=20f=C3=BCr=20IO=20replacement=20Wenn=20replace=5Fio=5F?= =?UTF-8?q?file=20verwendet=20wird,=20ist=20.replace=5Fio=20gesperrt=20Ver?= =?UTF-8?q?arbeitung=20der=20Datei=20direkt=20beim=20Instanziieren?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- doc/revpimodio2.modio.html | 42 +++++----- doc/revpimodio2.netio.html | 9 +- eric-revpimodio2.api | 14 ++-- revpimodio2/io.py | 7 ++ revpimodio2/modio.py | 163 +++++++++++++++++++++++-------------- revpimodio2/netio.py | 18 ++-- 6 files changed, 154 insertions(+), 99 deletions(-) diff --git a/doc/revpimodio2.modio.html b/doc/revpimodio2.modio.html index b7ce297..2841f45 100644 --- a/doc/revpimodio2.modio.html +++ b/doc/revpimodio2.modio.html @@ -77,6 +77,9 @@ Methods _configure Verarbeitet die piCtory Konfigurationsdatei. +_configure_replace_io +Importiert ersetzte IOs in diese Instanz. + _create_myfh Erstellt FileObject mit Pfad zum procimg. @@ -134,9 +137,6 @@ Methods handlesignalend Signalhandler fuer Programmende verwalten. -import_replaced_ios -Importiert ersetzte IOs in diese Instanz. - mainloop Startet den Mainloop mit Eventueberwachung. @@ -164,7 +164,7 @@ Static Methods

RevPiModIO (Constructor)

-RevPiModIO(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False) +RevPiModIO(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None)

Instantiiert die Grundfunktionen.

@@ -189,6 +189,9 @@ Laedt das Modul als Simulator und vertauscht IOs
debug
Gibt bei allen Fehlern komplette Meldungen aus +
replace_io_file
+
+Replace IO Konfiguration aus Datei laden

@@ -216,6 +219,18 @@ RevPiModIO._configure

_configure(jconfigrsc)

Verarbeitet die piCtory Konfigurationsdatei. +

+

+RevPiModIO._configure_replace_io

+_configure_replace_io() +

+Importiert ersetzte IOs in diese Instanz. +

+ Importiert ersetzte IOs, welche vorher mit .export_replaced_ios(...) + in eine Datei exportiert worden sind. Diese IOs werden in dieser + Instanz wiederhergestellt. +

+

RevPiModIO._create_myfh

@@ -471,21 +486,6 @@ Signalhandler fuer Programmende verwalten. Funktion wird nach dem letzten Lesen der Inputs ausgefuehrt, gefolgt vom letzten Schreiben der Outputs - -

-RevPiModIO.import_replaced_ios

-import_replaced_ios(filename) -

-Importiert ersetzte IOs in diese Instanz. -

- Importiert ersetzte IOs, welche vorher mit .export_replaced_ios(...) - in eine Datei exportiert worden sind. Diese IOs werden in dieser - Instanz wieder hergestellt. -

-
filename
-
-Dateiname der Exportdatei -

RevPiModIO.mainloop

@@ -632,7 +632,7 @@ Static Methods

RevPiModIODriver (Constructor)

-RevPiModIODriver(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False) +RevPiModIODriver(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None)

Instantiiert die Grundfunktionen.

@@ -692,7 +692,7 @@ Static Methods

RevPiModIOSelected (Constructor)

-RevPiModIOSelected(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False) +RevPiModIOSelected(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None)

Instantiiert nur fuer angegebene Devices die Grundfunktionen.

diff --git a/doc/revpimodio2.netio.html b/doc/revpimodio2.netio.html index eb4a16a..4c614a8 100644 --- a/doc/revpimodio2.netio.html +++ b/doc/revpimodio2.netio.html @@ -423,7 +423,7 @@ Static Methods

RevPiNetIO (Constructor)

-RevPiNetIO(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False) +RevPiNetIO(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None)

Instantiiert die Grundfunktionen.

@@ -445,6 +445,9 @@ Laedt das Modul als Simulator und vertauscht IOs
debug
Gibt bei allen Fehlern komplette Meldungen aus +
replace_io_file
+
+Replace IO Konfiguration aus Datei laden

@@ -536,7 +539,7 @@ Static Methods

RevPiNetIODriver (Constructor)

-RevPiNetIODriver(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False) +RevPiNetIODriver(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None)

Instantiiert die Grundfunktionen.

@@ -599,7 +602,7 @@ Static Methods

RevPiNetIOSelected (Constructor)

-RevPiNetIOSelected(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False) +RevPiNetIOSelected(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None)

Instantiiert nur fuer angegebene Devices die Grundfunktionen.

diff --git a/eric-revpimodio2.api b/eric-revpimodio2.api index b580270..270362a 100644 --- a/eric-revpimodio2.api +++ b/eric-revpimodio2.api @@ -141,6 +141,7 @@ revpimodio2.io.StructIO.signed?7 revpimodio2.io.StructIO.value?7 revpimodio2.io.StructIO?1(parentio, name, frm, **kwargs) revpimodio2.modio.RevPiModIO._configure?5(jconfigrsc) +revpimodio2.modio.RevPiModIO._configure_replace_io?5() revpimodio2.modio.RevPiModIO._create_myfh?5() revpimodio2.modio.RevPiModIO._get_configrsc?5() revpimodio2.modio.RevPiModIO._get_cycletime?5() @@ -162,7 +163,6 @@ revpimodio2.modio.RevPiModIO.exit?4(full=True) revpimodio2.modio.RevPiModIO.export_replaced_ios?4(filename) revpimodio2.modio.RevPiModIO.get_jconfigrsc?4() revpimodio2.modio.RevPiModIO.handlesignalend?4(cleanupfunc=None) -revpimodio2.modio.RevPiModIO.import_replaced_ios?4(filename) revpimodio2.modio.RevPiModIO.ioerrors?7 revpimodio2.modio.RevPiModIO.length?7 revpimodio2.modio.RevPiModIO.mainloop?4(blocking=True, no_warn=False) @@ -175,9 +175,9 @@ revpimodio2.modio.RevPiModIO.setdefaultvalues?4(device=None) revpimodio2.modio.RevPiModIO.simulator?7 revpimodio2.modio.RevPiModIO.syncoutputs?4(device=None) revpimodio2.modio.RevPiModIO.writeprocimg?4(device=None) -revpimodio2.modio.RevPiModIO?1(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False) -revpimodio2.modio.RevPiModIODriver?1(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False) -revpimodio2.modio.RevPiModIOSelected?1(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False) +revpimodio2.modio.RevPiModIO?1(autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None) +revpimodio2.modio.RevPiModIODriver?1(virtdev, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, debug=False, replace_io_file=None) +revpimodio2.modio.RevPiModIOSelected?1(deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, simulator=False, debug=False, replace_io_file=None) revpimodio2.netio.NetFH._connect?5() revpimodio2.netio.NetFH._direct_send?5(send_bytes, recv_count) revpimodio2.netio.NetFH.clear_dirtybytes?4(position=None) @@ -204,9 +204,9 @@ revpimodio2.netio.RevPiNetIO.disconnect?4() revpimodio2.netio.RevPiNetIO.get_jconfigrsc?4() revpimodio2.netio.RevPiNetIO.net_cleardefaultvalues?4(device=None) revpimodio2.netio.RevPiNetIO.net_setdefaultvalues?4(device=None) -revpimodio2.netio.RevPiNetIO?1(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False) -revpimodio2.netio.RevPiNetIODriver?1(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False) -revpimodio2.netio.RevPiNetIOSelected?1(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False) +revpimodio2.netio.RevPiNetIO?1(address, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None) +revpimodio2.netio.RevPiNetIODriver?1(address, virtdev, autorefresh=False, monitoring=False, syncoutputs=True, debug=False, replace_io_file=None) +revpimodio2.netio.RevPiNetIOSelected?1(address, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, simulator=False, debug=False, replace_io_file=None) revpimodio2.netio._sysdeldirty?8 revpimodio2.netio._sysexit?8 revpimodio2.netio._sysflush?8 diff --git a/revpimodio2/io.py b/revpimodio2/io.py index 3b0b9ca..ce3ba20 100644 --- a/revpimodio2/io.py +++ b/revpimodio2/io.py @@ -917,6 +917,13 @@ class IntIOReplaceable(IntIO): >Python3 struct """ + # Sperre prüfen + if self._parentdevice._modio._lck_replace_io: + raise RuntimeError( + "can not use this function while using an external " + "replace_io_file" + ) + # StructIO erzeugen io_new = StructIO( self, diff --git a/revpimodio2/modio.py b/revpimodio2/modio.py index 306f75c..589d297 100644 --- a/revpimodio2/modio.py +++ b/revpimodio2/modio.py @@ -34,11 +34,13 @@ class RevPiModIO(object): "_looprunning", "_lst_devselect", "_lst_refresh", "_maxioerrors", \ "_myfh", "_myfh_lck", "_monitoring", "_procimg", "_simulator", \ "_syncoutputs", "_th_mainloop", "_waitexit", \ - "core", "app", "device", "exitsignal", "io", "summary", "_debug" + "core", "app", "device", "exitsignal", "io", "summary", "_debug", \ + "_lck_replace_io", "_replace_io_file" def __init__( self, autorefresh=False, monitoring=False, syncoutputs=True, - procimg=None, configrsc=None, simulator=False, debug=False): + procimg=None, configrsc=None, simulator=False, debug=False, + replace_io_file=None): """Instantiiert die Grundfunktionen. @param autorefresh Wenn True, alle Devices zu autorefresh hinzufuegen @@ -48,6 +50,7 @@ class RevPiModIO(object): @param configrsc Abweichender Pfad zur piCtory Konfigurationsdatei @param simulator Laedt das Modul als Simulator und vertauscht IOs @param debug Gibt bei allen Fehlern komplette Meldungen aus + @param replace_io_file Replace IO Konfiguration aus Datei laden """ # Parameterprüfung @@ -56,7 +59,8 @@ class RevPiModIO(object): syncoutputs=syncoutputs, simulator=simulator, debug=debug ) acheck( - str, procimg_noneok=procimg, configrsc_noneok=configrsc + str, procimg_noneok=procimg, configrsc_noneok=configrsc, + replace_io_file_noneok=replace_io_file ) self._autorefresh = autorefresh @@ -76,12 +80,14 @@ class RevPiModIO(object): self._imgwriter = None self._ioerror = 0 self._length = 0 + self._lck_replace_io = False self._looprunning = False self._lst_devselect = [] self._lst_refresh = [] self._maxioerrors = 0 self._myfh = None self._myfh_lck = Lock() + self._replace_io_file = replace_io_file self._th_mainloop = None self._waitexit = Event() @@ -246,6 +252,11 @@ class RevPiModIO(object): Warning ) + # Replace IO aus Datei verarbeiten + if self._replace_io_file is not None: + self._configure_replace_io() + self._lck_replace_io = True + # ImgWriter erstellen self._imgwriter = helpermodule.ProcimgWriter(self) @@ -280,6 +291,88 @@ class RevPiModIO(object): # Summary Klasse instantiieren self.summary = summarymodule.Summary(jconfigrsc["Summary"]) + def _configure_replace_io(self): + """Importiert ersetzte IOs in diese Instanz. + + Importiert ersetzte IOs, welche vorher mit .export_replaced_ios(...) + in eine Datei exportiert worden sind. Diese IOs werden in dieser + Instanz wiederhergestellt. + + """ + cp = ConfigParser() + + try: + with open(self._replace_io_file, "r") as fh: + cp.read_file(fh) + except Exception as e: + raise RuntimeError( + "replace_io_file: could not read file '{0}' | {1}" + "".format(self._replace_io_file, e) + ) + + for io in cp: + if io == "DEFAULT": + continue + + # IO prüfen + parentio = cp[io].get("replace", "") + + # Funktionsaufruf vorbereiten + dict_replace = { + "frm": cp[io].get("frm"), + } + + # Convert defaultvalue from config file + if "defaultvalue" in cp[io]: + if dict_replace["frm"] == "?": + try: + dict_replace["defaultvalue"] = \ + cp[io].getboolean("defaultvalue") + except Exception: + raise ValueError( + "replace_io_file: could not convert '{0}' " + "defaultvalue '{1}' to boolean" + "".format(io, cp[io].get("defaultvalue")) + ) + else: + try: + dict_replace["defaultvalue"] = \ + cp[io].getint("defaultvalue") + except Exception: + raise ValueError( + "replace_io_file: could not convert '{0}' " + "defaultvalue '{1}' to integer" + "".format(io, cp[io].get("bit")) + ) + + # Get bitaddress from config file + if "bit" in cp[io]: + try: + dict_replace["bit"] = cp[io].getint("bit", 0) + except Exception: + raise ValueError( + "replace_io_file: could not convert '{0}' " + "bit '{1}' to integer" + "".format(io, cp[io].get("bit")) + ) + + # Sonstige Werte laden, wenn vorhanden + if "bmk" in cp[io]: + dict_replace["bmk"] = cp[io].get("bmk") + if "byteorder" in cp[io]: + dict_replace["byteorder"] = cp[io].get("byteorder") + + # IO ersetzen + try: + self.io[parentio].replace_io(name=io, **dict_replace) + except Exception as e: + raise RuntimeError( + "replace_io_file: can not replace '{0}' with '{1}' " + "| RevPiModIO message: {2}".format( + parentio, io, e + ) + ) + def _create_myfh(self): """Erstellt FileObject mit Pfad zum procimg. return FileObject""" @@ -622,61 +715,6 @@ class RevPiModIO(object): signal(SIGINT, self.__evt_exit) signal(SIGTERM, self.__evt_exit) - def import_replaced_ios(self, filename): - """Importiert ersetzte IOs in diese Instanz. - - Importiert ersetzte IOs, welche vorher mit .export_replaced_ios(...) - in eine Datei exportiert worden sind. Diese IOs werden in dieser - Instanz wieder hergestellt. - - @param filename Dateiname der Exportdatei""" - acheck(str, filename=filename) - - # Load config file - cp = ConfigParser() - try: - with open(filename, "r") as fh: - cp.read_file(fh) - except Exception as e: - raise RuntimeError( - "could not read export file '{0}' | {1}" - "".format(filename, e) - ) - - # Pre-check - for io in cp: - if io == "DEFAULT": - continue - - do_replace_io = cp[io].get("replace", "") - if do_replace_io not in self.io: - raise RuntimeError( - "can not find io '{0}' to replace".format(do_replace_io) - ) - - # Replace IOs - for io in cp: - if io == "DEFAULT": - continue - - replace_io = cp[io].get("replace", "") - replace_frm = cp[io].get("frm") - - # Convert defaultvalue from config file - if replace_frm == "?": - replace_defaultvalue = cp[io].getboolean("defaultvalue") - else: - replace_defaultvalue = cp[io].getint("defaultvalue") - - self.io[replace_io].replace_io( - io, - frm=replace_frm, - bmk=cp[io].get("bmk", ""), - bit=cp[io].getint("bitaddress", 0), - byteorder=cp[io].get("byteorder", "little"), - defaultvalue=replace_defaultvalue - ) - def mainloop(self, blocking=True, no_warn=False): """Startet den Mainloop mit Eventueberwachung. @@ -980,7 +1018,7 @@ class RevPiModIOSelected(RevPiModIO): def __init__( self, deviceselection, autorefresh=False, monitoring=False, syncoutputs=True, procimg=None, configrsc=None, - simulator=False, debug=False): + simulator=False, debug=False, replace_io_file=None): """Instantiiert nur fuer angegebene Devices die Grundfunktionen. Der Parameter deviceselection kann eine einzelne @@ -993,7 +1031,7 @@ class RevPiModIOSelected(RevPiModIO): """ super().__init__( autorefresh, monitoring, syncoutputs, procimg, configrsc, - simulator, debug + simulator, debug, replace_io_file ) # Device liste erstellen @@ -1047,7 +1085,8 @@ class RevPiModIODriver(RevPiModIOSelected): def __init__( self, virtdev, autorefresh=False, monitoring=False, - syncoutputs=True, procimg=None, configrsc=None, debug=False): + syncoutputs=True, procimg=None, configrsc=None, debug=False, + replace_io_file=None): """Instantiiert die Grundfunktionen. Parameter 'monitoring' und 'simulator' stehen hier nicht zur @@ -1060,7 +1099,7 @@ class RevPiModIODriver(RevPiModIOSelected): # Parent mit monitoring=False und simulator=True laden super().__init__( virtdev, autorefresh, False, syncoutputs, procimg, configrsc, - True, debug + True, debug, replace_io_file ) diff --git a/revpimodio2/netio.py b/revpimodio2/netio.py index 7ac2dc2..d8c899f 100644 --- a/revpimodio2/netio.py +++ b/revpimodio2/netio.py @@ -489,7 +489,8 @@ class RevPiNetIO(_RevPiModIO): def __init__( self, address, autorefresh=False, monitoring=False, - syncoutputs=True, simulator=False, debug=False): + syncoutputs=True, simulator=False, debug=False, + replace_io_file=None): """Instantiiert die Grundfunktionen. @param address: IP-Adresse / (IP, Port) @@ -498,6 +499,7 @@ class RevPiNetIO(_RevPiModIO): @param syncoutputs Aktuell gesetzte Outputs vom Prozessabbild einlesen @param simulator Laedt das Modul als Simulator und vertauscht IOs @param debug Gibt bei allen Fehlern komplette Meldungen aus + @param replace_io_file Replace IO Konfiguration aus Datei laden """ check_ip = compile( @@ -546,7 +548,8 @@ class RevPiNetIO(_RevPiModIO): "{0}:{1}".format(*self._address), None, simulator, - debug + debug, + replace_io_file ) # Netzwerkfilehandler anlegen @@ -657,7 +660,8 @@ class RevPiNetIOSelected(RevPiNetIO): def __init__( self, address, deviceselection, autorefresh=False, - monitoring=False, syncoutputs=True, simulator=False, debug=False): + monitoring=False, syncoutputs=True, simulator=False, debug=False, + replace_io_file=None): """Instantiiert nur fuer angegebene Devices die Grundfunktionen. Der Parameter deviceselection kann eine einzelne @@ -670,7 +674,8 @@ class RevPiNetIOSelected(RevPiNetIO): """ super().__init__( - address, autorefresh, monitoring, syncoutputs, simulator, debug + address, autorefresh, monitoring, syncoutputs, simulator, debug, + replace_io_file ) # Device liste erstellen @@ -724,7 +729,7 @@ class RevPiNetIODriver(RevPiNetIOSelected): def __init__( self, address, virtdev, autorefresh=False, monitoring=False, - syncoutputs=True, debug=False): + syncoutputs=True, debug=False, replace_io_file=None): """Instantiiert die Grundfunktionen. Parameter 'monitoring' und 'simulator' stehen hier nicht zur @@ -737,5 +742,6 @@ class RevPiNetIODriver(RevPiNetIOSelected): """ # Parent mit monitoring=False und simulator=True laden super().__init__( - address, virtdev, autorefresh, False, syncoutputs, True, debug + address, virtdev, autorefresh, False, syncoutputs, True, debug, + replace_io_file )