Seite 1 von 2

gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Freitag 25. Oktober 2019, 16:30
von pumuckll
Hallo,

Verzeiht mir dass ich wieder Hilfe suche, weil ich Code schreibe von dem ich zuwenig Ahnung habe.

Um Gpio´s von einem Orangepi Zero auszulessen nutze ich die Bibliothek OPi.GPIO, funktioniert soweit ganz gut.

Ich erfasse die steigende flanke , mit "Threaded Callbacks", zweier Eingänge, der erste wird von einem Bewegungsmelder Betätigt der zweite von einem Reedkontakt.

Mein Problem bei Programm start ist der Reedkontakt schon auf High und die steigende flanke wird nur erfasst wenn der zustand einmal "Low" ist.

Da das irgendwann passieren kann , habe ich bis dahin eine Falsche Ausgabe und ich finde einfach kein Workaround das Funktioniert.

Ich habs mit einem Thread probiert aber dann funktioniert mein main nicht richtig.

hier mal der Code gekürzt auf das wesentliche:

Code: Alles auswählen

#!/usr/bin/env python3
import socket
import os
import datetime
from time import sleep
import OPi.GPIO as GPIO
import threading

BUFFER_SIZE = 8192
SERVER = ("", 8008)

TARGET_HOST = ("10.10.10.4", 8007)


udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
udp_socket.bind(SERVER)

GPIO.cleanup()
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)

