Python-Messdaten auf Firefox-Browser ausgeben

  • Hallo,
    eines meiner ersten kleinen Projekte als Neuling mit dem Raspi 2 ist, ein altes Projekt vom Arduino zu übertragen.
    Es handelt sich um eine kleine Wetterstation mit Python programmiert, bei der ich einen DHT22-Sensor (Temp und Feuchte) und einen BMP085 (Druck) auslese und die Messwerte auf einem LCD 16x2 darstelle. Zusätzlich werden die Daten noch in einer Datei auf einem USB-Stick (zum Schutz der SD-Karte) geloggt.
    Diese funktioniert super.

    Nun würde ich die Daten auch außerhalb des lokalen Netzes z.B. über Smartphone kontrollieren. Dazu sollen die drei Messwerte im Browser alle 30 Sekunden dargestellt werden.
    Ich habe schon im Internet und auch hier leider erfolglos nach einem Tutorial / Lösungsansatz gesucht. Da ich sicherlich einen Webserver auf meinem Raspi benötige habe ich als Server lighttpd installiert. Funktioniert.
    Getestet habe ich diesen mit einem kleinen Script mit "Formular"-Nutzung. D.h. HTML-Seite fordert zur Eingabe von Daten auf, diese werden an ein Python-Programm zur Auswertung gegeben, dass diese dann auf dem Browser darstellen. Findet man im Internet unter http://mschimmels.de/files/pythonbuch/ch23s08.html

    Da meine Daten aber aus dem Python-Programm kommen, brauche ich keine Eingaben des Nutzers. Ich bekomme diesen Transfer einfach nicht hin.

    Die aktuellen Messwerte werden von einem anderen Python-Programm erstellt und in 3 Textdateien temp.txt, hum.txt, und pres.txt gespeichert. In der Zeile print temp, hum, pres werden die Daten in der Python-shell richtig angezeigt.
    Im HTML-Code habe ich erst die Überschrift. Die formatierte Anzeige folgt, wenn das Problem mit dem Browser gelöst ist. Ist ja dann nur noch HTML-Code.

    Wer kann mir dabei helfen, wie ich die Anzeige der Daten auf den Browser umlenken kann? :helpnew:

    Ich schicke mal mein Python-Programm mit:

  • Mit Apache geht das so:

    Und dann:

    Code
    sudo cp pythoncgi /usr/lib/cgi-bin
    sudo chmod 755 /usr/lib/cgi-bin/pythoncgi

    Aufruf im Browser:

    Code
    http://192.168.1.203/cgi-bin/pythoncgi

    Einmal editiert, zuletzt von Tell (14. Januar 2016 um 13:01)

  • Hey Tell,
    danke für die schnelle Antwort. Ich habe in meinem Python-Script die Zeile
    print( "Content-Type: text/html\r\n\r\n" ) ;
    angepasst.
    Nach meinen Infos über lighttpd werden Python-Progr im Verzeichnis /var/www/cgi-bin abgelegt und HTML und PHP im Verzeichnis /var/www/htdocs . Das habe ich auch so gemacht (mit den Ausführungsrechten) und die Tests nach der Installation von lighttpd haben auch alle funktioniert.

    ich bekomme den Fehler: 500 - Internal Server Error

  • Dann prüf mal die Logdatei vom Webserver was zu dem Zeitpunkt drin steht, die sich normalerweise im Verzeichnis /var/log/lighttpd/ befinden.

    Du musst aber auch vorher ein mal das cgi Module für lighttpd einschalte:

    Code
    sudo lighty-enable-mod cgi

  • Dann prüf mal die Logdatei vom Webserver was zu dem Zeitpunkt drin steht, die sich normalerweise im Verzeichnis /var/log/lighttpd/ befinden.

    Du musst aber auch vorher ein mal das cgi Module für lighttpd einschalte:

    Code
    sudo lighty-enable-mod cgi

    Hallo,
    auf der Suche nach dem Fehler hatte ich mir die Logdatei von lightttpd unter /var/log/lightttpd/error.log angesehen. Da sind nur Einträge vo vorgestern drin.
    lighty-enable-mod cgi und fastcgi hatte ich schon aktiviert beim Installieren. Habe es aber noch einmal getestet.
    Zusätzlich habe ich jetzt noch eine Ethernet-Verbindung hergestellt, da WLan manchmal mit den kleinen Dongles Probleme macht.

    Aber weiterhin der selbe Fehler 500 Internal Server Error

    Ich habe mal das PDF zum Installieren und Testen des lighttpd angefügt.

  • Wenn alle Stricke reißen könntest du aber auch im Python Script mithilfe von zB bottle die Messwerte direkt anzeigen lassen - dann muss das Python Script permanent laufen und fungiert dann als eigenständiger "Webserver".

  • Hi,
    das werde ich mal im Hinterkopf behalten mit "bottle".
    Wichtig ist mir aber, diese WebServer-Technik zu lernen und zu verstehen, damit ich sie auch bei anderen Projekten anwenden kann. Also immer wenn Ausgaben des Python auch dezentral außerhalb des Heimnetzes sichtbar sein sollen. War beim Arduino auch so eine spezielle Angelegenheit. Mit Tips von den Profis dann gelöst.
    Da werde ich dann noch weiter suchen müssen.

    Problematisch ist ja immer die Rechtevergabe. Ich überlege schon den Nutzer Pi (der ich ja nach Anmeldung immer bin) zum SU zu machen. Dann ist dieses Problem gelöst.

    Das ist aber sicherlich nicht das Webserver-Problem.

    Einmal editiert, zuletzt von BillowingFog33696 (14. Januar 2016 um 15:41)


  • Problematisch ist ja immer die Rechtevergabe. Ich überlege schon den Nutzer Pi (der ich ja nach Anmeldung immer bin) zum SU zu machen. Dann ist dieses Problem gelöst.

    Das wäre aber keine Problemlösung, damit umgehst du nur ein mögliches Problem ohne es zu verstehen und tatsächlich zu lösen.

    Wenn du mit dem Benutzer 'pi' arbeitest, verwendet man üblicherweise "sudo" vor den Befehlen um diesen als root auszuführen. Du kannst aber auch vollständig zum root Benutzer wechseln: sudo -i
    Es besteht also kein Grund auch noch den 'pi' Benutzer zum SuperUser (root) zu machen.

    Ein Webserver läuft über einen normalen Benutzer, bei nginx und apache2 ist das: www-data
    Andere Benutzer haben auf fremde Dateien bzw Verzeichnisse i.d.R. keine Rechte, und das ist auch gut so.
    Wenn du also ein Rechteproblem hast dann veränder den Besitzer der Datei. Siehe dazu https://wiki.ubuntuusers.de/Rechte/ beziehungsweise https://wiki.ubuntuusers.de/chmod/ und https://wiki.ubuntuusers.de/chown/

    //EDIT: wiki.ubuntuusers.de läuft übrigens auch ausschließlich über ein Python-Framework also ohne Webserver wie apache2, nginx oder lighttpd

  • Da hast du natürlich vollkommen Recht. Aber als Windows-Nutzer nervt es schon ein bischen, wenn man plötzlich ein Verzeichnis nicht nutzen darf weil man kein SU ist. Im Terminal schalte ich ja mit sudo su ja schon instinktiv immer um.

    Aber aktuell stocher ich wie nach der Nadel im Heuhaufen nach der Lösung des Web-Problems.

  • Die Loesung hat IMHO meigrafd schon erwaehnt - statt sich mit den Spezialitaeten von Rechten der Webserver (die ja aus gutem Grund so sind) rumzuschlagen, schreib dein Programm einfach mit bottle oder Tornado. Entweder ignorierst du dann die "grossen" Webserver komplett, weil es fuer den Heimgebrauch ist. Oder du bindest auf "localhost" statt auf die extern sichtbare IP, und benutzt NGINX & proxy-forwarding (3 Zeilen in der Config), und greifst darueber dann sicher zu. CGI und die integration in einen Webserver sind IMHO archaisch.

  • Hallo,
    herzlichen Dank für euren Tip mit "Bottle". Ich habe diesen Server auf meinem raspi installiert und habe sogar etwas auf den Browser ausgegeben. Ausgegeben wurde der Code bei return.
    Schon mal sehr gut und mehr als davor.
    Leider werden dort für temp hum pres aber nicht die gemessenen Werte ausgegeben, die kurz darüber der print-Befehl in der Shell ausgibt. Wie muss ich denn hier den Code anpassen, damit der Wert und nicht der Text ausgegeben wird?


  • Vorab:

    Das "try:" würde ich außerhalb der "while" setzen.
    Du verwendest zudem zwar das "with"-Statement, kümmerst dich aber trotzdem selbst noch ums output.close() :s Das brauchst du nicht, darum kümmert sich "with" automatisch. "output" ist aber auch nur ein Object, also in diesem Fall ein File Handler.

    Der größte Fehler ist aber auch Bottle innerhalb der while zu setzen - das ist ganz böse

    Zu deinem Anliegen:

    Beim Einsatz von bottle muss du bei Dynamisch erzeugten Inhalten natürlich auch Werte einsetzen. Das geschieht genau so wie bei normalen Python Ausgaben.
    Du könntest also zum Beispiel den ganzen HTML Code erst in eine 'Liste' schreiben lassen wo du auch die Werte einfügst und Anschließend return'st du dann diese Variable, bzw wandelst die 'List' in einen String um... Das wäre schneller als mit " += " und nur Strings zu arbeiten.

    Der @route() decorator musst nicht genau so heißen wie die Funktion über der es steht. Wichtig ist nur das es über der dazu gehörigen Funktion steht ;)


    Beispiel:
    [code=php]
    from time import strftime
    from sys import exit
    from bottle import route, run

    try:

    @route('/')
    def WetterServer():
    html=[]
    html.append( '<html>' )
    html.append( ' <head> <title>Messwerte-Ausgabe</title> </head>' )
    html.append( ' <body>' )
    html.append( ' <p>Aktuelle Uhrzeit: {}</p>' . format(strftime("%d.%m.%Y %H:%M:%S")) )
    html.append( ' </body>' )
    html.append( '</html>' )
    return ''.join(html)

    run(host='0.0.0.0', port=80)

    except KeyboardInterrupt:
    exit()
    [/php](die Leerzeichen zwischen ( und ' sowie ' und ) müssen nicht sein, hab ich nur gemacht damit für Dich Anfang und Ende besser ersichtlich ist)
    Du brauchst dann auch kein Pfad angeben sondern einfach http://192.168.178.35/ ansurfen.

    Besser wäre es jedoch mit einem Template zu arbeiten. Siehe dazu: http://wiki.ubuntuusers.de/Bottle/#Simple-Template

    Desweiteren wäre es denk ich besser wenn du bottle auf 0.0.0.0 bindest, damit lauscht er auf allen IP's. Das wäre vorausschauend besser sofern sich die IP des RaspberryPi's mal ändern sollte, dann brauchst du daran nichts verändern.

  • Danke für deine Zeit.
    Ich werde mir das Alles genau ansehen, auch wenn ich aktuell noch nicht ganz genau weiss, wie ich es umsetze. Aber das ist ja meine Absicht. Lösungen suchen, finden und verstehen. Und daraus für das nächste Projektchen lernen.
    Leider ist es aber für einen Einsteiger nicht immer so einfach im Internet aus den vielen Informationen die Spreu vom Weizen zu trennen. So liest man z.B. immer, dass ein open einer Datei IMMER ein close braucht. Und dann testet man den dort im Tutorial abgedruckten Code.

    Mit "bottle" in der Schleife fiel mir vorhin auch auf. Das Problem ist ja, dass solange der Server "lauscht" der Ablauf der Schleife unterbrochen ist und damit auch keine neuen Messungen erfolgen. Ich hatte schon gesucht, ob man den Server nur kurzzeitig lauschen lässt und dann stoppt und die Schleife dann weiter läuft und beim nächsten Durchlauf wieder startet.

    Noch eine kurze Frage, auf die ich im Internet noch keine Antwort gefunden habe:
    Wie ergibt sich eigentlich die IP eines raspi? Ist diese durch den WLan-Stick gegeben? D.h. wenn ich den Stich tausche, dann ändert sich auch die IP.

    Gruß


  • Leider ist es aber für einen Einsteiger nicht immer so einfach im Internet aus den vielen Informationen die Spreu vom Weizen zu trennen. So liest man z.B. immer, dass ein open einer Datei IMMER ein close braucht. Und dann testet man den dort im Tutorial abgedruckten Code.

    Allgemein ist das ja auch richtig, aber im Fall von "with" kümmert sich "with" selbstständig darum sobald die dazugehörige Einrückung beendet ist ;)

    Mit "bottle" in der Schleife fiel mir vorhin auch auf. Das Problem ist ja, dass solange der Server "lauscht" der Ablauf der Schleife unterbrochen ist und damit auch keine neuen Messungen erfolgen. Ich hatte schon gesucht, ob man den Server nur kurzzeitig lauschen lässt und dann stoppt und die Schleife dann weiter läuft und beim nächsten Durchlauf wieder startet.

    Hm ne das macht eigentlich auch kein Sinn. Sobald "run()" von bottle ausgeführt wird, wird das Script ab dieser Stelle blockiert. Weitere Aktionen wie eine zuvor ausgeführte while sind dann also nicht mehr möglich - bottle läuft aber kontinuierlich weiter.
    Stell dir das einfach so vor, dass das Script ein Thread ist, also ein Prozess, was von oben nach unten abgearbeitet wird. Führt man dann eine "while" aus, dreht die sich unendlich im Kreis, bis entweder dessen Bedingung sich ändert oder sie durch zB ein 'break' unterbrochen wird. Ebenso wird es durch zB ein "time.sleep(100)" ab der Stelle für 100 Sekunden blockiert und erst nach Auflauf wird der Code danach ausgeführt.

    Es gäbe in diesem Fall nun (wie immer) mehrere Möglichkeiten das zu lösen.

    • Ein separates Script was die Messwerte regelmäßig in eine Datenbank schreibt. Ein anderes Script für dein LCD-Display um die Werte aus der Datenbank auszulesen und anzuzeigen. Und dann noch ein Script für bottle.
    • Nur ein Script in dem mehrere Threads gestartet werden und dann parallel laufen. Dann würde zB ein Thread zum auslesen der Messwerte laufen, ein weiterer Thread für dein LCD-Display und der Script-eigene Thread wird für bottle genutzt.
    • ...

    Wie ergibt sich eigentlich die IP eines raspi? Ist diese durch den WLan-Stick gegeben? D.h. wenn ich den Stich tausche, dann ändert sich auch die IP.

    Die wird i.d.R. von deinem Router über DHCP vergeben.
    Jede Netzwerkkarte hat eine Hardware-Adresse, die sog. MAC-Addr. Anhand dieser wird das Netzwerk-Gerät im Netzwerk identifiziert. Solange die gleicht bleibt vergeben heutige Router i.d.R. immer die selbe (W)LAN-IP.
    Man kann die Netzwerkkonfiguration aber auch Statisch festlegen. Entweder auf dem Router indem man anhand der MAC diesem Gerät immer die selbe IP zuweisen lässt, oder man ändert die Konfiguration des Network-Devices am Computers und stellt DHCP aus...

  • Ich war mal so frei - beschäftige mich sowieso auch grad mit bottle und multiprocessing :daumendreh2:

    Script für Python3 => http://codepad.org/FwK5kpiF

    Das Script basiert im Prinzip auf deinem und dem was ich hier bisher gepostet habe.
    bottle wird in einem separaten Prozess gestartet und läuft (solange das Script auch läuft) simultan im Hintergrund weiter. Nachdem der bottle Prozess gestartet wurde, wird die Funktion fürs LCD-Display ausgeführt. Beide greifen auf die read_sensors() Funktion zu und um auch Codewiederholungen zu vermeiden hab ich Deinen Code bezüglich des Displays auch ein bisschen optimiert :fies:
    Zusätzlich zur Anzeige der Messwerte zeigt die Seite auch ggf einen Fehler beim Auslesen der Sensoren an. Und zu guter letzt kann man sich über bottle auch die Ausgaben vom Konsolen Befehl "top" sowie "w" anzeigen lassen.
    Alle Seiten führen alle 3 Sekunden einen refresh durch.

    :angel:

  • So, es funktioniert nun wie gewünscht.
    Im Firefox-Browser werden die Messdaten des DHT22 und des BMP085 angezeigt. Temp, Hum, Pres
    Natürlich kann man die HTML-Ausgabe noch schönen, aber rein informativ ist es so erst einmal ok.

    Vielen Dank an alle für die Tips u.a. rund um "bottle".

    Hier das aktuelle Python-Script:

Jetzt mitmachen!

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