GPIO und 1-Wire per UDP senden

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
MikeHF
User
Beiträge: 6
Registriert: Sonntag 2. April 2017, 21:43

Hallo Zusammen,

ich bin sehr neu in Sachen Python und hab da gleich ein Problem.

Ich versuche den Status bzw. die Status Änderung per UDP zu senden.
Das funktioniert soweit auch.

Aber bleibt einer der Taster an den GPIO´s geschlossen werden ab da die anderen GPIO´s ignoriert.

Ich möchte mit einem GPIO einen Betriebszustand einer Heizung und mit einem GPIO Impulse des Gaszählers übertragen.
Deswegen kommt es natürlich durchaus vor das einer der GPIO´s für eine längere Zeit aktiv ist.

Ich finde den Fehler im Script leider nicht.

Könnt Ihr mir helfen?

Danke und Viele Grüße
Mike



Code: Alles auswählen

# Beenden dauert solange wie in temperaturzeit drine steht

import os, sys, time, socket, RPi.GPIO as GPIO, threading # Importiert die Klassen
GPIO.setmode(GPIO.BCM) #BCM Modus fuer GPIO
GPIO.setwarnings(False) # Warnungen fuer GPIO Auschalten

#___________________UDP___________________________
UDP_IP = "172.16.1.40" # IP des empfaengers
UDP_PORT = 7007 # Port des empfeangers
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # UDP Seasion eaffnen
#__________________________________________________

#___________________Temperatur_sensoren____________
temperaturzeit = 10 # Zeit bis zur neachsten wiederholung in Sekunden
Sensor = ['28-041685fa3dff','28-041686101aff','28-041685eb30ff','28-0416860135ff','28-0516869ef8ff']#Sensoren hier eintragen -----> ['10-000802d3ab2f','Neachstersensor'] zufinden in /sys/devices/w1_bus_master1/
#___________________________________________________

