Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

Von Daten zu Diagrammen:Eine Webreise mit Flask und SQLite

Erfassen von Realdaten (RPi/DHT22), Speichern in einer Datenbank (SQLite), Erstellen von Grafiken (Matplotlib) und Präsentieren auf einer Webseite (Flask).

Einführung:Von den Daten zum Diagramm. eine Webreise mit Flask und SQLite

In meiner vorherigen Anleitung, Python WebServer mit Flask und Raspberry Pi, haben wir über eine mit Flask erstellte Web-Front-End-Seite gelernt, wie man mit der physischen Welt interagiert. Der nächste natürliche Schritt besteht also darin, Daten aus der realen Welt zu sammeln und sie uns auf einer Webseite zur Verfügung zu stellen. Sehr einfach! Aber was passiert, wenn wir wissen wollen, wie es zum Beispiel am Vortag war? Oder eine Art Analyse mit diesen Daten durchführen? In diesen Fällen müssen wir die Daten auch in einer Datenbank speichern lassen.

Kurz gesagt, in diesem neuen Tutorial werden wir:

Erfassen Sie echte Daten (Lufttemperatur und relative Luftfeuchtigkeit) mit einem DHT22-Sensor;Laden Sie diese Daten in einer lokalen Datenbank , erstellt mit SQLite;  Grafiken erstellen mit historischen Daten mit Matplotlib; Daten anzeigen mit animierten "Gages", erstellt mit JustGage; Stellen Sie alles online über einen lokalen Webserver bereit, der mit Python erstellt wurde und Flasche;

Das Blockschaltbild gibt uns eine Vorstellung vom gesamten Projekt:

Schritt 1:Stückliste – Stückliste

Schritt 2:SQLite installieren

OK, die allgemeine Idee besteht darin, Daten von einem Sensor zu sammeln und in einer Datenbank zu speichern.

Aber welche Datenbank-„Engine“ sollte verwendet werden?

Es gibt viele Optionen auf dem Markt und wahrscheinlich die beiden am häufigsten verwendeten mit Raspberry Pi und Sensoren sind MySQL und SQLite. MySQL ist sehr bekannt, aber etwas "schwer" für den Einsatz in einfachen Raspberry-basierten Projekten (außerdem ist es von Oracle!). SQLite ist wahrscheinlich die am besten geeignete Wahl. Weil es serverlos, leichtgewichtig, Open Source ist und den meisten SQL-Code unterstützt (seine Lizenz lautet „Public Domain“). Eine weitere praktische Sache ist, dass SQLite Daten in einer einzigen Datei speichert, die überall gespeichert werden kann.

Aber was ist SQLite?

SQLite ist ein relationales Datenbankverwaltungssystem, das in einer C-Programmierbibliothek enthalten ist. Im Gegensatz zu vielen anderen Datenbankverwaltungssystemen ist SQLite keine Client-Server-Datenbank-Engine. Vielmehr ist es in das Endprogramm eingebettet.

SQLite ist eine beliebte öffentliche Domäne Wahl als eingebettete Datenbanksoftware für die lokale/Client-Speicherung in Anwendungssoftware wie Webbrowsern. Es ist wohl die am weitesten verbreitete Datenbank-Engine, da sie heute unter anderem von mehreren weit verbreiteten Browsern, Betriebssystemen und eingebetteten Systemen (wie Mobiltelefonen) verwendet wird. SQLite hat Bindungen zu vielen Programmiersprachen wie Python, die in unserem Projekt verwendet wird.

(Mehr auf Wikipedia)

Wir werden hier nicht auf allzu viele Details eingehen, aber die vollständige SQLite-Dokumentation finden Sie unter diesem Link: https://www.sqlite.org/docs.html

So sei es! Lassen Sie uns SQLite auf unserem Pi installieren

Installation:

Befolgen Sie die folgenden Schritte, um eine Datenbank zu erstellen.

1. Installieren Sie SQLite auf Raspberry Pi mit dem Befehl:

sudo apt-get install sqlite3 

2. Erstellen Sie ein Verzeichnis, um das Projekt zu entwickeln:

mkdir Sensors_Database 

3. Wechseln Sie in dieses Verzeichnis:

cd mkdir Sensors_Database/ 

3. Geben Sie einen Namen ein und erstellen Sie eine Datenbank wie databaseName.db (in meinem Fall „sensorsData.db“):

sqlite3 sensorData.db 

Es erscheint eine „Shell“, in die Sie mit SQLite-Befehlen eingeben können. Wir werden später darauf zurückkommen.

sqlite> 

Befehle beginnen mit einem „.“, wie „.help“, „.quit“ usw.

4. Beenden Sie die Shell, um zum Terminal zurückzukehren:

sqlite> .quit 

Der obige Terminal-Druckbildschirm zeigt, was erklärt wurde.

Das obige „sqlite>“ dient nur zur Veranschaulichung, wie die SQLite-Shell aussehen wird. Sie müssen es nicht eingeben. Es wird automatisch angezeigt.

Schritt 3:Erstellen und Auffüllen einer Tabelle

Um die gemessenen Daten des DHT-Sensors in der Datenbank zu protokollieren, müssen wir eine Tabelle  . erstellen (eine Datenbank kann mehrere Tabellen enthalten). Unsere Tabelle heißt „DHT_data“ und hat 3 Spalten, in denen wir unsere gesammelten Daten protokollieren:Datum und Stunde (Spaltenname: Zeitstempel ), Temperatur (Spaltenname: temp ) und Feuchtigkeit (Spaltenname: hum ).

