Aktuelle Messdaten von DHT22 per Skript auf Webserver anzeigen

Python auf Einplatinencomputer wie Raspberry Pi, Banana Pi / Python für Micro-Controller
Antworten
sprunus-ng
User
Beiträge: 7
Registriert: Samstag 20. April 2024, 21:14

Hi,

Ich bin neu im Forum, also erst einmal ein herzliches Hallo an alle. Meine Skript- und Programmierkenntnisse sind nicht allzu doll, zum Zusammenkopieren von Code-Schnipseln reicht es in der Regel aber doch.

Ich habe an meinem Pi einen DHT22 an die GPIO-Schnittstelle angeschlossen und erfasse alle 5 Minuten die Temperatur und die relative Luftfeuchtigkeit. Die Messergebnisse füge ich an eine csv-Datei an und das funktioniert alles wunderbar. Nun möchte ich gerne die aktuellsten Daten per Webbrowser einsehen können. Da mir nichts besseres eingefallen ist, lese ich per Python-Skript die letzte Zeile aus der csv-Datei aus und kopiere sie in die index.html meines Apache Webservers.

Leider benötigt das Skript root-Rechte, bzw. mehr Rechte als mein normaler User. Ein manuelles Ausführen mit sudo klappt ohne Probleme.

Dass das Skript root-Rechte braucht und der cronjob in der crontab des root-User liegt, stört mich. Habt ihr Ideen, wie man das eleganter lösen kann? Eventuell ohne root-Rechte?

Mein Skript:

Code: Alles auswählen

#!/usr/bin/env python3
import shutil
import os

with open("/home/tim/Adafruit_Python_DHT/examples/log.csv", "r") as f:
        for line in f:
                pass
last_line = line

data = [
"<html>\n"
"\t<head>\n"
"\t\t<title>Pi_Data</title>\n"
"\t</head>\n"
"\t<body>\n"
f"\t\t<h1>{last_line}</h1>"
"\n\t</body>\n"
"</html>"
]

file = open("/var/www/data/index.html", "w")

for line in data:
    file.write(line + "\n")

file.close()

c = "sudo /etc/init.d/apache2 reload"
os.system(c)

Gruß
Tim
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ist das nicht ein längst gelöstes Problem mit Heimautomations-Software wie FEHM oder so? Inklusive guter Visualisierungen etc.

Wie dem auch sei. Eine naheliegende Antwort wäre eine Datenbank, zb MariaDB, Postgres oder für solche Daten gerne auch Influx. Die lösen diese Rechteprobleme dadurch, das die Clients Zugangsdaten haben.
Sirius3
User
Beiträge: 17767
Registriert: Sonntag 21. Oktober 2012, 17:20

Eingerückt wird in Python immer mit 4 Leerzeichen und nicht nach 4 und mal 8. Dateien werden immer mit dem with-Statement geöffnet. Warum tust Du das bei der zweiten Datei nicht?
`data` ist eine Liste mit einem einzigen String. Die Liste und die anschließende for-Schleife kannst Du dir also sparen.
shutil wird importiert aber nicht benutzt. os.system sollte man nicht benutzen. Es kommt mir auch komisch vor, den Webserver neu zu starten, nur weil man eine htlm-Datei ändert. Ich kenne mich mit apache nicht aus. Wenn das zwingend wäre, würde ich aber einen anderen Webserver suchen. Deshalb sollte es also nicht nötig sein, mit root zu arbeiten.
Benutzeravatar
grubenfox
User
Beiträge: 434
Registriert: Freitag 2. Dezember 2022, 15:49

