Python mqtt on_message und Publish

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
roliver
User
Beiträge: 10
Registriert: Mittwoch 4. September 2019, 14:52

Hallo @all,

ich habe eine Verständnis Frage...

Code: Alles auswählen

def on_message(client, userdata, message):
  if topic == '/mach/was':
    if msg == 'NIX':
       print("ENDE")
        ... Publish eine Nachricht in ein topic ...
   if msg == 'START':
       ... oder wie kann ich das tun ...
 
Wie kann ich ein PUBLISH in einen TOPIC senden? oder wie kann ich das anders auswerten?

Gruß

Oliver
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Da fehlt mir zu viel Kontext. Welche Bibliothek benutzt du, woher kommt denn das topic (so gibt's nen NameError), was soll "oder wie kann ich das tun" heissen?
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

`msg` ist auch undefiniert und die Einrückung ist kaputt. Wäre schön wenn man tatsächlichen Code zu sehen bekäme. 🙂
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
roliver
User
Beiträge: 10
Registriert: Mittwoch 4. September 2019, 14:52

Hallo,

klar, habe jetzt mal so "gelöst"..

Code: Alles auswählen

#!/usr/bin/python3.5

import paho.mqtt.client as mqtt
global runme

def on_connect( client, userdata, flags, rc):
    print ("Connected with Code :" +str(rc))
    # Subscribe Topic from here
    client.subscribe("/abstand/#")


def on_message(client, userdata, message):
 msg = str(message.payload.decode("utf-8"))
 topic = str(message.topic)
 global runme
 if topic == '/abstand/pumpe':
   if msg == 'STOP':
       print("STOPen")
       runme = 1
       #mqtt.publish("/wassertonne/relay/", "0") # Versuch geht nicht
   if msg == 'START':
       print("STARTEN")
       #client.publish("/wassertonne/relay/", "0", hostname="iot.eclipse.org") # Auch der Versuch mit .loop_forever()
       runme = 2
       

client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message

client.username_pw_set("agent", "geheim")
client.connect("localhost", 1883, 60)

# client.loop_forever() # war vorher...
client.loop_start()
time.sleep(1)
runme = 0
while True:
    if runme == 1:
        client.publish("/wassertonne/relay/", "0")
        client.publish("/abstand/set", "pumpoff")
        runme = 0
        
    if runme == 2:
        client.publish("/wassertonne/relay/", "1")
        client.publish("/abstand/set", "pumpan")
        runme = 0
        
    time.sleep(0.5)

client.loop_stop()
client.disconnect()
geht das besser?

Gruß

Oliver
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

In on_message hast du doch den Client - warum rufst du da nicht einfach publish auf? So kann der Loop wieder für immer laufen.
roliver
User
Beiträge: 10
Registriert: Mittwoch 4. September 2019, 14:52

weil das nicht geht bei mir, da passiert nix...

Code: Alles auswählen

if msg == 'STOP':
       print("STOPen")
       mqtt.publish("/wassertonne/relay/", "0")
       print("fertig")
auf der console erscheint nur "STOPen" aber "fertig" nicht und es erfolgt kein Publish..

das war mein erster Ansatz...
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@roliver: Die Frage war warum Du auf dem *Client*-Exemplar das Du ja als *Argument* übergeben bekommst, nicht `publish()` aufrufst.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du sollst ja auch nicht mqtt nehmen. Sondern client. Das erste Argument für on_message. Steht in der Doku: https://pypi.org/project/paho-mqtt/#callbacks
roliver
User
Beiträge: 10
Registriert: Mittwoch 4. September 2019, 14:52

bitte um Beispiel, stehe jetzt ganz auf dem Schlauch.. sorry
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Schau in deinen eigenen Code. In die Funktion on_message. Wieviele Argumente hat die? Und wie heißen die?
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@roliver: Eine `publish()`-*Funktion* gibt es in dem Modul doch auch überhaupt gar nicht. Wie kommst Du also darauf so etwas wie ``mqtt.publish(…)`` zu schreiben? Es ist also auch falsch zu behaupten da passiere gar nichts – das gibt eindeutig einen `AttributeError` und das folgende `print()` wird nicht ausgeführt. 'fertig' erscheint da also sicher nicht. Die Fehlerbeschreibung passt also nicht zum gezeigten Quelltext.

Den Verdacht erhärtet auch das `time.sleep()` das mysteriöserweise verwendet wird ohne das Modul importiert zu haben.

``global`` ist schlecht – schmeiss das raus und programmiere das ordentlich. Alles was in einer Funktion oder Methode ausser Konstanten verwendet wird, sollte als Argument(e) übergeben werden. Auf Modulebene hat ``global`` zudem überhaupt gar keinen Effekt. Vergiss das Schlüsselwort am besten sofort wieder.

Eingerückt wird in Python mit vier Leerzeichen pro Ebene. Bring das Deinem Editor bei.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

`decode()` liefert bereits eine Zeichenkette, es macht keinen Sinn da noch mal `str()` mit aufzurufen. Bevor man `payload` dekodiert sollte man vielleicht auch *erst* prüfen ob das überhaupt das `topic` ist was einen interessiert, denn andere können da ja etwas ganz anderes kodiert haben als Zeichenketten in UTF-8.

Da sich die Kommandos gegenseitig ausschliessen ist nur im ersten Fall ein ``if`` sinnvoll und ab da ``elif``. Und zum Schluss noch ein ``else`` das dafür sorgt das unbekannte oder vielleicht falsch geschriebene Kommandos nicht einfach ohne irgendeine Meldung ignoriert werden. So zum Beispiel das irgendwer statt "pumpon" etwas wie "pumpan" in den Quelltext schreibt.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3.5
import paho.mqtt.client as mqtt


def on_connect(client, _userdata, _flags, return_code):
    print("Connected with Code:", return_code)
    client.subscribe("/abstand/#")


def on_message(client, _userdata, message):
    if message.topic == "/abstand/pumpe":
        command = message.payload.decode("utf-8")
        if command == "STOP":
            print("STOPen")
            client.publish("/wassertonne/relay/", "0")
            client.publish("/abstand/set", "pumpoff")
        elif command == "START":
            print("STARTEN")
            client.publish("/wassertonne/relay/", "1")
            client.publish("/abstand/set", "pumpon")
        else:
            print("Unbekanntes Kommando {!r}!".format(command))


def main():
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.username_pw_set("agent", "geheim")
    client.connect("localhost", 1883, 60)
    try:
        client.loop_forever()
    except KeyboardInterrupt:
        pass  # Ignored intentionally.
    finally:
        client.loop_stop()
        client.disconnect()


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
roliver
User
Beiträge: 10
Registriert: Mittwoch 4. September 2019, 14:52

Code: Alles auswählen

if msg == 'START':
       print("STARTEN")   # Erscheint auf der console
       client.publish("/wassertonne/relay/", "0", hostname="mywatercli") # auch keine Meldung auf Server
       print("STARTEN")  # Erscheint NICHT auf der console
das hat ich doch auch getestet aber auch ohne erfolg...
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@roliver: Wenn Du schon nicht verraten magst wie Du auf ``mqtt.publish()`` gekommen bist, verrate doch mal wie Du darauf kommst das `Client.publish()` ein Argument mit dem Namen `hostname` hat? Zeig doch bitte mal die Stelle in der Dokumentation wo die `Client.publish()`-Methode dokumentiert ist und dort dann dieses Argument…
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
roliver
User
Beiträge: 10
Registriert: Mittwoch 4. September 2019, 14:52

Hallo,

erst mal danke an __blackjack__.
Es ist meine erstes Python Programm, ja ich habe da wohl ein paar Fehler gemacht. Das mit dem mqtt.publish war so eine Blitz Idee, warum auch immer. Sorry jetzt klar, wenn ich als client übergebe kann ich auf nix anders auch zugreifen.
Das mit dem Hostname, hat mir Frau Google gezeigt. Und Nein, habe noch nicht RTFM gemacht...

Danke für die Hilfe, hoffe darf noch dumme Fragen stellen...


PS.: __blackjack__ dein Code geht, Danke habe ihn auch soweit verstanden.

Wozu ist das ganze.. habe ein paar Kapazitive feuchte Sensoren erhalten für Bewässerung. Damit kann ich jetzt die Pumpe starten und stoppen, so das sich alles selbst bewässert. Passieren kann nix, nur 12V, außer Kanister leer, Pumpe trocken... naja das löse ich noch.. es läuft schon mal...

Gruß

Oliver
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wenn das auf Dauer laufen soll, wuerde ich den PI eliminieren, und stattdessen einen ESP32 oder aehnliches damit beauftragen. Den kannst du auch mit micropython programmieren. Ein PI ist viel zu fehleranfaellig. Da sind die Pflanzen dann schnell vertrocknet.
roliver
User
Beiträge: 10
Registriert: Mittwoch 4. September 2019, 14:52

klar geht das auch ohne Linux PC aber ich wollt auch die Sprache etwas lernen, naja verstehen. Eines noch off Topic, kann Python auch als Service/Dienst laufen oder geht das nur über den Screen weg?
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@roliver: Die Frage ist nicht ob das auch ohne Linux-PC geht, sondern ob es wirklich *mit* geht. Je komplexer das System, Hardware und Software, desto mehr kann schief laufen.

Man kann auch Services/Dienste mit Python programmieren. Wie eigentlich in jeder anderen Programmiersprache auch.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Tholo
User
Beiträge: 177
Registriert: Sonntag 7. Januar 2018, 20:36

https://www.heise.de/ratgeber/Automatis ... 21096.html

Vielleicht findest du ja Inspirationen in diesem Artikel.
Benutzeravatar
__blackjack__
User
Beiträge: 13117
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Tholo: Ich vermute mal Du hast ein Heise+-Abo, bist angemeldet, und kannst den Artikel komplett lesen. Falls nicht wird ab dem Absatz „Notwendig ist eine Lösung, …“ der Text ausgeblendet und es folgt Werbung und Anmeldemöglichkeit für's Abo.
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten