Timer (Ausschaltverzögerung)

Heute ist Stammtischzeit:
Jeden Donnerstag 20:30 Uhr hier im Chat.
Wer Lust hat, kann sich gerne beteiligen. ;)
  • Hallo liebe Forengemeinschaft,

    ich würde mich freuen, wenn ihr euch mein nachstehendes Script einmal ansehen und mir Verbesserungen mitteilen könntet. Zur Funktion:
    Das Script stellt einen Timer dar, welcher per "Hand" den GPIO6 auf EIN setzt und nach einer einstellbaren Zeit (Beispiel 15 Minuten) den GPIO6 "automatisch" wieder auf AUS setzt. Darüber hinaus wollte ich die Möglichkeit haben, den Timer, also den GPIO6 jederzeit auf AUS setzen zu können. Das ist eigentlich schon alles. Die Abfrage des GPIO6 erfolgt alle 30 Sekunden, das ist für mich ausreichend. Das Script funktioniert soweit auch gut, kann den Timer ein-und jederzeit ausschalten oder die vorgegebene Zeit ablaufen lassen. Das kann aber, weil die beiden Schleifen nun ständig alle 30 Sekunden (auch wenn der Timer nicht eingeschaltet ist) durchlaufen, zu Störungen des zeitlichen Ablaufes führen, z.B. dann, wenn der GPIO z.B. in der Mitte eines AUS-Durchlaufes auf EIN gesetzt wird. Dann läuft nämlich nur noch die Restzeit ab. Wie gesagt, wäre echt nett, wenn jemand eine Lösung für mich hätte.

    Vielen Dank vorab

    Meisengeier

    Einmal editiert, zuletzt von dbv (18. März 2017 um 20:49)

  • Wo wird der GPIO auf EIN bzw auf AUS gesetzt? Ich sehe nur eine "write" Zeile :s Wird er als Eingang oder als Ausgang genutzt?

    Auch wenn für bash Einrückungen nicht wichtig sind, fördern sie trotzdem die Lesbarkeit und das Verständnis der Zusammenhänge. Auch vernünftige Variable Namen helfen beim Verständnis... Sowas wie "zahl" ist nicht wirklich hilfreich.
    Dein Code mit Einrückungen:

    Wenn du Zahlenwerte setzt benötigst du keine ". Auch kann bash "else if" => elif

    Desweiteren rate ich lieber sysfs zu verwenden und auf den wiringpi Befehl "gpio" zu verzichten:

    Bei Zahlen kann man aber besser -eq verwenden anstatt =.

    Dann sehe ich eine Verbesserungsmöglichkeit bei der ersten if Abfrage, und zwar prüfst du quasi 2x "$wert" = 1 was man besser verschachteln könnte:

    Ob das funktioniert weiß ich nicht, war nur das was mir dazu spontan einfiel ;)

  • Hallo meigrafd,

    vielen Dank für deine Unterstützung.

    Der bzw. die GPIOs werden durch das nachstehende Programm geschaltet:

    https://translate.google.de/translate?hl=d…be/&prev=search

    Von daher dient mein Script im wesentlichen nur der Abfrage der GPIOs, wobei ich den GPIO6 zum Timer "aufrüsten" möchte. Wie erwähnt, wird Der EIN- oder AUS-Zustand alle 30 Sekunden abgefragt (und eine Meldung verschickt, welche ich hier der Einfachheit halber herausgenommen habe). Wird der GPIO EINgeschaltet, läuft die frei wählbare Zeit ab und schaltet den GPIO wieder aus. Mein Problem ist die eigentliche Zeitschleife (z.B. 15 Minuten), welche bei jeder 30 Sekunden-Abfrage ebenfalls mit "leer durchlaufen" wird, was wie beschrieben zu Fehlern führt, wenn der GPIO genau in diesem Leerdurchlauf gesetzt wird. Es wäre daher wünschenswert, wenn die eigentliche Zeitschleife nur in "Gang" gesetzt werden würde, wenn der GPIO auch EIN ist. Anstatt der 2. Schleife hätte auch ein "sleep" genügt, aber damit gäbe es keine Möglichkeit den Timer vorzeitig zu beenden. Vielleicht mal noch zum Sinn und zum besseren Verstänsdnis des Ganzen: Ich möchte meine Gartenberegnung damit einschalten (auch aus der Ferne) und weil ich schon langsam vergesslich werde, soll diese dann automatisch wieder ausgeschaltet werden. Gern kannst du mir auch einen anderen Vorschlag zur "Zeitbasis" machen. Wichtig ist mir nur, dass ich die Zeit in Minuten am Scriptanfang separat eintragen kann. Dabei sollte das Script möglichst einfach bleiben, damit ich es noch verstehe.

    Gruß Meisengeier

  • Hallo meigrafd,

    ich habe soeben dein 1.Script ausprobieren wollen und festgestellt, dass es bei mir nur den Pfad: /sys/class/gpio/ dateien: "unexport, export" gibt, nicht aber: sys/class/gpio/gpio/direction. Damit wird zwar die Schleife durchlaufen, aber der GPIO nicht abgefragt. Ich arbeite noch mit Raspi Pi 2 (u.a., weil das oben genannte Programm nicht mit dem Betriebssystem des Raspi 3 läuft) und Noobs (glaube 1.4 ).

    Gruß Meisengeier


  • ich habe soeben dein 1.Script ausprobieren wollen und festgestellt, dass es bei mir nur den Pfad: /sys/class/gpio/ dateien: "unexport, export" gibt, nicht aber: sys/class/gpio/gpio/direction.

    Die Dateien werden vom Kernel erst dann erzeugt wenn ein gpio initialisiert wurde, sprich:

    Code
    ## init GPIOpin
    if [ ! -f /sys/class/gpio/gpio${GPIOpin}/value ]; then
        echo $GPIOpin > /sys/class/gpio/export
        echo out > /sys/class/gpio/gpio${GPIOpin}/direction
    fi

    Desweiteren gibts einen Unterschied zwischen sys/class/gpio/gpio/direction und /sys/class/gpio/gpio/direction und /sys/class/gpio/gpio6/direction


    ich empfehle dir in deinen Beiträgen abunzu auch mal ENTER zu drücken - ich tu mich schwer deine Beiträge zu lesen bzw das was du erreichen willst rauszufriemeln...

    Warum muss es unbedingt bash sein?

  • Hallo meigrafd,

    mit der bash frage ich auch alle anderen GPIOs ab und komme damit eigentlich ganz gut zurecht. Mit der "sys" kenne ich mich garnicht aus. Wie gesagt, habe ich im Prinzip "nur" mit der Verschachtelung der 2 Schleifen Probleme. Dein Hinweis zum Einrücken ist übrigens schon sehr hilfreich. Weil ich mich (programmtechnisch) nicht besser auszudrücken weiß, hatte ich dir ja vorhin geschrieben wofür ich das Timer-Script nutzen möchte. Du müsstest dich also überhaupt nicht an meine "Vorlage" halten. Vielleicht noch 2 Punkte: 1. Der GPIO6 wird bereits beim Start des Raspi auf "mode out" gesetzt und 2. bitte noch daran denken, dass ich bei weitem nicht dein Können besitze; soll heißen, dass Script sollte möglichst "einfach gestrickt" sein.

    Gruß Meisengeier

  • Ja gut, das der GPIO bereits vorher initialisiert wird ist ein wichtiger Hinweis der bereits in Beitrag#1 hätte stehen müssen.

    Ich zerbrösel mal deinen klumpen Text um das hervorzuheben was du erreichen willst:

    Wo/Wie fest gelegt wird, wie lange die 2.Schleife laufen soll, steht nirgends.
    Egal... Wenn ich das richtig verstanden habe:
    Das Script läuft permanent.
    GPIO#6 ist als AUSGANG geschaltet.
    Alle 30 Sekunden soll GPIO#6 abgefragt werden. Vermutlich wird der GPIO#6 über irgend ein anderes Script auf HIGH gestellt... Deshalb soll Dieses Script hier nur den aktuellen Status auslesen.
    Ist der GPIO#6 auf HIGH (ein) soll ein "Timer" gestartet werden und den GPIO nach 15 Minuten wieder auf LOW (aus) setzen.
    Zusätzlich soll aber auch die Möglichkeit bestehen den "Timer" frühzeitig zu beenden - wie auch immer das passieren soll, steht leider auch nirgends.

    Diese 30 Sekunden Sache macht es nur unnötig kompliziert. Du hast eine Laufzeit von zB 15 Minuten, ein "sleep" kann "Minuten" oder "Sekunden" dauern am einfachsten sind hier Sekunden.


    Mit Python wär das alles soooo viel einfacher zu erreichen - insbesondere dein Problem. Mit bash bricht man sich da einen extrem ab, mit Python und einer Interrupt-Callback wär das nen Klax. Aber vor allem bräuchte man dann nicht 1000 verschiedener Scripts sondern nur ein einziges. Aber nun ja, es soll ja unbedingt bash sein....


    Die Laufzeit kann beim aufrufen des Scripts übergeben werden: bash script.sh 900

    Besser und einfacher wäre aber wie gesagt das ganze in Python zu realisieren - alles, nicht nur dieses eine Teil.

  • Hallo meigrafd,

    "Wo/Wie fest gelegt wird, wie lange die 2.Schleife laufen soll, steht nirgends."

    Doch, und zwar ganz oben: "Zeit=15" Dummerweise habe ich die Kommentarzeile, nämlich: "Hier die Zeit in Minuten eingeben" nicht mitkopiert, habs übersehen. Ich bitte um Entschuldigung. Die Timer-Zeit ergibt sich in etwa wie folgt: 1 Durchgang dauert 6 Sekunden = sleep 6, der nächste Faktor = 9, was rund 1 Minute ergibt. x 15 = 45 Schleifendurchläufe = 15 Minuten. Der GPIO6 bzw. die GPIOs wird/werden mittels 8 Button auf der Weboberfläche des Programmes (siehe Link) praktisch per Hand EIN- und Ausgeschaltet. Lediglich der Timer-GPIO6 soll sich nach der vorgegebenen Zeit (z.B. 15 Minuten) automatisch ausschalten.

    "Diese 30 Sekunden Sache macht es nur unnötig kompliziert. Du hast eine Laufzeit von zB 15 Minuten, ein "sleep" kann "Minuten" oder "Sekunden" dauern am einfachsten sind hier Sekunden."

    Wielche Möglichkeit empfiehlst du sonst, um den Schaltzustand des GPIO6 oder der GPIOs kontinuierlich abzufragen? Mache ich die Laufzeit mit "sleep", bleibt das Script an dieser Stelle solange stehen, bis der sleep beendet ist und genau das ist ja mein Problem! Deshalb der Versuch mit den Schleifen. Damit kann ich zumindest schon mal den Timer jederzeit stoppen und auch wieder starten. Es ist aber wie eingangs beschrieben immer noch fehlerbehaftet.
    Ansonsten hast du vollkommen richtig erkannt, wie ich den Timer gerne hätte. Ich hätte auch nicht gedacht, dass die Lösung so schwierig ist, dachte vielmehr, das liegt einzig an meinen geringen Fähigkeiten.
    Wie du schreibst, wäre das Script mit "php" einfacher zu realisieren. Ja, wenn das so ist und du so freundlich wärst, mir ein Script in "php" zu schreiben, dann würde ich den GPIO6 eben für sich allein abfragen. Dann müsste ich aber bitte noch wissen, wie man ein php-Script auf der Konsole ausprobieren kann und wie es beim Start des Raspi automatisch gestartet wird. ich weiß es echt nicht.

    Gruß Meisengeier


  • Wielche Möglichkeit empfiehlst du sonst, um den Schaltzustand des GPIO6 oder der GPIOs kontinuierlich abzufragen?

    Siehe Beitrag#7

    Schon ausprobiert?

    Wie du schreibst, wäre das Script mit "php" einfacher zu realisieren. Ja, wenn das so ist und du so freundlich wärst, mir ein Script in "php" zu schreiben, dann würde ich den GPIO6 eben für sich allein abfragen.

    Nein, mit Python. Wie kommst du auf PHP? :-/

    FAQ => Nützliche Links / Linksammlung => Interrupt
    FAQ => Nützliche Links / Linksammlung => Python

    Lies dich mal bitte selber ein und frag dann gezielt(er) - wenn ich dir alles vorkaue lernst du dabei nichts.


    Ich hätte auch nicht gedacht, dass die Lösung so schwierig ist, dachte vielmehr, das liegt einzig an meinen geringen Fähigkeiten.

    Das liegt an bash.

  • Hallo meigrafd,

    ja, habe ich gemacht.
    Es kommt folgende Fehlermeldung:
    /home/pi/versuch.sh: Zeile 8: Syntaxfehler beim unerwarteten Wort `then'
    /home/pi/versuch.sh: Zeile 8: ` if [ "$gpio_state" -eq 1 ]; then'

    Da ich ja nun nicht gerade der "Schleifenfuchs" bin, habe ich den Fehler nicht gefunden.

    Gruß meisengeier

  • Servus,


    ...
    Da ich ja nun nicht gerade der "Schleifenfuchs" bin, habe ich den Fehler nicht gefunden.


    auch an Dich mal den Tipp: füge mal, möglichst am Anfang gleich nach dem shebang eine Zeile mit

    Code
    set -x


    in den bash-script ein. Dadurch wird es gesprächig und Du findest Fehler leichter ;)
    cu,
    -ds-

  • Das Script aus Beitrag#7 funktioniert bei mir so wie erwartet bzw macht das was du haben wolltest.

    1:1 unverändert copy&pasted => http://raspberrypi.roxxs.org/gpio_timer.mp4

  • Hallo und vielen Dank,

    ich habe das Script nochmal gründlich nach Übertragungsfehlern (beim kopieren), falsch eingerückt, usw. abgesucht und Fehler dieser Art nicht gefunden.
    Habe nach dem Shebang "set -x" eingefügt, hier die Meldung:

    + '[' '!' -z '' ']'
    + Laufzeit=300
    /home/pi/versuch.sh: Zeile 8: Syntaxfehler beim unerwarteten Wort `then'
    /home/pi/versuch.sh: Zeile 8: ` if [ "$gpio_state" -eq 1 ]; then'

    Ich benutze übrigens Raspian GNU/Linux 7 (whezzy). Hat das vielleicht was zu sagen?

    Gruß Meisengeier


  • Das Script aus Beitrag#7 funktioniert bei mir so wie erwartet bzw macht das was du haben wolltest.
    1:1 unverändert copy&pasted => http://raspberrypi.roxxs.org/gpio_timer.mp4


    Komisch, habs gerade auf meinem Wheezy getestet, es läuft bei mir auch.

    Spoiler anzeigen


    #!/bin/bash
    set -x
    [ ! -z "$1" ] && Laufzeit=$1 || Laufzeit=300 # sekunden

    while true; do
    gpio_state=$(gpio read 6)

    if [ "$gpio_state" -eq 1 ]; then
    echo "Timer EIN"
    i=0
    while [ $i -le $Laufzeit ]; do
    i=$(($i+1))
    gpio_state=$(gpio read 6)
    if [ "$gpio_state" -eq 0 ]; then
    break
    fi
    sleep 1
    done
    echo "Timer AUS"
    gpio write 6 0
    fi

    sleep 1
    done

  • Hallo meigrafd,

    wenn Mehrere, noch dazu 5 und 6 Sterne-Generäle sagen, dass das Script bei ihnen läuft, dann muss der Fehler bei mir liegen. War auch so, denn jetzt ist alles ****PERFEKT***!!! Besser kann es nicht funktionieren. Habe inzwischen auch meine Meldungen eingebunden; funktioniert ebenfalls 1A! Brauche nicht mal mehr Merker zu setzen (damit die Meldungen nicht ständig wiederholt werden).

    Danke, danke meigrafd für deine Geduld mit mir. Punkt folgt.

    Warum hats nicht gleich funktioniert? Ich hatte das Script zunächst auf meinen PC kopiert und von dort weiter auf den Raspi. Schätze mal, dass es daran gelegen hat, denn ich habs (jetzt) ein 2.Mal direkt auf den Raspi kopiert und gut wars! Hätte ichs gleich so gemacht, wäre das schon ab Beitrag 7 erledigt gewesen. Ärgerlich, aber zumindest weiß ich das jetzt für das nächste mal.

    Jetzt wäre es natürlich noch schön, wenn du mir die Funktionsweise des Scriptes vielleicht noch erläutern könntest. Ein Teil davon ist mir bekannt, aber nicht die 1. Zeile, der Ausdruck "gpio_state", sowie "-eq". Und wie du das mit dem "Video" gemacht hast würde mich auch interessieren.

    :danke_ATDE:

  • Code
    [ ! -z "$1" ] && Laufzeit=$1 || Laufzeit=300    # sekunden

    Ist eine kurze Schreibweise einer if Abfrage. Man könnte das auch wie folgt schreiben:

    Code
    if [ ! -z "$1" ]; then
        Laufzeit=$1
    else
        Laufzeit=300
    fi


    Das && ist eine "wenn Bedingung wahr, dann" Verknüpfung und || ist quasi das "else" also wenn Bedingung nicht wahr.
    Das " -z " fragt die nachfolgende Variable ab, ob diese existiert oder leer ist. Das davor stehende " ! " negiert das ganze und macht daraus: wenn $1 nicht leer. Anstatt " ! -z " könnte man auch " -n " verwenden.
    Führt man ein Script aus und übergibt beim Aufruf direkt Parameter (getrennt durch Leerzeichen) werden diese in $1 , $2 , $3 usw hinterlegt sodass sie gezielt im Script abrufbar sind. Du kannst das Script also einfach wie folgt ausführen:

    Code
    ./script.sh 10


    die 10 ist dann das erste Parameter und wird in $1 hinterlegt und somit trifft die Bedingung zu und Laufzeit wird auf 10 gestellt.
    Rufst du das Script aber so auf:

    Code
    ./script.sh

    wird kein Parameter übergeben und es wird der default Wert Laufzeit = 300 gesetzt, weil $1 dann nicht existiert oder leer ist.

    -eq ist ein Operant und steht für "is equal to" und ist für Zahlenvergleiche besser. Siehe dazu auch http://tldp.org/LDP/abs/html/comparison-ops.html

    "gpio_state" ist ja nur eine beliebig benannte Variable die die Ausgabe des Befehls "gpio read 6" enthält, also ob der GPIO gerade auf HIGH (1) oder LOW (0) ist.

Jetzt mitmachen!

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