- Some better logging

- Split pairing into seperate class
This commit is contained in:
Dorian Zedler 2021-08-19 10:29:23 +02:00
parent a7fa0e665d
commit cbffbc92a6
Signed by: dozedler
GPG key ID: 989DE36109AFA354
8 changed files with 124 additions and 33 deletions

1
.gitignore vendored
View file

@ -1 +1,2 @@
/data /data
__pycache__

View file

@ -70,6 +70,19 @@ class MaDbHelper:
else: else:
return False return False
def getAllUsers(self):
query = "SELECT username FROM `vmq_auth_acl`;"
self.mysqlCur.execute(
query
)
users = []
for user in self.mysqlCur:
users.append(user[0])
return users
def _updateUser(self, username, password, publishAclPatterns, subscribeAclPatterns): def _updateUser(self, username, password, publishAclPatterns, subscribeAclPatterns):
query = """ query = """

View file

@ -1,59 +1,69 @@
import paho.mqtt.client as mqtt import paho.mqtt.client as mqtt
from dbHelper import MaDbHelper from dbHelper import MaDbHelper
import random from pairingHandler import MaPairingHandler
import string import logging, coloredlogs
coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s')
class MlmAccess: class MlmAccess:
def __init__(self): def __init__(self):
logging.info("=== MlmAccess ===")
self._initDb() self._initDb()
self._initMqtt() self._initMqtt()
self._pairingHanlder = MaPairingHandler(self._mqtt, self._db)
self._mqtt.loop_forever()
def _initDb(self): def _initDb(self):
self.db = MaDbHelper() logging.info("Initializing Database")
self._db = MaDbHelper()
initUsers = [ initUsers = [
("backend", "backend", ["mlmAccess/#"], ["mlmAccess/#"]), ("backend", "backend", ["mlmAccess/#"], ["mlmAccess/#"]),
("pair-actor", "pair-actor", ["mlmAccess/pair/request/actor"], ["mlmAccess/pair/response/actor"]) ("pair-actor", "pair-actor", ["mlmAccess/pair/request/actor"], ["mlmAccess/pair/response/actor"])
] ]
for username, password, publishAclPatterns, subscribeAclPatterns in initUsers: for username, password, publishAclPatterns, subscribeAclPatterns in initUsers:
if not self.db.addUser(username, password, publishAclPatterns, subscribeAclPatterns): if not self._db.addUser(username, password, publishAclPatterns, subscribeAclPatterns):
self.db.updateUser(username, password, publishAclPatterns, subscribeAclPatterns) self._db.updateUser(username, password, publishAclPatterns, subscribeAclPatterns)
def _initMqtt(self): def _initMqtt(self):
self.mqtt = client = mqtt.Client(client_id="backend") logging.info("Initializing MQTT")
self.mqtt.username_pw_set("backend", "backend") self._mqtt = client = mqtt.Client(client_id="backend")
self._mqtt.username_pw_set("backend", "backend")
self.mqtt.on_connect = self._mqttOnConnect self._mqtt.on_connect = self._mqttOnConnect
self.mqtt.on_message = self._mqttOnMessage self._mqtt.on_message = self._mqttOnMessage
print("connecting to broker") self._mqtt.connect("localhost", 1883, 60)
print(self.mqtt.connect("localhost", 1883, 60))
self.mqtt.loop_forever()
def _handleActorPairRequest(self, id):
print(f"Pair request for type actor with ID {id}")
if not self.db.userExists(f"actor-{id}"):
password = ''.join(random.choices(string.ascii_uppercase + string.digits, k=10))
self.db.addUser(f"actor-{id}", password, [f"mlmAccess/actor/{id}/status"], [f"mlmAccess/actor/{id}/action"])
self.mqtt.publish("mlmAccess/pair/response/actor", password)
else:
self.mqtt.publish("mlmAccess/pair/response/actor", "")
def _mqttOnConnect(self, client, userdata, flags, rc): def _mqttOnConnect(self, client, userdata, flags, rc):
print("Connected with result code "+str(rc))
if rc != 0: if rc != 0:
print("") logging.error(f"Error connecting to MQTT broker: {rc}")
return
print(client.subscribe("mlmAccess/pair/request/actor")) logging.info("Successfully connected to MQTT broker")
logging.info("Subscribing to actor subjects:")
for user in self._db.getAllUsers():
if user.startswith("actor-"):
actorSubject = f"mlmAccess/actor/{user.replace('actor-', '')}/status"
logging.info(f"* {actorSubject}")
client.subscribe(actorSubject)
# call hooks of child objects
self._pairingHanlder._mqttOnConnect(client, userdata, flags, rc)
def _mqttOnMessage(self, client, userdata, message): def _mqttOnMessage(self, client, userdata, message):
if message.topic == "mlmAccess/pair/request/actor": topic = message.topic
self._handleActorPairRequest(str(message.payload.decode("utf-8"))) topic = topic.replace("mlmAccess/", "")
messageContent = str(message.payload.decode("utf-8"))
logging.info(f"Message on topic {topic}: {messageContent}")
if topic.startswith("pair"):
self._pairingHanlder.handlePairingRequest(topic, messageContent)
if __name__ == "__main__": if __name__ == "__main__":
MlmAccess() MlmAccess()