Tabelle erstellen:

Um eine Tabelle zu erstellen, können Sie dies tun:

1. Verwenden der Shell:

Öffnen Sie die im letzten Schritt erstellte Datenbank:

sqlite3 sensorData.db 

Und Eingabe mit SQL-Anweisungen:

sqlite> BEGIN;sqlite> CREATE TABLE DHT_data (Zeitstempel DATETIME, temp NUMERIC, hum NUMERIC);sqlite> COMMIT; 

Alle SQL-Anweisungen müssen mit „;“ enden. Außerdem werden diese Aussagen normalerweise in Großbuchstaben geschrieben. Es ist nicht obligatorisch, aber eine gute Praxis.

2. Python verwenden

sqlite3 importieren als liteimport syscon =lite.connect('sensorsData.db')with con:cur =con.cursor() cur.execute("DROP TABLE IF EXISTS DHT_data") cur.execute("CREATE TABLE DHT_data(timestamp DATETIME, temp NUMERIC, hum NUMERIC)") 

Öffnen Sie den obigen Code von meinem GitHub: createTableDHT.py

Führen Sie es auf Ihrem Terminal aus:

python3 createTableDHT.py 

Unabhängig von der verwendeten Methode sollte die Tabelle erstellt werden. Sie können dies in der SQLite-Shell mit dem Befehl „.table“ überprüfen. Öffnen Sie die Datenbank-Shell:

sqlite3>sensorenData.db 