sprunus-ng hat geschrieben: Samstag 20. April 2024, 22:21 Ich habe an meinem Pi einen DHT22 an die GPIO-Schnittstelle angeschlossen und erfasse alle 5 Minuten die Temperatur und die relative Luftfeuchtigkeit. Die Messergebnisse füge ich an eine csv-Datei an und das funktioniert alles wunderbar. Nun möchte ich gerne die aktuellsten Daten per Webbrowser einsehen können. Da mir nichts besseres eingefallen ist, lese ich per Python-Skript die letzte Zeile aus der csv-Datei aus und kopiere sie in die index.html meines Apache Webservers.
Also wenn da irgendetwas ist (wohl ein anderes Skript) das Daten an eine csv-Datei anhängen kann, dann sollte dieses andere Skript doch auch gleich die index.html-Datei mit erzeugen können. Ob nun Daten an eine (csv-)Datei anhängen oder eine andere Datei komplett neu schreiben, ist doch kein großer Unterschied.
Benutzeravatar
__blackjack__
User
Beiträge: 13133
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sprunus-ng: Anmerkungen zum Quelltext:

Namen sollte man nicht kryptisch abkürzen. Einbuchstabige Namen sind selten gute Namen. Ausnahmen sind `i`, `j`, und `k` für ganze Zahlen als Laufvariablen in Schleifen und wenn die für Indexzugriffe verwendet werden, und `x`, `y`, und `z` für Koordinaten. Aber wenn man `file` meint, sollte man nicht nur `f` schreiben, und statt `c` besser `command`.

Wobei man den Wert von `c` auch nicht extra an einen Namen binden muss. Genau wie `data`, denn das sollte keine Liste mit *einem* Element sein, sondern einfach eine Zeichenkette. Und die kann man dann auch direkt als Argument in den Methodenaufruf schreiben. Dann fällt auch auf, dass es einfacher ist das abschliessende Zeilenende-Zeichen mit in die Zeichenkette zu schreiben statt es nachträglich mit ``+`` anzuhängen.

Bei den Zeilen steht überall das "\n" am Ende, ausser bei einer, da steht es am Anfang der nächsten Zeile. Das übersieht man leicht.

Semantisch ist die Zeile einer CSV-Datei jetzt nicht wirklich eine Überschrift, sollte also auch nicht als solche gesetzt werden.

In HTML-Quelltext haben bestimmte Zeichen eine Bedeutung für die Auszeichnung, darum ist es besser wenn man sicherstellt, das die entsprechend maskiert werden in Daten die man da einfügt. Es gibt im `html`-Modul eine Funktion dafür.

Beim öffnen von Textdateien sollte man immer explizit die Kodierung der Datei angeben. Bei der CSV-Datei müsstest Du das selber wissen. Bei der HTML-Datei müsste man wissen ob der Webserver in den Headerdaten eine Kodierung vorgibt. Tut er das nicht, dann muss die Kodierung entsprechend in den Kopfdaten des HTML-Dokuments angegeben werden, oder es wird vom Browser CP1252 erwartet wenn da nichts steht.

Beim einlesen der CSV-Datei wurde ``with`` verwendet, beim schreiben der HTML-Datei aber nicht. Warum nicht?

Das Programm wird mit einer Ausnahme enden wenn die CSV-Datei leer ist. In dem Fall wird `line` nicht definiert, und die Zuweisung nach der Schleife funktioniert nicht.

`os.system()` sollte man nicht verwenden. Da steht in der Dokumentation auch ein Verweis auf das `subprocess`-Modul.

