Erfassen von GPIO

  • Hallo,


    ich bin gerade dabei, das Signal von Bewegungsmelder mittels:

    Code
    IO.add_event_detect(GPIO_PIN_1,IO.RISING,callback=Switch1,bouncetime=400)


    in Python zu erfassen.


    Ganz unten im Programm habe ich eine Dauerschleife:

    Code
    while True:
    print ("Programm läuft")
    time.sleep (30)


    Wenn der Bewegungsmelder auslöst, dann gibt es eine Ausgabe auf dem Bildschirm und ich bekomme eine E-Mail.
    Das funktioniert so weit ganz gut.


    Jetzt wollte ich das Ganze schöne in PHP verpacken und möchte die Möglichkeit haben, diese "Alarmanlage" nur wenn es mir passt ein oder auszuschalten.
    Das Einschalten funktioneirt zwar, aber (so vermute ich) aufgrund der Dauerschleife in Python reagiert die Webseite träge. Sie ist mit sich selbst beschäftigt.


    Kann mir jemand Tipp geben, wie ich Python ändern kann, damit es nicht so hängt?


  • Hört sich jetzt hart an, aber ich würde es ohne php machen.


    Mit PHP kann ich die Seite schön gestalten und aus der mySQL Datenbank paar Werte holen.
    Vielleicht gibt es eine Möglichkeit mit PHP?

  • Vielleicht besteht mein Problem darin, dass ich GPIOs in Python belege, nachher mit kill die Datei zwar beende, aber die GPIO immer noch für die eine Aktion belegt sind?
    Vielleicht müsste ich in Python:

    Code
    finally:
    GPIO.cleanup() # this ensures a clean exit


    anhängen?

  • Das bringt leider auch nichts, sobald die While Schleife in Python aufgerufen wird, läuft PHP entsprechend in "Endlosmodus".
    Gibt es noch andere Ideen vielleicht?

  • Kurz: Mach es so wie bootsmann sagt.


    Echt, du machst dir keine Freude mit der Vermischung von Python und PHP, also würde ich mich an deiner Stelle auf eines festlegen. Es gibt zig Webserver und Frameworks in Python und auch Datenbanken. Mir ist kein Vorteil von PHP gegenüber Python in der Webentwicklung bekannt... (Außer, dass es bei manchen Shared hosting Servern bei den billigen Paketen kein Python gibt, immer nur PHP :wallbash: )


    LG

  • Linus


    Korrekt. Leider wird diese LAMP Schiene von viel zu vielen Hostern gefahren, weil sie eben fast nichts tun müssen. Wenn - wie in der Vergangenheit so oft passiert - ihre vServer kompromittiert werden, dann machen sie den Laden zu und morgen unter einen neuen Namen auf. Zum grössten Teil haben die gar keine eingenen Server, sondern mieten diese bei irgend welchen Serverfarmen in Nürnberg, Frankfurt etc.

  • Ich habe sowohl für den Pythonscript als auch für den PHP Script viel aufwand betrieben und bis auf die Tatsache, dass es ewig rumeiert, läuft und sieht gut aus.
    Aber ok, falls es keine Möglichkeit gibt, dann werde ich es wohl umschreiben müssen.

    Edited once, last by AndyKL ().

  • Du könntest in deiner Callbackfunktion "Switch1" eine Prüfung einbauen, die du mittels PHP ändern kannst.
    Mit PHP in eine Datei schreiben und in der Funktion prüfst du den Inhalt, bevor du etwas ausführen lässt.

  • Zunächst sollte man wissen das ein Interrupt basiertes Python Script besser ist als ein sog. "Polling" mit ner while Schleife.. Warum ist relativ einfach: Weniger CPU Auslastung, genauer, einfacher.
    Dann sollte man wissen das in der Interrupt_Callback nichts wildes gemacht werden sollte, da sonst diese wichtige Funktion derweil blockiert wird und in der Zeitspanne kein weiterer ISR erfasst werden kann.
    Und dann sollte man noch wissen das die Callback in einem separaten Thread läuft... Also das Script ist ein Thread, dort können Dinge abgehandelt werden, und die ISR Funktion ist davon abgekoppelt und quasi eigenständig.


    Auf dieser Grundlage erstellt man also ein Script mit einer Callback die bei einem Flankenwechsel nur den ausgelösten Pin sowie dessen Status in ein Queue ablegt. Dieses Queue verarbeitet man dann im Script-Thread.


    Normalerweise wird der Interrupt-Callback nur "channel" übergeben, also der GPIO-Pin der das Event ausgelöst hat. Wir müssen der Funktion aber auch das Queue zugänglich machen und die hierfür eleganteste Vorgehensweise ist mithilfe von 'partial' direkt die Übergabe zu modifizieren:
    [code=php]
    queue=Queue()
    GPIO.add_event_detect(switchPi, GPIO.BOTH, callback=partial(interrupt_Event, queue), bouncetime=150)
    GPIO.add_event_detect(switchWin, GPIO.BOTH, callback=partial(interrupt_Event, queue), bouncetime=150)
    [/php]


    Und die Callback Funktion könnte dann wie folgt aussehen:
    [code=php]
    def interrupt_Event(q, channel):
    q.put( (channel, GPIO.input(channel), datetime.now()) )
    [/php]


    Sobald ein Flankenwechsel stattfindet - egal was für einer - wird ins Queue ein Eintrag in Form einer Tuple vorgenommen... In diesem Fall der ausgelöste Channel, dessen Status und ein datetime Objekt, also zum Beispiel (17, 1). Die 1 steht für GPIO.HIGH bzw eigentlich andersherum aber egal ;)


    So, was brauchen wir jetzt noch?
    => Das Script muss das Queue abarbeiten
    Wie bereits erwähnt läuft die Interrupt_Callback im Hintergrund und trägt munter Dinge ins Queue ein. Parallel dazu können wir nun im Script ganz wilde Sachen anstellen und sozusagen unendlich viel Zeit verplempern, die ISR wird davon nicht beeinträchtigt.


    Wie sowas aussehen könnte siehst du hier => https://github.com/meigrafd/Sa…master/PIR_interrupt_2.py



    Ungeachtet dessen würde ich hier in diesem Fall lieber 'multiprocessing' verwenden und den Webserver via Python sowie den PIR in jeweils unterschiedlichen Scripts laufen lassen.
    In folgender Anleitung findet man einfache Beispiele inkl. Code für bottle und tornado: FAQ => Nützliche Links / Linksammlung => [Python] Webserver, Websocket und ein bisschen AJAX
    Ich würde in dem web_bottle.py Script wie gesagt mithilfe von 'multiprocessing' die PIR Geschichte separat laufen lassen und mit einem shared dictionary zwischen den Prozessen kommunizieren.


    Alternativ kann man auch Socket für IPC (inter process communication) verwenden... Was dann ebenfalls mit der in obiger Anleitung erwähnten Geschichte kombiniert werden kann: WebSocket (das Protokoll unterscheidet sich von purem Socket). PHP kann aber kein WebSocket sondern nur Socket. JavaScript kann WebSocket.


    Über eine extra Datei würde ich nicht gehen, das verursacht nur unnötige Schreibzugriffe auf der SD, die aber nicht unendlich viele verträgt. Alternativ eine temporäre Datei in einem ramfs Ordner, oder eine FIFO...


    ...Möglichkeiten gibts etliche...

  • Vielen Dank für die Vorschläge,
    jedoch um ehrlich zu sein, überschreitet der Ansatz meine Kompetenz.


    Ich weiß, dass es nicht sauber ist, aber ich starte aus PHP heraus Python (Alarm an) und kille es, wenn es nicht mehr benötigt wird (Alarm aus).

  • Ich hatte sowas ähnliches hier schon mal genauer erklärt und bereitgestellt => http://www.forum-raspberrypi.d…lage?pid=248873#pid248873
    Dort wird ebenfalls ein PIR zwecks "motion" verwendet - Hintergrund war ebenfalls eine Alarmanlage.


    Du kannst das ja problemlos parallel mal ausprobieren, da es unabhängig von apache2 & Co funktioniert und auch auf einem anderen Port läuft: 8080



    //EDIT: Der Code liegt nun auch in meinem Sample-Code github repo, in einer etwas überarbeiteten Version => https://github.com/meigrafd/Sa…aster/_bottle/Alarmanlage