GPIO.setup(8, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def eingang_1(channel):

	while( GPIO.input(8) == 1):
		GPIO.output(23, True)
		sleep(2)
		udp_socket.sendto(b"eingang_1", TARGET_HOST)
	else:
		GPIO.output(23, False)

def eingang_2(channel):
	while( GPIO.input(10) == 1):
		udp_socket.sendto(b"eingang_2", TARGET_HOST)
		sleep(2)


GPIO.add_event_detect(8, GPIO.RISING)
GPIO.add_event_callback(8, callback=eingang_1, bouncetime=50)

GPIO.add_event_detect(10, GPIO.RISING)
GPIO.add_event_callback(10, callback=eingang_2, bouncetime=50)


def main():
	eingang2_startup = threading.Thread(target=eingang_2(10))
	eingang2_startup.start()
	print("UDPServer Waiting for client on port", SERVER)
	while True:
	
		data, addr = udp_socket.recvfrom(BUFFER_SIZE)
		print(data)
		try:
			options[data](udp_socket, TARGET_HOST)
		except KeyError:
			print("KeyError")
			print(data)
			udp_socket.sendto(b"KeyError",TARGET_HOST)


if __name__ == '__main__':
	main()

Ich weiss man sollte keine globalen Variablen verwenden, aber dann funktioniert das senden mit udp nicht richtig.

Mein Versuch war einen Thread zu starten der die Funktion eingang_2 einmal ausführt.

die Funktion wird richtig ausgeführt, mein Programm stoppt aber bei den Thread und ich komm nicht weiter.

Code: Alles auswählen

	print("UDPServer Waiting for client on port", SERVER)
wird erst angezeigt wenn der Thread beendet ist.


wie könnte ich das lösen, bzw was mache ich falsch?

grüsse Gerhard

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Freitag 25. Oktober 2019, 17:00
von Sirius3
Eingerückt wird immer mit 4 Leerzeichen pro Ebene.
Um die Bedingung der while-Schleife gehört keine Klammer. Ein else-Block nach einer while-Schleife ohne `break` ist unsinnig. while-Schleifen im Callback sind sowieso falsch, weil die Routine darin möglichst kurz sein soll.
Bei Threads muß target ein Funktionsobjekt sein und nicht der Rückgabewert einer Funktion.

GPIO.cleanup sollte am Ende eines Programms aufgerufen werden und nicht am Anfang. Warnings sind dazu da, dass man sie behebt und nicht ignoriert.

Wenn ich alles richtig verstanden habe, dann sind zwei Threads, für jeden Eingang einen, das einfachste:

Code: Alles auswählen

#!/usr/bin/env python3
import socket
from time import sleep
from OPi import GPIO
import threading

BUFFER_SIZE = 8192
SERVER = ("", 8008)
TARGET_HOST = ("10.10.10.4", 8007)

def initialize():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(8, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    return udp_socket

def loop_eingang1(udp_socket):
    edge = threading.Event()
    if GPIO.input(8):
        edge.set()
    GPIO.add_event_detect(8, GPIO.RISING, callback=lambda c:edge.set(), bouncetime=50)
    while True:
        edge.wait()
        edge.clear()
        GPIO.output(23, True)
        while GPIO.input(8):
            sleep(2)
            udp_socket.sendto(b"eingang_1", TARGET_HOST)
        GPIO.output(23, False)

def loop_eingang2(udp_socket):
    edge = threading.Event()
    if GPIO.input(10):
        edge.set()
    GPIO.add_event_detect(10, GPIO.RISING, callback=lambda c:edge.set(), bouncetime=50)
    while True:
        edge.wait()
        edge.clear()
        while GPIO.input(10):
            udp_socket.sendto(b"eingang_2", TARGET_HOST)
            sleep(2)


def main():
    try:
        udp_socket = initialize()
	    eingang1 = threading.Thread(target=loop_eingang1, args=(udp_socket,))
        eingang1.daemon = True
        eingang1.start()
	    eingang2 = threading.Thread(target=loop_eingang2, args=(udp_socket,))
        eingang2.daemon = True
        eingang2.start()
        print("UDPServer Waiting for client on port", SERVER)
        while True:
            data, addr = udp_socket.recvfrom(BUFFER_SIZE)
            print(data)
            try:
                options[data](udp_socket, TARGET_HOST)
            except KeyError:
                print("KeyError")
                print(data)
                udp_socket.sendto(b"KeyError",TARGET_HOST)
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
	main()

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Freitag 25. Oktober 2019, 17:20
von __blackjack__
@pumuckll: Ich weiss nicht warum ein Thread da irgendetwas am Verhalten der Hardware ändern sollte. Du startest den auf jeden Fall falsch, denn Du rufst ``eingang_2(10)`` ja *selbst* auf, im Hauptthread, und übergibst dann den *Rückgabewert* davon, also `None`, als `target` an `Thread`, was keinen Sinn macht. Du musst als `target` etwas Aufrufbares übergeben was dann in einem eigenen Thread läuft. Wenn das Argumente braucht, müssen die als `args` und/oder `kwargs` übergeben werden. ``daemon=True`` wäre als Argument auch empfehlenswert.

Was heisst die `main()` funktioniert nicht richtig? Da wird offensichtlich auf `options` zugegriffen was nirgends definiert ist und damit zu einem `NameError` führt. Das hat aber auch nichts mit der Hardware oder dem Thread zu tun. Du schreibst Du hast das Programm gekürzt — dann lass bitte auch das gekürzte Programm laufen und beschreibe *dessen* Probleme. Denn einfach das Programm zu kürzen und nicht zu prüfen ob das immer noch das gleiche Verhalten hat was Du beschreibst, lässt uns dann raten wie Dein Programm denn tatsächlich aussehen mag und ob Du nicht was wichtiges rausgekürzt hast was zum Problem beiträgt.

Hast Du denn mal nachgemessen ob der Pin tatsächlich High ist? Denn da kann dann alle Programmierung der Welt nichts dran ändern wenn da tatsächlich Strom anliegt.

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Freitag 25. Oktober 2019, 17:58
von pumuckll
Danke schon mal für eure antworten und den Code


Mein Haupt Problem ist das beim Programm start schon high anliegt und das Programm auf die steigende flanke wartet.

Ich müsste den zustand des gpio´s auslesen und weitergeben, so funktioniert mein Bisheriges Programm, das könnte ich bis zu fallenden flanke machen.

Der weggekürzte Teil hat damit nichts zutun, werde ich aber zufunkt alles Posten.

Ich schau mir das morgen in ruhe an und überarbeite das Programm
dann melde mich wieder

danke schon mal

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Samstag 26. Oktober 2019, 18:15
von pumuckll
Nabend,

Der Code ist den Ganzen Tag fehlerlos gelaufen und macht was es soll.



vielen dank

Code: Alles auswählen

#!/usr/bin/env python3
import socket
from time import sleep
from OPi import GPIO
import threading


BUFFER_SIZE = 8192
SERVER = ("", 8008)
TARGET_HOST = ("10.10.10.4", 8007)



def initialize():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(13, GPIO.OUT)
    GPIO.setup(15, GPIO.OUT)
    GPIO.setup(19, GPIO.OUT)
    GPIO.setup(21, GPIO.OUT)
    GPIO.setup(23, GPIO.OUT)
    GPIO.setup(8, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.setup(10, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    return udp_socket

def loop_eingang1(udp_socket):
    edge = threading.Event()
    edge = threading.Event()
    if GPIO.input(8):
        edge.set()
    GPIO.add_event_detect(8, GPIO.RISING, callback=lambda c:edge.set(), bouncetime=50)
    while True:
        edge.wait()
        edge.clear()
        GPIO.output(23, True)
        while GPIO.input(8):
            sleep(2)
            udp_socket.sendto(b"eingang_1", TARGET_HOST)
        GPIO.output(23, False)

def loop_eingang2(udp_socket):
    edge = threading.Event()
    if GPIO.input(10):
        edge.set()
    GPIO.add_event_detect(10, GPIO.RISING, callback=lambda c:edge.set(), bouncetime=50)
    while True:
        edge.wait()
        edge.clear()
        while GPIO.input(10):
            udp_socket.sendto(b"eingang_2", TARGET_HOST)
            sleep(2)

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

def ausgang1_on(udp_socket, TARGET_HOST):
    GPIO.output(13, True)
    udp_socket.sendto(b"ausgang1 on", TARGET_HOST)
    print("ausgang1 on")

def ausgang1_off(udp_socket, TARGET_HOST):
    GPIO.output(13, False)
    udp_socket.sendto(b"ausgang1 off", TARGET_HOST)
    print("ausgang1 off")

def ausgang2_on(udp_socket, TARGET_HOST):
    GPIO.output(15, True)
    udp_socket.sendto(b"ausgang2 on", TARGET_HOST)
    print("ausgang2 on")

def ausgang2_off(udp_socket, TARGET_HOST):
    GPIO.output(15, False)
    udp_socket.sendto(b"ausgang2 off", TARGET_HOST)
    print("ausgang2 off")	

def ausgang3_on(udp_socket, TARGET_HOST):
    GPIO.output(19, True)
    udp_socket.sendto(b"ausgang3 on", TARGET_HOST)
    print("ausgang3 on")

def ausgang3_off(udp_socket, TARGET_HOST):
    GPIO.output(19, False)
    udp_socket.sendto(b"ausgang3 off", TARGET_HOST)
    print("ausgang3 off")

def ausgang4_on(udp_socket, TARGET_HOST):
    GPIO.output(21, True)
    udp_socket.sendto(b"ausgang4 on", TARGET_HOST)
    print("ausgang4 on")

def ausgang4_off(udp_socket, TARGET_HOST):
    GPIO.output(21, False)
    udp_socket.sendto(b"ausgang4 off", TARGET_HOST)
    print("ausgang4 off")

options = {
    b"reply_loxone": reply_loxone,
    b"ausgang1_on": ausgang1_on,
    b"ausgang1_off": ausgang1_off,
    b"ausgang2_on": ausgang2_on,
    b"ausgang2_off": ausgang2_off,
    b"ausgang3_on": ausgang3_on,
    b"ausgang3_off": ausgang3_off,
    b"ausgang4_on": ausgang4_on,
    b"ausgang4_off": ausgang4_off,
}

def main():
    try:
        udp_socket = initialize()
        eingang1 = threading.Thread(target=loop_eingang1, args=(udp_socket,))
        eingang1 = threading.Thread(target=loop_eingang1, args=(udp_socket,))
        eingang1.daemon = True
        eingang1.start()
        eingang2 = threading.Thread(target=loop_eingang2, args=(udp_socket,))
        eingang2.daemon = True
        eingang2.start()
        print("UDPServer Waiting for client on port", SERVER)
        while True:
            data, addr = udp_socket.recvfrom(BUFFER_SIZE)
            print(data)
            try:
                options[data](udp_socket, TARGET_HOST)
            except KeyError:
                print("KeyError")
                print(data)
                udp_socket.sendto(b"KeyError",TARGET_HOST)
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()


Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Samstag 26. Oktober 2019, 18:50
von Sirius3
In loop_eingang1 ist eine Zeile doppelt. Die ganzen ausgangY_on/off lassen sich zu einer Funktion zusammenfassen. TARGET_HOST ist laut Schreibweise eine Konstante und muss nicht als Argument übergeben werden.

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Dienstag 29. Oktober 2019, 13:44
von pumuckll
Hab eine weile gebraucht, aber ich hab einen weg, zur Zusammenfassung gefunden.

Code: Alles auswählen

#!/usr/bin/env python3
import socket
from time import sleep
import RPi.GPIO as GPIO
import threading


BUFFER_SIZE = 8192
SERVER = ("", 8008)
TARGET_HOST = ("10.10.10.4", 8007)


def initialize():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(29, GPIO.OUT, initial=1)
    GPIO.setup(31, GPIO.OUT, initial=1)
    GPIO.setup(33, GPIO.OUT, initial=1)
    GPIO.setup(35, GPIO.OUT, initial=1)
    GPIO.setup(37, GPIO.OUT, initial=1)
    GPIO.setup(16, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    return udp_socket


def initialize_werte(udp_socket, data):
    werte = {
    b"reply_loxone": [udp_socket, data, 0, 0],
    b"ausgang1_on": [udp_socket, data, 35, 1],
    b"ausgang1_off": [udp_socket, data, 35, 0],
    b"ausgang2_on": [udp_socket, data, 33, 1],
    b"ausgang2_off": [udp_socket, data, 33, 0],
    b"tor_auf_zu": [udp_socket, data, 0, 0],
    }
    return werte


def loop_eingang1(udp_socket):
    edge = threading.Event()
    if GPIO.input(16):
        edge.set()
    GPIO.add_event_detect(16, GPIO.RISING, callback=lambda c:edge.set(), bouncetime=50)
    while True:
        edge.wait()
        edge.clear()
        GPIO.output(29, True)
        while GPIO.input(16):
            sleep(2)
            udp_socket.sendto(b"eingang_1", TARGET_HOST)
        GPIO.output(29, False)

def loop_eingang2(udp_socket):
    edge = threading.Event()
    if GPIO.input(18):
        edge.set()
    GPIO.add_event_detect(18, GPIO.RISING, callback=lambda c:edge.set(), bouncetime=50)
    while True:
        edge.wait()
        edge.clear()
        while GPIO.input(18):
            udp_socket.sendto(b"eingang_2", TARGET_HOST)
            sleep(2)


def reply_loxone(udp_socket, data, pin, zustand):
    udp_socket.sendto(b"reply_loxone", TARGET_HOST)
    print("reply_loxone")


def ausgang_setzen(udp_socket, data, pin, zustand):
    GPIO.output(pin, zustand)
    udp_socket.sendto(data, TARGET_HOST)
    print("ausgang ",pin, zustand)


def tor_auf_zu(udp_socket, data, pin, zustand):
    GPIO.output(37, True)
    sleep(0.4)
    GPIO.output(37, False)
    udp_socket.sendto(b"tor_auf_zu", TARGET_HOST)
    print("toraufzu")





options = {
    b"reply_loxone": reply_loxone,
    b"ausgang1_on": ausgang_setzen,
    b"ausgang1_off": ausgang_setzen,
    b"ausgang2_on": ausgang_setzen,
    b"ausgang2_off": ausgang_setzen,
    b"tor_auf_zu": tor_auf_zu,
}

def main():
    try:
        udp_socket = initialize()
        data, addr = udp_socket.recvfrom(BUFFER_SIZE)
        werte = initialize_werte(udp_socket, data)
        eingang1 = threading.Thread(target=loop_eingang1, args=(udp_socket,))
        eingang1.daemon = True
        eingang1.start()
        eingang2 = threading.Thread(target=loop_eingang2, args=(udp_socket,))
        eingang2.daemon = True
        eingang2.start()
        print("UDPServer Waiting for client on port", SERVER)
        while True:
            data, addr = udp_socket.recvfrom(BUFFER_SIZE)
            werte = initialize_werte(udp_socket, data)
            print(data)
            try:
                werte[data]
                options[data](*werte[data])
            except KeyError:
                print("KeyError")
                print(data)
                udp_socket.sendto(b"KeyError",TARGET_HOST)
    finally:
        GPIO.cleanup()

if __name__ == '__main__':
    main()


Was ich noch nicht ganz verstehe ist wenn in :

Code: Alles auswählen

def initialize_werte(udp_socket, data):
die Zeile:

Code: Alles auswählen

    b"tor_auf_zu": [udp_socket, data, 0, 0],
    
fehlt, bekomme ich einen Keyerror, wenn "tor_auf_zu" gesendet wird.

PS: ich hab noch eine andere frage:
wie könnte ich von diesen Stream :

Code: Alles auswählen

rtsp://10.10.10.xx:xxxxx/user=xxxxxx&password=xxxxxxxx&channel=1&stream=0.sdp?
den ton aufzeichnen.

per befehl möchte ich die Aufzeichnung starten und stoppen
welche Bibliothek eignet sich am besten?

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Dienstag 29. Oktober 2019, 15:50
von __deets__
Zu deiner ersten Frage: wenn du einen Schluessel in einem Woerterbuch nachschlaegst, den es darin nicht gibt, dann ist das das erwartete Ergebnis. Was sonst soll passieren?

Zur zweiten kann ich nur googeln.

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Dienstag 29. Oktober 2019, 16:42
von __blackjack__
@pumuckll: Du verstehst nicht warum es zu einem `KeyError` kommt wenn man auf ein Wörterbuch auf einen Schlüssel zugreift den es nicht gibt?

Das erste empfangen eines UDP-Pakets vor der Schleife sieht sinnlos aus. Das `werte` was in der nächsten Zeile erzeugt wird, wird nie irgendwo verwendet.

`loop_eingang1()` und `loop_eingang2()` sind fast identisch. Ausser durch Pin-Nummer und Text der gesendet wird, was man einfach als Argumente heraus ziehen kann, unterscheiden die sich nur durch einen Ausgabepin und die Position des `sleep()` innerhalb der Schleife. Ist dieser Unterschied mit dem `sleep()` *tatsächlich* wichtig?

`initialize_werte()` ist komisch. Da sind sowohl ”statische” als auch ”dynamische” Werte in den Werten und die Schlüssel sind die gleichen wie bei `options`. Nur weil da dynamische Werte drin sind, muss diese Datenstruktur ständig neu aufgebaut werden. Das wäre besser gelöst wenn man schon in `options` die ”statischen” Werte per `functools.partial()` binden würde.

`tor_auf_zu()` hat ein `pin`-Argument das nicht benutzt wird, und eine hart kodierte Pin-Nummer.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
import socket
import threading
from time import sleep

from RPi import GPIO

BUFFER_SIZE = 8192
SERVER = ("", 8008)
TARGET_HOST = ("10.10.10.4", 8007)


def loop_eingang(udp_socket, in_pin, out_pin, command):
    edge = threading.Event()
    if GPIO.input(in_pin):
        edge.set()
    GPIO.add_event_detect(
        in_pin, GPIO.RISING, callback=lambda _: edge.set(), bouncetime=50
    )
    while True:
        edge.wait()
        edge.clear()

        if out_pin is not None:
            GPIO.output(out_pin, True)

        while GPIO.input(in_pin):
            sleep(2)
            udp_socket.sendto(command, TARGET_HOST)

        if out_pin is not None:
            GPIO.output(out_pin, False)


def reply_loxone(udp_socket, command):
    udp_socket.sendto(command, TARGET_HOST)
    print("reply_loxone")


def ausgang_setzen(udp_socket, pin, zustand, command):
    GPIO.output(pin, zustand)
    udp_socket.sendto(command, TARGET_HOST)
    print("ausgang ", pin, zustand)


def tor_auf_zu(udp_socket, pin, command):
    GPIO.output(pin, True)
    sleep(0.4)
    GPIO.output(pin, False)
    udp_socket.sendto(command, TARGET_HOST)
    print("toraufzu")


def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    command_to_function = {
        b"reply_loxone": partial(reply_loxone, udp_socket),
        b"ausgang1_on": partial(ausgang_setzen, udp_socket, 35, True),
        b"ausgang1_off": partial(ausgang_setzen, udp_socket, 35, False),
        b"ausgang2_on": partial(ausgang_setzen, udp_socket, 33, True),
        b"ausgang2_off": partial(ausgang_setzen, udp_socket, 33, False),
        b"tor_auf_zu": partial(tor_auf_zu, udp_socket, 37),
    }
    try:
        GPIO.setmode(GPIO.BOARD)
        GPIO.setup([29, 31, 33, 35, 37], GPIO.OUT, initial=GPIO.HIGH)
        GPIO.setup([16, 18], GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

        eingang_1_thread = threading.Thread(
            target=loop_eingang,
            args=(udp_socket, 16, 29, b"eingang_1"),
            daemon=True,
        )
        eingang_1_thread.start()

        eingang_2_thread = threading.Thread(
            target=loop_eingang,
            args=(udp_socket, 18, None, b"eingang_2"),
            daemon=True,
        )
        eingang_2_thread.start()

        print("UDPServer Waiting for client on port", SERVER)
        while True:
            command, _addr = udp_socket.recvfrom(BUFFER_SIZE)
            print(command)
            try:
                function = command_to_function[command]
            except KeyError:
                print("KeyError")
                udp_socket.sendto(
                    f"Unknown command {command!a}".encode("ascii"), TARGET_HOST
                )
            else:
                function(command)
    finally:
        GPIO.cleanup()


if __name__ == "__main__":
    main()

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Sonntag 1. Dezember 2019, 11:22
von pumuckll
Vielen danke euch beiden,
ich hatte endlich wieder Zeit um dieses Projekt weiterzuverfolgen und bis auf 2 kleine Probleme, läuft der Code prima.


hier hab ich einen Invaliden Syntax:

Code: Alles auswählen

udp_socket.sendto(f"Unknown command {command!a}".encode("ascii"), TARGET_HOST)
vor .encode ist die "^" Markierung

Ich komm nicht drauf was hier Fehlt.



Von Zeit zu zeit gab es ein Problem mit den GPIO´s, deswegen lasse ich das Programm einmal am Tag neustarten.
Dabei wird das Programm anscheinend nicht richtig geschlossen und beim neustart sind die gpio´s schon belegt.
deswegen hab ich am Anfang wieder :

Code: Alles auswählen

GPIO.cleanup()
eingefügt, damit nach dem Fehler Fall alles wieder läuft.


Außerdem möchte ich Led´s eine Bestimmte anzahl Blinken lassen, aber in einem Thread.

Eine Funktion zum Blinken und eine um einen Thread zu erstellen.
Ich bin mir nicht sicher ob ich das so richtig mache bzw was ich wo übergeben muss.

Code: Alles auswählen

def blink_led(udp_socket, pin, anzahl, command):
    udp_socket.sendto(command, TARGET_HOST)
    for x in range(anzahl):
	    GPIO.output(pin, True)
	    sleep(0.5)
	    GPIO.output(pin, False)
	
def blinken_thread(udp_socket, pin, anzahl, command):
    blinken_thread = threading.Thread(
        target=blink_led,
        args=(udp_socket, pin, anzahl, command),
        daemon=True,
    )
    blinken_thread.start()   
Im main wird mit "command" "b"tasterled_blink": partial(blinken_thread, udp_socket, 29, 10)" , der "blinken_thread" aktiviert

Code: Alles auswählen

def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    command_to_function = {
        b"reply_loxone": partial(reply_loxone, udp_socket),
        b"tasterled_ein": partial(ausgang_setzen, udp_socket, 29, True),
        b"tasterled_aus": partial(ausgang_setzen, udp_socket, 29, False),
        b"tasterled_blink": partial(blinken_thread, udp_socket, 29, 10),
        b"verstaerker_ein": partial(ausgang_setzen, udp_socket, 31, False),
        b"verstaerker_aus": partial(ausgang_setzen, udp_socket, 31, True),
        b"nacht_ein": partial(ausgang_setzen, udp_socket, 33, False),
        b"nacht_aus": partial(ausgang_setzen, udp_socket, 33, True),
        b"onewireled_ein": partial(ausgang_setzen, udp_socket, 35, True),
        b"onewireled_aus": partial(ausgang_setzen, udp_socket, 35, False),
        b"onewireled_blink": partial(blinken_thread, udp_socket, 35, 11),
    }
    try:
        GPIO.setmode(GPIO.BOARD)
        GPIO.cleanup()
        GPIO.setup([29, 31, 33, 35, 37], GPIO.OUT, initial=GPIO.HIGH)
        GPIO.setup([16, 18], GPIO.IN, pull_up_down=GPIO.PUD_DOWN)


        print("UDPServer Waiting for client on port", SERVER)
        while True:
            command, _addr = udp_socket.recvfrom(BUFFER_SIZE)
            print(command)
            try:
                function = command_to_function[command]
            except KeyError:
                print("KeyError")
                udp_socket.sendto(command, TARGET_HOST)
#                udp_socket.sendto(f"Unknown command {command!a}".encode("ascii"), TARGET_HOST)
            else:
                function(command)
    finally:
        GPIO.cleanup()

bzw kann ich das auch gleich mit einer Funktion machen.

mit Gpiozero wäre es einfach, aber dann könnte ich den Code nur auf einem RPI laufenlassen, so läuft er auch auf anderen SBC´s.

Schönen ersten Advent

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Sonntag 1. Dezember 2019, 20:42
von Fire Spike
poste mal deinen Fehler.
Mein Beispiel funktioniert.

Code: Alles auswählen

>>> command = "dj"
>>> f"Unknown command {command!a}".encode("ascii")
b"Unknown command 'dj'"

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Sonntag 1. Dezember 2019, 21:24
von __deets__
Die format strings gehen erst seit Python 3.6.

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Samstag 22. Februar 2020, 13:28
von pumuckll
Hallo allerseits,

Mein (euer) Code läuft jetzt schon auf 3 Geräten und ich frage mich, ob man ihn noch etwas optimieren kann. Da die CPU last recht hoch ist.



Im speziellen lässt sich "loop_status_out", auch auf einen Thread reduzieren?

Ich kann die abzufragenden Pins als Liste übergeben, aber wie mache ich den loop am effizientesten?

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
import socket
import threading
from time import sleep
from RPi import GPIO
from random import randrange


BUFFER_SIZE = 8192
SERVER = ("", 8008)
TARGET_HOST = ("10.10.10.4", 8007)


def loop_eingang(udp_socket, in_pin, command):
    edge = threading.Event()
    if GPIO.input(in_pin):
        edge.set()

    GPIO.add_event_detect(
        in_pin, GPIO.RISING, callback=lambda _: edge.set(), bouncetime=500)
    while True:
        edge.wait()
        edge.clear()
        while GPIO.input(in_pin):
            udp_socket.sendto(command, TARGET_HOST)
            sleep(1)

def loop_status_out(udp_socket, in_pin, command):
    while True:
        while GPIO.input(in_pin):
            udp_socket.sendto(command, TARGET_HOST)
            print(command)
            sleep(1)

def reply_loxone(udp_socket, command):
    udp_socket.sendto(command, TARGET_HOST)
    print("reply_loxone")

def ausgang_setzen(udp_socket, pin, zustand, command):
    GPIO.output(pin, zustand)
    udp_socket.sendto(command, TARGET_HOST)
    print("ausgang ", pin, zustand)

def tor_auf_zu(udp_socket, command):
    GPIO.output(37, False)
    sleep(0.5)
    GPIO.output(37, True)
    udp_socket.sendto(command, TARGET_HOST)
    print("toraufzu")

def main():
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    command_to_function = {
        b"reply_loxone": partial(reply_loxone, udp_socket),
        b"tor_auf_zu": partial(tor_auf_zu, udp_socket),        
        b"ausgang1_ein": partial(ausgang_setzen, udp_socket, 35, True),
        b"ausgang1_aus": partial(ausgang_setzen, udp_socket, 35, False),
        b"ausgang2_ein": partial(ausgang_setzen, udp_socket, 33, True),
        b"ausgang2_aus": partial(ausgang_setzen, udp_socket, 33, False),
        b"ausgang3_ein": partial(ausgang_setzen, udp_socket, 31, True),
        b"ausgang3_aus": partial(ausgang_setzen, udp_socket, 31, False),
        b"ausgang4_ein": partial(ausgang_setzen, udp_socket, 29, True),
        b"ausgang4_aus": partial(ausgang_setzen, udp_socket, 29, False),
    }
    try:
        GPIO.setmode(GPIO.BOARD)
        GPIO.cleanup()
        GPIO.setup([29,31, 33, 35], GPIO.OUT, initial=GPIO.LOW)
        GPIO.setup( 37, GPIO.OUT, initial=GPIO.HIGH)
        GPIO.setup([16, 18], GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
        eingang_1_thread = threading.Thread(
            target=loop_eingang,
            args=(udp_socket, 16, b"eingang 1"),
            daemon=True,
        )
        eingang_1_thread.start()
        eingang_2_thread = threading.Thread(
            target=loop_eingang,
            args=(udp_socket, 18, b"eingang 2"),
            daemon=True,
        )
        eingang_2_thread.start()

        loop_ausgang1_ein_thread = threading.Thread(
            target=loop_status_out,
            args=(udp_socket, 35, b"ausgang1_ein"),
            daemon=True,
        )
        loop_ausgang1_ein_thread.start()

        loop_ausgang2_ein_thread = threading.Thread(
            target=loop_status_out,
            args=(udp_socket, 33, b"ausgang2_ein"),
            daemon=True,
        )
        loop_ausgang2_ein_thread.start()

        loop_ausgang3_ein_thread = threading.Thread(
            target=loop_status_out,
            args=(udp_socket, 31, b"ausgang3_ein"),
            daemon=True,
        )
        loop_ausgang3_ein_thread.start()

        loop_ausgang4_ein_thread = threading.Thread(
            target=loop_status_out,
            args=(udp_socket, 29, b"ausgang4_ein"),
            daemon=True,
        )
        loop_ausgang4_ein_thread.start()

        print("UDPServer Waiting for client on port", SERVER)
        while True:
            command, _addr = udp_socket.recvfrom(BUFFER_SIZE)
            print(command)
            try:
                function = command_to_function[command]
            except KeyError:
                print("KeyError")
                udp_socket.sendto(f"Unknown command {command!a}".encode("ascii"), TARGET_HOST)
            else:
                function(command)
    finally:
        GPIO.cleanup()
        
if __name__ == "__main__":
    main()

grüsse

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Samstag 29. Februar 2020, 11:40
von pumuckll
Ich habe den Code umgeschrieben.

So verbraucht das Programm fast keine CPU Leistung. Habe den Code auf einen Thread reduziert und Sende den Zustand von mehreren Ausgängen und Eingängen auf einmal.
soweit bin ich  zufrieden 
Wenn der vorige Code länger gelaufen ist, gab es hin und wieder Fehler (mit dem alten code) mit den gpio´s und die Eingänge wurden nicht mehr angezeigt.
Wie kann ich den Code neustarten wenn das Gpio System einen Fehler ausgibt.

andere Optimierung Vorschläge sind auch willkommen.

Schönes Wochenende

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
import socket
import threading
from time import sleep
from RPi import GPIO
from random import randrange

BUFFER_SIZE = 8192
SERVER = ("", 8008)
TARGET_HOST = ("10.10.10.4", 8007)

PIN_AUS = [29, 31, 33, 35, 37]
PIN_EIN = [16, 18]
zustand_aus = []
zustand_ein = []

# gpio definieren
def set_gpio():
    GPIO.cleanup()
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(PIN_AUS, GPIO.OUT, initial=GPIO.HIGH)
    GPIO.setup(PIN_EIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)


#arbeits loop
def loop_einaus_abfragen(udp_socket):
    while True:
        for loop_aus in PIN_AUS:# status ausgänge abfragen
            if not GPIO.input(loop_aus):
                zustand_aus.insert(PIN_AUS.index(loop_aus), 1)
            if GPIO.input(loop_aus):
                zustand_aus.insert(PIN_AUS.index(loop_aus), 0)
        for loop_ein in PIN_EIN:# status eingänge abfragen
            if not GPIO.input(loop_ein):
                zustand_ein.insert(PIN_EIN.index(loop_ein), 0)
            if GPIO.input(loop_ein):
                zustand_ein.insert(PIN_EIN.index(loop_ein), 1)
        print(zustand_aus)
        print(zustand_ein)
        num = 0
        for b in zustand_aus:
            num = 2 * num + b
        num = str(num)
        num1 = 0
        for b1 in zustand_ein:
            num1 = 2 * num1 + b1
        num1 = str(num1)
        zustand_aus_senden = (b"zustand_aus," + num.encode())
        zustand_ein_senden = (b"zustand_ein," + num1.encode())
        udp_socket.sendto(zustand_aus_senden, TARGET_HOST)# status ausgänge senden
        udp_socket.sendto(zustand_ein_senden, TARGET_HOST)
        sleep(0.5)	
        zustand_aus.clear()
        zustand_ein.clear()

def reply_loxone(udp_socket, command):# rückmeldung ob das Programm noch läuft
    udp_socket.sendto(command, TARGET_HOST)
    print("reply_loxone")

def ausgang_setzen(udp_socket, pin, zustand, command):
    GPIO.output(pin, zustand)
    udp_socket.sendto(command, TARGET_HOST)
    print("ausgang ", pin, zustand)

def tor_auf_zu(udp_socket, command):
    GPIO.output(37, False)
    sleep(0.5)
    GPIO.output(37, True)
    udp_socket.sendto(command, TARGET_HOST)
    print("toraufzu")

def main():
    set_gpio()
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    udp_socket.sendto(b"tets", TARGET_HOST)
    command_to_function = {
        b"reply_loxone": partial(reply_loxone, udp_socket),
        b"tor_auf_zu": partial(tor_auf_zu, udp_socket),        
        b"ausgang1_ein": partial(ausgang_setzen, udp_socket, 35, False),
        b"ausgang1_aus": partial(ausgang_setzen, udp_socket, 35, True),
        b"ausgang2_ein": partial(ausgang_setzen, udp_socket, 33, False),
        b"ausgang2_aus": partial(ausgang_setzen, udp_socket, 33, True),
        b"ausgang3_ein": partial(ausgang_setzen, udp_socket, 31, False),
        b"ausgang3_aus": partial(ausgang_setzen, udp_socket, 31, True),
        b"ausgang4_ein": partial(ausgang_setzen, udp_socket, 29, False),
        b"ausgang4_aus": partial(ausgang_setzen, udp_socket, 29, True),
    }
    try:
        udp_socket.sendto(b"test", TARGET_HOST)	
        loop_einaus_thread = threading.Thread(
            target=loop_einaus_abfragen,
            args=(udp_socket,),
            daemon=True,
        )
        loop_einaus_thread.start()
        print("UDPServer Waiting for client on port", SERVER)
        while True:
            command, _addr = udp_socket.recvfrom(BUFFER_SIZE)
            print(command)
            try:
                function = command_to_function[command]
            except KeyError:
                print("KeyError")
                udp_socket.sendto(f"Unknown command {command!a}".encode("ascii"), TARGET_HOST)
            else:
                function(command)
    finally:
        GPIO.cleanup()


if __name__ == "__main__":
    main()

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Samstag 29. Februar 2020, 13:58
von Sirius3
In `loop_einaus_abfragen` ist einiges schief.
Benutze keine globalen Variablen, erst recht nicht mit Threads.
`insert` oder `index` sind Methoden von Listen, die man eigentlich nie braucht. Man erzeugt immer frische Listen und hängt auch nur Daten an.

Code: Alles auswählen

        zustand_aus = []
        for loop_aus in PIN_AUS:
            if not GPIO.input(loop_aus):
                zustand_aus.append(1)
            if GPIO.input(loop_aus):
                zustand_aus.append(0)
Wenn die if-Bedingung des zweiten ifs genau das Gegenteil der ersten Bedingung ist, dann benutzt man else.

Code: Alles auswählen

        zustand_aus = []
        for loop_aus in PIN_AUS:
            if not GPIO.input(loop_aus):
                zustand_aus.append(1)
            else:
                zustand_aus.append(0)
Wenn die Befehle im if-Block identisch sind, bis auf einen Wert, dann setzt man den Wert und ruft den Befehl nach den ifs auf. Und wenn dann der Wert schon identisch ist zur Bedingung, dann braucht man es gar nicht mehr.

Code: Alles auswählen

        zustand_aus = []
        for loop_aus in PIN_AUS:
            zustand_aus.append(not GPIO.input(loop_aus))
Und das ist ein typischer Fall für Listcomprehension:

Code: Alles auswählen

        zustand_aus = [not GPIO.input(loop_aus) for loop_aus in PIN_AUS]
Statt an Variablen irgendwelche Nummern zu hängen, sollte man sprechende Namen wählen.
Statt Strings mit + zusammenzustückeln, benutzt man Stringformatierung.

Code: Alles auswählen

def loop_einaus_abfragen(udp_socket):
    while True:
        zustand_aus = [int(not GPIO.input(pin)) for pin in PIN_AUS]
        zustand_ein = [int(not GPIO.input(pin)) for pin in PIN_EIN]
        print(zustand_aus)
        print(zustand_ein)
        num_aus = 0
        for b in zustand_aus:
            num_aus = 2 * num_aus + b
        num_ein = 0
        for b in zustand_ein:
            num_ein = 2 * num_ein + b
        udp_socket.sendto(b"zustand_aus,%d" % num_aus, TARGET_HOST)
        udp_socket.sendto(b"zustand_ein,%d" % num_ein, TARGET_HOST)
        sleep(0.5)
Wenn man jetzt die Print-Ausgabe mit Listen nicht braucht, wird es noch einfacher:

Code: Alles auswählen

def read_pins(pins)
    result = 0
    for pin in pins:
        result = result * 2 + (not GPIO.input(pin))
    return result

def loop_einaus_abfragen(udp_socket):
    while True:
        zustand_aus = read_pins(PIN_AUS)
        zustand_ein = read_pins(PIN_EIN)
        udp_socket.sendto(b"zustand_aus,%d" % zustand_aus, TARGET_HOST)
        udp_socket.sendto(b"zustand_ein,%d" % zustand_ein, TARGET_HOST)
        sleep(0.5)

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Samstag 29. Februar 2020, 15:43
von __blackjack__
Ich hätte bei `read_pins()` Bitoperationen (``<<`` und ``|``) verwendet, damit klarer wird was da passiert. Aber das ist letztlich Geschmackssache.

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Montag 2. März 2020, 00:16
von pumuckll
Danke euch

Ich hab eine weile gebraucht, um die Dualzahl Rechnung zu verstehen, da bin ich etwas aus der Übung
Sirius3 hat geschrieben: Samstag 29. Februar 2020, 13:58 result = 0
for pin in pins:
result = result * 2 + (not GPIO.input(pin))
return result
nochlänger dafür:
__blackjack__ hat geschrieben: Samstag 29. Februar 2020, 15:43 Ich hätte bei `read_pins()` Bitoperationen (``<<`` und ``|``) verwendet, damit klarer wird was da passiert. Aber das ist letztlich Geschmackssache.

Code: Alles auswählen

result = (result <<1) | (not GPIO.input(pin)) #Dualzahl als Dezimalzahl darstellen

Im Arbeits Thread hab ich eine Zähl schleife erstellt, um gewisse Funktionen nicht in jeden Zyklus auszuführen.
Außerdem werden noch 1Wire Sensoren ausgelesen, falls welche vorhanden sind.


Ist das so OK?

Code: Alles auswählen

#!/usr/bin/env python3
from functools import partial
import socket
import threading
from time import sleep
from RPi import GPIO
from random import randrange

BUFFER_SIZE = 8192
SERVER = ("", 8008)
TARGET_HOST = ("10.10.10.4", 8007)

PIN_AUS = [29, 31, 33, 35, 37]
PIN_EIN = [16, 18]

# gpio definieren
def set_gpio():
    GPIO.cleanup()#falls dei gpios schon aktive sind
    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(PIN_AUS, GPIO.OUT, initial=GPIO.HIGH)
    GPIO.setup(PIN_EIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

def read_pins(pins):
    result = 0
    for pin in pins:
        result = (result <<1) | (not GPIO.input(pin)) #Dualzahl als Dezimalzahl darstellen
        # alternative       result = result * 2 + (not GPIO.input(pin))
    return result

def onewire_devices():#1wire geräte auslesen
    file = open('/sys/devices/w1_bus_master1/w1_master_slaves')
    w1_slaves = file.readlines()
    file.close()
    return w1_slaves

def onewire(udp_socket,w1_slaves):#1wire sensoren einzeln auslesen
    for line in w1_slaves:
        try:
            file = open('/sys/bus/w1/devices/' + line.split("\n")[0] + '/w1_slave')
            filecontent = file.read()
            file.close()
            stringvalue = ((filecontent.split("\n")[1].split(" ")[9])[2:]).encode()#formatieren und in bytes konvertieren
            temperatur = ("sensor " + line.split("\n")[0] +",").encode() + stringvalue
            print(temperatur)
            udp_socket.sendto(temperatur, TARGET_HOST)
        except OSError:
            print("OSError")

def reply_loxone(udp_socket, command):# Rückmeldung ob das Programm noch läuft
    udp_socket.sendto(command, TARGET_HOST)
    print("reply_loxone")

def ausgang_setzen(udp_socket, pin, zustand, command):
    #setzen der ausgänge
    GPIO.output(pin, zustand)
    udp_socket.sendto(command, TARGET_HOST)
    print("ausgang ", pin, zustand)

def tor_auf_zu(udp_socket, command):
    #tor öffner wird "gedrückt"
    GPIO.output(37, False)
    sleep(0.5)
    GPIO.output(37, True)
    udp_socket.sendto(command, TARGET_HOST)
    print("toraufzu")


#arbeits loop
def loop_einaus_abfragen(udp_socket,w1_slaves):
    while True:
        for counter in range(0, 150):
            zustand_aus = read_pins(PIN_AUS)
            zustand_ein = read_pins(PIN_EIN)
            udp_socket.sendto(b"zustand_aus,%d" % zustand_aus, TARGET_HOST)
            udp_socket.sendto(b"zustand_ein,%d" % zustand_ein, TARGET_HOST)
            if counter == 1:
                onewire(udp_socket, w1_slaves)
                # 1wire sensoren senden
            elif counter == 50 or counter == 75:
                print("schleife bei", counter)
                # platzhalter für andere funktionen
            elif counter in [25,45,90]:
                print("schleife bei", counter)
                # platzhalter für andere funktionen
            sleep(0.5)

def main():
    set_gpio()
    w1_slaves = onewire_devices()
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    udp_socket.sendto(b"tets", TARGET_HOST)
    command_to_function = {
        b"reply_loxone": partial(reply_loxone, udp_socket),
        b"tor_auf_zu": partial(tor_auf_zu, udp_socket),        
        b"ausgang1_ein": partial(ausgang_setzen, udp_socket, 35, False),
        b"ausgang1_aus": partial(ausgang_setzen, udp_socket, 35, True),
        b"ausgang2_ein": partial(ausgang_setzen, udp_socket, 33, False),
        b"ausgang2_aus": partial(ausgang_setzen, udp_socket, 33, True),
        b"ausgang3_ein": partial(ausgang_setzen, udp_socket, 31, False),
        b"ausgang3_aus": partial(ausgang_setzen, udp_socket, 31, True),
        b"ausgang4_ein": partial(ausgang_setzen, udp_socket, 29, False),
        b"ausgang4_aus": partial(ausgang_setzen, udp_socket, 29, True),
    }
    try:
        udp_socket.sendto(b"test", TARGET_HOST)	
        loop_einaus_thread = threading.Thread(
            target=loop_einaus_abfragen,
            args=(udp_socket,w1_slaves),
            daemon=True,
        )
        loop_einaus_thread.start()
        print("UDPServer Waiting for client on port", SERVER)
        while True:
            command, _addr = udp_socket.recvfrom(BUFFER_SIZE)
            print(command)
            try:
                function = command_to_function[command]
            except KeyError:
                print("KeyError")
                udp_socket.sendto(f"Unknown command {command!a}".encode("ascii"), TARGET_HOST)
            else:
                function(command)
    finally:
        GPIO.cleanup()


if __name__ == "__main__":
    main()
Gruss

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Montag 2. März 2020, 08:58
von Sirius3
Dateien öffnet man immer in einem with-Block. Konstante Strings sollten als Konstanten am Anfang der Datei stehen. Man stückelt keine Pfade per + zusammen. Um das Zeile-Ende-Zeichen zu entfernen gibt es rsplit. Den Dateiinhalt von w1_slave sollte man noch etwas genauer analysieren. Die Zeilen zu stringvalue und temperatur sind zu lang und unleserlich, vor allem, weil hier zu viel mit Strings verumgefummelt wird. Man berechnet nicht zwei mal das selbe, sondern merkt sich das Ergebnis. Die Umwandlung von Slave-Nummern sollte aber schon in onewire_devices stattfinden.

Code: Alles auswählen

W1_MASTER_SLAVES = '/sys/devices/w1_bus_master1/w1_master_slaves' 
DEVICE_PATH = '/sys/bus/w1/devices/{}/w1_slave'

def onewire_devices():
    """ 1wire geräte auslesen """
    with open(W1_MASTER_SLAVES) as lines:
        return [l.strip() for l in lines]

def read_temperature(slave):
    with open(DEVICE_PATH.format(slave)) as lines:
        crc_ok = next(lines).split()[-1] == 'YES'
        if not crc_ok:
            raise OSError("crc not ok")
        temperature = next(lines).split()[-1]
        if not temperature.startswith('t='):
            raise OSError("format currupt")
        return temperature[2:]

def onewire(udp_socket, w1_slaves):
    """ 1wire sensoren einzeln auslesen """
    for slave in w1_slaves:
        try:
            temperature = read_temperature(slave)
            text = f"sensor {slave},{temperature}"
            udp_socket.sendto(text.encode(), TARGET_HOST)
        except OSError:
            print("OSError")

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Montag 2. März 2020, 21:47
von pumuckll
Danke
das ist viel übersichtlicher so.

Re: gpio bei Programmstart schon High (OPi.GPIO threading)

Verfasst: Freitag 6. März 2020, 12:25
von pumuckll
Ich hab versucht, hier gelerntes anzuwenden und das Programm umgeschrieben, damit ich es leichter für verschieden Anwendungen anpassen kann.

Erstaunlicherweise Funktioniert läuft es auch.

UDP Nachrichten hab ic auf ein Minimum reduziert und das Wörterbuch wird von einer Schleife erstellt.
Somit brauche ich nur die gpio^s definieren und die Eingangs Kommandos werden automatisch generiert.
Habe ich das so gut gelöst?

Ich konnte den Logger nicht in eine Funktion verschieben, obwohl ich viel probiert habe.
Return in einer Funktion hat nicht funktioniert.

Wie macht man das?

Warum wird das entweder als Kommentar erkannt oder als string?

Code: Alles auswählen

""" 1wire sensoren einzeln auslesen """
Wie kommentiere ich den Code am besten?



Gruss

Code: Alles auswählen

#!/usr/bin/env python3
"""Diese Script Sendet und empfängt UDP Nachrichten,
   um Ausgänge zu schalten und um  den Status von Eingängen, Ausgängen sowie von 1Wire Sensoren  auszugeben.
   Verwendbar für Raspberrypi 3 und 4, orangepi zero """

from functools import partial
import socket
import threading
import OPi.GPIO as GPIO   #OrangePi
#from RPi import GPIO    #RaspberryPi
import logging
from logging.handlers import TimedRotatingFileHandler
from time import sleep

# """ UDP einstellungen  """
BUFFER_SIZE = 8192
SERVER = ("", 8006)
TARGET_HOST = ("10.10.10.4", 8005)

#gpio einstellungen
PIN_AUS = [11, 13, 15, 19]
INITIAL_AUS = [GPIO.HIGH, GPIO.HIGH, GPIO.HIGH, GPIO.HIGH]
PIN_EIN = [16, 18]
INITIAL_EIN = [GPIO.PUD_DOWN, GPIO.PUD_DOWN]

#1wire einstellungen
ONEWIRE_VORHANDEN = True
W1_MASTER_SLAVES = '/sys/devices/w1_bus_master1/w1_master_slaves'
DEVICE_PATH = '/sys/bus/w1/devices/{}/w1_slave'

#logger
logger = logging.getLogger("Rotating Log")
logger.setLevel(logging.DEBUG)
handler = TimedRotatingFileHandler("in_out.log", when='D', interval=1, backupCount=7, encoding=None,
                                   delay=False, utc=False, atTime=None)
fileformatter = logging.Formatter('%(asctime)s : %(levelname)s : %(name)s : %(message)s')
handler.setFormatter(fileformatter)
logger.addHandler(handler)

logger.debug("logger started")

# Wörterbuch erstellen
def dictionary_function(udp_socket):
    command_to_func = {b"tor_auf_zu": partial(tor_auf_zu, udp_socket),
                           b"reply_loxone": partial(reply_loxone, udp_socket)}
    for aus_nummer, aus_pin, initial_wert in zip(range(len(PIN_AUS)), PIN_AUS, INITIAL_AUS):
        aus_nummer += 1
        if initial_wert == True:
            initial_wert_ein = False
            command_to_func[str("ausgang_{}_ein".format(aus_nummer)).encode()] = partial(ausgang_setzen, udp_socket,
                                                                                             aus_pin, initial_wert_ein)
        else:
            initial_wert_ein = True
            command_to_func[str("ausgang_{}_ein".format(aus_nummer)).encode()] = partial(ausgang_setzen, udp_socket,
                                                                                             aus_pin, initial_wert_ein)
        if initial_wert == True:
            initial_wert_aus = True
            command_to_func[str("ausgang_{}_aus".format(aus_nummer)).encode()] = partial(ausgang_setzen, udp_socket,
                                                                                             aus_pin, initial_wert_aus)
        else:
            initial_wert_aus = False
            command_to_func[str("ausgang_{}_aus".format(aus_nummer)).encode()] = partial(ausgang_setzen, udp_socket,
                                                                                             aus_pin, initial_wert_aus)
    return command_to_func



# gpio definieren
def set_gpio():
    try:
        GPIO.cleanup()#falls die gpios schon aktive sind
        GPIO.setmode(GPIO.BOARD)
        for pin,initial  in zip(PIN_AUS,INITIAL_AUS):
            GPIO.setup(pin, GPIO.OUT, initial=initial)
        for pin, initial in zip(PIN_EIN, INITIAL_EIN):
            GPIO.setup(pin, GPIO.IN, pull_up_down=initial)
    except OSError:
        logger.exception("gpio set error")

def read_pins(pins):
    result = 0
    for pin in pins:
        result = result * 2 + (not GPIO.input(pin))
    return result

def onewire_devices():
    """ 1wire geräte auslesen """
    with open(W1_MASTER_SLAVES) as lines:
        one_wire = [l.strip() for l in lines]
        logger.debug("1Wire slaves {}".format(one_wire))
        return one_wire

def read_temperature(slave):
    with open(DEVICE_PATH.format(slave)) as lines:
        crc_ok = next(lines).split()[-1] == 'YES'
        if not crc_ok:
            raise OSError("crc not ok")
            logger.exception("crc not ok")
        temperature = next(lines).split()[-1]
        if not temperature.startswith('t='):
            raise OSError("format currupt")
            logger.exception("format currupt")

        return temperature[2:]
def onewire(udp_socket, w1_slaves):
    """ 1wire sensoren einzeln auslesen """
    for slave in w1_slaves:
        try:
            temperature = read_temperature(slave)
            text = f"sensor {slave},{temperature}"
            udp_socket.sendto(text.encode(), TARGET_HOST)
        except OSError:
            logger.exception("OSError")

def reply_loxone(udp_socket, command):
    udp_socket.sendto(command, TARGET_HOST)

def ausgang_setzen(udp_socket, pin, zustand, command):
    try:
        GPIO.output(pin, zustand)
        logging.debug(" Asugang {} = {} ".format(pin, zustand))
    except Exception:
        logger.exception("gpio error")

#tor öffner wird "gedrückt"
def tor_auf_zu(udp_socket, command):
    try:
        GPIO.output(37, False)
        sleep(0.5)
        GPIO.output(37, True)
    except Exception:
        logger.exception("gpio tor_auf_zu error")

#arbeits loop
def loop_einaus_abfragen(udp_socket,w1_slaves):
    try:
        komparator_aus = 0
        komparator_ein = 0
        while True:
            for counter in range(0, 150):
                zustand_aus = read_pins(PIN_AUS)
                zustand_ein = read_pins(PIN_EIN)
                if zustand_aus != komparator_aus:
                    udp_socket.sendto(b"zustand_aus,%d" % zustand_aus, TARGET_HOST)
                    komparator_aus = zustand_aus
                    logger.debug(" zustand_aus {} ungleich".format(zustand_aus))
                if zustand_ein != komparator_ein:
                    udp_socket.sendto(b"zustand_ein,%d" % zustand_ein, TARGET_HOST)
                    komparator_ein = zustand_ein
                    logger.debug(" zustand_ein {} ungleich".format(zustand_ein))
                if counter == 1:
                    if ONEWIRE_VORHANDEN:
                        onewire(udp_socket, w1_slaves)
                        logger.debug("1Wire device {}".format(onewire))
                        #1wire sensoren senden
                elif counter == 50:
                    logger.debug("schleife bei {}".format(counter))
                    #platzhalter für andere funktionen
                elif counter in [0,30,60,120]:
                    udp_socket.sendto(b"zustand_aus,%d" % zustand_aus, TARGET_HOST)
                    udp_socket.sendto(b"zustand_ein,%d" % zustand_ein, TARGET_HOST)
                    logger.debug("zustand_ein {} ".format(zustand_aus))
                    logger.debug("zustand_aus {} ".format(zustand_aus))
                sleep(0.5)
    except Exception:
        logger.exception("arbeits loop error")

def main():
    set_gpio()
    w1_slaves = onewire_devices()
    udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    udp_socket.bind(SERVER)
    dictionary_function(udp_socket)
    command_to_function =dictionary_function(udp_socket)
    logger.debug("dictionary created : {} ".format(command_to_function))
#
    try:
        loop_einaus_thread = threading.Thread(
            target=loop_einaus_abfragen,
            args=(udp_socket,w1_slaves),
            daemon=True,
        )
        loop_einaus_thread.start()

        logger.debug("UDPServer Waiting for client on port : {} ".format(SERVER))
        while True:
            command, _addr = udp_socket.recvfrom(BUFFER_SIZE)
            logger.debug("UDPServer command : {} ".format(command))
            try:
                function = command_to_function[command]
            except KeyError:
                udp_socket.sendto(f"Unknown command {command!a}".encode("ascii"), TARGET_HOST)
                logger.exception("KeyError")
            else:
                function(command)
                logger.debug(" function {} ".format(function))

    finally:
        GPIO.cleanup()

if __name__ == "__main__":
    main()