paho.mqtt.client, Gleichzeitig Subscribe 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
Jankie
User
Beiträge: 28
Registriert: Mittwoch 26. September 2018, 14:06

Dienstag 16. April 2019, 10:45

Hey,

ich habe hier zwei Code-Snippets für einen Chat mit MQTT. Meine Frage ist, ob und wie man das hin bekommt, dass man die Nachrichten in dem Terminal abschicken kann, indem auch die Nachrichten ankommen, also dass ich nicht ein Extra Terminal zum Subscriben muss.

Code: Alles auswählen

#Subscribe
import paho.mqtt.client as mqtt

ip = "localhost"
topic = "chat"
user= "User"

def on_connect(client, userdata, flags, rc):
    client.subscribe(topic)

def on_message(client, userdata, message):
    print(str(message.payload.decode("utf-8")))


def main():
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect(ip)
    client.loop_forever()
    
    
main()



#Publish
import paho.mqtt.client as mqtt


client = mqtt.Client()
client.connect("localhost")
while True:
    eingabe = input("Bitte Nachricht eingeben: ")
    client.publish("chat", eingabe)
Benutzeravatar
__blackjack__
User
Beiträge: 2764
Registriert: Samstag 2. Juni 2018, 10:21

Dienstag 16. April 2019, 11:24

@Jankie: Du kannst den Subscribe-Teil nicht-blockierend in einem eigenen Thread starten lassen. Schau Dir dazu in der Dokumentation einfach mal die vier möglichen Varianten an wie man die Netzwerkschleife realisieren kann.
“All tribal myths are true, for a given value of 'true'.” – Terry Pratchett, The Last Continent
Jankie
User
Beiträge: 28
Registriert: Mittwoch 26. September 2018, 14:06

Mittwoch 17. April 2019, 11:00

Danke für die Hilfe, habe es hinbekommen. Statt mit

Code: Alles auswählen

client.loop_forever()
arbeite ich jetzt mit

Code: Alles auswählen

client.loop_start()
und

Code: Alles auswählen

client.loop_stop()
Jankie
User
Beiträge: 28
Registriert: Mittwoch 26. September 2018, 14:06

Donnerstag 18. April 2019, 09:35

Hey,

habe jetzt folgendes Problem:

Bild

Wie man sieht, ist beim Sender alles schön strukturiert dargestellt. Beim Empfänger aber nicht. Hätte jemand eine Idee wie man das lösen kann?

Relevanter Codeauschnitt:

Code: Alles auswählen

def chat_subscribe():
    print("Subscribed!")
    ip = "localhost"
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect(ip)
    client.loop_start()


def write_in_chat(benutzer):
    client = mqtt.Client(benutzer)
    client.connect("localhost")
    while True:
        uhrzeit ='{0:%H:%M:%S}'.format(DateTime.now())
        eingabe = input(f"{benutzer}:")
        if eingabe == "quit":
            client.loop_stop()
            break
        else:
            nachricht = f"[{uhrzeit}][{benutzer}]: {eingabe}"
            client.publish("chat", nachricht)
            time.sleep(1)

def on_connect(client, userdata, flags, rc):
    topic = "chat"
    client.subscribe(topic)


def on_message(client, userdata, message):
    print(str(message.payload.decode("utf-8")))
Sirius3
User
Beiträge: 9529
Registriert: Sonntag 21. Oktober 2012, 17:20

Donnerstag 18. April 2019, 09:57

Was meinst Du mit "schön strukturiert dargestellt"?
Bitte erkläre genau, was Dein erwartetes/gewünschtes Verhalten ist, und wie es von dem, was Du siehst abweicht.
Und bitte den Text als Text posten und nicht als Bild.
Jankie
User
Beiträge: 28
Registriert: Mittwoch 26. September 2018, 14:06

Donnerstag 18. April 2019, 10:33

beim Sender wird die gesendete Nachricht unter der Eingabe des inputs geschrieben. Beim Empfänger wird aber die ankommende Nachricht direkt hinter den input geschrieben.


Sender Ausgabe im Terminal:

Code: Alles auswählen

Subscribed! Um dich abzumelden gebe 'quit' ein
TEST1:TEST
[11:31:58][TEST1]: TEST
TEST1:
Empfänger Ausgabe im Terminal:

Code: Alles auswählen

Subscribed! Um dich abzumelden gebe 'quit' ein
TEST2:[11:31:58][TEST1]: TEST
*an dieser stelle wartet er auf das input*

Beim User TEST2 soll es so aussehen wir beim User TEST1
Benutzeravatar
__blackjack__
User
Beiträge: 2764
Registriert: Samstag 2. Juni 2018, 10:21

Donnerstag 18. April 2019, 11:09

@Jankie: Dann musst Du bei Benutzern die den Text nicht selbst eingegebenen haben und darum kein Zeilenendezeichen schon selbst vor der Ausgabe eingegeben und damit auch wieder ausgegeben haben, ein solches Zeilenendezeichen vor der Ausgabe ausgeben.

Insgesamt dürfte es schwierig werden nur mit `input()` und `print()` eine benutzbare Textoberfläche hin zu bekommen. Weil ja zum Beispiel auch wenn jemand gerade etwas eingibt, eingehende Nachrichten diese Eingabe unterbrechen werden.

Der `str()`-Aufruf in `on_message()` macht übrigens keinen Sinn.
“All tribal myths are true, for a given value of 'true'.” – Terry Pratchett, The Last Continent
Jankie
User
Beiträge: 28
Registriert: Mittwoch 26. September 2018, 14:06

Donnerstag 18. April 2019, 11:26

Gibt es denn eine Möglichkeit, dass die Zeile vom input überschrieben wird?

Code: Alles auswählen

test
[12:24:51][Test]: test
das "test" in der ersten Zeile ist die Eingabe für den input Befehl. Dieses soll nach drücken von Enter mit der darauffolgenden Zeile überschrieben werden


Habe vom Modul curses gehört, ist das damit realisierbar?

#edit:

Habe es jetzt hinbekommen mit

Code: Alles auswählen

        CURSOR_UP_ONE = '\x1b[1A'
        ERASE_LINE = '\x1b[2K'
#edit2: klappt damit doch nicht so gut wie ich mir vorstelle, aber denke damit kann ich weiter arbeiten

#edit3:
Also der Text vom input wird gelöscht, allerdings ist die Zeile dann leer.

Code: Alles auswählen

[12:52:05][Test]: test

[12:52:12][Jan]: test
[12:52:18][Test]: test
                                                                         <- input line
[12:52:20][Jan]: test
[12:52:23][Test]: test
                                                                         <- input line
[12:52:25][Jan]: test
[12:52:28][Test]: test
Jankie
User
Beiträge: 28
Registriert: Mittwoch 26. September 2018, 14:06

Donnerstag 18. April 2019, 11:58

letzter Nachtrag:

habe es geschafft.

Code: Alles auswählen

def chat_subscribe():
    print("Subscribed! Um dich abzumelden gebe 'quit' ein")
    ip = "localhost"
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect(ip)
    client.loop_start()


def write_in_chat(benutzer):
    CURSOR_UP_ONE = '\x1b[1A'
    ERASE_LINE = '\x1b[2K'
    client = mqtt.Client(benutzer)
    client.connect("localhost")
    while True:
        uhrzeit ='{0:%H:%M:%S}'.format(DateTime.now())
        eingabe = input()
        print(CURSOR_UP_ONE + ERASE_LINE, end = "\r")
        if eingabe == "quit":
            client.publish("chat", f"{benutzer} hat den Chat verlassen")
            client.loop_stop()
            break
        else:
            nachricht = f"[{uhrzeit}][{benutzer}]: {eingabe}"
            client.publish("chat", nachricht)
            time.sleep(1)

def on_connect(client, userdata, flags, rc):
    topic = "chat"
    client.subscribe(topic)


def on_message(client, userdata, message):
    print(message.payload.decode("utf-8"))
Benutzeravatar
__blackjack__
User
Beiträge: 2764
Registriert: Samstag 2. Juni 2018, 10:21

Donnerstag 18. April 2019, 12:20

@Jankie: Konstanten definiert man üblicherweise auf Modulebene und am Anfang, nach den Importen, und nicht in einer Funktion.
“All tribal myths are true, for a given value of 'true'.” – Terry Pratchett, The Last Continent
Antworten