Zeitschaltung

  • Es soll ein PIR BewegungsSensor zu einer bestimmten Zeit ein (läuft über Nacht) und wieder ausgeschaltet werden. Bei erkannter Bewegung wird dann ein Relais geschaltet.
    Irgendwie funktioniert das noch nicht wie gewollt.
    Habe mal den Code angehangen (ausser die Classen zur Zeit und den GPio), vielleicht hat ja jemand eine Idee wo der Fehler liegt, kann auch ganz anders sein.

    "Config"


    [pir_config]
    pir = 7
    rel = 6
    startzeit = 11,00 #ohne funktion
    endzeit = 06,00 #ohne funktion
    schaltdauer = 4

    [cron_sprache]
    txt_1 = Zeit aktiv
    txt_2 = Zeit inaktiv
    txt_3 = aktuelles Datum & Zeit
    txt_4 = eingestellte Startzeit
    txt_5 = Startzeit + Schaltdauer
    txt_6 = Ende

    [pir_sprache]
    txt_0 = Bewegungsmelder Zeit Test (CTRL-C Ende)
    txt_1 = Warte auf Bewegungsmelder Einstellungen ...
    txt_2 = Fertig
    txt_3 = Bewegung erkannt
    txt_4 = Ende

    "start.py"


    #!/usr/bin/python

    import time
    import datetime
    import subprocess
    from ClassZeit import Zeit
    from ConfigParser import SafeConfigParser

    #ruft Biblothek auf
    parser= SafeConfigParser()
    #liest die configDatei zeilen weise ein
    parser.read ('/home/pi/meins/script/pir/pirconfig.ini')
    #Configzeile
    anfangszeit = str(parser.get('pir_config','startzeit'))
    endzeit = str(parser.get('pir_config','endzeit'))
    txt_4 = parser.get('pir_sprache','txt_4')

    myZeit = Zeit
    schalter1 = myZeit('Licht')
    schalter1.set(00,00, 06,00) # 00:00 --> 6:00
    schalter1.set(11,00, 23,59) # 22:00 --> 00:00

    while(True):
    time.sleep(5)
    now = datetime.datetime.now()
    h = now.hour
    m = now.minute

    r = schalter1.check(h, m)
    print("",schalter1.name,r)
    if(r==True):
    print(subprocess.call(['/home/pi/meins/script/pir/pir.py']), schalter1.name, r)
    else:
    print("nein")
    time.sleep(50)

    #Abbruch Tastatur
    #except KeyboardInterrupt:
    #print " " + (txt_4)

    "pir.py"


    #!/usr/bin/python

    #importiert python Biblotheken
    import time
    from time import sleep, localtime
    import datetime
    import RPi.GPIO as GPIO
    import os
    import subprocess
    from ConfigParser import SafeConfigParser
    from ClassGpio import SimpleGPIO
    from ClassZeit import Zeit

    #ruft Biblothek auf
    parser= SafeConfigParser()
    #liest die configDatei zeilen weise ein
    parser.read ('/home/pi/meins/script/pir/pirconfig.ini')
    #Configzeile
    GPIO_PIR = int(parser.get('pir_config','pir'))
    GPIO_REL = int(parser.get('pir_config','rel'))
    anfangszeit = str(parser.get('pir_config','startzeit'))
    endzeit = str(parser.get('pir_config','endzeit'))
    txt_0 = parser.get('pir_sprache','txt_0')
    txt_1 = parser.get('pir_sprache','txt_1')
    txt_2 = parser.get('pir_sprache','txt_2')
    txt_3 = parser.get('pir_sprache','txt_3')
    txt_4 = parser.get('pir_sprache','txt_4')

    print (txt_0)

    #Verwendet BCM GPIO 00..nn numern
    GPIO.setmode(GPIO.BCM)
    #Setzt pins als input&output
    GPIO.setup(GPIO_PIR,GPIO.IN)
    #GPIO.setup(GPIO_REL,GPIO.OUT)
    #Variablen
    Current_State = 0
    Previous_State = 0

    try:
    print (txt_1)
    while GPIO.input(GPIO_PIR)==1:
    Current_State = 0
    print " " + (txt_2)
    while True:
    #Liest Pir Status
    Current_State = GPIO.input(GPIO_PIR)
    #Bedingung
    if Current_State==1 and Previous_State==0:
    print " " + (txt_3)#Hilfetext
    gpio_7 = SimpleGPIO(GPIO_REL)
    gpio_7.write(1)
    sleep(100)#Zeitveroegerung koennte Body aussetzen?
    Previous_State=1
    elif Current_State==0 and Previous_State==1:
    print " " + (txt_2)#Hilfetext ini
    gpio_7.writeaus(0)
    Previous_State=0
    time.sleep(0.01)#Zeitverzoegerung Script

    myZeit = Zeit
    schalter1 = myZeit('Licht')
    schalter1.set(0,0, 06,00) # 00:00 --> 6:00
    schalter1.set(11,00, 23,59) # 22:00 --> 00:00
    while(True):
    time.sleep(5)
    now = datetime.datetime.now()
    h = now.hour
    m = now.minute

    r = schalter1.check(h, m)
    print("",schalter1.name,r)
    if(r==False):
    os.system('/home/pi/meins/script/pir/start.py')


    #Abbruch Tastatur
    except KeyboardInterrupt:
    print " " + (txt_4)
    # Reset GPIO settings
    GPIO.cleanup()

    Einmal editiert, zuletzt von bkm (12. April 2015 um 20:47)

  • Hm :denker:
    Ich denke es wäre gut zu sehen was im Script ClassZeit drin steht.

    Es ist imho überflüssig 2 Scripts, also start.py und pir.py, zu verwenden, das kann man auch in einem Script unterbringen, insbesondere ist es Quatsch in einem Python Script ein anderes Python Script über subprocess auszuführen - wieso importierst du das nicht? :-/

    Auch das separate setzen der 'txt_' Variablen ist imho überflüssig und verbraucht nur unnötig Ram.

    Es soll doch nur so sein das PIR im Zeitraum von 23Uhr bis 06Uhr aktiv ist, oder nicht? Wieso überschreibst du dann 'schalter1.set' mit anderen Werten?


    PS: Python2 ist in einigen Dingen anders als Python3. Du verwendest aber teilweise print Zeilen von python3 die in python2 keine Funktion sind. Siehe dazu > hier <


  • Hm :denker:
    Ich denke es wäre gut zu sehen was im Script ClassZeit drin steht.

    &quot;ClassZeit&quot;


    #!/usr/bin/python

    import time
    import datetime

    class Zeit:
    minArray = None
    name = None

    def __init__(self, name):
    self.name = name
    self.minArray = []
    for _ in range(0, 24*60):
    self.minArray.append(False)

    def clear(self):
    for i in range(0, 24*60):
    self.minArray[i] = False

    def set(self, vH, vM, tH, tM):
    v = vH * 60 + vM
    t = tH * 60 + tM

    for i in range(v, t):
    self.minArray[i] = True

    def check(self, h, m :(
    t = h * 60 + m
    return self.minArray[t]

    Einmal editiert, zuletzt von bkm (12. April 2015 um 20:48)

  • Hm ich versteh irgendwie nicht wieso solch ein großer Aufwand für so etwas eigentlich Simples betrieben wird :-/

    Also als erstes solltest du eine Funktion im pir.py definieren worüber du diesen ansprichst - so kannst du das einfach in das 'start.py' importieren und ausführen. Im pir.py ist der untere Teil aber eigentlich auch überflüssig da das pir.py nicht das start.py starten sollte, start.py sollte eigentlich die ganze Zeit durch laufen.

    Als nächstes solltest du PIR aber auch besser über Interrupts bewerkstelligen, denn diese while Geschichte ist suboptimal und die sleep's blockieren das Script, in der Zeit kann also auf nichts reagiert werden und somit auch kein auslösen des PIR festgestellt werden.
    Das würde dann zB so aussehen:

    &quot;PIR_interrupt.py&quot;

    [code=php]#!/usr/bin/python
    import time
    import RPi.GPIO as GPIO
    import signal

    PIR_PIN = 24
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(PIR_PIN, GPIO.IN)

    def interrupt_event(pin):
    zeit = time.strftime('%d.%m.%Y %H:%M:%S')
    print '{} -> GPIO {} ausgeloest! Motion detected'.format(zeit, pin)
    # hier kann man dann z.B. mit dem picamera modul ein Bild schiessen ...

    def main():
    try:
    GPIO.add_event_detect(PIR_PIN, GPIO.RISING, callback=interrupt_event, bouncetime=100)
    #keep script running
    signal.pause()
    except (KeyboardInterrupt, SystemExit):
    print "Quit"

    if __name__ == '__main__':
    main()
    GPIO.cleanup()
    print "Ende des Scripts"
    [/php]

    Davon unabhängig ist die einfache Überlegung dass das Script im Zeitraum von 23 Uhr bis 06 Uhr arbeiten soll.
    Nun gäbe es wie immer mehrere Möglichkeiten...
    - Man könnte zum Beispiel ausrechnen wie viel Sekunden von 23Uhr und 06Uhr vergehen müssen. Dann prüft man am Anfang der Schleife anhand der Unixtime ( time.time() ) ob man sich noch innerhalb dieses Zeitfensters befindet und führt den Rest nur dann aus. Unixtime ist ein Standard welcher die Sekunden die seit dem 1.1.1970 vergangen sind, ausgibt.

    Ich guck gleich mal ob ich da was basteln kann - muss eben erst noch was anderes fertig proggn ;)

  • Ich würde es wie meigrafd lösen (sprich mit Interrupts) und in der Übergebenen Callback-Funktion bei Änderung des GPIO Pegels prüfen, ob die aktuelle Uhrzeit zwischen 23:00 und 6:00 liegt und anschließend das Relais entsprechend schalten. :)

    Offtopic: Wieso führen hier so viele Leute Python Skripte mit subprocess aus? Komischer Trend.. :s

    ---
    Edit: Alternativ könntest Du Dir auch die APScheduler Bibliothek ansehen. Damit kannst Du festlegen, wann Methoden (Jobs) ausgeführt werden sollen. Dann könntest Du für 23 Uhr einen Job anmelden, der den Interrupt aktiviert und einen weiteren um 6 Uhr, der das ganze wieder abschaltet.

    Einmal editiert, zuletzt von Chris1705 (12. April 2015 um 16:39)

  • Vorschlag:

    &quot;/home/pi/meins/script/pir/pirconfig.ini&quot;


    &quot;/home/pi/meins/script/pir/start.py&quot;


    [code=php]
    #!/usr/bin/python

    from ConfigParser import SafeConfigParser
    import RPi.GPIO as GPIO
    import signal, time

    #---------------------------------------------------------------------

    #ruft Biblothek auf
    parser= SafeConfigParser()
    #liest die configDatei zeilen weise ein
    parser.read('/home/pi/meins/script/pir/pirconfig.ini')

    #---------------------------------------------------------------------

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(parser.get('pir_config','pir'), GPIO.IN)
    GPIO.setup(parser.get('pir_config','rel'), GPIO.OUT)

    def relais():
    GPIO.output(parser.get('pir_config','rel'), GPIO.HIGH)
    time.sleep(100)
    GPIO.output(parser.get('pir_config','rel'), GPIO.LOW)
    print parser.get('pir_sprache','txt_2')

    def interrupt_event(pin):
    #zeit = time.strftime('%d.%m.%Y %H:%M:%S')
    #print '{} -> GPIO {} ausgeloest! Motion detected'.format(zeit, pin)
    stunde = time.strftime('%H')
    if (stunde > (parser.get('pir_config','startzeit') - 1)) and (stunde is not parser.get('pir_config','endzeit')):
    print parser.get('pir_sprache','txt_3')
    relais()

    def main():
    try:
    GPIO.add_event_detect(parser.get('pir_config','pir'), GPIO.RISING, callback=interrupt_event, bouncetime=100)
    #keep script running
    signal.pause()
    except (KeyboardInterrupt, SystemExit):
    print parser.get('cron_sprache','txt_6')

    if __name__ == '__main__':
    main()
    GPIO.cleanup()
    print "Ende des Scripts"
    [/php]

    Mehr als diese zwei Dateien brauchst du nicht.

    Man kann aber auch den Interrupt auf GPIO.BOTH stellen um sowohl RISING als auch FALLING mitzukriegen, also in dem Fall dann wenn es keine Bewegung mehr gibt und der Pegel abfällt. Dann muss man aber die relais() entsprechend anpassen sodass es den entgegengesetzt Zustand als aktuell schaltet....
    Das könnte dann wie folgt aussehen:

    &quot;/home/pi/meins/script/pir/start.py&quot;


    [code=php]
    #!/usr/bin/python

    from ConfigParser import SafeConfigParser
    import RPi.GPIO as GPIO
    import signal, time

    #---------------------------------------------------------------------

    #ruft Biblothek auf
    parser= SafeConfigParser()
    #liest die configDatei zeilen weise ein
    parser.read('/home/pi/meins/script/pir/pirconfig.ini')

    #---------------------------------------------------------------------

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(parser.get('pir_config','pir'), GPIO.IN)
    GPIO.setup(parser.get('pir_config','rel'), GPIO.OUT)

    def relais():
    GPIO.output(parser.get('pir_config','rel'), not GPIO.input(parser.get('pir_config','rel')))

    def interrupt_event(pin):
    zeit = time.strftime('%d.%m.%Y %H:%M:%S')
    if GPIO.input(pin):
    print '{} Rising edge detected on {}'.format(zeit, pin)
    else:
    print '{} Falling edge detected on {}'.format(zeit, pin)
    stunde = time.strftime('%H')
    if (stunde > (parser.get('pir_config','startzeit') - 1)) and (stunde is not parser.get('pir_config','endzeit')):
    print parser.get('pir_sprache','txt_3')
    relais()

    def main():
    try:
    GPIO.add_event_detect(parser.get('pir_config','pir'), GPIO.BOTH, callback=interrupt_event, bouncetime=100)
    #keep script running
    signal.pause()
    except (KeyboardInterrupt, SystemExit):
    print parser.get('cron_sprache','txt_6')

    if __name__ == '__main__':
    main()
    GPIO.cleanup()
    print "Ende des Scripts"
    [/php]

  • Funktioniert noch nicht so richtig. Das Relais schaltet auch noch wenn die >>endzeit<<
    abgelaufen ist =(

    Code
    if (stunde > (parser.get('pir_config','startzeit') - 1)) and (stunde is not parser.get('pir_config','endzeit')):
  • Spoiler anzeigen

    Wie immer sehr hilfreich deine Kommentare bootsmann.
    Man kann immer vieles irgendwie anders machen, aber deine Kommentare sind nicht wirklich konstruktiv. Kein Beispiel, kein direkter Code für den jeweils aktuellen Fall. :wallbash:
    Sowas hilft nicht.

    Entschlüsselt lautet die Zeile
    [code=php]if (stunde > (parser.get('pir_config','startzeit') - 1)) and (stunde is not parser.get('pir_config','endzeit')):[/php]
    ->
    [code=php]if (23 > (23 -1)) and (23 is not 06):[/php]
    wenn 23 größer 22 und 23 nicht 06

    Für die Startzeit würde das also soweit passen.

    Für die Endzeit lautet der Vergleich:


    wenn 06 größer 05 und 06 nicht 06


    Die Prüfung passt also. Es sollte also nicht mehr ausgeführt werden da der zweite part abgelehnt wird.


    Spinnt man das Netz weiter wird es um 0 Uhr aber problematisch, da ich einfach nur eine normale Rechnung angestellt habe, also eine Zahl von der anderen abziehe...


    Problem:
    wenn 00 größer -01 und 00 nicht 06


    Kein Problem:
    wenn 01 größer 00 und 01 nicht 06
    wenn 02 größer 01 und 02 nicht 06
    wenn 03 größer 02 und 03 nicht 06
    wenn 04 größer 03 und 04 nicht 06
    wenn 05 größer 04 und 05 nicht 06

    Warum er bei dir also um 6 Uhr noch weiter macht weiß ich gerade nicht. Eigentlich müsste er wie gesagt um 0 Uhr Probleme machen aber nicht um 06 Uhr.

    :denker:


    //EDIT: ach... jetzt fällt mir das erst auf - alles Quatsch was ich zum Schluss geschrieben hab :blush: Die Rechnung trifft ja immer auf die Startzeit zu, nicht auf stunde...


  • Hm ... sollte das nicht eher so aussehen:

    wenn 22 größer 23-1 und 22 nicht 06
    wenn 23 größer 23-1 und 23 nicht 06
    wenn 24 größer 23-1 und 24 nicht 06 bzw. wenn 00 größer 23-1 und 00 nicht 06
    wenn 01 größer 23-1 und 01 nicht 06
    wenn 02 größer 23-1 und 02 nicht 06
    wenn 03 größer 23-1 und 03 nicht 06
    wenn 04 größer 23-1 und 04 nicht 06
    wenn 05 größer 23-1 und 05 nicht 06
    wenn 06 größer 23-1 und 06 nicht 06
    wenn 07 größer 23-1 und 07 nicht 06
    ...

    //EDIT: ah ... schon selbst bemerkt ;)
    btw: sicher, dass der Rückgabewert dieser parser-Funktion passt?

    Es würde übrigens vollkommen ausreichen nachzuprüfen, ob die aktuelle Stunden != 6 bzw. 23 ist ...

    Stunde == 23 und runflag == 0
    runflag = 1
    Stunde == 6 und runflag == 1
    runflag = 0

    Nachtrag: ich weiss jetzt nicht, wie das in Python ist ... darauf achten, dass die richtige Zeitzone verwendet wird (localtime()).


    cu,
    -ds-

  • ..die ganze Config Sache ist doch eh bescheuert für son kleines Script.. Macht es komplizierter als es is und is nur ne weitere Schwachstelle/Fehlerquelle
    Der Parser is eh mist wenn er Kommentare nicht also solche behandelt.

    &quot;GPIO.RISING&quot;

    [code=php]
    #!/usr/bin/python

    import RPi.GPIO as GPIO
    import signal, time

    #---------------------------------------------------------------------

    #GPIO pins
    PIR = 7
    REL = 6

    #Times in 24h Format
    startTime = 23
    endTime = 06

    #---------------------------------------------------------------------

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(PIR, GPIO.IN)
    GPIO.setup(REL, GPIO.OUT)

    def relais():
    GPIO.output(REL, GPIO.HIGH)
    time.sleep(100)
    GPIO.output(REL, GPIO.LOW)
    print "Done"

    def interrupt_event(pin):
    hourNow = time.strftime('%H')
    startTime2 = startTime - 1
    if startTime2 == -1:
    startTime2 = 23
    if (hourNow > startTime2) and (hourNow is not endTime):
    print "Motion detected"
    relais()

    def main():
    try:
    GPIO.add_event_detect(PIR, GPIO.RISING, callback=interrupt_event, bouncetime=100)
    #keep script running
    signal.pause()
    except (KeyboardInterrupt, SystemExit):
    print "Quit"

    if __name__ == '__main__':
    main()
    GPIO.cleanup()
    print "End of Script"
    [/php]...sieht doch gleich viel besser und angenehmer aus oder nicht...

    &quot;GPIO.BOTH&quot;


    Man kann aber auch den Interrupt auf GPIO.BOTH stellen um sowohl RISING als auch FALLING mitzukriegen, also in dem Fall dann wenn es keine Bewegung mehr gibt und der Pegel abfällt. Dann muss man aber die relais() entsprechend anpassen sodass es den entgegengesetzt Zustand als aktuell schaltet....
    Das könnte dann wie folgt aussehen:
    [code=php]
    #!/usr/bin/python

    import RPi.GPIO as GPIO
    import signal, time

    #---------------------------------------------------------------------

    #GPIO pins
    PIR = 7
    REL = 6

    #Times in 24h Format
    startTime = 23
    endTime = 06

    #---------------------------------------------------------------------

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(PIR, GPIO.IN)
    GPIO.setup(REL, GPIO.OUT)

    def relais():
    GPIO.output(REL, not GPIO.input(REL))

    def interrupt_event(pin):
    hourNow = time.strftime('%H')
    startTime2 = startTime - 1
    if startTime2 == -1:
    startTime2 = 23
    if (hourNow > startTime2) and (hourNow is not endTime):
    print "Motion detected"
    relais()

    def main():
    try:
    GPIO.add_event_detect(PIR, GPIO.BOTH, callback=interrupt_event, bouncetime=100)
    #keep script running
    signal.pause()
    except (KeyboardInterrupt, SystemExit):
    print "Quit"

    if __name__ == '__main__':
    main()
    GPIO.cleanup()
    print "End of Script"
    [/php]

  • Das sehe ich anders:


  • ``is not`` heißt nicht ``ist nicht`` sonder mit ``is not`` prüft man auf ``None`` und ``hourNow `` und ``endTime`` ist niemals hier im Beispiel ``None``.
    dreamshader hat das richtig erkannt...

    Das stimmt so nicht. Vorrangig ist der Unterschied, dass mit "is" zwei Instanzen (bzw. die Speicheradressen der Instanzen) miteinander verglichen werden und mit == auf Wertgleichheit geprüft wird.

    Edit: Auf None kann man sowohl mit is als auch mit == vergleichen, da None ein Singleton ist.
    Edit 2: Der Vergleich auf None ist eh nicht relevant, da weder hourNow noch endTime None sind...
    Edit 3: Ich würde es so lösen (ungetestet, ohne Konfigurationsdatei und ohne Fehlerbehandlung):

    Spoiler anzeigen

    [code=php]from time import sleep
    from apscheduler.schedulers.blocking import BlockingScheduler
    import RPi.GPIO as GPIO

    scheduler = BlockingScheduler()

    GPIO.setmode(GPIO.BCM)
    GPIO.setup(7, GPIO.IN)
    GPIO.setup(6, GPIO.OUT)

    @scheduler.scheduled_job('cron', id="attach_event", hour="23", minute="00")
    def attach_event():
    GPIO.add_event_detect(7, GPIO.RISING, callback=interrupt_event, bouncetime=100)

    @scheduler.scheduled_job('cron', id="detach_event", hour="06", minute="00")
    def detach_event():
    GPIO.remove_event_detect(7)

    def interrupt_event():
    GPIO.output(6, GPIO.HIGH)
    sleep(100)
    GPIO.output(6, GPIO.LOW)

    if __name__ == "__main__":
    scheduler.start()[/php]

    Einmal editiert, zuletzt von Chris1705 (13. April 2015 um 23:14)

Jetzt mitmachen!

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