Zwischenstand (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import html
import subprocess


def main():
    with open(
        "/home/tim/Adafruit_Python_DHT/examples/log.csv", "r", encoding="ASCII"
    ) as lines:
        line = None
        for line in lines:
            pass

    html_fragment = (
        "<em>(Keine Messwerte in Logdatei vorhanden)</em>"
        if line is None
        else html.escape(line)
    )

    with open("/var/www/data/index.html", "w", encoding="CP1252") as file:
        file.write(
            "<html>\n"
            "\t<head>\n"
            "\t\t<title>Pi Data</title>\n"
            "\t</head>\n"
            "\t<body>\n"
            f"\t\t<p>{html_fragment}</p>\n"
            "\t</body>\n"
            "</html>\n"
        )

    subprocess.run(["sudo", "/etc/init.d/apache2", "reload"], check=True)


if __name__ == "__main__":
    main()
Jetzt könnte man dem Benutzer unter dem das läuft in ``/etc/sudoers`` das Recht geben nur genau diesen Neustart ausführen zu dürfen. Schon braucht's keine Root-Rechte mehr. Allerdings ist die Frage warum da überhaupt der Webserver neu gestartet wird. Das sollte normalerweise gar nicht nötig sein.

Was zumindest theoretisch noch ein Problem ist, ist die Behandlung der CSV-Datei als wenn eine Textzeile einem Datensatz entspricht. Das muss grundsätzlich nicht so sein, weil CSV ein bisschen komplexer ist und auch Zeilenenden innerhalb von Zellen erlaubt.
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
sprunus-ng
User
Beiträge: 7
Registriert: Samstag 20. April 2024, 21:14

__deets__ hat geschrieben: Sonntag 21. April 2024, 08:04 Ist das nicht ein längst gelöstes Problem mit Heimautomations-Software wie FEHM oder so? Inklusive guter Visualisierungen etc.

Wie dem auch sei. Eine naheliegende Antwort wäre eine Datenbank, zb MariaDB, Postgres oder für solche Daten gerne auch Influx. Die lösen diese Rechteprobleme dadurch, das die Clients Zugangsdaten haben.
Moin __deets__,

FHEM habe ich mir angeschaut, scheint für meine Zwecke aber ein wenig viel zu sein. Auf den ersten Blick wirkt es so, als sei die Konfiguration nicht ganz trivial. Und das alles nur für einen Pi? Den Hinweis mit der Datenbank verfolge ich gerade und versuche per Python die Dateien in die Datenbank zu schreiben. Wenn sie erstmal da sind, muss ich nur noch schauen, wie ich die auf der Webseite angezeigt bekomme.
Danke.
sprunus-ng
User
Beiträge: 7
Registriert: Samstag 20. April 2024, 21:14

Sirius3 hat geschrieben: Sonntag 21. April 2024, 09:28 Eingerückt wird in Python immer mit 4 Leerzeichen und nicht nach 4 und mal 8. Dateien werden immer mit dem with-Statement geöffnet. Warum tust Du das bei der zweiten Datei nicht?
`data` ist eine Liste mit einem einzigen String. Die Liste und die anschließende for-Schleife kannst Du dir also sparen.
shutil wird importiert aber nicht benutzt. os.system sollte man nicht benutzen. Es kommt mir auch komisch vor, den Webserver neu zu starten, nur weil man eine htlm-Datei ändert. Ich kenne mich mit apache nicht aus. Wenn das zwingend wäre, würde ich aber einen anderen Webserver suchen. Deshalb sollte es also nicht nötig sein, mit root zu arbeiten.
Moin Sirius3,

das mit den Leerzeichen wusste ich nicht, danke für den Hinweis. Das Skript habe in Notepad++ erstellt und mit Tabs gearbeitet. Auf dem Pi dann die Datei per nano geöffnet und alles stumpf reinkopiert. Die nächsten Skripte schreibe ich in Visual Studio Code, da ist ein Tab gleich 4 Leerzeichen.

Warum ich nicht mit einen with arbeite, ist ganz einfach erklärt: Ich finde Code-Schnipsel, die funktionieren und füge sie wie eine Art Collage zusammen. Was die einzelnen Funktionen tun, weiß ich gar nicht. Da hat auch die Schleife ihren Ursprung. Dass ich die nicht brauche, kann ich aber nachvollziehen.

shutil und os.system habe ich jetzt aus dem Skript entfernt, es waren noch Überbleibsel aus vorherigen Versuchen. Läuft auch ohne. Danke.
sprunus-ng
User
Beiträge: 7
Registriert: Samstag 20. April 2024, 21:14

grubenfox hat geschrieben: Sonntag 21. April 2024, 13:35
sprunus-ng hat geschrieben: Samstag 20. April 2024, 22:21 Ich habe an meinem Pi einen DHT22 an die GPIO-Schnittstelle angeschlossen und erfasse alle 5 Minuten die Temperatur und die relative Luftfeuchtigkeit. Die Messergebnisse füge ich an eine csv-Datei an und das funktioniert alles wunderbar. Nun möchte ich gerne die aktuellsten Daten per Webbrowser einsehen können. Da mir nichts besseres eingefallen ist, lese ich per Python-Skript die letzte Zeile aus der csv-Datei aus und kopiere sie in die index.html meines Apache Webservers.
Also wenn da irgendetwas ist (wohl ein anderes Skript) das Daten an eine csv-Datei anhängen kann, dann sollte dieses andere Skript doch auch gleich die index.html-Datei mit erzeugen können. Ob nun Daten an eine (csv-)Datei anhängen oder eine andere Datei komplett neu schreiben, ist doch kein großer Unterschied.
Moin grubenfox,

ich hatte ein weiteres Skript erstellt, damit ich in Ruhe rumprobieren kann, ohne das erste kaputt zu machen.

Das erste Skript sieht so aus. (Geht bestimmt auch besser, aber es tut was es soll.)

Code: Alles auswählen

#!/bin/bash

datum=`date +%F`
zeit=`date +%H:%M`
filler="00" # damit Excel daraus kein Datum macht

cd /home/tim/Adafruit_Python_DHT/examples
werte=$(./AdafruitDHT.py 22 2)
temp=$(echo $werte | cut -d "=" -f2 | cut -c1-4)
luft=$(echo $werte | cut -d "=" -f3 | cut -c1-4)

# Ausgabe semikolonsepariert in Datei
echo "$datum;$zeit;$temp$filler;$luft$filler" >> log.csv
Wichtig ist, dass die csv-Datei da ist. Das sind die Daten, die ich brauche und mir per SCP auf meinen Rechner kopiere. Die aktuellen Daten im Browser sind nur Spielerei. Ich werde daher die Skripte wahrscheinlich auch weiterhin nicht in einem konsolidieren.
sprunus-ng
User
Beiträge: 7
Registriert: Samstag 20. April 2024, 21:14

__blackjack__ hat geschrieben: Sonntag 21. April 2024, 14:43 @sprunus-ng: Anmerkungen zum Quelltext:

Namen sollte man nicht kryptisch abkürzen. Einbuchstabige Namen sind selten gute Namen. Ausnahmen sind `i`, `j`, und `k` für ganze Zahlen als Laufvariablen in Schleifen und wenn die für Indexzugriffe verwendet werden, und `x`, `y`, und `z` für Koordinaten. Aber wenn man `file` meint, sollte man nicht nur `f` schreiben, und statt `c` besser `command`.

Wobei man den Wert von `c` auch nicht extra an einen Namen binden muss. Genau wie `data`, denn das sollte keine Liste mit *einem* Element sein, sondern einfach eine Zeichenkette. Und die kann man dann auch direkt als Argument in den Methodenaufruf schreiben. Dann fällt auch auf, dass es einfacher ist das abschliessende Zeilenende-Zeichen mit in die Zeichenkette zu schreiben statt es nachträglich mit ``+`` anzuhängen.

Bei den Zeilen steht überall das "\n" am Ende, ausser bei einer, da steht es am Anfang der nächsten Zeile. Das übersieht man leicht.

Semantisch ist die Zeile einer CSV-Datei jetzt nicht wirklich eine Überschrift, sollte also auch nicht als solche gesetzt werden.

In HTML-Quelltext haben bestimmte Zeichen eine Bedeutung für die Auszeichnung, darum ist es besser wenn man sicherstellt, das die entsprechend maskiert werden in Daten die man da einfügt. Es gibt im `html`-Modul eine Funktion dafür.

Beim öffnen von Textdateien sollte man immer explizit die Kodierung der Datei angeben. Bei der CSV-Datei müsstest Du das selber wissen. Bei der HTML-Datei müsste man wissen ob der Webserver in den Headerdaten eine Kodierung vorgibt. Tut er das nicht, dann muss die Kodierung entsprechend in den Kopfdaten des HTML-Dokuments angegeben werden, oder es wird vom Browser CP1252 erwartet wenn da nichts steht.

Beim einlesen der CSV-Datei wurde ``with`` verwendet, beim schreiben der HTML-Datei aber nicht. Warum nicht?

Das Programm wird mit einer Ausnahme enden wenn die CSV-Datei leer ist. In dem Fall wird `line` nicht definiert, und die Zuweisung nach der Schleife funktioniert nicht.

`os.system()` sollte man nicht verwenden. Da steht in der Dokumentation auch ein Verweis auf das `subprocess`-Modul.

Jetzt könnte man dem Benutzer unter dem das läuft in ``/etc/sudoers`` das Recht geben nur genau diesen Neustart ausführen zu dürfen. Schon braucht's keine Root-Rechte mehr. Allerdings ist die Frage warum da überhaupt der Webserver neu gestartet wird. Das sollte normalerweise gar nicht nötig sein.

Was zumindest theoretisch noch ein Problem ist, ist die Behandlung der CSV-Datei als wenn eine Textzeile einem Datensatz entspricht. Das muss grundsätzlich nicht so sein, weil CSV ein bisschen komplexer ist und auch Zeilenenden innerhalb von Zellen erlaubt.
Moin __blackjack__,

vielen Dank für deine ausführliche Antwort und das angepasste Skript. In Kombinationen mit den anderen Antworten konnte ich mein Skript jetzt so anpassen, dass es ohne root-Rechte läuft und in die crontab meines normalen Users geschrieben werden kann.

Das Skript wird nochmal hinsichtlich Lesbarkeit überarbeitet und um Kommentare ergänzt.
Benutzeravatar
grubenfox
User
Beiträge: 434
Registriert: Freitag 2. Dezember 2022, 15:49

sprunus-ng hat geschrieben: Sonntag 21. April 2024, 15:45 Wichtig ist, dass die csv-Datei da ist. Das sind die Daten, die ich brauche und mir per SCP auf meinen Rechner kopiere. Die aktuellen Daten im Browser sind nur Spielerei. Ich werde daher die Skripte wahrscheinlich auch weiterhin nicht in einem konsolidieren.
ich habe jetzt lange nichts mehr mit der Bash gemach (und hier aktuell läuft die zsh mit der ich auch nichts mache), aber diese Zeile sollte es meiner Meinung nach tun.... (hinten dran hängen, nach der bisher letzten `echo`-Zeile)

Code: Alles auswählen

echo "<html><head><title>Pi Data</title></head><body><p>$datum;$zeit;$temp$filler;$luft$filler</p></body></html>" > /var/www/data/index.html
Ich habe das ganze HTML-Zeug in eine Zeile gesetzt weil ich zum einen jetzt nicht weiß wie das bei der Bash mit mehrzeiligen Ausgaben geht, aber zweitens weil es für die Darstellung im Browser völlig egal ist ob der HTML-Text nun in einer oder mehreren Zeilen steht. Nur bei der Darstellung vom HTML-Quelltext selbst ist es eigentlich hübscher und übersichtlicher wenn es mehrere Zeilen sind. Aber diese paar Tags sind jdoch auch einzeilig sehr übersichtlich...
Benutzeravatar
__blackjack__
User
Beiträge: 13133
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sprunus-ng: Mit dem ``AdafruitDHT.py`` sind das ja dann schon *drei* Skripte wo man eigentlich nur eines bräuchte.

Anmerkungen zum Shell-Skript:

Um die Ausgabe von Programmen als Zeichenkette zu bekommen verwendet man besser ``$(…)`` statt der veralteten „backticks“. ``$(…)`` ist Posix-Standard, lässt sich verschachteln, und viele Editoren heben die jeweils andere Klammer hervor wenn man mit dem Cursor über einer Klammer steht. In der Regel gibt es auch Tastenkürzel um zur jeweils anderen Klammer zu springen, oder alles zwischen den Klammern zu markieren.

Datum und Zeit sollte man nicht getrennt ermitteln, denn dazwischen vergeht ja Zeit, wodurch es dann passieren kann, dass man beispielsweise das Datum von einem Tag und die Uhrzeit vom nächsten ermittelt, und damit die Angaben fast 24 Stunden daneben liegen. Und man sollte die auch nicht in zwei Spalten speichern, denn das ist als Zeitpunkt *ein* Wert.

Den ``$filler`` würde ich mir sparen. Das ist ein Problem mit einem anderen Programm, welches man *dort* lösen sollte. Entweder öffnet man die Datei mit dem Dialog wo man einstellen kann was der Dezimalbruchtrenner sein soll, oder man erzeugt Daten mit einem Komma statt einem Punkt als Dezimalbruchtrenner.

``cd`` kann schiefgehen und dann arbeitet das Skript mit einem anderen Verzeichnis weiter und die Daten werden woanders in eine ``log.csv`` protokolliert. Man sollte ``cd``-Aufrufe deshalb immer absichern, beispielsweise mit einem Skriptabbruch wenn das nicht funktioniert hat:

Code: Alles auswählen

cd /home/tim/Adafruit_Python_DHT/examples || exit 1
Oder besser nicht mit ``cd`` arbeiten, sondern mit kompletten Pfaden.

Auch bei Shellskripten gilt: keine komischen Abkürzungen. Insbesondere `temp` ist Mehrdeutig, weil das traditionell sehr gerne für Zwischenergebnisse genommen wird bei denen man zu faul war sich einen passenden Namen auszudenken und deswegen „temporary“ abkürzt.

Die ``cut``-Befehle funktionieren nicht für alle Werte. Negative zweistellige Werte verlieren beispielsweise eine Ziffer nach dem Komma und bei einstelligen positiven Werten ist der "*" beziehungsweise das "%" mit im Ergebnis:

Code: Alles auswählen

$ werte='Temp=-10.3*  Humidity=9.8%'
$ echo "$werte" | cut -d "=" -f2 | cut -c1-4
-10.
$ echo "$werte" | cut -d "=" -f3 | cut -c1-4
9.8%
Man könnte sich da eine Shell-Funktion schreiben, die mittels ``sed`` den jeweiligen Wert aus der Ausgabe holt und den "." durch ein "," ersetzt.

Das Shell-Skript berücksichtigt nicht, dass ``AdafruitDHT.py`` auch eine Fehlermeldung ausgeben kann! Dann sollten keine Werte in die Datei geschrieben werden, die es ja auch gar nicht gibt in dem Fall.

Zwischenstand:

Code: Alles auswählen

#!/bin/bash

readonly BasePath=/home/tim/Adafruit_Python_DHT/examples

GetValue() {
    local line=$1
    local name=$2
    local end=$3
    echo "$line" | sed "s/.*$name=\([^$end]*\).*/\1/" | tr . ,
}

werte=$("$BasePath/AdafruitDHT.py" 22 2) || exit 1
zeitpunkt=$(date +'%F %H:%M')
temperature=$(GetValue "$werte" Temp '*')
luftfeuchtigkeit=$(GetValue "$werte" Humidity '%')

echo "$zeitpunkt;$temperature;$luftfeuchtigkeit" >> "$BasePath/log.csv"
Alles in einem Python-Programm (ungetestet):

Code: Alles auswählen

#!/usr/bin/env python3
import csv
import html
from datetime import datetime as DateTime

import Adafruit_DHT


def main():
    humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 2)
    timestamp_text = DateTime.now().strftime("%Y-%m-%d %H:%M")
    if humidity is not None and temperature is not None:
        with open(
            "/home/tim/Adafruit_Python_DHT/examples/log.csv",
            "a",
            newline="",
            encoding="ASCII",
        ) as csv_file:
            csv.writer(csv_file, delimiter=";").writerow(
                [f"{timestamp_text}", temperature, humidity]
            )

        html_fragment = html.escape(
            f"{timestamp_text} Temperatur: {temperature:.2f}°C,"
            f" Luftfeuchtigkeit {humidity:.2f}%"
        )
    else:
        html_fragment = f"<em>{timestamp_text}: Keine Messwerte vorhanden</em>"

    with open("/var/www/data/index.html", "w", encoding="CP1252") as file:
        file.write(
            "<html>\n"
            "\t<head>\n"
            "\t\t<title>Pi Data</title>\n"
            "\t</head>\n"
            "\t<body>\n"
            f"\t\t<p>{html_fragment}</p>\n"
            "\t</body>\n"
            "</html>\n"
        )


