HTML, PHP und GPIO

  • Hallo, liebe Gemeinde,
    ich bin neu hier und war schon in einem fremden Thema gelandet. Im Moment probiere erst mal einiges mit dem Raspi aus. Der Webserver läuft und ich kann per Browser auf php-Seiten zugreifen. Die Fehlermeldungen (vorbidden...) sind behoben, aber habe eine Frage zu PHP.
    Meine Seite gpio.php funktioniert im Prinzip fast so, wie ich mir das gedacht habe, allerdings mit einem Effekt, den ich mir nicht erklären kann.
    [code=php]
    <html>
    <head>
    <meta name="viewport" content="width=device-width"/>
    <title>GPIO per PHP schalten</title>
    </head>
    <body>
    <h2>GPIO 4 schalten:</h2>
    <form method="get" action="gpio.php">
    <input type="submit" value="LED_ein" name="ein">
    <input type="submit" value="LED_aus" name="aus">
    <input type="submit" value="Blinkzeichen" name="morsen">


    </form>


    <?php
    $modeon4 = trim(@shell_exec("/usr/local/bin/gpio -g mode 4 out"));


    if(isset($_GET['morsen'])){
    print "<b>Kannst Du es entziffern?</b>";
    }


    if(isset($_GET['ein'])){
    $val = trim(@shell_exec("./an.sh"));
    echo "LED an GPIO4 ist <b><font color='green'>an</font></b>";
    }
    else if(isset($_GET['aus'])){
    $val = trim(@shell_exec("./aus.sh"));
    echo "LED an GPIO4 ist <b><font color='red'>aus</font></b>";
    }
    if(isset($_GET['morsen'])){
    sleep(2);
    $val = trim(@shell_exec("python Text-morsen.py &"));
    }
    ?>
    </body>
    </html>


    [/php]


    Wenn ich "Blinkzeichen" auswähle, dann werden erst die Blinkzeichen ausgegeben und danach erscheint der Text "Kannst Du es entziffern?". Es soll aber erst der Text ausgegeben werden und dann nach 2 Sekunden das Blinken starten.
    Alles, was ich probiert habe, hatte keinen Einfluss auf die Reihenfolge. Woran kann das liegen?

  • Das geht so nicht wie du dir das vorstellst. Solange die PHP-Datei nicht zur Gaenze abgearbeitet ist, wird auch nichts an den Browser zurueckgeschickt. Mit anderen Worten: du kannst ein Programm immer nur *vor* dem erscheinen einer Antwort starten, wenn du so wie oben gezeigt vorgehst.


    Um dein Ziel zu erreichen musst du mit Browser/Client-seitiger Programmierung arbeiten. Vulgo: Javascript. Damit kannst du auf Knopfdruck einen Text einblenden, und dann ein AJAX-Request abfeuern, welches im Hintergrund dein Blinkprozess startet.


    Das ist aber mit PHP eh alles eher knoedelig, weil du immer nur Programme startest, die du dann hart beenden musst, und dann ein neues starten. Das ist wenig elegant & erlaubt zB auch nicht, auf GPIO *Eingaben* zu reagieren.


    meigrafd hat schon darauf hingewiesen - ein Tornado oder Bottle webserver geschrieben in Python erlaubt dir, auf dem Server GPIO Funktionalitaet umzuschalten, ohne das der Prozess beendet wird - und sogar mit Websockets oder per AJAX-Polling Rueckmeldungen an die in Javascript geschriebene Webseite zu liefern.

  • Auch wenn es für PHP / HTML weniger von Bedeutung ist, solltest du dir lieber jetzt als später angewöhnen auch hier Einrückungen zu nutzen. Das steigert die Lesbarkeit enorm und hilft Zusammenhänge besser zu erkennen.


    Zunächst ist shell_exec(); nicht sehr toll da es keine brauchbare Rückmeldung gibt ob der Befehl erfolgreich ausgeführt wurde - der einzige Hinweis wäre 'false' als Rückgabewert falls er nicht erfolgreich war, aber woran es dann lag ist darüber nicht zu ermitteln. Daher ist es besser exec(); zu verwenden, siehe dazu auch "exec() vs shell_exec()" hier: FAQ => Nützliche Links / Linksammlung => Befehle über PHP mit root Rechten ausführen (sudo webscript)


    Desweiteren würde ich dir empfehlen von folgender Anleitung die Einführung sowie Grundlagen zu lesen: FAQ => Nützliche Links / Linksammlung => PHP: Anleitung zum schalten von GPIO


    Du behandelst die selbe Sache 2x .... Besser wäre nicht 2x eine if für den selben Fall nutzen sondern alles in die erste, da wo auch dein "print" steht anschließend das python Script ausführen..
    Also nicht:[code=php]if(isset($_GET['morsen'])){
    print "<b>Kannst Du es entziffern?</b>";
    }
    #...
    if(isset($_GET['morsen'])){
    sleep(2);
    $val = trim(@shell_exec("python Text-morsen.py &"));
    }
    [/php]
    Sondern:
    [code=php]
    if (isset($_GET['morsen'])) {
    print "<b>Kannst Du es entziffern?</b>";
    sleep(2);
    $val = trim(@shell_exec("python Text-morsen.py &"));
    }
    [/php]Aber wie gesagt, nutze lieber exec();
    (jedesmal wenn ich diese $val = trim(@shell_exec() Sache lese krieg ich nen brechreitz)



    Allerdings ist das Problem hier (was __deets__ auch eben angesprochen hat) Wie PHP mit der Ausgabe umgeht.
    Ausgaben sind quasi alles was dem Client angezeigt werden soll, also print/echos oder allgemein HTML.
    Standardmäßig ist es bei PHP so das erst eine Ausgabe erfolgt wenn das vollständige Script verarbeitet wurde. Alle Ausgaben werden sozusagen in einen Speicher (Ausgabepuffer) abgelegt und erst dann ausgegeben wenn das Script fertig bzw bis ans Ende verarbeitet wurde.
    Um das zu umgehen gibt es zwei Möglichkeiten:


    1)
    Nach jeder Ausgabezeile sagst du dem Interpreter dass dieser sofort den Puffer leeren und so eine sofortige Ausgabe machen soll. Dazu fügst du flush(); nach jeder print / echo Zeile ein.
    [code=php]
    if (isset($_GET['morsen'])) {
    print "<b>Kannst Du es entziffern?</b>";
    flush();
    $val = trim(@shell_exec("python Text-morsen.py &"));
    }
    [/php]


    2)
    Du sagst dem PHP Interpreter dass dieser sofort und quasi ständig den Ausgabe Puffer zu leeren hat, also auch während das Script noch verarbeitet wird, automatisch nach jedem echo oder print Befehl. Damit kannst du dir alle weiteren flush(); sparen.
    Erreichen tut man das mithilfe von http://php.net/manual/de/function.ob-implicit-flush.php
    Das setzt du einfach ganz oben direkt unter <?php :
    [code=php]
    ob_implicit_flush(true);
    @ob_end_flush();
    [/php]
    Das hat aber den Nachteil das es manchmal so wirkt als würde sich die Seite nur Stück für Stück aufbauen, als wäre der Rechner auf dem das Script läuft lahm.
    In manchen Fällen ist das aber durchaus gewollt, zum Beispiel wenn man die Ausgabe eines Konsolen Befehls quasi in Echtzeit sehen möchte. Siehe dazu auch im obigen 'sudo webscript' Link die von mir gezeigte _exec Funktion bezüglich popen(); am Ende des dortigen Beitrags



    Da du aber GPIO's schalten willst und dafür ein Python Script nutzt, wäre es sinnvoller den Webserver gleich mit Python umzusetzen dann wären die Möglichkeiten umfassender und gestalten sich zudem auch weit aus einfacher:
    FAQ => Nützliche Links / Linksammlung => [Python] Webserver, Websocket und ein bisschen AJAX

  • Vielen Dank für die ausführliche Erläuterung. Das werde ich mal alles versuchen umzusetzen. Das mit den 2 if für die selbe Auswertung resultierte aus meinen verschiedenen Versuchen. Am Anfang war das natürlich zusammen. Apache und php5 läuft, aber Tornado wollte sich nicht installieren lassen. Aber ich lerne gerne dazu (68 und Raspi-Anfänger).
    Ein schönes gruselfreies Wochenende wünscht Buschkin