Prozessabbildübertragung per MQTT begonnen

This commit is contained in:
2018-04-09 13:56:11 +02:00
parent f937767479
commit 7f712aaf63
9 changed files with 392 additions and 2 deletions

View File

@@ -22,3 +22,14 @@ port = 55234
xmlrpc = 0
aclfile = /etc/revpipyload/aclxmlrpc.conf
bindip = *
[MQTT]
mqtt = 0
basetopic = revpi/data
sendinterval = 15
host =
port = 1883
tls_set = 0
username =
password =
client_id =

View File

@@ -27,6 +27,9 @@ Modules</h3>
<td><a style="color:#0000FF" href="logsystem.html">logsystem</a></td>
<td>Modul fuer die Verwaltung der Logdateien.</td>
</tr><tr>
<td><a style="color:#0000FF" href="mqttserver.html">mqttserver</a></td>
<td>Stellt die MQTT Uebertragung fuer IoT-Zwecke bereit.</td>
</tr><tr>
<td><a style="color:#0000FF" href="picontrolserver.html">picontrolserver</a></td>
<td>Modul fuer die Verwaltung der PLC-Slave Funktionen.</td>
</tr><tr>

145
doc/mqttserver.html Normal file
View File

@@ -0,0 +1,145 @@
<!DOCTYPE html>
<html><head>
<title>mqttserver</title>
<meta charset="UTF-8">
</head>
<body style="background-color:#FFFFFF;color:#000000"><a NAME="top" ID="top"></a>
<h1 style="background-color:#FFFFFF;color:#0000FF">
mqttserver</h1>
<p>
Stellt die MQTT Uebertragung fuer IoT-Zwecke bereit.
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Global Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Classes</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#MqttServer">MqttServer</a></td>
<td>Server fuer die Uebertragung des Prozessabbilds per MQTT.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Functions</h3>
<table>
<tr><td>None</td></tr>
</table>
<hr /><hr />
<a NAME="MqttServer" ID="MqttServer"></a>
<h2 style="background-color:#FFFFFF;color:#0000FF">MqttServer</h2>
<p>
Server fuer die Uebertragung des Prozessabbilds per MQTT.
</p>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Derived from</h3>
Thread
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Attributes</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Class Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Methods</h3>
<table>
<tr>
<td><a style="color:#0000FF" href="#MqttServer.__init__">MqttServer</a></td>
<td>Init MqttServer class.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#MqttServer._on_connect">_on_connect</a></td>
<td>Verbindung zu MQTT Broker.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#MqttServer._on_message">_on_message</a></td>
<td>Sendet piCtory Konfiguration.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#MqttServer.newlogfile">newlogfile</a></td>
<td>Konfiguriert die FileHandler auf neue Logdatei.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#MqttServer.run">run</a></td>
<td>Startet die Uebertragung per MQTT.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#MqttServer.stop">stop</a></td>
<td>Stoppt die Uebertragung per MQTT.</td>
</tr>
</table>
<h3 style="background-color:#FFFFFF;color:#FF0000">
Static Methods</h3>
<table>
<tr><td>None</td></tr>
</table>
<a NAME="MqttServer.__init__" ID="MqttServer.__init__"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
MqttServer (Constructor)</h3>
<b>MqttServer</b>(<i>basetopic, sendinterval, host, port=1883, tls_set=False, username="", password=None, client_id=""</i>)
<p>
Init MqttServer class.
</p><dl>
<dt><i>basetopic</i></dt>
<dd>
Basis-Topic fuer Datenaustausch
</dd><dt><i>sendinterval</i></dt>
<dd>
Prozessabbild alle n Sekunden senden
</dd><dt><i>host</i></dt>
<dd>
Adresse <class 'str'> des MQTT-Servers
</dd><dt><i>port</i></dt>
<dd>
Portnummer <class 'int'> des MQTT-Servers
</dd><dt><i>keepalive</i></dt>
<dd>
MQTT Ping bei leerlauf
</dd><dt><i>tls_set</i></dt>
<dd>
TLS fuer Verbindung zum MQTT-Server verwenden
</dd><dt><i>username</i></dt>
<dd>
Optional Benutzername fuer MQTT-Server
</dd><dt><i>password</i></dt>
<dd>
Optional Password fuer MQTT-Server
</dd><dt><i>client_id</i></dt>
<dd>
MQTT ClientID, wenn leer automatisch random erzeugung
</dd>
</dl><a NAME="MqttServer._on_connect" ID="MqttServer._on_connect"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
MqttServer._on_connect</h3>
<b>_on_connect</b>(<i>client, userdata, flags, rc</i>)
<p>
Verbindung zu MQTT Broker.
</p><a NAME="MqttServer._on_message" ID="MqttServer._on_message"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
MqttServer._on_message</h3>
<b>_on_message</b>(<i>client, userdata, msg</i>)
<p>
Sendet piCtory Konfiguration.
</p><a NAME="MqttServer.newlogfile" ID="MqttServer.newlogfile"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
MqttServer.newlogfile</h3>
<b>newlogfile</b>(<i></i>)
<p>
Konfiguriert die FileHandler auf neue Logdatei.
</p><a NAME="MqttServer.run" ID="MqttServer.run"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
MqttServer.run</h3>
<b>run</b>(<i></i>)
<p>
Startet die Uebertragung per MQTT.
</p><a NAME="MqttServer.stop" ID="MqttServer.stop"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
MqttServer.stop</h3>
<b>stop</b>(<i></i>)
<p>
Stoppt die Uebertragung per MQTT.
</p>
<div align="right"><a style="color:#0000FF" href="#top">Up</a></div>
<hr />
</body></html>