if __name__ == "__main__":
    main()
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
sprunus-ng
User
Beiträge: 7
Registriert: Samstag 20. April 2024, 21:14

@__blackjack__:
Vielen Dank für das Feedback. Einiges habe ich auch umgesetzt, so konnte ich auf die cut-Befehle verzichten. Die Skripte sehen im Moment so aus

Adafruit.py

Code: Alles auswählen

#!/usr/bin/python

import sys
import Adafruit_DHT
import locale

locale.setlocale(locale.LC_ALL, 'de_DE.utf8')

# Parse command line parameters.
sensor_args = { '11': Adafruit_DHT.DHT11,
                '22': Adafruit_DHT.DHT22,
                '2302': Adafruit_DHT.AM2302 }
if len(sys.argv) == 3 and sys.argv[1] in sensor_args:
    sensor = sensor_args[sys.argv[1]]
    pin = sys.argv[2]
else:
    print('Usage: sudo ./Adafruit_DHT.py [11|22|2302] <GPIO pin number>')
    print('Example: sudo ./Adafruit_DHT.py 2302 4 - Read from an AM2302 connected to GPIO pin #4')
    sys.exit(1)

# Try to grab a sensor reading.  Use the read_retry method which will retry up
# to 15 times to get a sensor reading (waiting 2 seconds between each retry).
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)

