GPIO - PIR-Motion - Countdown

  • Hallo zusammen,

    ich möchte über einen PIR Sensor am GPIO-PIN26 einen anderen GPIO Pin HIGH/LOW schalten (startet WebRadio).

    Nur soll der andere GPIO nur geschaltet werden wenn nicht bereits zuvor erfolgt.
    Zudem soll der GPIO automatisch wieder auf LOW gehen, wenn z.B. 5min. keine Bewegung/Motion am PIR-PIN26. (also WebRadio wieder aus wenn 5min. keine da gewesen)

    In Script habe ich die 5min. zum test erst mal auf 15sec gesetzt.

    Ich bin nicht der python Profi!
    Etwas geht schon.

    Nur sobald die 15sec. abgelaufen sind bzw. "TurnOff()" durchlaufen ist, dann wird in meinem Script nie wieder ein Motion am PIN26 registiert.

    Aber warum?
    Hat jemand einen Tipp für mich? Wenn es einfacher geht, bin ich auch für Tipps dankbar ;)

    Danke

    Einmal editiert, zuletzt von giovanne (25. April 2015 um 13:05)

  • Hallo Giovanne,

    Du startest mehrmals mit os.system() andere Programme. Dieser Aufruf wird erst fortgesetzt, wenn das aufgerufene Programm selber beendet wird. Da dies offensichtlich nicht der Fall wíst, verharrt Dein Programm in einem solchen os.system().

    Ich mag zwar kein Python, aber die Python-Koryphäen raten zu einem anderen Befehl. Auf die Schnelle (damit Du einen Schritt weiterkommst) ergänze mal den Aufruf durch Anhängen von

    Code
    &

    Dadurch erzeugst Du einen Parallelprozess. Dessen Prozess-ID pid musst Du ermitteln, um diesen Prozess über

    Code
    kill pid

    abzusch(l)ießen.

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Danke für Deine Antwort.
    Ganz verstanden habe ich es noch nicht ;) Auch das Anfügen von & hat erst einmal nicht geändert.

    Verstehen tue ich auch nicht, innerhalb "TurnOn()" ist ja auch ein os.system Aufruf "os.system('sudo touch /home/pi/motion_on')", danach geht es wie erwartet weiter.

    Allerdings stimmt es wenn ich den os.system Aufruf in "TurnOff()" auskommentiere "os.system('sudo rm /home/pi/motion_on')",
    dann läuft das Programm weiter.
    Hmm, schal schauen ... ob es einen anderen Weg gibt bzw. zu welchem die Python-Koryphäen raten oder ich werde es mal ohne python versuchen ...

    Hat sich erledigt,
    mit " os.remove(path)" funktioniert es wie erwartet ;)

    Einmal editiert, zuletzt von giovanne (25. April 2015 um 13:36)

  • Hallo Giovanne,

    so meinte ich es:

    Code
    os.system('sudo touch /home/pi/motion_on &')

    Beste Grüße

    Andreas

    Ich bin wirklich nicht darauf aus, Microsoft zu zerstören. Das wird nur ein völlig unbeabsichtigter Nebeneffekt sein.
    Linus Torvalds - "Vater" von Linux

    Linux is like a wigwam, no windows, no gates, but with an apache inside dancing samba, very hungry eating a yacc, a gnu and a bison.

  • Blöde Frage: Wieso überhaupt "touch /home/pi/motion_on" ausführen und wieso mit & ? :s Der touch Befehl erzeugt nur eine leere Datei mit aktuellem Timestamp. Das scheint hier nur dazu zu dienen um einen Schaltvorgang festzuhalten. Anschließend löscht er das File ja auch wieder...

    Alles was mit os.system zu tun hat versteh ich nicht wofür das überhaupt gebraucht wird. So wie ich das verstehe ist das ein Ersatz für eine Variable.. Das ließe sich aber auch einfacher/eleganter lösen indem man auch nicht die SD mit unnötigen Schreib/Lösch-Vorgängen belastet :fies:


    Also zunächst mal Überlegung zum Ablauf:

    * Bewegung wird erkannt -> GPIO-X soll auf HIGH.
    * Nach 5 Minuten Laufzeit soll GPIO-X wieder auf LOW.
    * Wird innerhalb der 5 Minuten erneut Bewegung erkannt soll die Laufzeit wieder auf 5 Minuten gesetzt werden.

    Anstatt 'global' zu nutzen würde ich eher Dictionary's nutzen: http://www.tutorialspoint.com/python/python_dictionary.htm
    Um das Script am beenden zu hindern nutze ich 'singal.pause()'

    Ohne jetzt von deinem Code allzuviel zu verändern, nehme ich das mal als Ausgangslage. Also, Grundgerüst für den PIR mit Interrupt:

    [code=php]
    import RPi.GPIO as GPIO
    import time, signal
    #---------------------------------------------------------------------
    GPIO.setmode(GPIO.BOARD)

    PIR_PIN = 26
    RADIO_PIN = 4

    OnTimeInSeconds=15
    Counter = 0
    #---------------------------------------------------------------------

    GPIO.setup(PIR_PIN, GPIO.IN)
    GPIO.setup(RADIO_PIN, GPIO.OUT)

    def TurnOn():
    print "TurnOn"
    GPIO.output(RADIO_PIN, True)
    #

    def TurnOff():
    print "TurnOff"
    GPIO.output(RADIO_PIN, False)
    #

    def MOTION(pin):
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    print 'Motion Detected: {}' .format(zeit)
    with open('motion.log', 'a') as f:
    f.write('Motion Detected: ' + str(zeit) + '\n')

    try:
    GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=MOTION, bouncetime=100)
    #keep script running
    signal.pause()
    except (KeyboardInterrupt, SystemExit):
    print "\nQuit\n"
    GPIO.cleanup()
    [/php]

    Das Dictionary definieren wir nun außerhalb einer Funktion wodurch diese automatisch global ist und ohne Probleme innerhalb Funktionen verändert werden kann.

    Zunächst muss die jeweilige Variable als Dictionary initialisiert werden:
    [code=php]dictionary = {}[/php](wie die Variable heißt ist fast egal...)

    Danach kann man - ähnlich wie bei Arrays in PHP - einen Schlüssel und Wert einfügen:

    [code=php]dictionary['Counter'] = 0
    dictionary['Status'] = False[/php]

    Nun könnte man das genau so machen wie du, nur eben schöner :D Nur zur Veranschaulichung - das Problem würde dann aber vermutlich immer noch bestehen:
    [code=php]
    def TurnOn():
    print "TurnOn"
    GPIO.output(RADIO_PIN, True)
    dictionary['Status'] = True

    def TurnOff():
    print "TurnOff"
    GPIO.output(RADIO_PIN, False)
    dictionary['Status'] = False

    def MOTION(pin):
    zeit = time.strftime("%d.%m.%Y %H:%M:%S")
    print 'Motion Detected: {}' .format(zeit)
    with open('motion.log', 'a') as f:
    f.write('Motion Detected: ' + str(zeit) + '\n')
    if dictionary['Status'] == True:
    print 'Counter Reset'
    dictionary['Counter'] = 0
    else:
    TurnOn()
    print dictionary['Counter']

    def Check():
    print dictionary['Counter']
    if (dictionary['Counter'] < (OnTimeInSeconds - 1)):
    dictionary['Counter'] += 1
    else:
    print "Check" + str(dictionary['Counter'])
    TurnOff()
    [/php]


    ...Soweit verstanden? Wenn ja gehts weiter ;)

  • meigrafd,
    Danke für die Hinweise und Anregungen es besser zu machen.
    Ich versuche das mal auf Deinen Vorschlag umzubauen...

    Andreas,
    mit den & an der Stelle hatte ich es versucht, jedoch keine Änderung.
    Wobei es mit "os.remove(path)" funktioniert. Aber aufgrund der SD Schreibzugriffe versuche ch mal den von meigrafd vorgeschlagenen Weg...

    meigrafd,

    vielen Dank nochmal.
    Habe es nun mal umgebaut und es funzt :D

    Mit dem signal.pause() muss ich mich noch einlesen. Deshalb habe ich zum Aufruf der Check() Funktion vorerst die bisherige while Endlos-Schleife genutzt.

    Update/Edit: Script erneut editiert. Mit Popen funktioniert der Aufruf der shell Befehle.
    Ich benötige keinen Pin mehr um das Radio Ein/Aus zu schalten. Mache das nun direkt.

    Einmal editiert, zuletzt von giovanne (25. April 2015 um 18:07)

Jetzt mitmachen!

Du hast noch kein Benutzerkonto auf unserer Seite? Registriere dich kostenlos und nimm an unserer Community teil!