View File

@@ -87,6 +87,9 @@ Methods</h3>
<td><a style="color:#0000FF" href="#RevPiPyLoad._loadconfig">_loadconfig</a></td>
<td>Load configuration file and setup modul.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad._plcmqtt">_plcmqtt</a></td>
<td>Konfiguriert den MQTT-Thread fuer die Ausfuehrung.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad._plcslave">_plcslave</a></td>
<td>Erstellt den PlcSlave-Server Thread.</td>
</tr><tr>
@@ -111,6 +114,9 @@ Methods</h3>
<td><a style="color:#0000FF" href="#RevPiPyLoad.stop">stop</a></td>
<td>Stop revpipyload.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.stop_plcmqtt">stop_plcmqtt</a></td>
<td>Beendet MQTT Sender.</td>
</tr><tr>
<td><a style="color:#0000FF" href="#RevPiPyLoad.stop_plcprogram">stop_plcprogram</a></td>
<td>Beendet PLC Programm.</td>
</tr><tr>
@@ -217,7 +223,18 @@ RevPiPyLoad._loadconfig</h3>
<b>_loadconfig</b>(<i></i>)
<p>
Load configuration file and setup modul.
</p><a NAME="RevPiPyLoad._plcslave" ID="RevPiPyLoad._plcslave"></a>
</p><a NAME="RevPiPyLoad._plcmqtt" ID="RevPiPyLoad._plcmqtt"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad._plcmqtt</h3>
<b>_plcmqtt</b>(<i></i>)
<p>
Konfiguriert den MQTT-Thread fuer die Ausfuehrung.
</p><dl>
<dt>Returns:</dt>
<dd>
MQTT-Thread Object or None
</dd>
</dl><a NAME="RevPiPyLoad._plcslave" ID="RevPiPyLoad._plcslave"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad._plcslave</h3>
<b>_plcslave</b>(<i></i>)
@@ -288,6 +305,12 @@ RevPiPyLoad.stop</h3>
<b>stop</b>(<i></i>)
<p>
Stop revpipyload.
</p><a NAME="RevPiPyLoad.stop_plcmqtt" ID="RevPiPyLoad.stop_plcmqtt"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.stop_plcmqtt</h3>
<b>stop_plcmqtt</b>(<i></i>)
<p>
Beendet MQTT Sender.
</p><a NAME="RevPiPyLoad.stop_plcprogram" ID="RevPiPyLoad.stop_plcprogram"></a>
<h3 style="background-color:#FFFFFF;color:#FF0000">
RevPiPyLoad.stop_plcprogram</h3>

View File