26
backend/pairingHandler.py Normal file
View file

@ -0,0 +1,26 @@
import random, string, logging
class MaPairingHandler:
def __init__(self, mqtt, db):
self._mqtt = mqtt
self._db = db
def handlePairingRequest(self, topic, message):
if "actor" in topic:
self._handleActorPairRequest(message)
else:
logging.warn(f"Invalid pairing request: {topic}, {message}, Device type not know.")
def _handleActorPairRequest(self, id):
logging.info(f"Pair request for type actor with ID {id}")
if not self._db.userExists(f"actor-{id}"):
logging.info(f"Pair request {id} accepted")
password = ''.join(random.choices(string.ascii_uppercase + string.ascii_lowercase + string.digits, k=20))
self._db.addUser(f"actor-{id}", password, [f"mlmAccess/actor/{id}/status"], [f"mlmAccess/actor/{id}/action"])
self._mqtt.publish("mlmAccess/pair/response/actor", password)
else:
logging.warning(f"Rejecting pair request for ID {id}: ID already exists")
self._mqtt.publish("mlmAccess/pair/response/actor", "")
def _mqttOnConnect(self, client, userdata, flags, rc):
client.subscribe("mlmAccess/pair/request/actor")

View file

@ -0,0 +1,41 @@
import paho.mqtt.client as mqtt
import logging, coloredlogs
coloredlogs.install(level='INFO', fmt='%(asctime)s - [%(levelname)s] %(message)s')
PAIR_ID = "106"
def on_connect(client, userdata, flags, rc):
global PAIR_ID
if rc != 0:
logging.error(f"Error connecting to MQTT broker: {rc}")
return
logging.info("Successfully connected to MQTT broker")
client.subscribe("mlmAccess/pair/response/actor")
logging.info("Requesting pairing")
client.publish("mlmAccess/pair/request/actor", PAIR_ID)
def on_message(client, userdata, message):
messageContent = str(message.payload.decode("utf-8"))
if len(messageContent) > 0:
logging.info(f"Pairing was successfull! The password is: {messageContent}")
exit(0)
else:
logging.error("Pairing was not successfull!")
exit(1)
client = mqtt.Client(client_id="pair-actor")
client.username_pw_set("pair-actor", "pair-actor")
client.on_connect = on_connect
client.on_message = on_message
logging.info("Initializing MQTT")
client.connect("localhost", 1883, 60)
client.loop_forever()

View file

@ -6,9 +6,9 @@ def on_connect(client, userdata, flags, rc):
# Subscribing in on_connect() means that if we lose the connection and # Subscribing in on_connect() means that if we lose the connection and
# reconnect then subscriptions will be renewed. # reconnect then subscriptions will be renewed.
print("Subscribing to topic","mlmAccess/pair/response/actor") print("Subscribing to topic","mlmAccess/pair/response/actor")
print(client.subscribe("mlmAccess/pair/response/actor")) print(client.subscribe("mlmAccess/actor/102/action"))
print("Publishing message to topic","mlmAccess/pair/request/actor") print("Publishing message to topic","mlmAccess/pair/request/actor")
print(client.publish("mlmAccess/pair/request/actor", "101")) print(client.publish("mlmAccess/actor/102/status", "0", retain=True))
def on_message(client, userdata, message): def on_message(client, userdata, message):
print("message received " ,str(message.payload.decode("utf-8"))) print("message received " ,str(message.payload.decode("utf-8")))
@ -16,8 +16,8 @@ def on_message(client, userdata, message):
print("message qos=",message.qos) print("message qos=",message.qos)
print("message retain flag=",message.retain) print("message retain flag=",message.retain)
client = mqtt.Client(client_id="pair-actor") client = mqtt.Client(client_id="actor-102")
client.username_pw_set("pair-actor", "pair-actor") client.username_pw_set("actor-102", "YWT2JPOEZH")
client.on_connect = on_connect client.on_connect = on_connect
client.on_message = on_message client.on_message = on_message