KeyError nach empfangener UDP nachricht

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
pumuckll
User
Beiträge: 8
Registriert: Donnerstag 30. August 2018, 17:45

Mittwoch 10. Juli 2019, 09:25

Hallo ich brauche mal wieder etwas Hilfe,

Ich hab schon vor ca einem Jahr ein Python Programm geschrieben um an "rpi und co" UDP befehle, von meiner Smarthome, Steuerung zu empfangen.

Auf einem Organe Pi one läuft das Programm, das senden und empfangen von UDP nachrichten Funktioniert, aber nicht stabil bzw hat Funktions Aussetzer. Nach einem Geräte neustart geht es dann wieder.


Deswegen möchte ich es gegen ein Raspberry pi b3+ tauschen und hab begonnen meine Programme neu für Python3 zuschreiben.

Aber das Neue Programm funktioniert nicht, bzw wenn ich mit PacketSender ein UDP Nachricht sende um einen Funktion auszuführen bekomme ich jetzt immer einen KeyError.

Hier mal der code:

Code: Alles auswählen

#!/usr/bin/env python3
#-*- coding: utf-8 -*-

import socket
import sys
import time
from time import sleep

bufsize = 8192  # 8 kByte

receive = ("", 8020 )
send = ("10.10.11.2", 8021 )

UDPSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
UDPSock.bind(receive)

print( "UDPServer Waiting for client on port", receive )

def Ausgang1on():

    UDPSock.sendto(b"Ausgang1 on", send)
    print( "Ausgang1 on"    )

def Ausgang1off():
    UDPSock.sendto(b"Ausgang1 off", send)
    print( "Ausgang1 off"   )

options = {     "Ausgang1on"  :  Ausgang1on,
                "Ausgang1off" : Ausgang1on,
}


while True:
    try:
        dataFromClient, addr = UDPSock.recvfrom(bufsize)
        options[dataFromClient]()
        print( dataFromClient)
        print( options)  
    except KeyError:
        print( dataFromClient)
        print( "KeyError")
        UDPSock.sendto(b"KeyError", send)
Das passiert beim ausführen bzw nach dem ich "Ausgang1on" sende:

Code: Alles auswählen

pi@door:~/skripte $ sudo python3 tets1.py
UDPServer Waiting for client on port ('', 8020)
b'Ausgang1on'
KeyError
Ich hab den code jetzt auch auf einem Windows Interpreter getestet mit dem selben Ergebnis:

Code: Alles auswählen

UDPServer Waiting for client on port ('', 8020)
b'Ausgang1on'
KeyError
b'Ausgang1off'
KeyError
b'falscheszeichen'
KeyError
Was muss ich machen damit das Funktioniert?

bzw was könnte ich besser machen?


grüsse
Gerhard
Benutzeravatar
sparrow
User
Beiträge: 1194
Registriert: Freitag 17. April 2009, 10:28

Mittwoch 10. Juli 2019, 09:30

Code: Alles auswählen

>>> a = "Ausgang1on"
>>> b = b'Ausgang1on'
>>> a == b
False
>>> type(a)
<class 'str'>
>>> type(b)
<class 'bytes'>
__deets__
User
Beiträge: 5782
Registriert: Mittwoch 14. Oktober 2015, 14:29

Mittwoch 10. Juli 2019, 10:06

Du musst entweder immer Byte-Strings benutzen, oder Byte-Strings in "echte" Strings dekodieren.

Code: Alles auswählen

"foobar" == b"foobar".encode()
Wobei dabei das encoding UTF-8 ist. Falls das auf deine Daten nicht zutrifft, musst du das korrekte nehmen.
Sirius3
User
Beiträge: 9999
Registriert: Sonntag 21. Oktober 2012, 17:20

Mittwoch 10. Juli 2019, 10:11

Konstanten schreibt man nach Konvention KOMPLETT_GROSS also `BUFSIZE`, oder receive -> SERVER, send -> TARGET_HOST. Variablennamen und Funktionen werden klein_mit_unterstrich geschrieben: udp_socket. Nach öffnenden und vor schließenden Klammern kommen keine Leerzeichen.

Keinen ausführbaren Code mit Funktionsdefinitionen mischen, keine globalen Variablen benutzen.

Das ganze könnte so aussehen:

Code: Alles auswählen

#!/usr/bin/env python3
import socket

BUFFER_SIZE = 8192
SERVER = ("", 8020)
TARGET_HOST = ("10.10.11.2", 8021)

def ausgang1_on(udp_socket, address):
    udp_socket.sendto(b"Ausgang1 on", address)
    print("Ausgang1 on")

def ausgang1_off(udp_socket, address):
    udp_socket.sendto(b"Ausgang1 off", address)
    print("Ausgang1 off")

options = {
    b"Ausgang1on": Ausgang1on,
    b"Ausgang1off": Ausgang1on,
}

def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    print("UDPServer Waiting for client on port", SERVER)

    while True:
        data, addr = udp_socket.recvfrom(BUFFER_SIZE)
        print(data)
        try:
            options[data](udp_socket, addr)
        except KeyError:
            print("KeyError")
            udp_socket.sendto(b"KeyError", addr)

if __name__ == '__main__':
    main()
pumuckll
User
Beiträge: 8
Registriert: Donnerstag 30. August 2018, 17:45

Mittwoch 10. Juli 2019, 11:20

Vielen dank euch

das b davor ist die Medizin

Ich hatte damals schon Probleme beim senden die wurden durch setzen des "b" vor den text gelöst, aber damals hab ich mich nicht weiter damit befasst.

Wenn man "Bytes" braucht um zu senden sollten auch "Bytes" ankommen.


Der Code Vorschlag funktioniert

Werde mir die Empfehlungen zu herzen nehmen und das gelernte gleich heute Abend anwenden.

In den Code auch gleich eine Anregung gefunden die ich testen möchte.

nochmals danke
pumuckll
User
Beiträge: 8
Registriert: Donnerstag 30. August 2018, 17:45

Freitag 12. Juli 2019, 09:18

Hallo nochmal,

der Großteil von meinen Programm funktioniert, ich aber aber noch Probleme zu lösen.

Ich verstehe nicht ganz warum das senden von UDP funktioniert, bzw ich sehe nicht wo der Port "8021" aktiviert wird, aber an diesen Port kommen die Nachrichten an.

TARGET_HOST wird nicht verwendet oder?

wie wird im "min" aus "addr" , "adress" in den "options"

Code: Alles auswählen

data, addr = udp_socket.recvfrom(BUFFER_SIZE)

def amplifier_off(udp_socket, address):
AMPLIFIER.off()
udp_socket.sendto(b"amplifier_off", address)
in data wird die UDP info geschrieben aber was in addr? bis das teil der Deklaration von udp_socket.recvfrom ?
____________________________________________________

Ich hab 2 Eingänge die auch eine UDP nachricht senden sollen, das hab ich aber noch nicht hinbekommen.
Der socket wird im main definiert und ist deswegen in dieser Funktion nicht bekannt.

Wie macht man das richtig? kann ich den selben port verwenden?

Den Socket wieder global deklarieren wollte ich nicht.

Code: Alles auswählen

#eingänge
def es_klingelt(udp_socket, address):
	print("es_klingelt!")
	udp_socket.sendto(b"es_klingelt", address)

def ein_alarm(udp_socket, address):
	print("ein_alarm!")
	udp_socket.sendto(b"ein_alarm", address)

KLINGEL= Button(18,pull_up=False, bounce_time=None)
ALARM = Button(23,pull_up=False, bounce_time=None)

KLINGEL.when_pressed = es_klingelt
ALARM.when_pressed = ein_alarm
__________________________________________________________

zu guter letzt möchte ich noch Threads einfügen

vermutlich soll ich sie im main aufrufen oder?

Code: Alles auswählen

def func_1():
	t2 = threading.Thread(target=func2)
	t2.start()
	t3 = threading.Thread(target=func3)
	t3.start()
	print("func1 aufgerufen")
def func_2():
	while True:
		try:
			print( "func2 schleife läuft")
			udp_socket.sendto(b"func2 schleife läuft", address)
			sleep(4)
		except KeyError:
			print( "KeyError")
			udp_socket.sendto(b"KeyError", address)
	
def func_3():
	time.sleep(6)
	print("func3   läuft auch ")
daraus möchte ich auch nachrichten senden

hier nochmal der Ganze code:

Code: Alles auswählen

#!/usr/bin/env python3
import socket
import os
import datetime
from time import sleep
from gpiozero import LED
from gpiozero import Button

BUFFER_SIZE = 8192
SERVER = ("", 8020)
TARGET_HOST = ("10.10.11.2", 8021)

udp_socket1 = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

#Ausgänge definieren

TASTERLED = LED(27,initial_value=False, active_high=True)
IRLED = LED(17,initial_value=False, active_high=True)
STATUSLED = LED(22,initial_value=False, active_high=True)

AMPLIFIER = LED(5,initial_value=False, active_high=False)
RESERVE = LED(6,initial_value=True, active_high=False)

#eingänge
def es_klingelt():
	print("es_klingelt!")
	udp_socket1.sendto(b"es_klingelt", address)

def ein_alarm():
	print("ein_alarm!")
	udp_socket1.sendto(b"ein_alarm", address)

KLINGEL= Button(18,pull_up=False, bounce_time=0.1)
ALARM = Button(23,pull_up=False, bounce_time=None)

KLINGEL.when_pressed = es_klingelt
ALARM.when_pressed = ein_alarm
#funktionen deklarieren

def reply_loxone(udp_socket, address):
	udp_socket.sendto(b"reply_loxone", address)
	print("reply_loxone")
	#heute_jetzt = datetime.datetime.now()
	#f = open("reply_loxone.txt", "w")
	#f.write(str(heute_jetzt) +"\n" )
	#f.close()
	

def try_restart(udp_socket, address):
	udp_socket.sendto(b"try_restart", address)
	print("try_restart")
	heute_jetzt = datetime.datetime.now()
	f = open("try_restart.txt", "a")
	f.write("try_restart" + str(heute_jetzt) +"\n" )
	f.close()
	os.system('sudo service door restart')

def try_reboot(udp_socket, address):
	udp_socket.sendto(b"try_reboot", address)
	print("try_reboot")
	heute_jetzt = datetime.datetime.now()
	f = open("rebootlog.txt", "a")
	f.write("try_reboot" + str(heute_jetzt) +"\n" )
	f.close()
	os.system('sudo shutdown -r now')

#ausgänge
def taster_led_on(udp_socket, address):
	TASTERLED.on()
	udp_socket.sendto(b"taster_led_on", address)
	print( "taster_led_on on")

def taster_led_off(udp_socket, address):
	TASTERLED.off()
	udp_socket.sendto(b"taster_led_off", address)
	print( "taster_led_off"	)

def taster_led_blink(udp_socket, address):
	TASTERLED.blink(on_time=0.5, off_time=0.5, n=None, background=True)
	udp_socket.sendto(b"taster_led_blink", address)
	print("taster_led_blink")

def ir_led_on(udp_socket, address):
	IRLED.on()
	udp_socket.sendto(b"ir_led_on", address)
	print("ir_led_on")
	
def ir_led_off(udp_socket, address):
	IRLED.off()
	udp_socket.sendto(b"ir_led_off", address)
	print("ir_led_off")
	
def status_led_on(udp_socket, address):
	STATUSLED.on()
	udp_socket.sendto(b"status_led_on", address)
	print("status_led_on")
	
def status_led_off(udp_socket, address):
	STATUSLED.off()
	udp_socket.sendto(b"status_led_off", address)
	print("status_led_off")
	
def status_led_blink(udp_socket, address):
	STATUSLED.blink(on_time=0.5, off_time=0.5, n=None, background=True)
	udp_socket.sendto(b"status_led_blink", address)
	print("status_led_blink")
	
def amplifier_on(udp_socket, address):
	AMPLIFIER.on()
	udp_socket.sendto(b"amplifier_on", address)
	print("amplifier_on")
	
def amplifier_off(udp_socket, address):
	AMPLIFIER.off()
	udp_socket.sendto(b"amplifier_off", address)
	print("amplifier_off")
	
def reserve_on(udp_socket, address):
	RESERVE.on()
	udp_socket.sendto(b"reserve_on", address)
	print("reserve_on")
	
def reserve_off(udp_socket, address):
	RESERVE.off()
	udp_socket.sendto(b"reserve_off", address)
	print("reserve_off")


	
options = {
	b"reply_loxone": reply_loxone,
	b"try_restart": try_restart,
	b"try_reboot": try_reboot,
	b"taster_led_on": taster_led_on,
	b"taster_led_off": taster_led_off,
	b"taster_led_blink": taster_led_blink,
	b"ir_led_on": ir_led_on,
	b"ir_led_off": ir_led_off,
	b"status_led_on": status_led_on,
	b"status_led_off": status_led_off,
	b"status_led_blink": status_led_blink,
	b"amplifier_on": amplifier_on,
	b"amplifier_off": amplifier_off,
	b"reserve_on": reserve_on,
	b"reserve_off": reserve_off,
}

def func_1():
	t2 = threading.Thread(target=func_2)
	t2.start()
	t3 = threading.Thread(target=func_3)
	t3.start()
	print("func1 aufgerufen")
def func_2():
	while True:
		try:
			print( "func2 schleife läuft")
			sleep(4)
		except KeyError:
			print( "KeyError")
			udp_socket.sendto(b"KeyError", address)
	
def func_3():
	time.sleep(6)
	print("func3   läuft auch ")


def main():
	udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	udp_socket.bind(SERVER)
	
	func_1()
	
	print("UDPServer Waiting for client on port", SERVER)
	while True:
		data, addr = udp_socket.recvfrom(BUFFER_SIZE)
		print(data)
		
		try:
			options[data](udp_socket, addr)
		except KeyError:
			print("KeyError")
			udp_socket.sendto(b"KeyError", addr)


if __name__ == '__main__':
	main()
grüsse
Gerhard
Benutzeravatar
__blackjack__
User
Beiträge: 3524
Registriert: Samstag 2. Juni 2018, 10:21

Samstag 13. Juli 2019, 10:17

@pumuckll: Die erste Frage verstehe ich nicht. `es_klingelt()` wird in `main()` mit zwei Argumenten aufgerufen. Als zweites Argument wird in `main` der Wert von `addr` übergeben. Und in der Funktion heisst das zweite Argument `address`. Und das hat nichts mit der Definition von `socket.recvfrom()` zu tun.

`KLINGEL` und `ALARM` sind keine Konstanten. Das sind Objekte mit Zustand und verhalten und die sollten so nicht auf Modulebene global definiert werden.

Wenn die Funktion, die da aufgerufen werden soll wenn Klingel oder Alarm ausgelöst werden, Argumente erwartet, dann muss man eine Funktion dazwischen schalten die keine Argumente erwartet und die dann die Funktion mit den Argumenten aufruft. Am einfachsten ist ein ``lambda``-Ausdruck an der Stelle. Also beispielsweise:

Code: Alles auswählen

    klingel.when_pressed = lambda: es_klingelt(udp_socket, target_address)
Da die Rückrufe von einem anderen Thread aus erfolgen, muss das alles was in der Rückruffunktion passiert gegenüber anderen Threads im Programm „thread safe“ sein. `socket.sendto()` ist AFAIK nicht „thread safe“.

Das ist dann auch ein Problem das man in dem Thread berücksichtigen muss, den Du über die furchtbar schlecht benannten `func_1()` bis `func_3()` startest.
A train station is where trains stop.
A bus station is where busses stop.
A Work Station is where …
pumuckll
User
Beiträge: 8
Registriert: Donnerstag 30. August 2018, 17:45

Sonntag 14. Juli 2019, 10:56

Sirius3 hat geschrieben:
Mittwoch 10. Juli 2019, 10:11
Das ganze könnte so aussehen:

Code: Alles auswählen

#!/usr/bin/env python3
import socket

BUFFER_SIZE = 8192
SERVER = ("", 8020)
TARGET_HOST = ("10.10.11.2", 8021)