@@ -12,6 +12,12 @@ logsystem.PipeLogwriter.newlogfile?4()
logsystem.PipeLogwriter.run?4()
logsystem.PipeLogwriter.stop?4()
logsystem.PipeLogwriter?1(logfilename)
mqttserver.MqttServer._on_connect?5(client, userdata, flags, rc)
mqttserver.MqttServer._on_message?5(client, userdata, msg)
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()
@@ -52,6 +58,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)
@@ -61,6 +68,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()

View File

@@ -1,3 +1,4 @@
MqttServer Thread
PipeLogwriter Thread
RevPiPlc Thread
RevPiSlave Thread

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Project SYSTEM "Project-5.1.dtd">
<!-- eric project file for project revpipyload -->
<!-- Saved: 2018-04-07, 19:21:46 -->
<!-- Saved: 2018-04-09, 11:54:43 -->
<!-- Copyright (C) 2018 Sven Sager, akira@narux.de -->
<Project version="5.1">
<Language>en_US</Language>
@@ -25,6 +25,7 @@
<Source>revpipyload/xrpcserver.py</Source>
<Source>revpipyload/shared/ipaclmanager.py</Source>
<Source>revpipyload/shared/__init__.py</Source>
<Source>revpipyload/mqttserver.py</Source>
</Sources>
<Forms/>
<Translations/>

129
revpipyload/mqttserver.py Normal file
View File

@@ -0,0 +1,129 @@
# -*- 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 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 <class 'str'> des MQTT-Servers
@param port Portnummer <class 'int'> 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._sendinterval = sendinterval
self._host = host
self._port = port
# 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
# TODO: self._mq.on_disconnect = self._on_disconnect
def _on_connect(self, client, userdata, flags, rc):
"""Verbindung zu MQTT Broker."""
print("Connect rc:", rc)
if rc > 0:
self.__mqttend = True
raise RuntimeError("can not connect to mqtt server")
# Subscribe piCtory Anforderung
client.subscribe(self._mqtt_sendpictory)
def _on_message(self, client, userdata, msg):
"""Sendet piCtory Konfiguration."""
with open(proginit.pargs.configrsc, "rb") as fh:
client.publish(self._mqtt_pictory, fh.read())
# Prozessabbild senden
self._evt_data.set()
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(self._host, self._port, keepalive=60)
self._mq.loop_start()
# mainloop
while not self.__exit:
self._evt_data.clear()
# FIXME: Ganzes Prozessabbild übertragen
self._mq.publish(self._mqtt_picontrol, fh_proc.read(4096))
fh_proc.seek(0)
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()")

View File

@@ -32,6 +32,7 @@ begrenzt werden!
"""
import gzip
import logsystem
import mqttserver
import picontrolserver
import plcsystem
import proginit
@@ -185,6 +186,28 @@ class RevPiPyLoad():
self.zeroonexit = \
int(self.globalconfig["DEFAULT"].get("zeroonexit", 1))
# 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 = 0
if "PLCSLAVE" in self.globalconfig:
@@ -241,6 +264,9 @@ class RevPiPyLoad():
)
os.chdir(self.plcworkdir)
# MQTT konfigurieren
self.th_mqtt = self._plcmqtt()
# PLC Programm konfigurieren
if restart_plcprogram:
self.stop_plcprogram()
@@ -368,6 +394,30 @@ 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:
th_plc = mqttserver.MqttServer(
self.mqttbasetopic,
self.mqttsendinterval,
self.mqtthost,
self.mqttport,
self.mqtttls_set,
self.mqttusername,
self.mqttpassword,
self.mqttclient_id
)
except:
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"""
@@ -503,6 +553,10 @@ class RevPiPyLoad():
proginit.logger.info("start xmlrpc-server")
self.xsrv.start()
if self.mqtt:
# MQTT Uebertragung starten
self.th_mqtt.start()
if self.plcslave:
# Slaveausfuehrung übergeben
self.th_plcslave.start()
@@ -519,6 +573,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():
@@ -543,6 +599,7 @@ class RevPiPyLoad():
proginit.logger.info("stopping revpipyload")
# Alle Sub-Systeme beenden
self.stop_plcmqtt()
self.stop_plcslave()
self.stop_plcprogram()
self.stop_xmlrpcserver()
@@ -558,6 +615,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 revpiplc 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()")