mit mqtt topic einen gpio mit gpiozero schalten

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Stelaku
User
Beiträge: 2
Registriert: Sonntag 5. Mai 2024, 15:10

Hallo alle zusammen

Ich bin seit längeren dabei meine gpio´s neu am Raspberry pi anzusteuern. bis Bullseye ging das alles ohne Probleme über GPIO.rpi
Ich habe einen mqtt Broker auf meinen Fhem Server der mir die gewünschten topics sendet die ich zum ansteuern einzelner GPIO´s sendet.

Ich habe zur Zeit eine wie ich finde sehr Aufwändige Lösung mit einen Python script am laufen.

Code: Alles auswählen

#!/usr/bin/env python3

import logging
import time
import paho.mqtt.client as mqtt
import sys
from gpiozero import LED
from gpiozero import Button

GPIO22 = LED(22)
GPIO10 = LED(10)
GPIO9 = LED(9)
GPIO11 = LED(11)
GPIO0 = LED(0)
GPIO6 = LED(6)
GPIO13 = LED(13)
GPIO16 = LED(16)
GPIO25 = LED(25)
GPIO24 = LED(24)
GPIO23 = LED(23)
GPIO15 = LED(15)
GPIO14 = LED(14)

TOPIC = "gpio/#"

broker_address="localhost"
port = 1883
client = mqtt.Client("GPIO")
username = 'username'
password = 'password'



def on_message(client, userdata, message):

	if "gpio/22/on" in (message.topic):
		GPIO22.on()
	if "gpio/22/off" in (message.topic):
		GPIO22.off()


	if "gpio/10/on" in (message.topic):
		GPIO10.on()
	if "gpio/10/off" in (message.topic):
		GPIO10.off()


	if "gpio/9/on" in (message.topic):
		GPIO9.on()
	if "gpio/9/off" in (message.topic):
		GPIO9.off()


	if "gpio/11/on" in (message.topic):
		GPIO11.on()
	if "gpio/11/off" in (message.topic):
		GPIO11.off()


	if "gpio/0/on" in (message.topic):
		GPIO0.on()
	if "gpio/0/off" in (message.topic):
		GPIO0.off()


	if "gpio/6/on" in (message.topic):
		GPIO6.on()
	if "gpio/6/off" in (message.topic):
		GPIO6.off()


	if "gpio/13/on" in (message.topic):
		GPIO13.on()
	if "gpio/13/off" in (message.topic):
		GPIO13.off()


	if "gpio/16/on" in (message.topic):
		GPIO16.on()
	if "gpio/16/off" in (message.topic):
		GPIO16.off()


	if "gpio/25/on" in (message.topic):
		GPIO25.on()
	if "gpio/25/off" in (message.topic):
		GPIO25.off()


	if "gpio/24/on" in (message.topic):
		GPIO24.on()
	if "gpio/24/off" in (message.topic):
		GPIO24.off()


	if "gpio/23/on" in (message.topic):
		GPIO23.on()
	if "gpio/23/off" in (message.topic):
		GPIO23.off()


	if "gpio/15/on" in (message.topic):
		GPIO15.on()
	if "gpio/15/off" in (message.topic):
		GPIO15.off()


	if "gpio/14/on" in (message.topic):
		GPIO14.on()
	if "gpio/14/off" in (message.topic):
		GPIO14.off()




def on_connect(client, userdata, flags, rc):
    print("Connected to MQTT Broker: " + broker_address)
    client.subscribe(TOPIC)

if __name__ == "__main__":
	client = mqtt.Client()
	client.on_connect = on_connect
	client.on_message = on_message
	client.username_pw_set(username, password)
	client.connect(broker_address, port)
	client.loop_forever()




ist es möglich die ganzen if Abfragen auf eine für alle gpio´s zu reduzieren. Ich bekomme ja im topic und im payload eigentlich alles was ich brauche.
wie zum Beispiel

Code: Alles auswählen

gpio/22/on
gpio/22/off
ich hatte mir gedacht das ich das topic zerlegen müsste und dann die einzelnen Variablen zum schalten der gpio´s verwendet werden. z.B. wie hier gedacht.

Code: Alles auswählen

gpio/22/on  wird zu 
gpio $1 $2   		womit ich dann statt hard codiert
GPIO22.on()  	schreibe vieleicht schreiben könnte
GPIO$1.$2()
Meine Suchanfragen haben mir leider keine Lösung gebracht.
Vieleicht hat hier ja einer eine Idee wie das funktionieren könnte.
Ich habe leider auch noch keine grosse Erfahrung mit python.
Taste mich erst ganz langsam an das Thema heran.

