Elegantere Variante gesucht

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
Neodog
User
Beiträge: 3
Registriert: Mittwoch 11. Januar 2017, 00:28

Mittwoch 11. Januar 2017, 00:36

Hallo liebes Forum!

Ich bin blutiger Anfänger in Sachen programmieren. (Dafür ist der kleine Raspi ja gedacht) Nachdem ich viele tolle Anleitungen gefunden habe habe ich ein script erstellt welches auch funktioniert. Ich habe jedoch für einen Punkt keine Lösung gefunden.
Als Einführung: Ein Türkontakt (GPIO.input) schaltet ein Relais zum einschalten einer Beleuchtung (GPIO.output) und versendet einen Nachricht via Pushbullet. Die Nachricht soll natürlich nicht in einen permanenten Schleife kommen sonder nur alle x Minuten.

Wenn das Licht eingeschaltet ist dann bleibt es so lange an wie time.sleep definiert ist. Schöner wäre wenn es natürlich sofort bei geschlossenem Kontakt wieder aus geht.


Wie kann ich das eleganter lösen?

Code: Alles auswählen

#!/usr/bin/python
 import time
 import RPi.GPIO as GPIO
 GPIO.setwarnings(False)
 GPIO.setmode(GPIO.BCM)
 GPIO.setup(27,GPIO.IN)
 GPIO.setup(18,GPIO.OUT)


 while True:

        if not GPIO.input(27):
                GPIO.output(18, 1) #Licht einschalten
                import subprocess
                print "Nachricht versenden, Licht eingeschaltet"
                subprocess.call ("pushbullet.sh") #Nachricht versenden
                print "Nachricht wurde versendet"
                time.sleep(10)

        else:
                GPIO.output(18, 0) #Licht ausschalten

Zuletzt geändert von Anonymous am Mittwoch 11. Januar 2017, 10:11, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Mittwoch 11. Januar 2017, 08:25

Du könntest in die While-Schleife noch ein time.sleep(1) setzen.
Damit würde die Schleife nur jede Sekunde durchlaufen.

Für das andere Problem kannst du dir eine Variable erstellen (zustand_alt=False).
Dann reagiert er nur, wenn es wirklich eine Zustandänderung gibt.
Vielleicht so:

Code: Alles auswählen

#PSEUDOCODE
zustand_neu = GPIO.input(27)
zustand_alt = False
while True:
    if zustand_neu != zustand_alt:
        if zustand_neu:
            licht ein
        else:
            licht aus
        zustand_alt = zustand_neu    
    zustand_neu = GPIO.input(27)
    time.sleep(1)
    
Sirius3
User
Beiträge: 7790
Registriert: Sonntag 21. Oktober 2012, 17:20

Mittwoch 11. Januar 2017, 09:12

@sebastian0202: man will wohl nicht eine Sekunde lang warten, bis das Lich angeht. Schon nach 200ms fragt man sich, ähm, ist das Licht vielleicht kaputt? zustand_neu zwei mal im Code zu setzen ist unnötig, wenn man das am Anfang der Schleife macht.

@Neodog: Warnings sind dazu da, Dich zu warnen. Sollte also eine Warnung stören, solltest Du den Grund und nicht die Meldung abschalten. Es wird immer mit 4 Leerzeichen pro Ebene eingerückt. subprocess.call erwartet eine Liste und keinen String als Argument. Importe sollten immer ganz am Anfang der Datei stehen, damit man auf einen Blick die Abhängigkeiten sieht.

Code: Alles auswählen

#!/usr/bin/python
import time
import subprocess
import RPi.GPIO as GPIO

def switch(state):
    # Licht ein- oder ausschalten
    GPIO.output(18, state) 
    if state:
        # Nachricht versenden
        subprocess.call(["pushbullet.sh"])

def process():
    old_state = False
    while True:
        new_state = not GPIO.input(27)
        if new_state != old_state :
            switch(new_state)
            old_state = new_state
        time.sleep(0.1)

def main():
    try:  
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(27, GPIO.IN)
        GPIO.setup(18, GPIO.OUT)
        process()
    except KeyboardInterrupt:  
        pass
    finally:  
        GPIO.cleanup()
                
if __name__ == '__main__':
    main()
BlackJack

Mittwoch 11. Januar 2017, 12:03

@Neodog: Ich würde dann noch die ”magischen” Pin-Nummern im Programm durch Konstanten ersetzen, so dass man den Wert nur einmal im Programm stehen hat, und überall wo er benutzt wird, am Namen ablesen kann, was der Pin bedeutet.

Mit `wait_for_edge()` sollte man das „busy waiting“ beseitigen können.

Ungetestet:

Code: Alles auswählen

#!/usr/bin/env python
import subprocess
import time
from RPi import GPIO

LIGHT_PIN = 18
SWITCH_PIN = 27


def switch(state):
    GPIO.output(LIGHT_PIN, state)
    if state:
        # Nachricht versenden.
        subprocess.call(['pushbullet.sh'])
 

def process():
    while True:
        GPIO.wait_for_edge(SWITCH_PIN, GPIO.BOTH)
        switch(not GPIO.input(SWITCH_PIN))


def main():
    try:  
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(SWITCH_PIN, GPIO.IN)
        GPIO.setup(LIGHT_PIN, GPIO.OUT)
        process()
    except KeyboardInterrupt:  
        pass
    finally:  
        GPIO.cleanup()
              

if __name__ == '__main__':
    main()
Neodog
User
Beiträge: 3
Registriert: Mittwoch 11. Januar 2017, 00:28

Mittwoch 11. Januar 2017, 17:27

Vielen Dank für die Antworten!
Und auch danke das keiner "schon mal gegoogelt" oder "benutz die Forensuche" geantwortet hat!

Heute morgen kurz vor ende der Nachtschicht bin ich noch über die steigenden/fallenden Flanken gestolpert. Das habe ich mir jetzt mal genauer angesehen. Was haltet ihr davon wenn man damit die Türkontakte überwacht?
Neodog
User
Beiträge: 3
Registriert: Mittwoch 11. Januar 2017, 00:28

Donnerstag 12. Januar 2017, 02:19

BlackJack hat geschrieben:

Mit `wait_for_edge()` sollte man das „busy waiting“ beseitigen können.
Das hätte ich vor meinem letzten Beitrag besser gegoogelt.
Scheint genau das zu sein was ich brauche.

Ich werde mir eure Tipps und Vorschläge zu Herzen nehmen und das mal anpassen und zur "Kontrolle" hier nochmal posten.
Antworten