# Un-comment the line below to convert the temperature to Fahrenheit.
# temperature = temperature * 9/5.0 + 32

# Note that sometimes you won't get a reading and
# the results will be null (because Linux can't
# guarantee the timing of calls to read the sensor).
# If this happens try again!
if humidity is not None and temperature is not None:
    #print('Temp={0:0.1f}*  Humidity={1:0.1f}%'.format(temperature, humidity))
    print('{0:n};{1:n}'.format(temperature, humidity))
else:
    print('Failed to get reading. Try again!')
    sys.exit(1)
Ich habe die print-Ausgabe so angepasst, dass cut oder sed nicht mehr notwendig sind und Excel die Daten nicht sofort beim Öffnen verunstaltet.

auslesen.sh

Code: Alles auswählen

#!/bin/bash

#Aktuelles Datum mit Uhrzeit einer Variablen zuweisen
datum=$(date +%F)
zeit=$(date +%H:%M)

werte=$(/home/tim/Adafruit_Python_DHT/examples/Adafruit.py 22 2)
echo "$datum;$zeit;$werte" >> /home/tim/Adafruit_Python_DHT/examples/log.csv
Zeit und Datum halte ich weiterhin getrennt, da es so für mich in Excel einfacher ist. Um in PowerPivot eine Übersicht zu bekommen, welche Durchschnittswerte am Tag und in der Nacht anliegen, brauche ich lediglich die Zelle prüfen und muss mir keine Gedanken darüber machen, wo die Uhrzeit im String auftaucht.