Wenn Sie in der Shell die .table . verwenden, Befehl werden die Namen der erstellten Tabellen angezeigt (in unserem Fall nur einer:"DHT_table". Beenden Sie die Shell danach mit dem Befehl .quit  Befehl.

sqlite> .tableDHT_datasqlite> .quit 

Daten in eine Tabelle einfügen:

Lassen Sie uns in unsere Datenbank 3 Datensätze eingeben, wobei jeder Satz jeweils 3 Komponenten enthält:(Zeitstempel, Temperatur und Summen). Die Komponente Zeitstempel wird echt sein und aus dem System genommen, mit der eingebauten Funktion "jetzt" und temp und summen sind Dummy-Daten in oC bzw. %.

Hinweis dass die Zeit in "UTC" angegeben ist, was gut ist, da Sie sich nicht um Sommerzeit und andere Angelegenheiten kümmern müssen. Wenn Sie das Datum in lokalisierter Zeit ausgeben möchten, konvertieren Sie es einfach anschließend in die entsprechende Zeitzone.

Auf die gleiche Weise wie bei der Tabellenerstellung können Sie Daten manuell über die SQLite-Shell oder über Python einfügen. In der Shell würden Sie dies tun, Daten für Daten mit SQL-Anweisungen wie diesen (In unserem Beispiel werden Sie dies dreimal tun):

sqlite> INSERT INTO DHT_data VALUES(datetime('now'), 20.5, 30); 

Und in Python würden Sie dasselbe tun, aber sofort:

sqlite3 importieren als liteimport syscon =lite.connect('sensorsData.db')with con:cur =con.cursor() cur.execute("INSERT INTO DHT_data VALUES (datetime('now'), 20.5, 30)") cur.execute("INSERT INTO DHT_data VALUES(datetime('now'), 25.8, 40)") cur.execute("INSERT INTO DHT_data VALUES(datetime(' jetzt'), 30.3, 50)") 

Öffnen Sie den obigen Code von meinem GitHub: insertTableDHT.py

Führen Sie es auf dem Pi-Terminal aus:

python3 insertTableDHT.py 

Um zu bestätigen, dass der obige Code funktioniert, können Sie die Daten in der Tabelle über die Shell mit der SQL-Anweisung überprüfen:

sqlite> SELECT * FROM DHT_DATA; 

Der obige Terminal-Druckbildschirm zeigt, wie die Tabellenzeilen aussehen werden.

Schritt 4:Daten mit Python einfügen und überprüfen

Machen wir zunächst dasselbe wie zuvor (Daten eingeben und abrufen), aber sowohl mit Python als auch mit dem Drucken der Daten auf dem Terminal:

import sqlite3import sysconn=sqlite3.connect('sensorsData.db')curs=conn.cursor()# Funktion zum Einfügen von Daten in eine Tabledef add_data (temp, hum) :curs.execute("INSERT INTO DHT_data values(datetime('now'), (?), (?))", (temp, hum)) conn.commit()# Aufruf der Funktion zum Einfügen von dataadd_data (20.5, 30 )add_data (25.8, 40)add_data (30.3, 50)# drucke Datenbankinhaltprint ("\nGesamter Datenbankinhalt:\n")for row in curs.execute("SELECT * FROM DHT_data"):print (row)# close the Datenbank nach useconn.close() 

Öffnen Sie den obigen Code von meinem GitHub: insertDataTableDHT.pyund führen Sie ihn auf Ihrem Terminal aus:

python3 insertDataTableDHT.py 

Der obige Terminal-Druckbildschirm zeigt das Ergebnis.

Schritt 5:DHT22 Temperatur- und Feuchtigkeitssensor

Bisher haben wir in unserer Datenbank eine Tabelle erstellt, in der wir alle Daten speichern, die ein Sensor ausliest. Wir haben dort auch einige Dummy-Daten eingetragen. Jetzt ist es an der Zeit, echte Daten zu verwenden, die in unserer Tabelle, der Lufttemperatur und der relativen Luftfeuchtigkeit gespeichert werden. Dafür verwenden wir das alte und gute DHTxx (DHT11 oder DHT22). Die ADAFRUIT-Website bietet großartige Informationen zu diesen Sensoren. Unten, einige Informationen, die von dort abgerufen wurden:

Übersicht

Die kostengünstigen DHT-Temperatur- und Feuchtigkeitssensoren sind sehr einfach und langsam, eignen sich jedoch hervorragend für Bastler, die grundlegende Datenprotokollierung durchführen möchten. Die DHT-Sensoren bestehen aus zwei Teilen, einem kapazitiven Feuchtigkeitssensor und einem Thermistor. Es gibt auch einen sehr einfachen Chip, der eine Analog-Digital-Wandlung durchführt und ein digitales Signal mit Temperatur und Luftfeuchtigkeit ausspeist. Das digitale Signal kann mit jedem Mikrocontroller relativ einfach gelesen werden.

DHT11 vs. DHT22

Wir haben zwei Versionen des DHT-Sensors, sie sehen etwas ähnlich aus und haben die gleiche Pinbelegung, aber unterschiedliche Eigenschaften. Hier sind die Spezifikationen:

DHT11 (normalerweise blau)

Gut für 20-80 % Luftfeuchtigkeitsmessungen mit 5 % Genauigkeit Gut für 0-50 °C Temperaturmesswerte ±2 °C Genauigkeit Nicht mehr als 1 Hz Abtastrate (einmal pro Sekunde)

DHT22 (normalerweise weiß)

Gut für 0-100 % Feuchtigkeitsmesswerte mit 2-5% Genauigkeit Gut für -40 bis 125 °C Temperaturmesswerte ±0,5 °C Genauigkeit Nicht mehr als 0,5 Hz Abtastrate (einmal alle 2 Sekunden)

Wie Sie sehen, ist der DHT22 über einen etwas größeren Bereich etwas genauer und gut. Beide verwenden einen einzigen digitalen Pin und sind insofern „träge“, als Sie sie nicht mehr als einmal pro Sekunde (DHT11) oder zwei (DHT22) abfragen können.

Beide Sensoren funktionieren gut, um Indoor-Informationen zu erhalten, die in unserer Datenbank gespeichert werden.

Das DHTxx hat 4 Pins (zum Sensor gerichtet, Pin 1 ist ganz links):

Wir werden in unserem Projekt einen DHT22 verwenden.

Wenn Sie den Sensor normalerweise auf Entfernungen von weniger als 20 m verwenden, sollte ein 4K7-Ohm-Widerstand zwischen den Daten- und VCC-Pins geschaltet werden. Der DHT22-Ausgangsdaten-Pin wird mit Raspberry GPIO 16 verbunden.

Überprüfen Sie das obige elektrische Diagramm, das den Sensor wie folgt mit den RPi-Pins verbindet:

Vergessen Sie nicht, den 4K7-Ohm-Widerstand zwischen Vcc- und Data-Pins zu installieren. Sobald der Sensor angeschlossen ist, müssen wir auch seine Bibliothek auf unserem RPi installieren. Wir werden dies im nächsten Schritt tun.

Schritt 6:DHT-Bibliothek installieren

Gehen Sie auf Ihrem Raspberry, beginnend mit /home, zu /Dokumente:

CD-Dokumente  

Erstellen Sie ein Verzeichnis, um die Bibliothek zu installieren, und wechseln Sie dorthin:

mkdir DHT22_Sensorcd DHT22_Sensor 

Gehen Sie in Ihrem Browser zu Adafruit GITHub: https://github.com/adafruit/Adafruit_Python_DHT

Laden Sie die Bibliothek herunter, indem Sie rechts auf den Download-Zip-Link klicken und das Archiv auf Ihrem kürzlich erstellten Raspberry Pi-Ordner entpacken. Gehen Sie dann in das Verzeichnis der Bibliothek (Unterordner, der beim Entpacken der Datei automatisch erstellt wird) und führen Sie den Befehl aus:

sudo python3 setup.py install 

Öffne ein Testprogramm (DHT22_test.py) von meinem GITHUB:

import Adafruit_DHTDHT22Sensor =Adafruit_DHT.DHT22DHTpin =16humidity, temperature =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin)wenn Luftfeuchtigkeit nicht None und Temperatur nicht None ist:print('Temp={0:0.1f}*C Humidity={1:0.1f}%'.format(Temperature, Humidity))else:print('Fehler beim Lesen. Versuchen Sie es erneut!') 

Führen Sie das Programm mit dem Befehl aus:

python3 DHT22_test.py 

Der obige Terminal-Druckbildschirm zeigt das Ergebnis.

Schritt 7:Erfassen echter Daten

Nachdem wir sowohl den Sensor als auch unsere Datenbank installiert und konfiguriert haben, ist es an der Zeit, echte Daten zu lesen und zu speichern.

Dafür verwenden wir den Code:

import timeimport sqlite3import Adafruit_DHTdbname='sensorsData.db'sampleFreq =2 # Zeit in Sekunden# Daten von DHT abrufen sensordef getDHTdata():DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 hum, temp =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin) if hum is not None and temp is not None:hum =round(hum) temp =round(temp, 1) logData (temp, hum)# log sensor data on databasedef logData (temp, hum):conn=sqlite3.connect(dbname) curs=conn.cursor() curs.execute("INSERT INTO DHT_data values(datetime('now'), (?), (?))", (temp , hum)) conn.commit() conn.close()# Datenbank anzeigen datadef displayData():conn=sqlite3.connect(dbname) curs=conn.cursor() print ("\nGesamter Datenbankinhalt:\n") for row in curs.execute("SELECT * FROM DHT_data"):print (row) conn.close()# main functiondef main():für i im Bereich (0,3):getDHTdata() time.sleep(sampleFreq) displayData ()# Programm main() ausführen 

Öffnen Sie die obige Datei von meinem GitHub: appDHT.py und führen Sie sie auf Ihrem Terminal aus:

python3 appDHT.py 

Die Funktion getDHTdata() erfasst 3 Proben des DHT-Sensors, testet sie auf Fehler und wenn OK, speichern Sie die Daten in der Datenbank mit der Funktion logData (temp, hum) . Der letzte Teil des Codes ruft die Funktion displayData() . auf das den gesamten Inhalt unserer Tabelle auf dem Terminal ausgibt.

Der obige Druckbildschirm zeigt das Ergebnis. Beachten Sie, dass die letzten 3 Zeilen (Zeilen) die echten Daten sind, die mit diesem Programm erfasst wurden, und die drei vorherigen Zeilen die zuvor manuell eingegebenen waren.

Tatsächlich ist appDHT.py kein guter Name. Im Allgemeinen wird „appSomething.py“ mit Python-Skripten auf Webservern verwendet, wie wir weiter in diesem Tutorial sehen werden. Aber natürlich kannst du es hier verwenden.

Schritt 8:Daten automatisch erfassen

An dieser Stelle müssen wir einen Mechanismus zum automatischen Lesen und Einfügen von Daten in unsere Datenbank implementieren, unseren „Logger“.

Öffne ein neues Terminalfenster und geben Sie mit folgendem Python-Code ein:

import timeimport sqlite3import Adafruit_DHTdbname='sensorsData.db'sampleFreq =1*60 # Zeit in Sekunden ==> Probe alle 1 min# Daten von DHT abrufen sensordef getDHTdata() :DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 hum, temp =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin) wenn hum nicht None und temp ist nicht None:hum =round(hum) temp =round(temp, 1) return temp, hum # Sensordaten auf der Datenbank protokollierendef logData (temp, hum):conn=sqlite3.connect(dbname) curs=conn.cursor() curs.execute("INSERT INTO DHT_data values(datetime('now'), (?), ( ?))", (temp, hum)) conn.commit() conn.close()# main functiondef main():while True:temp, hum =getDHTdata() logData (temp, hum) time.sleep(sampleFreq) # ------------ Programm main() ausführen 

Oder holen Sie es von meinem GitHub: logDHT.py. Führen Sie es auf dem Terminal aus:

python3 logDHT.py 

Was die main() Funktion macht ist:

Rufen Sie die Funktion getDHTdata() auf , das die vom DHT22-Sensor erfassten Daten zurückgibt. Nehmen Sie diese Daten (Temperatur und Luftfeuchtigkeit) und übergeben Sie sie an eine andere Funktion: logData(temp, hum) die sie zusammen mit dem tatsächlichen Datum und der aktuellen Uhrzeit in unsere Tabelle einfügen.Und geht in den Ruhezustand und wartet bis zum nächsten geplanten Zeitpunkt, um Daten zu erfassen (definiert durch sampleFreq , was in diesem Beispiel 1 Minute dauert).

Lassen Sie das Terminalfenster geöffnet.

Bis Sie das Programm beispielsweise mit [Strg+z] beenden, erfasst das Programm kontinuierlich Daten und speist sie in unsere Datenbank ein. Ich habe es eine Weile mit einer Frequenz von 1 Minute laufen lassen, um die Datenbank schneller zu füllen, und die Frequenz nach einigen Stunden auf 10 Minuten geändert.

Es gibt andere Mechanismen, die viel effizienter sind, um diese Art von „automatischer Protokollierung“ durchzuführen, als die Verwendung von „time.sleep“, aber der obige Code wird für unseren Zweck hier gut funktionieren. Wie auch immer, wenn Sie einen besseren "Scheduler" implementieren möchten, können Sie Crontab . verwenden , ein praktisches UNIX-Tool zum Planen von Jobs. Eine gute Erklärung dafür, was Crontab ist, finden Sie in dieser Anleitung:"Aufgaben unter Linux mit Crontab planen", von Kevin van Zonneveld.

Schritt 9:Abfragen

Da unsere Datenbank jetzt automatisch gefüttert wird, sollten wir Wege finden, mit all diesen Daten zu arbeiten. Wir machen es mit Anfragen!

Was ist eine Abfrage?

Eine der wichtigsten Funktionen beim Arbeiten mit der SQL-Sprache über Datenbanken ist die Möglichkeit, „Datenbankabfragen“ zu erstellen. Mit anderen Worten, Abfragen extrahieren Daten aus einer Datenbank und formatieren sie in einer lesbaren Form. Eine Abfrage muss in SQL-Sprache . geschrieben sein , die ein SELECT . verwendet Anweisung, um bestimmte Daten auszuwählen.