#___________________GPIO__________________________
buttonsend = 5 # Wird 5 Mal gesendet
druchlaeufe = 0
buttonwait = 0.01 # x Sec Warten bis zum naechsten senden
button1 = 13
button2 = 17
button3 = 18
buttonstatus1 = 0
buttonstatus2 = 0
buttonstatus3 = 0
GPIO.setup(button1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(button2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(button3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
#______________________________________________________

def aktuelleTemperatur():
while not stop:
 time.sleep(temperaturzeit)
 for index in range(len(Sensor)):
   # 1-wire Slave Datei lesen
   file = open('/sys/bus/w1/devices/' + str(Sensor[index]) +'/w1_slave')
   filecontent = file.read()
   file.close()

   # Temperaturwerte auslesen und konvertieren
   stringvalue = filecontent.split("\n")[1].split(" ")[9]
   temperature = float(stringvalue[2:]) / 1000

   # Temperatur ausgeben
   rueckgabewert = '%0.2f' % temperature  #<-------- wird aktuell in 21.25 ausgegeben fuer Temperatur 21,25 C  [rueckgabewert = '%0.2f' % temperature]
   print "Aktuelle Temperatur von Sensor " + (Sensor[index])+ ":" , rueckgabewert, "C"
 
   sock.sendto(Sensor[index] + ":"+ rueckgabewert, (UDP_IP, UDP_PORT))# Sendet wert an UDP Client
def buttonsender(button,status):
global druchlaeufe
global buttonsend
if status == 0:
 if not druchlaeufe == buttonsend:
      for x in range(0,buttonsend):
       time.sleep(buttonwait)
       print(str(button) + ":1" )
       sock.sendto(str(button) + ":1", (UDP_IP, UDP_PORT))
       druchlaeufe += 1
#        print status
#        print druchlaeufe
if status == 1:
 if druchlaeufe == buttonsend:
     if not GPIO.input(button): #Wenn Button
       for x in range(0,buttonsend):
        time.sleep(buttonwait)
        print(str(button) +":0" )
        sock.sendto(str(button) +":0", (UDP_IP, UDP_PORT))
        druchlaeufe=0  
#         print status
#         print druchlaeufe  

try:
   stop = False
   t1 = threading.Thread(target=aktuelleTemperatur)
   t1.start()
   

   while True:
#______Buttons senden___________
     if GPIO.input(button1):
      if buttonstatus1 == 0:
       buttonsender(button1,buttonstatus1)
       buttonstatus1 = 1
     if not GPIO.input(button1):
      if druchlaeufe == buttonsend:
       buttonsender(button1,buttonstatus1)
       buttonstatus1 = 0

   
     if GPIO.input(button2):
      if buttonstatus2 == 0:
       buttonsender(button2,buttonstatus2)
       buttonstatus2 = 1
     if not GPIO.input(button2):
      if druchlaeufe == buttonsend:
       buttonsender(button2,buttonstatus2)
       buttonstatus2 = 0


      if GPIO.input(button3):
       if buttonstatus3 == 0:
        buttonsender(button3,buttonstatus3)
        buttonstatus3 = 1
      if not GPIO.input(button3):
       if druchlaeufe == buttonsend:
        buttonsender(button3,buttonstatus3)
        buttonstatus3 = 0
#________________________________

#---------Unwichtig-----
except (KeyboardInterrupt, SystemExit):
   stop = True
#-----------------------
sock.close
print("Ende")
Zuletzt geändert von Anonymous am Sonntag 2. April 2017, 23:16, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@MikeHF: Die Einrückung ist kaputt und wo (wahrscheinlich) richtig vorhanden hält sie sich nicht an die Konvention von vier Leerzeichen pro Einrückebene.

Threads und ``global`` sind ein Grund sich das gar nicht erst näher anzuschauen. (Einigen reicht schon ``global`` alleine aus.)

Das gleiche Socket-Objekt aus zwei verschiedenen Threads gleichzeitig zum Senden von Daten zu verwenden ist ziemlich sicher keine robuste Idee.
MikeHF
User
Beiträge: 6
Registriert: Sonntag 2. April 2017, 21:43

Hallo BlackJack,

ich habe mal versucht die Einrückungen nach den Konventionen zu berichtigen.

Leider bin ich kein Programmierer der Python beherrscht ich kann mich nur irgendwie an ein Ergebnis ran tasten und hoffen das es funktioniert.

Wüsste ich wie man es richtig mach hätte ich nicht um Hilfe bitten müssen.

Sich in das Thema Python einlesen ist die eine Sache es verstehen und richtig machen ist eine andere.
Da ich Python vorerst vermutlich nur für dieses eine Projekt brauchen werde wird das erlernte vermutlich auch nicht lange anhalten.

Vielleicht kann mir ja jemand zeigen wie man es richtig macht und ich kann dadurch bissen was lernen.

Danke und Viele Grüße
Mike

Code: Alles auswählen

# Beenden dauert solange wie in temperaturzeit drine steht 

import os, sys, time, socket, RPi.GPIO as GPIO, threading # Importiert die Klassen
GPIO.setmode(GPIO.BCM) #BCM Modus fuer GPIO
GPIO.setwarnings(False) # Warnungen fuer GPIO Auschalten

#___________________UDP___________________________
UDP_IP = "172.16.1.40" # IP des empfaengers
UDP_PORT = 7007 # Port des empfeangers
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # UDP Seasion eaffnen
#__________________________________________________

#___________________Temperatur_sensoren____________
temperaturzeit = 10 # Zeit bis zur neachsten wiederholung in Sekunden
Sensor = ['28-041685fa3dff','28-041686101aff','28-041685eb30ff','28-0416860135ff','28-0516869ef8ff']#Sensoren hier eintragen -----> ['10-000802d3ab2f','Neachstersensor'] zufinden in /sys/devices/w1_bus_master1/
#___________________________________________________

#___________________Knoepfe__________________________
buttonsend = 4 # Wird 4 Mal gesendet
druchlaeufe = 0 
buttonwait = 0.01 # x Sec Warten bis zum naechsten senden
button1 = 13
button2 = 17
button3 = 18
buttonstatus1 = 0
buttonstatus2 = 0
buttonstatus3 = 0
GPIO.setup(button1, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(button2, GPIO.IN, pull_up_down=GPIO.PUD_UP)
GPIO.setup(button3, GPIO.IN, pull_up_down=GPIO.PUD_UP)
#______________________________________________________

def aktuelleTemperatur():
    while not stop:
        time.sleep(temperaturzeit)
        for index in range(len(Sensor)):
        # 1-wire Slave Datei lesen
            file = open('/sys/bus/w1/devices/' + str(Sensor[index]) +'/w1_slave')
            filecontent = file.read()
            file.close()
 
        # Temperaturwerte auslesen und konvertieren
            stringvalue = filecontent.split("\n")[1].split(" ")[9]
            temperature = float(stringvalue[2:]) / 1000
 
        # Temperatur ausgeben
            rueckgabewert = '%0.2f' % temperature  #<-------- wird aktuell in 21.25 ausgegeben fuer Temperatur 21,25 C  [rueckgabewert = '%6.2f' % temperature]
            print "Aktuelle Temperatur von Sensor " + (Sensor[index])+ ":" , rueckgabewert, "C"
   
            sock.sendto(Sensor[index] + ":"+ rueckgabewert, (UDP_IP, UDP_PORT))# Sendet wert an UDP Client
def buttonsender(button,status):
    global druchlaeufe
    global buttonsend
    if status == 0:
        if not druchlaeufe == buttonsend:
            for x in range(0,buttonsend):
                time.sleep(buttonwait)
                print(str(button) + ":1" )
                sock.sendto(str(button) + ":1", (UDP_IP, UDP_PORT))
                druchlaeufe += 1
                print status
                print druchlaeufe
    if status == 1:
        if druchlaeufe == buttonsend:
#            if not GPIO.input(button): #Wenn Button 
            for x in range(0,buttonsend):
                time.sleep(buttonwait)
                print(str(button) +":0" )
                sock.sendto(str(button) +":0", (UDP_IP, UDP_PORT))
                druchlaeufe = 0  
                print status
                print druchlaeufe		  

try:
    stop = False
    t1 = threading.Thread(target=aktuelleTemperatur)
    t1.start()
    

    while True: 
#______Buttons senden___________
        if GPIO.input(button1):
            if buttonstatus1 == 0:
                buttonsender(button1,buttonstatus1)
                buttonstatus1 = 1
        if not GPIO.input(button1): 
            if druchlaeufe == buttonsend:
                buttonsender(button1,buttonstatus1)
                buttonstatus1 = 0

     
        if GPIO.input(button2):
            if buttonstatus2 == 0:
                buttonsender(button2,buttonstatus2)
                buttonstatus2 = 1
        if not GPIO.input(button2): 
            if druchlaeufe == buttonsend:
                buttonsender(button2,buttonstatus2)
                buttonstatus2 = 0


        if GPIO.input(button3):
            if buttonstatus3 == 0:
                buttonsender(button3,buttonstatus3)
                buttonstatus3 = 1
        if not GPIO.input(button3):
            if druchlaeufe == buttonsend:
                buttonsender(button3,buttonstatus3)
                buttonstatus3 = 0

#________________________________

#---------Unwichtig-----
except (KeyboardInterrupt, SystemExit):
    stop = True
#-----------------------
sock.close
print("Ende")
Sirius3
User
Beiträge: 17703
Registriert: Sonntag 21. Oktober 2012, 17:20

@MikeHF: bevor man so ein Programm überhaupt verstehen kann, muß man es in eine Form bringen, die einigermaßen lesbar ist, das heißt, keine globalen Variablen, kein Mischen von Definitionen und ausführbaren Code. Nutzen von True und False statt 1 und 0; die richtige Logik, also nicht dass auch noch 0 und 1 vertauscht sind. Keine endlosen Code-Wiederholungen. Dann fallen auch so einige unnützen Zeilen auf, die man ohne Änderung der Logik löschen kann (durchlaeufe). Dann kommt man ungefähr hier raus:

Code: Alles auswählen

import os
import time
import socket
import RPi.GPIO as GPIO
import threading

UDP_ADDRESS = ("172.16.1.40", 7007) # Adresse des Empfaengers

WAITING_TIME = 10 # Zeit bis zur neachsten wiederholung in Sekunden
SENSORS = ['28-041685fa3dff','28-041686101aff','28-041685eb30ff','28-0416860135ff','28-0516869ef8ff']

BUTTON_PINS = [13, 17, 18]
BUTTON_SEND_REPEAT = 4
BUTTON_SEND_WAIT_TIME = 0.01

def read_temperature_loop(sock, stop_event):
    while not stop_event.wait(WAITING_TIME):
        for sensors in SENSORS:
            # Temperaturwerte auslesen und konvertieren
            with open(os.path.join('/sys/bus/w1/devices', sensor, 'w1_slave')) as device:
                filecontent = device.read()
            temperature = 0.001 * float(filecontent.rsplit('t=', 1)[-1])
            print "Aktuelle Temperatur von Sensor {}: {:.2f}C".format(sensor, temperature)
            sock.sendto("{}:{.2f}".format(sensor, temperature), UDP_ADDRESS)

def send_button_status(sock, pin, status):
    for _ in range(BUTTON_SEND_REPEAT):
        time.sleep(BUTTON_SEND_WAIT_TIME)
        text = "{}:{:d}".format(pin, status)
        print text
        sock.sendto(text, UDP_ADDRESS)

def main():
    GPIO.setmode(GPIO.BCM) #BCM Modus fuer GPIO
    # GPIO.setwarnings(False) # Warnungen sollten nicht ausgeschaltet werden
    for pin in BUTTON_PINS:
        GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    button_status = dict.from_keys(BUTTON_PINS, False)
    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # UDP Seasion eaffnen
    
    stop_event = threading.Event()
    temperature_read_thread = threading.Thread(target=read_temperature_loop, args=(sock, stop_event))
    temperature_read_thread.start()

    try:
        while True:
            for pin in BUTTON_PINS:
                new_status = GPIO.input(pin)
                if new_status != button_status[pin]:
                    button_status[pin] = new_status
                    send_button_status(sock, pin, button_status[pin])
    except KeyboardInterrupt:
        pass
    finally:
        stop_event.set()
        temperature_read_thread.wait()
        sock.close()
        GPIO.cleanup() 
    print("Ende")
    
if __name__ == '__main__':
    main()
MikeHF
User
Beiträge: 6
Registriert: Sonntag 2. April 2017, 21:43

Hallo Sirius3,

ja das schaut natürlich gleich ganz anders aus.
Danke.

Leider scheint mein Wissen auch zum Starten deines Scripts nicht zu reichen. :K

Bei Starten kommt folgende Meldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "/usr/MKSkript/sender.py", line 62, in <module>
    main()
  File "/usr/MKSkript/sender.py", line 38, in main
    button_status = dict.from_keys(BUTTON_PINS, False)
AttributeError: type object 'dict' has no attribute 'from_keys'
Was mach ich falsch?

Danke und Viele Grüße
Mike
BlackJack

@MikeHF: Die Methode heisst `fromkeys()`. Sirius3 konnte das ohne die enstprechende Hardware ja sicherlich nicht ausführen, also können solche Fehler drin sein.
MikeHF
User
Beiträge: 6
Registriert: Sonntag 2. April 2017, 21:43

Ok verstehe.

Hab es angepasst und läuft nach ein paar kleinen Änderung super.

Das einzige ist noch das beim Beenden ein Fehler auftritt der besagt das, das Attribut 'wait' in Zeile 56 'temperature_read_thread.wait()' nicht stimmt.
Was bewirkt die Zeile?

Viele Grüße
Mike
BlackJack

@MikeHF: Die Zeile bewirkt gar nichts, weil es das `wait`-Attribut ja nicht gibt. Versuch's mal mit `join()` statt `wait()`. :-)
MikeHF
User
Beiträge: 6
Registriert: Sonntag 2. April 2017, 21:43

@Sirius3 und BlackJack: Vielen Dank jetzt funktioniert das ganze genauso wie ich mir das vorgestellt habe.

Und jetzt zum Lern Aspekt:
Wo finde man zum Beispiel die Info welche Attribute es für „Thread“ gibt?
Hab sleep; close; exit usw. versucht auf join bin ich nicht gestoßen.

Wenn ich das ganze richtig versteh gibt es dann noch bezogen auf die Hardware unterschiedliche Möglichkeiten?

Anbei noch der CODE der nun bei mir seinen Dienst verrichtet:

Code: Alles auswählen

import os
import time
import socket
import RPi.GPIO as GPIO
import threading
 
UDP_ADDRESS = ("172.16.1.40", 7007) # Adresse des Empfaengers
 
WAITING_TIME = 10 # Zeit bis zur neachsten wiederholung in Sekunden
SENSORS = ['28-041685fa3dff','28-041686101aff','28-041685eb30ff','28-0416860135ff','28-0516869ef8ff']
 
BUTTON_PINS = [13, 17, 18,]
BUTTON_SEND_REPEAT = 2
BUTTON_SEND_WAIT_TIME = 0.01
 
def read_temperature_loop(sock, stop_event):
    while not stop_event.wait(WAITING_TIME):
        for sensors in SENSORS:
            # Temperaturwerte auslesen und konvertieren
            with open(os.path.join('/sys/bus/w1/devices', sensors, 'w1_slave')) as device:
                filecontent = device.read()
            temperature = 0.001 * float(filecontent.rsplit('t=', 1)[-1])
            print "Aktuelle Temperatur von Sensor {}: {:.2f}C".format(sensors, temperature)
            sock.sendto("{}:{:.2f}".format(sensors, temperature), UDP_ADDRESS)
 
def send_button_status(sock, pin, status):
    for _ in range(BUTTON_SEND_REPEAT):
        time.sleep(BUTTON_SEND_WAIT_TIME)
        text = "{}:{:d}".format(pin, status)
        print text
        sock.sendto(text, UDP_ADDRESS)
 
def main():
    GPIO.setmode(GPIO.BCM) #BCM Modus fuer GPIO
    # GPIO.setwarnings(False) # Warnungen sollten nicht ausgeschaltet werden
    for pin in BUTTON_PINS:
        GPIO.setup(pin, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    button_status = dict.fromkeys(BUTTON_PINS, False)
    sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # UDP Seasion eaffnen
   
    stop_event = threading.Event()
    temperature_read_thread = threading.Thread(target=read_temperature_loop, args=(sock, stop_event))
    temperature_read_thread.start()
 
    try:
        while True:
            for pin in BUTTON_PINS:
                new_status = GPIO.input(pin)
                if new_status != button_status[pin]:
                    button_status[pin] = new_status
                    send_button_status(sock, pin, button_status[pin])
    except KeyboardInterrupt:
        pass
    finally:
        stop_event.set()
        temperature_read_thread.join()
        sock.close()
        GPIO.cleanup()
    print("Ende")
   
if __name__ == '__main__':
    main()
BlackJack

@MikeHF: Es gibt eine umfangreiche Dokumentation von Python und der Standardbibliothek, da steht drin was `Thread`-Objekte für Attribute haben und was die bedeuten.
MikeHF
User
Beiträge: 6
Registriert: Sonntag 2. April 2017, 21:43

Ok dann werde ich mir das mal genauer ansehen.

Vielen Dank noch mal.

VG Mike
Antworten