Code: Alles auswählen

=WENN(B3="";"";(WENN(UND(B3>ZEIT(6;59;59);B3<ZEIT(21;59;59));"Tag";"Nacht")))
data2web.py

Code: Alles auswählen

#!/usr/bin/env python3

with open("/home/tim/Adafruit_Python_DHT/examples/log.csv", "r") as file1:
        for line in file1:
                pass
last_line = line
data = "<html>\n"+"\t<head>\n"+"\t\t<title>Pi_Data</title>\n"+"\t</head>\n"+"\t<body>\n"+f"\t\t{last_line}"+"\t</body>\n"+"</html>"

with open("/var/www/data/index.html", "w") as file2:
    file2.write(data)
file2.close()
Das hat mir sehr geholfen.
Benutzeravatar
__blackjack__
User
Beiträge: 13133
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@sprunus-ng: Jetzt macht das Shell-Skript ja noch weniger Sinn wenn Du das Python-Programm sowieso schon anpasst, könnte man dort auch die Ausgabe in die Datei gleich mit rein schreiben.

Das mit der Zeit ist IMHO keine Begründung. Also höchstens gegen Excel beziehungsweise gegen eine CSV-Datei wenn Excel da von Haus aus so schlecht mit umgehen kann. Die Zeit ist ja keine Zeichenkette sondern eine Zahl. Sollte sie in der Tabellenkalkulation jedenfalls sein. Und dann gibt es eine Funktion die aus dem Zeitpunkt die Uhrzeit extrahiert und man so Tag und Nacht unterscheiden/trennen kann.

