Parameter replace_io_file hinzugefügt für IO replacement

Wenn replace_io_file verwendet wird, ist .replace_io gesperrt
Verarbeitung der Datei direkt beim Instanziieren
This commit is contained in:
2019-06-16 13:44:59 +02:00
parent 2e802544c9
commit 2dbd37f2e7
6 changed files with 154 additions and 99 deletions

View File

@@ -917,6 +917,13 @@ class IntIOReplaceable(IntIO):
>Python3 struct</a>
"""
# 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,

View File

@@ -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
)

View File

@@ -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 <class 'str'> / (IP, Port) <class 'tuple'>
@@ -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
)