def ausgang1_on(udp_socket, [address):
    udp_socket.sendto(b"Ausgang1 on", address)
    print("Ausgang1 on")

def ausgang1_off(udp_socket, address):
    udp_socket.sendto(b"Ausgang1 off", address)
    print("Ausgang1 off")

options = {
    b"Ausgang1on": Ausgang1on,
    b"Ausgang1off": Ausgang1on,
}

def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    print("UDPServer Waiting for client on port", SERVER)

    while True:
        data, addr = udp_socket.recvfrom(BUFFER_SIZE)
        print(data)
        try:
            options[data](udp_socket, addr)
        except KeyError:
            print("KeyError")
            udp_socket.sendto(b"KeyError", addr)

if __name__ == '__main__':
    main()
Darauf aufbauend hab ich mein Programm umgeschrieben, aber versteh nicht wie das senden von UDP hier funktioniert.

Die Variable "TARGET_HOST = ("10.10.11.2", 8021)" wird global definiert aber nicht verwendet oder?

"options" wird im main "data" und "(udp_socket, addr)" zugeweisen, aber was ist "addr" wo wird es definiert?

Wie wird in der "ausgang1_on" funktion aus "addr" zu " adress"?

________________________________________________________________________________________________
klingel.when_pressed ist ein eine threading funktion aus gpiozero, wäre das so richtig Programmiert?


func1 2 und 3 hatte eich schnell aus einem test script reinkopiert, das soll ungefähr so aussehen:
#threading
def thread_ping(udp_socket, target_address):
while True:
try:
print( "thread_ping läuft")
sleep(6)
except KeyError:
print( "KeyError thread_ping")
udp_socket.sendto(b"KeyError thread_ping", target_address)

def thread_status(udp_socket, target_address):
while True:
try:
print( "thread_status läuft")
sleep(8)
except KeyError:
print( "KeyError thread_status")
udp_socket.sendto(b"KeyError thread_status", target_address)

#eingänge
def es_klingelt():
print("es_klingelt!")
udp_socket.sendto(b"es_klingelt", TARGET_HOST)

def ein_alarm():
print("ein_alarm!")
udp_socket.sendto(b"ein_alarm", TARGET_HOST)


#main
def main():
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(SERVER)

thread_thread_ping = threading.Thread(target=thread_ping)
thread_thread_ping.start()
thread_thread_status = threading.Thread(target=thread_status)
thread_thread_status.start()

klingel= Button(18,pull_up=False, bounce_time=0.1)
alarm = Button(23,pull_up=False, bounce_time=None)

klingel.when_pressed = lambda: es_klingelt(udp_socket, target_address)
alarm.when_pressed = lambda: ein_alarm(udp_socket, target_address)



print("UDPServer Waiting for client on port", SERVER)
while True:
data, addr = udp_socket.recvfrom(BUFFER_SIZE)
print(data)

try:
options[data](udp_socket, addr)
except KeyError:
print("KeyError")
udp_socket.sendto(b"KeyError", addr)


if __name__ == '__main__':
main()


"target_address" sollte vermulich auch "address" sein , aber das hab ich eben noch nicht verstanden.

grüsse
__deets__
User
Beiträge: 5782
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sonntag 14. Juli 2019, 11:28

Das addr kommt als Ergebnis des recvfrom. Das liefert dir eben die Quelle der UDP Nachricht. Und dann wird addr eben weiterhin verwendet. Wo soll es sonst her kommen?
pumuckll
User
Beiträge: 8
Registriert: Donnerstag 30. August 2018, 17:45

Sonntag 14. Juli 2019, 14:23

The return value is a pair (bytes, address) where bytes is a bytes object representing the data received and address is the address of the socket sending the data.
data, addr = udp_socket.recvfrom(BUFFER_SIZE)

"addr" ist der ankommende Port 8020, bzw der gebundene Port

da ist mir jetzt klar

__________________________

Aber ich sehe nicht woher der wert address von

Code: Alles auswählen

udp_socket.sendto(b"KeyError thread_status", address)
kommt, bzw wie dieser den wert 8021 bekommt
__deets__
User
Beiträge: 5782
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sonntag 14. Juli 2019, 14:27

Abgesehen davon, dass du den Code ziemlich verhackstueckt hast, durch verschiedene Schreibweisen und rumfliegende Zeichen wie [ die da nix verloren haben - wo kommt denn addr noch so vor, und was koennte das dann bedeuten fuer die beiden Funktionen, in denen ein Argument address vorkommt?
__deets__
User
Beiträge: 5782
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sonntag 14. Juli 2019, 14:36

Ich sehe gerade, schon Sirius3 hat diesen Fehler gemacht. Das muss also erstmal korrigiert werden. Und es kann so auch nicht gelaufen sein, weil Python da sofort meckert. Zeig also bitte den Code, den du wirklich laufen laesst. Und bitte mit code-tags, nicht quote-tags.
pumuckll
User
Beiträge: 8
Registriert: Donnerstag 30. August 2018, 17:45

Sonntag 14. Juli 2019, 15:08

Das habe ich nach der Empfehlung von Sirius3 geschrieben.

Es Funktioniert solange ich den Taster nicht drücke.
Darauf habe ich dann aufgebaut, das der Teil mit den Eingängen nicht funktioniert hatte ich erst später bemerkt.


Code: Alles auswählen

#!/usr/bin/env python3
import socket
import os
import datetime
from time import sleep
from gpiozero import LED
from gpiozero import Button

BUFFER_SIZE = 8192
SERVER = ("", 8020)
TARGET_HOST = ("10.10.11.2", 8021)

#Ausgänge definieren

TASTERLED = LED(27,initial_value=False, active_high=True)
IRLED = LED(17,initial_value=False, active_high=True)
STATUSLED = LED(22,initial_value=False, active_high=True)

AMPLIFIER = LED(5,initial_value=False, active_high=False)
RESERVE = LED(6,initial_value=True, active_high=False)

#eingänge
def es_klingelt():
	print("es_klingelt!")
	udp_socket.sendto(b"es_klingelt", address)

def ein_alarm():
	print("ein_alarm!")
	udp_socket.sendto(b"ein_alarm", address)

klingel= Button(18,pull_up=False, bounce_time=None)
alarm = Button(23,pull_up=False, bounce_time=None)

klingel.when_pressed = es_klingelt
alarm.when_pressed = ein_alarm

#funktionen deklarieren

def reply_loxone(udp_socket, address):
	udp_socket.sendto(b"reply_loxone", address)
	print("reply_loxone")
	#heute_jetzt = datetime.datetime.now()
	#f = open("reply_loxone.txt", "w")
	#f.write(str(heute_jetzt) +"\n" )
	#f.close()
	

def try_restart(udp_socket, address):
	udp_socket.sendto(b"try_restart", address)
	print("try_restart")
	heute_jetzt = datetime.datetime.now()
	f = open("try_restart.txt", "a")
	f.write("try_restart" + str(heute_jetzt) +"\n" )
	f.close()
	os.system('sudo service door restart')

def try_reboot(udp_socket, address):
	udp_socket.sendto(b"try_reboot", address)
	print("try_reboot")
	heute_jetzt = datetime.datetime.now()
	f = open("rebootlog.txt", "a")
	f.write("try_reboot" + str(heute_jetzt) +"\n" )
	f.close()
	os.system('sudo shutdown -r now')

#ausgänge
def taster_led_on(udp_socket, address):
	TASTERLED.on()
	udp_socket.sendto(b"taster_led_on", address)
	print( "taster_led_on on")

def taster_led_off(udp_socket, address):
	TASTERLED.off()
	udp_socket.sendto(b"taster_led_off", address)
	print( "taster_led_off"	)

def taster_led_blink(udp_socket, address):
	TASTERLED.blink(on_time=0.5, off_time=0.5, n=None, background=True)
	udp_socket.sendto(b"taster_led_blink", address)
	print("taster_led_blink")

def ir_led_on(udp_socket, address):
	IRLED.on()
	udp_socket.sendto(b"ir_led_on", address)
	print("ir_led_on")
	
def ir_led_off(udp_socket, address):
	IRLED.off()
	udp_socket.sendto(b"ir_led_off", address)
	print("ir_led_off")
	
def status_led_on(udp_socket, address):
	STATUSLED.on()
	udp_socket.sendto(b"status_led_on", address)
	print("status_led_on")
	
def status_led_off(udp_socket, address):
	STATUSLED.off()
	udp_socket.sendto(b"status_led_off", address)
	print("status_led_off")
	
def status_led_blink(udp_socket, address):
	STATUSLED.blink(on_time=0.5, off_time=0.5, n=None, background=True)
	udp_socket.sendto(b"status_led_blink", address)
	print("status_led_blink")
	
def amplifier_on(udp_socket, address):
	AMPLIFIER.on()
	udp_socket.sendto(b"amplifier_on", address)
	print("amplifier_on")
	
def amplifier_off(udp_socket, address):
	AMPLIFIER.off()
	udp_socket.sendto(b"amplifier_off", address)
	print("amplifier_off")
	
def reserve_on(udp_socket, address):
	RESERVE.on()
	udp_socket.sendto(b"reserve_on", address)
	print("reserve_on")
	
def reserve_off(udp_socket, address):
	RESERVE.off()
	udp_socket.sendto(b"reserve_off", address)
	print("reserve_off")


	
options = {
	b"reply_loxone": reply_loxone,
	b"try_restart": try_restart,
	b"try_reboot": try_reboot,
	b"taster_led_on": taster_led_on,
	b"taster_led_off": taster_led_off,
	b"taster_led_blink": taster_led_blink,
	b"ir_led_on": ir_led_on,
	b"ir_led_off": ir_led_off,
	b"status_led_on": status_led_on,
	b"status_led_off": status_led_off,
	b"status_led_blink": status_led_blink,
	b"amplifier_on": amplifier_on,
	b"amplifier_off": amplifier_off,
	b"reserve_on": reserve_on,
	b"reserve_off": reserve_off,
}

def main():
	udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	udp_socket.bind(SERVER)
	
	print("UDPServer Waiting for client on port", SERVER)
	while True:
		data, addr = udp_socket.recvfrom(BUFFER_SIZE)
		print(data)
		
		try:
			options[data](udp_socket, addr)
		except KeyError:
			print("KeyError")
			udp_socket.sendto(b"KeyError", addr)


if __name__ == '__main__':
	main()
das empfangen von Nachrichten und die Rückmeldung funktioniert.
Der Log vom Packet sender, zuerst die gesendet Nachricht dann kommt die Rückmeldung:

Code: Alles auswählen

TIME	From IP	From Port	To IP	To Port	Method	Error	ASCII	Hex
15:59:13.089	10.10.11.61	8020	You	8021	UDP		amplifier_off	61 6D 70 6C 69 66 69 65 72 5F 6F 66 66 	
15:59:13.074	You	8021	10.10.11.61	8020	UDP		amplifier_off	61 6d 70 6c 69 66 69 65 72 5f 6f 66 66	
15:59:11.644	10.10.11.61	8020	You	8021	UDP		amplifier_on	61 6D 70 6C 69 66 69 65 72 5F 6F 6E 	
15:59:11.634	You	8021	10.10.11.61	8020	UDP		amplifier_on	61 6d 70 6c 69 66 69 65 72 5f 6f 6e	
15:58:57.039	10.10.11.61	8020	You	8021	UDP		taster_led_blink	74 61 73 74 65 72 5F 6C 65 64 5F 62 6C 69 6E 6B 	
15:58:57.032	You	8021	10.10.11.61	8020	UDP		taster_led_blink	74 61 73 74 65 72 5f 6c 65 64 5f 62 6c 69 6e 6b	

nur wenn ich den Taster betätige passiert das:

Code: Alles auswählen

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/gpiozero/pins/rpigpio.py", line 244, in _call_when_changed
    super(RPiGPIOPin, self)._call_when_changed()
  File "/usr/lib/python3/dist-packages/gpiozero/pins/local.py", line 141, in _call_when_changed
    self.state if state is None else state)
  File "/usr/lib/python3/dist-packages/gpiozero/pins/pi.py", line 293, in _call_when_changed
    method(ticks, state)
  File "/usr/lib/python3/dist-packages/gpiozero/input_devices.py", line 197, in _pin_changed
    self._fire_events(ticks, bool(self._state_to_value(state)))
  File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 368, in _fire_events
    self._fire_activated()
  File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 397, in _fire_activated
    super(HoldMixin, self)._fire_activated()
  File "/usr/lib/python3/dist-packages/gpiozero/mixins.py", line 344, in _fire_activated
    self.when_activated()
  File "door1.py", line 25, in es_klingelt
    udp_socket.sendto(b"es_klingelt", address)
NameError: name 'udp_socket' is not defined
das ist auch zu erwarten weil ich noch nicht verstanden habe wie Sirius3 das programmiert hat.
__deets__
User
Beiträge: 5782
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sonntag 14. Juli 2019, 15:34

Das liegt daran, das du das setup der Pins auf Modul-Ebene machst. Da gibt's aber noch keinen udp_socket. Wenn du das dort machen wuerdest, wo sie hingehoeren - in main - dann kannst du das *nach* der Erzeugung zB des udp_socket machen, und deinen GPIO-callback zusammen mit functools.partial so erzeugen, dass socket und Zieladresse bekannt sind. Allerdings ist das ein bisschen schwierig, weil es so nie vorkommen darf, dass die GPIOs triggern *bevor* per UDP was reingekommen ist. Da waere es dann ggf. eben besser, doch ein global definiertes TARGET_ADDRESS zu haben, wenn das technisch geht.
Sirius3
User
Beiträge: 9999
Registriert: Sonntag 21. Oktober 2012, 17:20

Sonntag 14. Juli 2019, 18:39

@__deets__: ich habe keinen Fehler gemacht, sondern absichtlich `address` als lokale Variable in den Funktionen benutzt, und `addr` in main.
Antworten