Wir haben es tatsächlich im letzten Schritt auf "breitem Weg" verwendet:"SELECT * FROM DHT_data".

Beispiele:

Lassen Sie uns einige Abfragen über die Daten in der Tabelle erstellen, die wir bereits erstellt haben. Geben Sie dazu mit dem folgenden Code ein:

import sqlite3conn=sqlite3.connect('sensorsData.db')curs=conn.cursor()maxTemp =27.6print ("\nGesamter Datenbankinhalt:\n") for row in curs.execute("SELECT * FROM DHT_data"):print (row)print ("\nDatenbankeinträge für einen bestimmten Feuchtigkeitswert:\n")for row in curs.execute("SELECT * FROM DHT_data WHERE hum='29'"):print (Zeile) print ("\nDatenbankeinträge wo die Temperatur über 30oC liegt:\n")für Zeile in curs.execute("SELECT * FROM DHT_data WHERE temp>
30.0"):print (Zeile) print ("\nDatenbankeinträge wo die Temperatur über x:\n liegt")for row in curs.execute("SELECT * FROM DHT_data WHERE temp>
(?)", (maxTemp,)):print (row)  

Oder holen Sie es von meinem GitHub: queryTableDHT.py und führen Sie es auf dem Terminal aus:

python3 queryTableDHT.py 

Sie können das Ergebnis oben auf dem Druckbildschirm des Terminals sehen. Dies sind einfache Beispiele, um Ihnen eine Vorstellung von Abfragen zu geben. Nehmen Sie sich Zeit, um die SQL-Anweisungen im obigen Code zu verstehen.

Wenn Sie mehr über die SQL-Sprache erfahren möchten, ist das W3School SQL-Tutorial eine gute Quelle.

Schritt 10:Zuletzt in eine Tabelle eingegebene Daten:

Eine sehr wichtige Abfrage ist die Abfrage der zuletzt eingegebenen Daten (oder protokolliert) auf einem Tisch. Wir können dies direkt in der SQLite-Shell tun, mit dem Befehl:

sqlite> SELECT * FROM DHT_data ORDER BY Zeitstempel DESC LIMIT 1; 

Oder führen Sie einen einfachen Python-Code wie folgt aus:

import sqlite3conn =sqlite3.connect('sensorsData.db')curs=conn.cursor()print ("\nLetzte Daten, die in der Datenbank protokolliert wurden:\n")für row in curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):print (row) 

Sie können das Ergebnis oben auf dem ersten Terminal-Druckbildschirm sehen.

Beachten Sie, dass das Ergebnis als „Tupel von Werten“ angezeigt wird:(„timestamp“, temp, hum).

Das Tupel hat den Inhalt der letzten Zeile unserer Tabelle zurückgegeben, die aus 3 Elementen besteht:

So können wir unseren Code besser bearbeiten, um „saubere“ Daten aus der Tabelle abzurufen, zum Beispiel:

import sqlite3conn=sqlite3.connect('sensorsData.db')curs=conn.cursor()print ("\nLetzte Rohdaten, die in der Datenbank protokolliert wurden:\n") for row in curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):print (str(row[0])+" ==> Temp ="+str(row[1])+" Hum ="+str(Reihe[2])) 

Öffnen Sie die Datei von meinem GitHub: lastLogDataTableDHT.py und führen Sie sie auf dem Terminal aus:

python3 lastLogDataTableDHT.py 

Sie können das Ergebnis oben auf dem 2. Terminal-Druckbildschirm sehen.

Schritt 11:Ein Web-Front-End für die Datenvisualisierung

In meinem letzten Tutorial: Python WebServer mit Flask und Raspberry Pi haben wir gelernt, wie man einen Webserver (mit Flask) implementiert, um Daten von Sensoren zu erfassen und ihren Status auf einer Webseite anzuzeigen.

Das wollen wir auch hier erreichen. Der Unterschied liegt in den an unser Frontend zu sendenden Daten, die aus einer Datenbank entnommen werden und nicht direkt von Sensoren, wie wir es in diesem Tutorial getan haben.

Erstellen einer Webserverumgebung:

Als erstes installieren Sie Flask auf Ihrem Raspberry Pi. Wenn Sie es nicht haben, gehen Sie zum Terminal und geben Sie ein:

sudo apt-get install python3-flask 

Wenn Sie ein neues Projekt starten, erstellen Sie am besten einen Ordner, in dem Ihre Dateien organisiert werden. Zum Beispiel:

Gehen Sie von zu Hause aus in unser Arbeitsverzeichnis:

CD Documents/Sensors_Database 

Erstellen Sie einen neuen Ordner, zum Beispiel:

mkdir dhtWebServer 

Der obige Befehl erstellt einen Ordner namens „dhtWebServer“, in dem wir unsere Python-Skripte speichern:

/home/pi/Documents/Sensor_Database/rpiWebServer 

In diesem Ordner erstellen wir nun 2 Unterordner: statisch für CSS- und eventuell JavaScript-Dateien und Vorlagen  für HTML-Dateien. Gehen Sie zu Ihrem neu erstellten Ordner:

cd dhtWebServer 

Und erstelle die 2 neuen Unterordner:

mkdir statisch 

und

mkdir-Vorlagen 

Das endgültige Verzeichnis „Baum“ sieht wie folgt aus:

├── Sensors_Database sensorData.db ├── logDHT.py ├── dhtWebSensor ├── Vorlagen └── statisch 

Wir belassen unsere erstellte Datenbank im Verzeichnis /Sensor_Database, daher müssen Sie SQLite mit „../sensorsData.db“ verbinden.

OK! Nachdem wir unsere Umgebung eingerichtet haben, bauen wir die Teile zusammen und erstellen unsere Python WebServer-Anwendung . Das obige Diagramm gibt uns eine Vorstellung davon, was zu tun ist!

Schritt 12:Die Python WebServer-Anwendung

Beginnen wir mit dem letzten Diagramm, erstellen wir einen Python-Webserver mit Flask. Ich schlage Geany als zu verwendende IDE vor,  Sobald Sie gleichzeitig mit verschiedenen Dateitypen arbeiten können (.py, .html und .css).

Der folgende Code ist das Python-Skript, das auf unserem ersten Webserver verwendet werden soll:

from Flask import Flask, render_template, requestapp =Flask(__name__)import sqlite3# Daten aus der Datenbank abrufendef getData():conn=sqlite3.connect('../sensorsData .db') curs=conn.cursor() for row in curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):time =str(row[0]) temp =row[1] hum =row [2] conn.close() return time, temp, hum# main route @app.route("/")def index():time, temp, hum =getData() templateData ={ 'time':time, ' temp':temp, 'hum':hum } return render_template('index.html', **templateData)if __name__ =="__main__":app.run(host='0.0.0.0', port=80, debug=Falsch) 

Sie können das Python-Skript appDhtWebServer.py von meinem GitHub herunterladen. Was der obige Code macht ist:

Bei dieser Anfrage nimmt der Code als erstes Daten aus der Datenbank mit der Funktion time, temp, hum =getData(). Diese Funktion ist im Grunde dieselbe Abfrage, die zuvor verwendet wurde, um in der Tabelle gespeicherte Daten abzurufen. Mit den vorliegenden Daten kehrt unser Skript zur Webseite (index.html ): Zeittemp  und summen als Antwort auf die vorherige Anfrage.

Sehen wir uns also die index.html an und style.css Dateien, die zum Erstellen unseres Frontends verwendet werden:

index.html

  DHT-Sensordaten     

DHT-Sensordaten

TEMPERATUR ==> {{ tempLab }} oC

FEUCHTIGKEIT (Rel.) ==> { { humLab }} %


Letzter Messwert der Sensoren:{{ time }} ==> REFRESH


@2018 Entwickelt von MJRoBot.org

Sie können die Datei index.html von meinem GitHub abrufen.

style.css