Beim Programm das die Webseite erstellt ist immer noch das Problem das eine leere CSV-Datei zu einem Fehler führt.

Die vielen Teilzeichenketten mit ``+`` zusammenfügen statt da einfach *eine* Zeichenkette mit allen hin zu schreiben macht nicht wirklich Sinn.

Die Namen für die Datei sollten keine angehängten Nummern haben.

Das ``file2.close()`` ist überflüssig. Dafür ist ja der ``with``-Block da.

Die Zeiten in dem Excel-Ausdruck sind IMHO ein bisschen komisch. eine Minute vor 22 Uhr ist schon Nacht? Und eine halbe Sekunde vor 7 ist schon Tag? Sicher dass das nicht die jeweils volle Stunde und ``>=`` beziehungsweise ``<`` als Vergleich sein sollte?
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
sprunus-ng
User
Beiträge: 7
Registriert: Samstag 20. April 2024, 21:14

@__blackjack__: Was eine schwere Geburt. Shell-Skript und data2web.py sind jetzt weg. Das Adafruit.py kann ohne root-Rechte ausgeführt werden und die Daten werden leserlich auf dem Webserver angezeigt. D A N K E !
Die Abfrage in Excel habe ich dann auch gleich korrigiert. Auch das Festlegen von Tag oder Nacht funktioniert jetzt mit dem Datum und der Zeit in einer Zelle.

