Verbindungsaufbau MQTT mit Python

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
NewPython19

Hallo Zusammen,

auf einem Linux-Rechner läuft der mosquitto-mqtt-broker. Dieser empfängt Daten von mehreren Sensoren. Damit ich die empfangenen Daten auswerten kann, möchte ich die Nachrichten zu den Topics in Datenbanken abspeichern.
Dafür möchte ich für jedes Topic einen MQTT-Client auf dem Rechner erstellen, welche die abonnierten Nachrichten in eine SQLite3-Datenbank ablegen.
Nun habe ich das Problem, dass mir die Datenbanken erstellt werden, aber das Abonnieren und abspeichern nicht funktioniert.

Das sind meine zugehörigen Programmschnipsel:

1. Hiermit bestimme ich die Ip-Adresse des Rechners:

Code: Alles auswählen

import netifaces as ni

ni.ifaddresses('eth0')
mqttBrokerIpAdress = ni.ifaddresses('eth0')[ni.AF_INET][0]['addr']
print(mqttBrokerIpAdress)
port = 1883 
2. Verbindungsaufbau und Subscriben von Topics:

Code: Alles auswählen

import paho.mqtt.client as mqtt

def mqttConnection(id, db, topic):
    directory = "/Mqtt/" + db
    connection = sqlite3.connect(directory)
    cursor = connection.cursor()
    client = mqtt.Client(id, False)                                                                              
    client.on_connect = on_connect
    client.subscribe(topic)
    client.on_message = on_message
    client.connect(mqttBrokerIpAdress, port, 60)
    client.loop_forever()


3. Hier noch die beiden Methoden on_connect und on_message (den Code hierzu habe ich im Internet gefunden):

Code: Alles auswählen

def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))

def on_connect(client, userdata, flags, rc):
    print("Connected with result code " + str(rc))
Hat jemand das schonmal gemacht oder eine Idee?
Benutzeravatar
__blackjack__
User
Beiträge: 13100
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@NewPython19: Du musst halt dafür sorgen, das in `on_message()` die Datenbankverbindung zur Verfügung steht und da dann auch Code steht der die Daten in die Datenbank schreibt.

Um die Verbindung dort hinein zu bekommen, muss sie als Argument übergeben werden. Entweder direkt, in dem man sie beispielsweise mit `functools.partial()` an die Funktion bindet bevor man sie als Rückruffunktion beim MQTT-Client registriert, oder in dem man mit objektorientierter Programmierung (OOP) arbeitet und das ein Attribut des Objekts ist, auf dem man die Rückrufmethode definiert.

Die `mqttBrokerIpAdress` sollte nicht auf Modulebene bestimmt werden und `port` ist eine Konstante und sollte entsprechend gross geschrieben werden. Alles ausser Konstanten (KOMPLETT_GROSS) und Klassen (MixedCase) schreibt man in Python klein_mit_unterstrichen. Also `mqtt_broker_ipaddress` (bei `address` fehlte bei Dir auch ein `d`).

Das erste ``ni.ifaddresses('eth0')`` in dem Code ist sinnfrei weil Du mit dem Ergebnis dieses Ausdrucks nichts machst.

Funktionen und Methoden haben üblicherweise die Tätigkeit die sie durchführen als Namen. `mqtt_connection` wäre ein guter Name für ein Objekt das eine Verbindung zu einem MQTT-Server oder -Client darstellt, aber nicht für eine Funktion die so eine Verbindung erstellt. Wobei die Funktion auch mehr macht als nur eine Verbindung zu erstellen.

`id` ist der Name einer eingebauten Funktion, den sollte man nicht für etwas anderes verwenden. `db` würde ich `db_name` oder `db_filename` nennen.

Pfade setzt man nicht mit ``+`` sondern mit `os.path.join()` zusammen oder man verwendet `pathlib.Path`. Der Pfad zu den Datenbanken wäre auch etwas was man als Konstante am Programmanfang definieren würde.

`Cursor`-Objekte sind eher etwas kurzlebiges. Das erstellt man nicht einmal am Anfang, sondern immer dann wenn man etwas in die Datenbank eintragen möchte.

Zeichenketten und Werte per `str()` und ``+`` zusammenstückeln ist eher BASIC als Python. In Python gibt es dafür Zeichenkettenformatierung mit der `format()`-Methode auf Zeichenketten und ab Python 3.6 f-Zeichenkettenliterale.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
NewPython19

@ __blackjack__
@NewPython19: Du musst halt dafür sorgen, das in `on_message()` die Datenbankverbindung zur Verfügung steht und da dann auch Code steht der die Daten in die Datenbank schreibt.

Um die Verbindung dort hinein zu bekommen, muss sie als Argument übergeben werden. Entweder direkt, in dem man sie beispielsweise mit `functools.partial()` an die Funktion bindet bevor man sie als Rückruffunktion beim MQTT-Client registriert, oder in dem man mit objektorientierter Programmierung (OOP) arbeitet und das ein Attribut des Objekts ist, auf dem man die Rückrufmethode definiert.
Kannst du diese Aussage etwas genauer beschreiben?
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Code: Alles auswählen

class MyMQTTConnectionEndpoint:

    def __init__(self, database_connection):
          self._database_connection = database_connection
    def on_message(self, userdata, msg):
          print("tu was mit", self._database_connection, userdata, msg)
NewPython19

__deets__ hat geschrieben: Donnerstag 25. Juli 2019, 11:51

Code: Alles auswählen

class MyMQTTConnectionEndpoint:

    def __init__(self, database_connection):
          self._database_connection = database_connection
    def on_message(self, userdata, msg):
          print("tu was mit", self._database_connection, userdata, msg)
Damit übergebe ich die Datenbank-Verbindung ?
__deets__
User
Beiträge: 14538
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist ein Objekt, das sowohl eine DB-Verbindung kennt, als auch ein on_message anbietet, das mit MQTT funktioniert. Ein Weg, um das Problem zu loesen.
Antworten