diff --git a/data/etc/revpipyload/revpipyload.conf b/data/etc/revpipyload/revpipyload.conf
index 8afb9c1..a518d5e 100644
--- a/data/etc/revpipyload/revpipyload.conf
+++ b/data/etc/revpipyload/revpipyload.conf
@@ -22,3 +22,14 @@ port = 55234
xmlrpc = 0
aclfile = /etc/revpipyload/aclxmlrpc.conf
bindip = *
+
+[MQTT]
+mqtt = 0
+basetopic = revpi/data
+sendinterval = 10
+host =
+port = 1883
+tls_set = 0
+username =
+password =
+client_id =
diff --git a/doc/index.html b/doc/index.html
index a43d5a3..2986894 100644
--- a/doc/index.html
+++ b/doc/index.html
@@ -13,7 +13,7 @@ Packages
@@ -27,6 +27,9 @@ Modules
logsystem
Modul fuer die Verwaltung der Logdateien.
+mqttserver
+Stellt die MQTT Uebertragung fuer IoT-Zwecke bereit.
+
picontrolserver
Modul fuer die Verwaltung der PLC-Slave Funktionen.
diff --git a/doc/mqttserver.html b/doc/mqttserver.html
new file mode 100644
index 0000000..aa97c35
--- /dev/null
+++ b/doc/mqttserver.html
@@ -0,0 +1,177 @@
+
+
+mqttserver
+
+
+
+
+mqttserver
+
+Stellt die MQTT Uebertragung fuer IoT-Zwecke bereit.
+
+
+Global Attributes
+
+
+Classes
+
+
+MqttServer
+Server fuer die Uebertragung des Prozessabbilds per MQTT.
+
+
+
+Functions
+
+
+
+MqttServer
+
+Server fuer die Uebertragung des Prozessabbilds per MQTT.
+
+
+Derived from
+Thread
+
+Class Attributes
+
+
+Class Methods
+
+
+Methods
+
+
+Static Methods
+
+
+
+MqttServer (Constructor)
+MqttServer (basetopic, sendinterval, host, port=1883, tls_set=False, username="", password=None, client_id="" )
+
+Init MqttServer class.
+
+basetopic
+
+Basis-Topic fuer Datenaustausch
+ sendinterval
+
+Prozessabbild alle n Sekunden senden
+ host
+
+Adresse des MQTT-Servers
+ port
+
+Portnummer des MQTT-Servers
+ keepalive
+
+MQTT Ping bei leerlauf
+ tls_set
+
+TLS fuer Verbindung zum MQTT-Server verwenden
+ username
+
+Optional Benutzername fuer MQTT-Server
+ password
+
+Optional Password fuer MQTT-Server
+ client_id
+
+MQTT ClientID, wenn leer automatisch random erzeugung
+
+
+
+MqttServer._get_procimglength
+_get_procimglength ( )
+
+Ermittelt aus piCtory Konfiguration die laenge.
+
+Returns:
+
+Laenge des Prozessabbilds
+
+
+
+MqttServer._on_connect
+_on_connect (client, userdata, flags, rc )
+
+Verbindung zu MQTT Broker.
+
+
+MqttServer._on_disconnect
+_on_disconnect (client, userdata, rc )
+
+Wertet Verbindungsabbruch aus.
+
+
+MqttServer._on_message
+_on_message (client, userdata, msg )
+
+Sendet piCtory Konfiguration.
+
+
+MqttServer._send_pictory_conf
+_send_pictory_conf ( )
+
+Sendet piCtory Konfiguration.
+
+
+MqttServer.newlogfile
+newlogfile ( )
+
+Konfiguriert die FileHandler auf neue Logdatei.
+
+
+MqttServer.run
+run ( )
+
+Startet die Uebertragung per MQTT.
+
+
+MqttServer.stop
+stop ( )
+
+Stoppt die Uebertragung per MQTT.
+
+
+
+
\ No newline at end of file
diff --git a/doc/revpipyload.html b/doc/revpipyload.html
index cda4677..149107e 100644
--- a/doc/revpipyload.html
+++ b/doc/revpipyload.html
@@ -9,8 +9,6 @@ revpipyload
Revolution Pi Python PLC Loader.
-Webpage: https://revpimodio.org/revpipyplc/
-
Stellt das RevPiPyLoad Programm bereit. Dieses Programm lauft als Daemon auf
dem Revolution Pi. Es stellt Funktionen bereit, die es ermoeglichen ein Python
Programm zu starten und fuehrt dessen Ausgaben in eine Logdatei. Die Logdaten
@@ -34,7 +32,7 @@ begrenzt werden!
Global Attributes
-__author__ __copyright__ __license__ __version__
+pyloadversion
Classes
@@ -89,6 +87,9 @@ Methods
_loadconfig
Load configuration file and setup modul.
+_plcmqtt
+Konfiguriert den MQTT-Thread fuer die Ausfuehrung.
+
_plcslave
Erstellt den PlcSlave-Server Thread.
@@ -113,6 +114,9 @@ Methods
stop
Stop revpipyload.
+stop_plcmqtt
+Beendet MQTT Sender.
+
stop_plcprogram
Beendet PLC Programm.
@@ -134,6 +138,15 @@ Methods
xml_getprocimg
Gibt die Rohdaten aus piControl0 zurueck.
+xml_mqttrunning
+Prueft ob MQTT Uebertragung noch lauft.
+
+xml_mqttstart
+Startet die MQTT Uebertragung.
+
+xml_mqttstop
+Stoppt die MQTT Uebertragung.
+
xml_plcdownload
Uebertraegt ein Archiv vom plcworkdir.
@@ -219,7 +232,18 @@ RevPiPyLoad._loadconfig
_loadconfig ( )
Load configuration file and setup modul.
-
+
+
+RevPiPyLoad._plcmqtt
+_plcmqtt ( )
+
+Konfiguriert den MQTT-Thread fuer die Ausfuehrung.
+
+Returns:
+
+MQTT-Thread Object or None
+
+
RevPiPyLoad._plcslave
_plcslave ( )
@@ -290,6 +314,12 @@ RevPiPyLoad.stop
stop ( )
Stop revpipyload.
+
+
+RevPiPyLoad.stop_plcmqtt
+stop_plcmqtt ( )
+
+Beendet MQTT Sender.
RevPiPyLoad.stop_plcprogram
@@ -352,6 +382,42 @@ Gibt die Rohdaten aus piControl0 zurueck.
xmlrpc.client.Binary()
+
+
+RevPiPyLoad.xml_mqttrunning
+xml_mqttrunning ( )
+
+Prueft ob MQTT Uebertragung noch lauft.
+
+Returns:
+
+True, wenn MQTT Uebertragung noch lauft
+
+
+
+RevPiPyLoad.xml_mqttstart
+xml_mqttstart ( )
+
+Startet die MQTT Uebertragung.
+
+Returns:
+
+Statuscode:
+ 0: erfolgreich gestartet
+ -1: Nicht aktiv in Konfiguration
+ -2: Laeuft bereits
+
+
+
+RevPiPyLoad.xml_mqttstop
+xml_mqttstop ( )
+
+Stoppt die MQTT Uebertragung.
+
+Returns:
+
+True, wenn stop erfolgreich
+
RevPiPyLoad.xml_plcdownload
diff --git a/eric-revpipyload.api b/eric-revpipyload.api
index d30697b..7e7e323 100644
--- a/eric-revpipyload.api
+++ b/eric-revpipyload.api
@@ -1,6 +1,3 @@
-helper.__author__?9
-helper.__copyright__?9
-helper.__license__?9
helper._setuprt?5(pid, evt_exit)
helper._zeroprocimg?5()
helper.refullmatch?4(regex, string)
@@ -15,9 +12,15 @@ logsystem.PipeLogwriter.newlogfile?4()
logsystem.PipeLogwriter.run?4()
logsystem.PipeLogwriter.stop?4()
logsystem.PipeLogwriter?1(logfilename)
-logsystem.__author__?9
-logsystem.__copyright__?9
-logsystem.__license__?9
+mqttserver.MqttServer._get_procimglength?5()
+mqttserver.MqttServer._on_connect?5(client, userdata, flags, rc)
+mqttserver.MqttServer._on_disconnect?5(client, userdata, rc)
+mqttserver.MqttServer._on_message?5(client, userdata, msg)
+mqttserver.MqttServer._send_pictory_conf?5()
+mqttserver.MqttServer.newlogfile?4()
+mqttserver.MqttServer.run?4()
+mqttserver.MqttServer.stop?4()
+mqttserver.MqttServer?1(basetopic, sendinterval, host, port=1883, tls_set=False, username="", password=None, client_id="")
picontrolserver.RevPiSlave.check_connectedacl?4()
picontrolserver.RevPiSlave.newlogfile?4()
picontrolserver.RevPiSlave.run?4()
@@ -26,9 +29,6 @@ picontrolserver.RevPiSlave?1(ipacl, port=55234)
picontrolserver.RevPiSlaveDev.run?4()
picontrolserver.RevPiSlaveDev.stop?4()
picontrolserver.RevPiSlaveDev?1(devcon, acl)
-picontrolserver.__author__?9
-picontrolserver.__copyright__?9
-picontrolserver.__license__?9
plcsystem.RevPiPlc.__get_autoreloaddelay?6()
plcsystem.RevPiPlc.__set_autoreloaddelay?6(value)
plcsystem.RevPiPlc._configureplw?5()
@@ -39,23 +39,14 @@ plcsystem.RevPiPlc.newlogfile?4()
plcsystem.RevPiPlc.run?4()
plcsystem.RevPiPlc.stop?4()
plcsystem.RevPiPlc?1(program, arguments, pversion)
-plcsystem.__author__?9
-plcsystem.__copyright__?9
-plcsystem.__license__?9
procimgserver.ProcimgServer.devices?4()
-procimgserver.ProcimgServer.ios?4(iotype)
+procimgserver.ProcimgServer.ios?4(type)
procimgserver.ProcimgServer.loadrevpimodio?4()
procimgserver.ProcimgServer.setvalue?4(device, io, value)
procimgserver.ProcimgServer.start?4()
procimgserver.ProcimgServer.stop?4()
procimgserver.ProcimgServer.values?4()
procimgserver.ProcimgServer?1(xmlserver)
-procimgserver.__author__?9
-procimgserver.__copyright__?9
-procimgserver.__license__?9
-proginit.__author__?9
-proginit.__copyright__?9
-proginit.__license__?9
proginit.cleanup?4()
proginit.configure?4()
proginit.forked?7
@@ -70,6 +61,7 @@ proginit.startdir?7
revpipyload.RevPiPyLoad._check_mustrestart_plcprogram?5()
revpipyload.RevPiPyLoad._check_mustrestart_plcslave?5()
revpipyload.RevPiPyLoad._loadconfig?5()
+revpipyload.RevPiPyLoad._plcmqtt?5()
revpipyload.RevPiPyLoad._plcslave?5()
revpipyload.RevPiPyLoad._plcthread?5()
revpipyload.RevPiPyLoad._sigexit?5(signum, frame)
@@ -79,6 +71,7 @@ revpipyload.RevPiPyLoad.packapp?4(mode="tar", pictory=False)
revpipyload.RevPiPyLoad.root?7
revpipyload.RevPiPyLoad.start?4()
revpipyload.RevPiPyLoad.stop?4()
+revpipyload.RevPiPyLoad.stop_plcmqtt?4()
revpipyload.RevPiPyLoad.stop_plcprogram?4()
revpipyload.RevPiPyLoad.stop_plcslave?4()
revpipyload.RevPiPyLoad.stop_xmlrpcserver?4()
@@ -86,6 +79,9 @@ revpipyload.RevPiPyLoad.xml_getconfig?4()
revpipyload.RevPiPyLoad.xml_getfilelist?4()
revpipyload.RevPiPyLoad.xml_getpictoryrsc?4()
revpipyload.RevPiPyLoad.xml_getprocimg?4()
+revpipyload.RevPiPyLoad.xml_mqttrunning?4()
+revpipyload.RevPiPyLoad.xml_mqttstart?4()
+revpipyload.RevPiPyLoad.xml_mqttstop?4()
revpipyload.RevPiPyLoad.xml_plcdownload?4(mode="tar", pictory=False)
revpipyload.RevPiPyLoad.xml_plcexitcode?4()
revpipyload.RevPiPyLoad.xml_plcrunning?4()
@@ -102,13 +98,7 @@ revpipyload.RevPiPyLoad.xml_reload?4()
revpipyload.RevPiPyLoad.xml_setconfig?4(dc, loadnow=False)
revpipyload.RevPiPyLoad.xml_setpictoryrsc?4(filebytes, reset=False)
revpipyload.RevPiPyLoad?1()
-revpipyload.__author__?9
-revpipyload.__copyright__?9
-revpipyload.__license__?9
-revpipyload.__version__?9
-revpipyload.shared.__author__?9
-revpipyload.shared.__copyright__?9
-revpipyload.shared.__license__?9
+revpipyload.pyloadversion?7
revpipyload.shared.ipaclmanager.IpAclManager.__get_acl?6()
revpipyload.shared.ipaclmanager.IpAclManager.__get_filename?6()
revpipyload.shared.ipaclmanager.IpAclManager.__get_regex_acl?6()
@@ -122,10 +112,6 @@ revpipyload.shared.ipaclmanager.IpAclManager.loadaclfile?4(filename)
revpipyload.shared.ipaclmanager.IpAclManager.regex_acl?7
revpipyload.shared.ipaclmanager.IpAclManager.writeaclfile?4(filename=None, aclname=None)
revpipyload.shared.ipaclmanager.IpAclManager?1(minlevel, maxlevel, acl=None)
-revpipyload.shared.ipaclmanager.__author__?9
-revpipyload.shared.ipaclmanager.__copyright__?9
-revpipyload.shared.ipaclmanager.__license__?9
-revpipyload.shared.ipaclmanager.__version__?9
revpipyload.shared.ipaclmanager.refullmatch?4(regex, string)
xrpcserver.SaveXMLRPCRequestHandler.parse_request?4()
xrpcserver.SaveXMLRPCServer._dispatch?5(method, params)
@@ -134,6 +120,3 @@ xrpcserver.SaveXMLRPCServer.register_function?4(acl_level, function, name=None)
xrpcserver.SaveXMLRPCServer.start?4()
xrpcserver.SaveXMLRPCServer.stop?4()
xrpcserver.SaveXMLRPCServer?1(addr, logRequests=True, allow_none=False, ipacl=None)
-xrpcserver.__author__?9
-xrpcserver.__copyright__?9
-xrpcserver.__license__?9
diff --git a/eric-revpipyload.bas b/eric-revpipyload.bas
index 9333951..0fe2ca4 100644
--- a/eric-revpipyload.bas
+++ b/eric-revpipyload.bas
@@ -1,3 +1,4 @@
+MqttServer Thread
PipeLogwriter Thread
RevPiPlc Thread
RevPiSlave Thread
diff --git a/revpipyload.e4p b/revpipyload.e4p
index 6b48e94..477f006 100644
--- a/revpipyload.e4p
+++ b/revpipyload.e4p
@@ -9,7 +9,7 @@
Python3
Console
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.
- 0.6.8
+ 0.7.0
Sven Sager
akira@narux.de
@@ -22,7 +22,7 @@
revpipyload/proginit.py
revpipyload/revpipyload.py
revpipyload/shared/__init__.py
- revpipyload/shared/ipaclmanager.py
+ revpipyload/mqttserver.py
revpipyload/xrpcserver.py
setup.py
diff --git a/revpipyload/mqttserver.py b/revpipyload/mqttserver.py
new file mode 100644
index 0000000..c198e4f
--- /dev/null
+++ b/revpipyload/mqttserver.py
@@ -0,0 +1,199 @@
+# -*- coding: utf-8 -*-
+#
+# RevPiPyLoad
+#
+# Webpage: https://revpimodio.org/revpipyplc/
+# (c) Sven Sager, License: LGPLv3
+#
+"""Stellt die MQTT Uebertragung fuer IoT-Zwecke bereit."""
+import proginit
+from json import load as jload
+from ssl import CERT_NONE
+from paho.mqtt.client import Client
+from threading import Thread, Event
+
+
+class MqttServer(Thread):
+
+ """Server fuer die Uebertragung des Prozessabbilds per MQTT."""
+
+ def __init__(
+ self, basetopic, sendinterval, host, port=1883,
+ tls_set=False, username="", password=None, client_id=""):
+ """Init MqttServer class.
+
+ @param basetopic Basis-Topic fuer Datenaustausch
+ @param sendinterval Prozessabbild alle n Sekunden senden
+ @param host Adresse des MQTT-Servers
+ @param port Portnummer des MQTT-Servers
+ @param keepalive MQTT Ping bei leerlauf
+ @param tls_set TLS fuer Verbindung zum MQTT-Server verwenden
+ @param username Optional Benutzername fuer MQTT-Server
+ @param password Optional Password fuer MQTT-Server
+ @param client_id MQTT ClientID, wenn leer automatisch random erzeugung
+
+ """
+ # TODO: Parameterprüfung
+
+ super().__init__()
+
+ # Klassenvariablen
+ self.__exit = False
+ self._evt_data = Event()
+ self._host = host
+ self._procimglength = self._get_procimglength()
+ self._port = port
+ self._sendinterval = sendinterval
+
+ # Topics konfigurieren
+ self._mqtt_picontrol = "{}/picontrol".format(basetopic)
+ self._mqtt_pictory = "{}/pictory".format(basetopic)
+ self._mqtt_sendpictory = "{}/needpictory".format(basetopic)
+
+ self._mq = Client(client_id)
+ if username != "":
+ self._mq.username_pw_set(username, password)
+ if tls_set:
+ self._mq.tls_set(cert_reqs=CERT_NONE)
+ self._mq.tls_insecure_set(True)
+
+ # Handler konfigurieren
+ self._mq.on_connect = self._on_connect
+ self._mq.on_message = self._on_message
+
+ def _get_procimglength(self):
+ """Ermittelt aus piCtory Konfiguration die laenge.
+ @return Laenge des Prozessabbilds """
+ try:
+ with open(proginit.pargs.configrsc, "r") as fh:
+ rsc = jload(fh)
+ except:
+ return 4096
+
+ length = 0
+
+ # piCtory Config prüfen
+ if "Devices" not in rsc:
+ return 0
+
+ # Letzes piCtory Device laden
+ last_dev = rsc["Devices"].pop()
+ length += last_dev["offset"]
+
+ # bei mem beginnen, weil nur der höchste IO benötigt wird
+ for type_iom in ["mem", "out", "inp"]:
+ lst_iom = sorted(
+ last_dev[type_iom],
+ key=lambda x: int(x),
+ reverse=True
+ )
+
+ if len(lst_iom) > 0:
+ # Daten des letzen IOM auswerten
+ last_iom = last_dev[type_iom][str(lst_iom[0])]
+ bitlength = int(last_iom[2])
+ length += int(last_iom[3])
+ length += 1 if bitlength == 1 else int(bitlength / 8)
+ break
+
+ return length
+
+ def _on_connect(self, client, userdata, flags, rc):
+ """Verbindung zu MQTT Broker."""
+ if rc > 0:
+ proginit.warning("can not connect to mqtt broker - will retry")
+ else:
+ # piCtory übertragen um alle RevPiMqttIO zu benachrichtigen
+ self._send_pictory_conf()
+
+ # Subscribe piCtory Anforderung
+ client.subscribe(self._mqtt_sendpictory)
+
+ def _on_disconnect(self, client, userdata, rc):
+ """Wertet Verbindungsabbruch aus."""
+ if rc != 0:
+ proginit.warning(
+ "unexpected disconnection from mqtt broker - "
+ "will try to reconnect"
+ )
+
+ def _on_message(self, client, userdata, msg):
+ """Sendet piCtory Konfiguration."""
+
+ # piCtory Konfiguration senden
+ self._send_pictory_conf()
+
+ # Prozessabbild senden
+ self._evt_data.set()
+
+ def _send_pictory_conf(self):
+ """Sendet piCtory Konfiguration."""
+ with open(proginit.pargs.configrsc, "rb") as fh:
+ self._mq.publish(self._mqtt_pictory, fh.read())
+
+ def newlogfile(self):
+ """Konfiguriert die FileHandler auf neue Logdatei."""
+ pass
+
+ def run(self):
+ """Startet die Uebertragung per MQTT."""
+ proginit.logger.debug("enter MqttServer.start()")
+
+ # Prozessabbild öffnen
+ try:
+ fh_proc = open(proginit.pargs.procimg, "r+b", 0)
+ except:
+ fh_proc = None
+ self.__exit = True
+ proginit.logger.error(
+ "can not open process image {}".format(proginit.pargs.procimg)
+ )
+
+ # MQTT verbinden
+ self._mq.connect_async(self._host, self._port, keepalive=60)
+ self._mq.loop_start()
+
+ # mainloop
+ buff = b''
+ err_count = 0
+ while not self.__exit:
+ self._evt_data.clear()
+
+ # Prozessabbild lesen
+ try:
+ fh_proc.seek(0)
+ buff = fh_proc.read(self._procimglength)
+ if err_count > 0:
+ proginit.warning(
+ "resume mqtt publishing after {} errors on "
+ "processimage".format(err_count)
+ )
+ err_count = 0
+ except IOError:
+ if err_count == 0:
+ proginit.logger.error(
+ "could not read process image for mqtt publishing"
+ )
+ err_count += 1
+ else:
+ # Prozessabbild übertragen
+ self._mq.publish(self._mqtt_picontrol, buff)
+
+ self._evt_data.wait(self._sendinterval)
+
+ # MQTT trennen
+ self._mq.loop_stop()
+ self._mq.disconnect()
+
+ # FileHandler schließen
+ if fh_proc is not None:
+ fh_proc.close()
+
+ proginit.logger.debug("leave MqttServer.start()")
+
+ def stop(self):
+ """Stoppt die Uebertragung per MQTT."""
+ proginit.logger.debug("enter MqttServer.stop()")
+ self.__exit = True
+ self._evt_data.set()
+ proginit.logger.debug("leave MqttServer.stop()")
diff --git a/revpipyload/plcsystem.py b/revpipyload/plcsystem.py
index 43fd6d9..c02e045 100644
--- a/revpipyload/plcsystem.py
+++ b/revpipyload/plcsystem.py
@@ -221,7 +221,12 @@ class RevPiPlc(Thread):
# Prozess beenden
count = 0
proginit.logger.info("term plc program {0}".format(self._program))
- self._procplc.terminate()
+ try:
+ self._procplc.terminate()
+ except ProcessLookupError:
+ proginit.logger.error("plc program was terminated unexpectedly")
+ proginit.logger.debug("leave RevPiPlc.stop()")
+ return
while self._procplc.poll() is None and count < 10:
count += 1
diff --git a/revpipyload/revpipyload.py b/revpipyload/revpipyload.py
index ff3835f..2be8733 100755
--- a/revpipyload/revpipyload.py
+++ b/revpipyload/revpipyload.py
@@ -78,6 +78,7 @@ class RevPiPyLoad():
self.xmlrpcacl = IpAclManager(minlevel=0, maxlevel=4)
# Threads/Prozesse
+ self.th_mqtt = None
self.th_plcslave = None
self.plc = None
@@ -144,6 +145,7 @@ class RevPiPyLoad():
proginit.logger.debug("enter RevPiPyLoad._loadconfig()")
# Subsysteme herunterfahren
+ self.stop_plcmqtt()
self.stop_xmlrpcserver()
# Konfigurationsdatei laden
@@ -182,6 +184,28 @@ class RevPiPyLoad():
self.zeroonexit = \
self.globalconfig["DEFAULT"].getboolean("zeroonexit", True)
+ # Konfiguration verarbeiten [MQTT]
+ self.mqtt = 0
+ if "MQTT" in self.globalconfig:
+ self.mqtt = \
+ int(self.globalconfig["MQTT"].get("mqtt", 0))
+ self.mqttbasetopic = \
+ self.globalconfig["MQTT"].get("basetopic", "")
+ self.mqttsendinterval = \
+ int(self.globalconfig["MQTT"].get("sendinterval", 15))
+ self.mqtthost = \
+ self.globalconfig["MQTT"].get("host", "")
+ self.mqttport = \
+ int(self.globalconfig["MQTT"].get("port", 1883))
+ self.mqtttls_set = \
+ int(self.globalconfig["MQTT"].get("tls_set", 0))
+ self.mqttusername = \
+ self.globalconfig["MQTT"].get("username", "")
+ self.mqttpassword = \
+ self.globalconfig["MQTT"].get("password", "")
+ self.mqttclient_id = \
+ self.globalconfig["MQTT"].get("client_id", "")
+
# Konfiguration verarbeiten [PLCSLAVE]
self.plcslave = False
if "PLCSLAVE" in self.globalconfig:
@@ -238,6 +262,12 @@ class RevPiPyLoad():
)
os.chdir(self.plcworkdir)
+ # MQTT konfigurieren
+ self.th_mqtt = self._plcmqtt()
+ if self.th_mqtt is not None and not self._exit:
+ proginit.logger.info("start mqtt publisher")
+ self.th_mqtt.start()
+
# PLC Programm konfigurieren
if restart_plcprogram:
self.stop_plcprogram()
@@ -303,6 +333,8 @@ class RevPiPyLoad():
0, self.xml_plcstop, "plcstop")
self.xsrv.register_function(
0, self.xml_reload, "reload")
+ self.xsrv.register_function(
+ 0, self.xml_mqttrunning, "mqttrunning")
self.xsrv.register_function(
0, self.xml_plcslaverunning, "plcslaverunning")
@@ -343,6 +375,10 @@ class RevPiPyLoad():
lambda: os.system(proginit.picontrolreset),
"resetpicontrol"
)
+ self.xsrv.register_function(
+ 3, self.xml_mqttstart, "mqttstart")
+ self.xsrv.register_function(
+ 3, self.xml_mqttstop, "mqttstop")
self.xsrv.register_function(
3, self.xml_plcslavestart, "plcslavestart")
self.xsrv.register_function(
@@ -366,6 +402,32 @@ class RevPiPyLoad():
proginit.logger.debug("leave RevPiPyLoad._loadconfig()")
+ def _plcmqtt(self):
+ """Konfiguriert den MQTT-Thread fuer die Ausfuehrung.
+ @return MQTT-Thread Object or None"""
+ proginit.logger.debug("enter RevPiPyLoad._plcmqtt()")
+
+ th_plc = None
+ if self.mqtt:
+ try:
+ from mqttserver import MqttServer
+ th_plc = MqttServer(
+ self.mqttbasetopic,
+ self.mqttsendinterval,
+ self.mqtthost,
+ self.mqttport,
+ self.mqtttls_set,
+ self.mqttusername,
+ self.mqttpassword,
+ self.mqttclient_id
+ )
+ except:
+ # TODO: Fehlermeldung ausgeben bezüglich paho.mqtt
+ pass
+
+ proginit.logger.debug("leave RevPiPyLoad._plcmqtt()")
+ return th_plc
+
def _plcthread(self):
"""Konfiguriert den PLC-Thread fuer die Ausfuehrung.
@return PLC-Thread Object or None"""
@@ -501,8 +563,12 @@ class RevPiPyLoad():
proginit.logger.info("start xmlrpc-server")
self.xsrv.start()
- if self.plcslave:
- # Slaveausfuehrung übergeben
+ # MQTT Uebertragung starten
+ if self.th_mqtt is not None:
+ self.th_mqtt.start()
+
+ # Slaveausfuehrung übergeben
+ if self.th_plcslave is not None:
self.th_plcslave.start()
# PLC Programm automatisch starten
@@ -517,6 +583,8 @@ class RevPiPyLoad():
proginit.logger.info("got reqeust to reload config")
self._loadconfig()
+ # TODO: MQTT prüfen und neu starten
+
# PLC Server Thread prüfen
if self.plcslave and self.th_plcslave is not None \
and not self.th_plcslave.is_alive():
@@ -541,8 +609,9 @@ class RevPiPyLoad():
proginit.logger.info("stopping revpipyload")
# Alle Sub-Systeme beenden
- self.stop_plcslave()
self.stop_plcprogram()
+ self.stop_plcmqtt()
+ self.stop_plcslave()
self.stop_xmlrpcserver()
# Logreader schließen
@@ -556,6 +625,18 @@ class RevPiPyLoad():
self._exit = True
proginit.logger.debug("leave RevPiPyLoad.stop()")
+ def stop_plcmqtt(self):
+ """Beendet MQTT Sender."""
+ proginit.logger.debug("enter RevPiPyLoad.stop_plcmqtt()")
+
+ if self.th_mqtt is not None and self.th_mqtt.is_alive():
+ proginit.logger.info("stopping mqtt thread")
+ self.th_mqtt.stop()
+ self.th_mqtt.join()
+ proginit.logger.debug("mqtt thread successfully closed")
+
+ proginit.logger.debug("leave RevPiPyLoad.stop_plcmqtt()")
+
def stop_plcprogram(self):
"""Beendet PLC Programm."""
proginit.logger.debug("enter RevPiPyLoad.stop_plcprogram()")
@@ -610,6 +691,17 @@ class RevPiPyLoad():
dc["zeroonerror"] = self.zeroonerror
dc["zeroonexit"] = self.zeroonexit
+ # MQTT Sektion
+ dc["mqtt"] = self.mqtt
+ dc["basetopic"] = self.mqttbasetopic
+ dc["sendinterval"] = self.mqttsendinterval
+ dc["host"] = self.mqtthost
+ dc["port"] = self.mqttport
+ dc["tls_set"] = self.mqtttls_set
+ dc["username"] = self.mqttusername
+ dc["password"] = self.mqttpassword
+ dc["client_id"] = self.mqttclient_id
+
# PLCSLAVE Sektion
dc["plcslave"] = self.plcslave
dc["plcslaveacl"] = self.plcslaveacl.acl
@@ -650,6 +742,42 @@ class RevPiPyLoad():
buff = fh.read()
return Binary(buff)
+ def xml_mqttrunning(self):
+ """Prueft ob MQTT Uebertragung noch lauft.
+ @return True, wenn MQTT Uebertragung noch lauft"""
+ proginit.logger.debug("xmlrpc call mqttrunning")
+ return False if self.th_mqtt is None \
+ else self.th_mqtt.is_alive()
+
+ def xml_mqttstart(self):
+ """Startet die MQTT Uebertragung.
+
+ @return Statuscode:
+ 0: erfolgreich gestartet
+ -1: Nicht aktiv in Konfiguration
+ -2: Laeuft bereits
+
+ """
+ if self.th_mqtt is not None and self.th_mqtt.is_alive():
+ return -2
+ else:
+ self.th_mqtt = self._plcmqtt()
+ if self.th_mqtt is None:
+ return -1
+ else:
+ self.th_mqtt.start()
+ return 0
+
+ def xml_mqttstop(self):
+ """Stoppt die MQTT Uebertragung.
+ @return True, wenn stop erfolgreich"""
+ if self.th_mqtt is not None:
+ self.stop_plcmqtt()
+ self.th_mqtt = None
+ return True
+ else:
+ return False
+
def xml_plcdownload(self, mode="tar", pictory=False):
"""Uebertraegt ein Archiv vom plcworkdir.
@@ -796,6 +924,17 @@ class RevPiPyLoad():
"zeroonerror": "[01]",
"zeroonexit": "[01]",
},
+ "MQTT": {
+ "mqtt": "[01]",
+ "mqttbasetopic": ".*",
+ "mqttsendinterval": "[0-9]+",
+ "mqtthost": ".+",
+ "mqttport": "[0-9]+",
+ "mqtttls_set": "[01]",
+ "mqttusername": ".*",
+ "mqttpassword": ".*",
+ "mqttclient_id": ".+",
+ },
"PLCSLAVE": {
"plcslave": "[01]",
"plcslaveacl": self.plcslaveacl.regex_acl,
diff --git a/setup.py b/setup.py
index 06fc127..ac304b5 100644
--- a/setup.py
+++ b/setup.py
@@ -27,7 +27,7 @@ setup(
license="LGPLv3",
name="revpipyload",
- version="0.6.8",
+ version="0.7.0",
scripts=["data/revpipyload"],