Ich habe deinen Vorschlag minimal angepasst und die Formatierung der Werte so geändert, dass nur zwei Nachkommastellen angezeigt werden und das Komma das Dezimaltrennzeichen ist.

Code: Alles auswählen

#!/usr/bin/env python3

import sys
import Adafruit_DHT
import locale
import csv
import html
from datetime import datetime as DateTime

def main():

    locale.setlocale(locale.LC_ALL, 'de_DE.utf8')
    timestamp = DateTime.now().strftime("%Y-%m-%d %H:%M")
    humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 2)

    if humidity is not None and temperature is not None:
        with open(
            "/home/tim/Adafruit_Python_DHT/examples/log.csv",
            "a",
            newline="",
            encoding="ASCII",
            ) as csv_file:
                csv.writer(csv_file, delimiter=";").writerow(
                  [timestamp, f"{temperature:n}", f"{humidity:n}"]
                )
                html_fragment = html.escape(
                f"{timestamp} Temperatur: {temperature:n}°C,"
                f" Luftfeuchtigkeit {humidity:n}%"
            )

    else:
        print('Failed to get reading. Try again!')
        html_fragment = f"<em>{timestamp}: Keine Messwerte vorhanden</em>"

    with open("/var/www/data/index.html", "w", encoding="CP1252") as file:
        file.write(
            "<html>\n"
            "\t<head>\n"
            "\t\t<title>Pi Data</title>\n"
            "\t</head>\n"
            "\t<body>\n"
            f"\t\t<p>{html_fragment}</p>\n"
            "\t</body>\n"
            "</html>\n"
        )
if __name__ == "__main__":
    main()
Danke für deine Mühe
Gruß Tim
Antworten