Raspi: Steuern und Messen mit PHP

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

    das folgende Tutorial zeigt euch, wie ihr mit Hilfe von PHP einfache Befehle dynamisch auf dem Raspberry Pi ausführen könnt. Das Tutorial ist vor allem für PHP Neulinge bzw. Anfänger gedacht und entstand unter Nutzung der Wheezy Distribution, es kann allerdings in abgeänderter Form, sicherlich auch für andere Distributionen als Inspiration dienen.

    Das meiste in diesem Tutorial lässt sich über das Terminal/Nano erledigen. Wer möchte, kann allerdings auch andere Tools nutzen.

    Was das Tutorial nicht ist
    Obacht! Das Tutorial ist keine Schritt für Schritt-Anleitung für die Umsetzung der Heimsteuerung, die ich hier vorgestellt habe. Mit einwenig Geduld und dem Wissen, das ihr euch hier aneignen könnt, könnt ihr das aber mindestens genauso gut umsetzen. Wer keine Lust hat, die Erklärungen zu lesen, kann auch einfach die Code-Beispiele rauskopieren und rum probieren. Ich gehe nur auf die wichtigsten Befehle ein und das auch nur sehr kurz und knapp. Wenn ihr weitere Informationen benötigt, schaut doch im PHP Manual nach.

    Quelltexte
    Am Ende des Tutorials ist eine Quelltext Datei, die alle vorgestellten Funktionen beinhaltet. Ihr könnt diese ruhig als Anreiz nutzen. :)

    Achtung! Die Beispiele hier sind sehr simpel gehalten. Sie sind nur zunächst nur zum Verdeutlichen und ausschließlich für das lokale Netzwerk gedacht! Den Raspberry also nicht öffentlich zugänglich machen!

    Grundvoraussetzungen

    • Raspberry Pi
    • Eingerichteter HTTP-Server inkl. PHP (Empfehlung meinerseits: Lighttpd + php5-cgi)
    • Nano oder anderen Text-Editor
    • Grundkenntnisse in Bash und HTML sind wünschenswert


    Inhalte
    Hello World! - PHP Crashkurs

    • echo
    • Varaiablen & Arrays
    • $_GET[]


    Teil 1: System Kommandos ausführen

    • Ausführen von ping google.de und Ausgabe
    • Integration in HTML
    • dynamisches Ausführen von ping über HTML-Formular


    Teil 2: GPIO

    • GPIO auslesen


    Hello World - PHP Crash Kurs
    Nach erfolgreicher Installation eures Servers geht ihr in dessen Dokumenten-Verzeichnis. Bei mir ist das /var/www.

    Code
    cd /var/www

    Mit '[font="Courier New"]nano index.php[/font]' eröffnen wir eine neue Datei und schreiben nur folgenden Code rein:

    PHP
    <?php
       echo "Hello World!";
    ?>

    Nun speichern wir dies mit STRG+O ab und öffnen nun unseren Browser: http://raspberrypi:8080/ (Die Adresse und der Port können natürlich von euer Konfiguration abweichen).
    Anschließend solltet ihr eine weiße Seite mit dem Inhalt "Hello World!" sehen.

    Mit dem [font="Courier New"]<?php ?>[/font]-Tag markiert ihr mehr oder weniger euren PHP-Code. Damit weiß der Interpreter was er zu tun hat, 'echo' ist wie in vielen anderen Sprachen auch, für die Ausgabe verantwortlich. Jeder Befehl wird in PHP mit einem Semikolon ';' abgeschlossen.

    Nun gehen wir zurück in die [font="Courier New"]index.php [/font]und ändern den Quelltext wie folgt ab:

    PHP
    <?php
       $var=1;
       echo $var;
    ?>

    $var ist eine Variable, diese wird durch das $-Zeichen markiert. Mit Variablen könnt ihr beispielsweise Rechnungen oder einfach nur Ausgaben beeinflussen. Wenn ihr nun den Browser öffnet, sollte nur eine 1 erscheinen.

    Mit PHP lässt sich mit Variablen auch sehr leicht rechnen:

    PHP
    <?php
       $var=1;
       $number=2;
       echo $var+$number;
    ?>

    Weitere Rechenoperatoren sind unter anderem: '-', '*', '/'

    Es gibt eine besondere Form von Variablen. Das sind Arrays. Mit Arrays könnt ihr mehrere Werte zusammenfassen. Das ist sinnvoll wenn beispielsweise Werte eines besonderen Typs gespeichert werden sollen.

    PHP
    <?php
    
    
     $array = array("Anton", "Petra", "Hans");
    
    
     echo $array[2];
    ?>

    Wenn ihr dies nun abspeichert und den Browser auf den Raspi richtet, solltet ihr "Hans" sehen. Arrays werden in PHP ab 0 gezählt. Ändert die Zahl in den Klammern bei echo $array[] ab und schaut was passiert.


    $_GET[]
    Es gibt einen System-Array der sehr hilfreich ist und im Laufe des Tutorials sicherlich mehrmals vorkommen wird: $_GET.

    $_GET symbolisiert die übergebenen GET-Parameter aus der URL. Aber was sind das für Parameter?

    Ruft einfach mal folgenden Link auf: http://www.google.de/?q=Hans

    Es erscheint die Google Webseite, mit dem Ausgefüllten Suchfeld. Mit Hilfe von GET-Parametern lassen sich Informationen an den Server übertragen. Das ist Hilfreich, wenn ihr eine Schnittstelle zu einer anderen Anwendung umsetzen möchtet.

    Mit folgendem Code könnt ihr den Parameter 'parameter' auslesen:

    PHP
    <?php
       echo $_GET['parameter'];
    ?>

    Wenn ihr nun euren Browser öffnet, steht wahrscheinlich nichts drin (oder eventuell auch ein Fehler). Ändert ihr die URL allerdings ab (http://raspberrypi:8080/index.php?parameter=RaspberryPi) sollte "RaspberryPi" erscheinen.

    Falls ihr einen Fehler bekommt, wenn ihr keinen Parameter übergibt, müsst ihr um das echo noch eine kleine Bedingung setzen:

    PHP
    <?php
     if(isset($_GET['parameter'])){
     echo $_GET['parameter'];
     } else {
     echo "Kein Parameter ";
     }
    ?>

    Die if-Bedingung prüft vor der Ausgabe, ob ein Parameter namens "Parameter" übergeben worden ist. Ist dies der Fall so wird der Parameter-Wert angezeigt, wird keiner Übermittelt erscheint die Meldung "Kein Parameter :(".


    Teil 1: System Kommandos ausführen

    Mit Hilfe von PHP könnt ihr ganz leicht System Kommandos ausführen. Dafür gibt es den '[font="Courier New"]shell_exec[/font]' Befehl:

    PHP
    <?php
     echo shell_exec("ping -c 1 google.de");
    ?>

    Wenn ihr euren Browser aufruft, sollte nun die Ausgabe des PING-Befehls erscheinen. Jetzt wird es Zeit einwenig zu kombinieren. Nicht immer möchte man nur Google anpingen, sondern auch dynamisch andere Seiten. Das geht ganz einfach:

    PHP
    <?php
     echo shell_exec("ping -c 1 ".$_GET['host']."");
    ?>

    Obacht! Wenn ihr einen Array in Strings (damit mein ich nicht die Unterwäsche, sondern die Zeichenfolgen die in den Anführungsstrichen stehen) setzen wollt, müsst ihr Anführungsstriche um den Array setzen und mit Punkten verbinden.

    Wenn ihr nun index.php?host=bild.de öffnet, wird jetzt nicht mehr google.de sondern Bild.de angepingt. Analog zu dem, könnt ihr das natürlich auch mit anderen Befehlen ausführen.


    Integration von HTML
    Wirklich elegant ist es natürlich nicht, den Parameter in die URL zu tippen. Deswegen verbinden wir das ganze jetzt mit ein paar Zeilen HTML:

    Erläuterung:
    Der [font="Courier New"]<form>[/font]-Tag definiert das HTML-Formular. Es teilt dem Browser im Prinzip nur mit, an welche URL der Parameter aus der Textbox angefügt werden soll.
    [font="Courier New"]<input type="text" name="host">[/font] erzeugt eine Textbox, die ihr in PHP mit $_GET['host'] auslesen könnt.
    [font="Courier New"]<input type="submit">[/font] erzeugt den Button zum Absenden der Formulardaten.

    Nun könnt' ihr das Beispiel noch weiter dynamisch gestalten:


    Teil 2: GPIO
    1. Auslesen der GPIO-Ports
    Kommen wir nun zum etwas spannenderen Teil: Dem Auslesen der GPIO Ports. Als Vorbereitung aktivieren wir den GPIO 17 als Ausgang im Terminal und schalten ihn auf High:

    Code
    echo "17" > /sys/class/gpio/export
    echo "out" > /sys/class/gpio/gpio17/direction
    echo "1" > /sys/class/gpio/gpio17/value

    Den aktuellen Status des Ausganges können wir mit Hilfe von '[font="Courier New"]cat[/font]' auslesen.

    Code
    cat /sys/class/gpio/gpio17/value

    Das sollte uns nun eine '1' zurückliefern. Genau das selbe setzen wir nun in PHP um. Dafür bieten sich grundsätzlich (mindestens) zwei Möglichkeiten an:

    • Wir öffnen die virtuelle Datei '[font="Monaco"]/s[/font][font="Monaco"]ys/class/gpio/gpio17/value[/font]' mit der PHP Funktion '[font="Courier New"]file_get_contents[/font]'
    • Wir führen den Befehl '[font="Monaco"]cat [/font][font="Monaco"]/s[/font][font="Monaco"]ys/class/gpio/gpio17/value[/font]' mit shell_exec(); aus


    Beide Varianten werden uns zum Ziel bringen, die sauberere Lösung ist meiner Meinung nach die erste.

    PHP
    <?php
      file_get_contents("/sys/devices/virtual/gpio/gpio17/value");
    ?>

    Nun liefert uns das Script hoffentlich eine '1' zurück. Wir wissen also, dass der GPIO 17 auf High steht. Die Information sollte für uns eigentlich ausreichen, das kann man aber noch einwenig schöner gestalten. Wir schreiben das Script einwenig um, um entweder die Ausgabe "EIN" oder "AUS" zu erhalten.

    PHP
    <?php
      $status = file_get_contents("/sys/devices/virtual/gpio/gpio17/value");
      if($status==1){
        echo "AN";
      } else {
        echo "AUS";
      }
    ?>

    Erläuterung: Wir rufen uns den Inhalt der Datei in die Variable '[font="Courier New"]$status[/font]'. Anschließend prüfen wir, ob der Inhalt 1 entspricht. Ist dies der Fall geben wir "AN" aus, für jeden anderen Wert wird "AUS" ausgegeben. Beachtet hierbei bitte, dass ihr zwei Gleichheitszeichen benutzt, andernfalls bekommt ihr immer den Wert "AN", da PHP die Bedingung einwenig anders interpretiert.

    Jetzt ist es natürlich sehr mühselig für mehrere Ports immer wieder das selbe auszuführen. Deswegen lagern wir das in eine Funktion aus. Das ist immer sinnvoll, wenn ihr wisst, dass ihr etwas mehr als einmal ausführen werdet. Grundsätzlich kann jeder Anweisung als Funktion eingesetzt werden, achtet dabei allerdings auf sinnvolle Funktions- und Parameternamen. Dann könnt ihr eure Funktionen auch in anderen Scripten nutzen.

    Eine Funktion wird mit '[font="Courier New"]function[/font]' eingeleitet, anschließend folgt der Name der Funktion und die Parameter, die entgegengenommen werden können. Das sieht dann so aus:

    Code
    function gpio_wert($GPIO){
        $status = file_get_contents("/sys/devices/virtual/gpio/gpio".$GPIO."/value");
        if($status==1){
        echo "AN";
     } else {
        echo "AUS";
     }
    }

    Üblicherweise werden Funktionen in PHP-Scripten direkt an den Anfang gestellt oder in separate Dateien ausgelagert. Das Aufrufen der Funktion erfolgt dann wie folgt:

    Das spart im eigentlichen Script dann nicht nur platz, sondern hält euren Quelltext auch übersichtlicher.

    Und das war es fürs erste. Bald geht's dann mit dem Schalten weiter.

    Gruß
    Christian

  • danke für das "Tutorial" :) wird mir die Tage sicher weiterhelfen, da heute mein Temperatur/Höhen/Luftdrucksensor gekommen ist. Werde das Ganze dann auch mit PHP auf dem Webserver anzeigen lassen.

  • Erklär bitte auch gleich noch htmlspecialchars und htmlentities :thumbs1:
    So kann man sich z.B. vor cross-site-scripting schüzen(z.B schadcode auf eurer webseite ausführen).

    Unsicher:
    [code=php]<?php
    echo $_GET['parameter'];
    ?>[/php]

    wird dann zu
    [code=php]<?php
    echo htmlspecialchars($_GET['parameter']);
    ?>
    [/php]

    bei mysql abfragen dann [code=php]mysql_real_escape_string()[/php]
    usw.

    Einmal editiert, zuletzt von Luca. (13. August 2013 um 21:42)

  • Super Tutorial. Gut erklärt. Auf den GPIO Teil freue ich mich auch.
    Eine Frage hätte ich zum letzten Beispiel, gibt es auch die Möglichkeit die Ausgabe "sauber" ausgeben zu lassen. So wie im Beispiel wird ja alles stur hinter einander und somit relativ unübersichtlich ausgegeben.


  • Ich glaube ich stehe gerade auf dem Schlauch wie meinst du das mit dem <pre> Tag? Kannst du vielleicht ein kleines Beispiel machen.

    Kein Problem! Gerne. :)

    Setz' einfach um den shell_exec(); Befehl den <pre>-Tag:

    PHP
    <?php
    if(isset($_GET['ping'])){
    echo "<pre>";
    echo shell_exec("ping -c 1 ".$_GET['host']."");
    echo "</pre>";
    }
    ?>

    Du kannst das natürlich auch um den kompletten PHP-Befehl setzten. Das macht allerdings keinen Sinn, wenn Du mehrere Ausgaben hast, die unterschiedlich formatiert werden sollen:

    Gruß
    Christian

  • Danke klappt super, habe das ganze jetzt mal noch mit Traceroute versucht.

    Das klappt leider noch nicht ganz. Ich erhalten nach einiger Zeit immer "[font="Times"]504 Gateway Time-out". Vermutlich liegt das aber an nginx das der einfach nicht solange warten will oder?[/font]

  • Hey Chris,

    ich möchte gerne mit einem Button ein shell_exec Befehl los werden. Doch im error-log steht immer, das { oder } zu viel da sind. Habe alle mal entfernt aber geht immer noch nicht. Wie würdest du das umsetzen? Also nur ein Button der beim Klick bspw. den RPI herunter fährt.

    Wenn ich dein Script so übernehme (Anhang) und dann eine Seite ins Feld eingebe und dann auf Ping! klicke, kommt bei mir die Startseite und nichts passiert.

    Einmal editiert, zuletzt von Racer j (16. August 2013 um 13:13)


  • Eine Frage hätte ich zum letzten Beispiel, gibt es auch die Möglichkeit die Ausgabe "sauber" ausgeben zu lassen. So wie im Beispiel wird ja alles stur hinter einander und somit relativ unübersichtlich ausgegeben.

    Es gibt verschiedene wege um über PHP shell Befehle auszuführen.
    Ich nutze vorzugsweise exec(); da dort die Ausgabe in ein Array und ein möglicher Fehlercode in eine weitere Variable geschrieben wird und ich somit nicht nur einfach jede Ausgabezeile mir anzeigen lassen kann sondern auch ob der Befehl fehlerfrei funktionierte ;)

    Im folgenden Beitrag habe ich dazu heute bereits ein paar Beispiele beschrieben: PHP Extension root Rechte


    Mit ein bischen Mehraufwand wäre auch eine "Echtzeit Ausgabe" möglich indem man " popen " nutzt..
    Das habe ich bei mir über eine extra function realisiert:


    Die ersten zwei Zeilen sorgen dafür das etwas sofor ausggeben wird.
    Mit der function werden auch Leerzeichen korrekt dargestellt (wegen des str_replace) und somit lässt sich auch eine formatierte Ausgabe besser erkennen :)


  • Wir schreiben das Script einwenig um, um entweder die Ausgabe "EIN" oder "AUS" zu erhalten.

    PHP
    <?php
      $status = file_get_contents("/sys/devices/virtual/gpio/gpio17/value");
      if($status=1){
        echo "AN";
      } else {
        echo "AUS";
      }
    ?>

    Typo !

    Code
    if($status == 1){

    Ansonsten sehr gut.

    Offizieller Schmier und Schmutzfink des Forum.
    Warum einfach wenn's auch schwer geht ?

    Kein Support per PN !
    Fragen bitte hier im Forum stellen. So hat jeder etwas davon.


  • Und das war es fürs erste. Bald geht's dann mit dem Schalten weiter.

    Gruß
    Christian

    An deinem Schalten Tutorial wäre ich auch sehr interessiert! Habe bis jetzt leider noch keine funktionierende Lösung für das Auslesen und Schalten der GPIOs auf der Raspberry über ein externes (bzw. einem im gleichen Netzwerk befindlichen Rechner zu steuern).
    Also webIOPi hab ich zum laufen bekommen und kann meine GPIOs auch über die Webseite steuern, nur möchte ich gerne die Möglichkeit haben, das ganze auch über PHP zu steuern und nicht nur über die Komplizierten Skripte.
    Bin da nicht so der Profi in den Bereichen :D

    mfG

Jetzt mitmachen!

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