body{ Hintergrund:blau; Farbe Gelb; padding:1%}.button { font:fett 15px Arial; Textdekoration:keine; Hintergrundfarbe:#EEEEEE; Farbe:#333333; Polsterung:2px 6px 2px 6px; Rahmen oben:1px solid #CCCCCC; Rahmen rechts:1px solid #333333; Rahmen unten:1px solid #333333; Rahmen-links:1px solid #CCCCCC;} 

Sie können die Datei style.css von meinem GitHub herunterladen. Die Dateien müssen wie folgt in Ihrem Verzeichnis abgelegt werden:

├── Sensors_Database sensorData.db logDHT.py ├── dhtWebSensor ├── appDhtWebSensor.py ├── templates │ ├── index .html └── statisch ├── style.css  

Führen Sie nun das Python-Skript auf dem Terminal aus:

sudo python3 appDhtWebServer.py 

Rufen Sie einen beliebigen Browser in Ihrem Netzwerk auf und geben Sie mit http://YOUR_RPI_IP . ein (zum Beispiel in meinem Fall: http://10.0.1.27)

Der obige Druckbildschirm zeigt, was Sie sehen müssen. HINWEIS:Wenn Sie sich bei Ihrer RPi-IP-Adresse nicht sicher sind, führen Sie auf Ihrem Terminal aus:

 ifconfig 

Im Abschnitt wlan0:finden Sie es. In meinem Fall:10.0.1.27

Schritt 13:Unser Web-Front-End-Fancier machen!

Lassen Sie uns einige Messgeräte vorstellen, um die tatsächlichen Temperatur- und Feuchtigkeitswerte besser darzustellen. Beachten Sie, dass sich unser Python-Skript nicht ändert, aber die Verwendung von JustGage für unsere HTML-/CSS-Dateien verbessert die Darstellung von Daten erheblich.

Was ist JustGage?

JustGage ist ein praktisches JavaScript-Plugin zum Generieren und Animieren schöner und sauberer Messgeräte. Es basiert auf der Raphaël-Bibliothek für Vektorzeichnungen, ist also völlig auflösungsunabhängig und selbstanpassend und funktioniert in fast jedem Browser.

Installation:

justgage-1.2.2.zip

 DHT-Datensensor    

DHT-Sensordaten


Letzter Messwert der Sensoren:{{ time }} ==> REFRESH


@2018 Entwickelt von MJRoBot.org

Laden Sie die Datei index_gage.html von meinem GitHub herunter und benennen Sie sie in index.html um (vergessen Sie nicht, die vorherige Datei mit einem anderen Namen umzubenennen, wenn Sie sie behalten möchten, z. B. index_txt.html).

Der endgültige Verzeichnisbaum sollte wie folgt aussehen:

├── Sensors_Database sensorData.db logDHT.py dhtWebServer appDhtWebServer.py ├── templates │ ├── index .html └── statisch ├── style.css ├── justgage.js ├── raphael-2.1.4.min.js 

Drücken Sie [Crl-C] auf Ihrem Terminal, um appDhtWebServer.py zu beenden und einfach neu zu starten. Wenn Sie Ihren Browser aktualisieren, müssen Sie den obigen Druckbildschirm sehen.

Sehen Sie sich die Beispieldateien an, die Sie von der JustGage-Website heruntergeladen haben. Versuchen Sie, Änderungen an Ihren Messgeräten vorzunehmen. Es ist ganz einfach.

Schritt 14:Der vollständige Prozess

Das obige Diagramm fasst zusammen, was wir bisher erreicht haben:2 separate Skripte, die parallel laufen und ihre Aufgaben unabhängig erledigen:

Daten mit Sensor erfassen und in eine Datenbank laden (logDHT.py )Suchen Sie nach Daten in der Datenbank und präsentieren Sie sie auf einem Web-Frontend (appDhtWebServer.py ).

Im Allgemeinen ist unser Projekt, Daten zu erfassen, in einer Datenbank zu speichern und diese Daten auf einer Webseite anzuzeigen, abgeschlossen. Aber es macht keinen Sinn, eine Datenbank mit historischen Daten zu haben und sie nur für die zuletzt erfassten Daten zu verwenden. Wir müssen mit historischen Daten spielen und das Einfachste ist, sie in einem Diagramm darzustellen. Los geht's!

Schritt 15:Grafische Darstellung der historischen Daten

Eine sehr gute Bibliothek zum Zeichnen von Daten ist Matplotlib that is a Python 2D plotting library which produces publication quality figures in a variety of hardcopy formats and interactive environments across platforms.

To install matplotlib , run the command below on your Terminal:

sudo apt-get install python3-matplotlib 

Before we start, let’s create a new environment, where we will save the new application to be developed: appDhtWebHist.py  and its correspondent index.html  and style.css

├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebHist ├── appDhtWebHist.py ├── templates │ ├── index.html └── static ├── style.css  

Create the new 3 directories (dhtWebHist; /templates  and /static ) same as we did before and open from my GitHub the 3 files below:

1. appDhtWebHist.py

from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvasfrom matplotlib.figure import Figureimport iofrom flask import Flask, render_template, send_file, make_response, requestapp =Flask(__name__)import sqlite3conn=sqlite3.connect('../sensorsData.db')curs=conn.cursor()# Retrieve LAST data from databasedef getLastData():for row in curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):time =str(row[0]) temp =row[1] hum =row[2] #conn.close() return time, temp, humdef getHistData (numSamples):curs.execute("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT "+str(numSamples)) data =curs.fetchall() dates =[] temps =[] hums =[] for row in reversed(data):dates.append(row[0]) temps.append(row[1]) hums.append(row[2]) return dates, temps, humsdef maxRowsTable():for row in curs.execute("select COUNT(temp) from DHT_data"):maxNumberRows=row[0] return maxNumberRows# define and initialize global variablesglobal numSamplesnumSamples =maxRowsTable() if (numSamples> 101):numSamples =100# main [email protected]("/")def index():time, temp, hum =getLastData() templateData ={ 'time' :time, 'temp' :temp, 'hum' :hum, 'numSamples' :numSamples } return render_template('index.html', **templateData)@app.route('/', methods=['POST'])def my_form_post():global numSamples numSamples =int (request.form['numSamples']) numMaxSamples =maxRowsTable() if (numSamples> numMaxSamples):numSamples =(numMaxSamples-1) time, temp, hum =getLastData() templateData ={ 'time' :time, 'temp' :temp, 'hum' :hum, 'numSamples' :numSamples } return render_template('index.html', **templateData)@app.route('/plot/temp')def plot_temp():times, temps, hums =getHistData(numSamples) ys =temps fig =Figure() axis =fig.add_subplot(1, 1, 1) axis.set_title("Temperature [°C]") axis.set_xlabel("Samples") axis.grid(True) xs =range(numSamples) axis.plot(xs, ys) canvas =FigureCanvas(fig) output =io.BytesIO() canvas.print_png(output) response =make_response(output.getvalue()) response.mimetype ='image/png' return [email protected]('/plot/hum')def plot_hum():times, temps, hums =getHistData(numSamples) ys =hums fig =Figure() axis =fig.add_subplot(1, 1, 1) axis.set_title("Humidity [%]") axis.set_xlabel("Samples") axis.grid(True) xs =range(numSamples) axis.plot(xs, ys) canvas =FigureCanvas(fig) output =io.BytesIO() canvas.print_png(output) response =make_response(output.getvalue()) response.mimetype ='image/png' return responseif __name__ =="__main__":app.run(host='0.0.0.0', port=80, debug=False) 

A new function was created here: getHistData (numSamples) , that receives as a parameter the number of rows that should be taken from the database. Basically, it is very similar to getLastData(), where numSamples  was “1”. Of course, now we must “append” the return array for all required rows.

In fact, we could use only this last function for both tasks.

The number of samples is set by default as 100, at the beginning (if there are more them 100 rows into the database) and also received it as an input from the webpage, during normal operation. When we receive the number of samples to be retrieved, we must also check if it is lower than the maximum number of rows in the database (otherwise we will get an error). The function maxRowsTable() , returns this number.

With the historical data in hand: times, temps  and hums  that are arrays, we must build the graphs saving them as a .png ímage . Those images will be the return for the routes:

@app.route(‘/plot/temp’)  and @app.route(‘/plot/hum’).

The request for the images is done by index.html, by the IMG TAG.

2. index.html

  DHT Sensor data     

DHT Sensor Data

TEMPERATURE ==> {{ temp }} oC

HUMIDITY (Rel.) ==> {{ hum }} %


Last Sensors Reading:{{ time }} ==> REFRESH


HISTORICAL DATA

Enter number of samples to retrieve:


Image Placeholder Image Placeholder

@2018 Developed by MJRoBot.org

3. style.css

body{ background:blue; color:yellow; padding:1%}.button { font:bold 15px Arial; text-decoration:none; background-color:#EEEEEE; color:#333333; padding:2px 6px 2px 6px; border-top:1px solid #CCCCCC; border-right:1px solid #333333; border-bottom:1px solid #333333; border-left:1px solid #CCCCCC;}img{ display:display:inline-block} 

The above print screen shows the result.

Step 16:Including Gage on History Webpage

If instead of text, you want also to include gages to display the actual data, you must have the 2 .js files that you have used before on /static and change the index.html file on /templates:

Below how the directory tree looks like:

├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebHist ├── appDhtWebHist.py ├── templates │ ├── index.html └── static ├── style.css ├── justgage.js ├── raphael-2.1.4.min.js 

From my GitHub, open index_gage.html and rename it index.html. Replace the actual index.html (text version) and voilá! You will get a beautiful webpage, showing as gages the last captured data of temperature and humidity by the DHT22 and the historical graphs of those data.

Press[Crl-C] on your Terminal to Quit appDhtWebServer.py and just start it again. When you refresh your browser you must see the above print screen.

Step 17:Retrieving Data by Time Instead of Samples

So far we have build our graphics based on historical data, sending as a input parameter the numbers of samples to be retrieved from our database. Alternatively we could use as a parameter the number of past minutes that we want to show on a graph.

In order to do that, the first thing to know is the frequency of logged data on our database. Remember that this task is done for an independent program (in our case, logDHT.py ). One simple way to finfd this frequency is to retrieve the last 2 data logged on database and subtracting their correspondent timeStamp data:

in general terms: frequency =timeStamp(1) – timeStamp(0)

The function below does the work for us, using “datetime.striptime()”:

# Get sample frequency in minutesdef freqSample():times, temps, hums =getHistData (2) fmt ='%Y-%m-%d %H:%M:%S' tstamp0 =datetime.strptime(times[0], fmt) tstamp1 =datetime.strptime(times[1], fmt) freq =tstamp1-tstamp0 freq =int(round(freq.total_seconds()/60)) return (freq) 

Once we we have this frequency parameter in minutes, we will show it on index.html and asking for a “rangeTime” number of minutes to be send back to our server ==> @app.route(‘/’, methods=[‘POST’]):

@app.route('/', methods=['POST'])def my_form_post():global numSamples global freqSamples global rangeTime rangeTime =int (request.form['rangeTime']) if (rangeTime  numMaxSamples):numSamples =(numMaxSamples-1) 

The picture shows the result:

Eliminating Possible errors when constructing the graphs:

Ocasionally, strange (or corrupted) data can be storaged on database, jeopardizing our analysis. Those data can be verified (or cleaneed) on several places (like during the time sensor are capturing the data, etc). But once the script that display data is independent of the one that logged the data, let’s “cap” the maximum and minimum values of our sensors, before using the data to buit the graphs. This can be achieved with the function testData(temps, hums) :

# Test data for cleanning possible "out of range" valuesdef testeData(temps, hums):n =len(temps) for i in range(0, n-1):if (temps[i] <-10 or temps[i]>50):temps[i] =temps[i-2] if (hums[i] <0 or hums[i]>100):hums[i] =temps[i-2] return temps, hums 

The scripts for this new version can be download from my GitHub: dhtWebHist_v2

Step 18:Conclusion

As always, I hope this project can help others find their way into the exciting world of electronics!

For details and final code, please visit my GitHub depository: RPI-Flask-SQLite

For more projects, please visit my blog: MJRoBot.org

Saludos from the south of the world!

See you at my next tutorial!

Thank you,

Source:From Data to Graph:A Web Journey With Flask and SQLite


Herstellungsprozess

  1. Sensible Daten mit Secret Manager speichern und verwalten
  2. Mikrochip:24-Bit- und 16-Bit-ADCs mit Datenraten bis zu 153,6 kSPS
  3. Heim-(Raum-)Temperatur- und Feuchtigkeitsmonitor mit webbasiertem Diagramm – Raspberry Pi
  4. Roboter bauen mit Raspberry Pi und Python
  5. Beschleunigung der digitalen Transformation mit IoT-Daten dank Cisco und IBM
  6. Nutzung von IoT-Daten vom Edge in die Cloud und zurück
  7. Der Weg des IIoT beginnt mit der Remote-Telemetrie
  8. Wie Sie IOT mit Tech Data und IBM Teil 2 verwirklichen können
  9. Wie Sie das IoT mit Tech Data und IBM Teil 1 verwirklichen
  10. Erzielung von Geschäftsergebnissen mit Big-Data-Projekten und KI