Viele Grüsse

Stephan
Benutzeravatar
__blackjack__
User
Beiträge: 13185
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Stelaku: Da wird ja sehr viel importiert was überhaupt nicht benutzt wird.

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

`client` darf nicht auf Modulebene existieren, wobei der Aufruf von `Client` dort auch falsch ist, denn diese Klasse erwartet keine Zeichenkette als Argument. Aber sie erwartet zwingend ein Argument, nämlich die API-Version die verwendet werden soll.

Die ganzen `GPIO…` sollten auch nicht auf Modulebene existieren, die gehören in eine Funktion als lokale Variablen. Beziehungsweise als *eine* lokale Variable, denn man nummeriert keine Namen. Dann will man entweder bessere Namen oder wie hier eine Datenstruktur. Zum Beispiel ein Wörterbuch, das Nummern auf `LED`-Objekte abbildet.

Wenn die `LED`-Objekte nicht mehr global sind, muss man sie an die Funktionen die sie verwenden als Argument(e) übergeben. Da bietet sich das bis jetzt ungenutzte `userdata` an.

Und die Konstanten die auf Modulebene stehen bleiben können, sind nicht KOMPLETT_GROSS geschrieben — was die Konvention für Konstanten ist.

Die Klammern um `message.topic` sind überflüssig und ``in`` ist der falsche Test wenn man auf *Gleichheit* testen möchte.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
import paho.mqtt.client as mqtt
from gpiozero import LED


TOPIC = "gpio/#"
BROKER_ADDRESS = "localhost"
BROKER_PORT = 1883
USERNAME = "username"
PASSWORD = "password"

ACTION_TEXT_TO_VALUE = {"on": 1, "off": 0}


def on_connect(client, _pin_number_to_led, _flags, _reason_code, _properties):
    print("Connected to MQTT Broker: " + client.host)
    client.subscribe(TOPIC)


def on_message(_client, pin_number_to_led, message):
    _, pin_number_text, action_text = message.topic.split("/")
    led = pin_number_to_led[int(pin_number_text)]
    led.value = ACTION_TEXT_TO_VALUE[action_text]


def main():
    client = mqtt.Client(
        mqtt.CallbackAPIVersion.VERSION2,
        userdata={
            pin_number: LED(pin_number)
            for pin_number in [0, 6, 9, 10, 11, 13, 14, 15, 16, 22, 23, 24, 25]
        },
    )
    client.on_connect = on_connect
    client.on_message = on_message
    client.username_pw_set(USERNAME, PASSWORD)
    client.connect(BROKER_ADDRESS, BROKER_PORT)
    client.loop_forever()


if __name__ == "__main__":
    main()
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Stelaku
User
Beiträge: 2
Registriert: Sonntag 5. Mai 2024, 15:10

Hallo blackjack

Vielen dank für die Antwort.
Ich bin ja noch vollkommen grün hinter den Ohren was python angeht.
Ich hatte in einen anderen mqtt script die jetzt ungenutzten bibliotheken importiert und einfach mit in das neue script kopiert.
über den Aufbau und die Struktur in einen python script habe ich mir überhaupt kein Kopf gemacht.
Viele sache im Netz gefunden und zusammen kopiert.
Immer einfach reintippen und ausprobieren bis zu meinen Ergebnis hat das auch geklapt.
Vielen dank für Deine Erklärungen wie ein python script normal aufgebaut ist.
Das lasse ich erstmal auf mich wirken und nach und nach werde ich das mal versuchen zu verstehen.
Dein angehängtes script von Dir funktioniert auf anhieb.
Ganz grossen dank dafür.
Ich verestehe zwar noch nicht ganz wie das funktioniert. Aber da werde ich mich weiter reinlesen.

Nochmals vielen dank für Deine hilfe.

Gruss

Stephan
Benutzeravatar
__blackjack__
User
Beiträge: 13185
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Da ist eigentlich nix komplexes oder exotisches dabei. Halt ein Wörterbuch (`dict`) das Pin-Nummern auf `LED`-Objekte abbildet. Darüber kommt man dann über die Nummer zum `LED`-Objekt und kann je nach Aktion "on" oder "off" den entsprechenden Wert setzen. Das sollten alles Sachen sein die im Grundlagentutorial in der Python-Dokumentation vorkommen.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Antworten