Industriële fabricage
Industrieel internet der dingen | Industriële materialen | Onderhoud en reparatie van apparatuur | Industriële programmering |
home  MfgRobots >> Industriële fabricage >  >> Manufacturing Technology >> Productieproces

Van data naar grafiek:een webreis met Flask en SQLite

Real data vastleggen (RPi/DHT22), opslaan in een database (SQLite), grafieken maken (Matplotlib) en presenteren op een webpagina (Flask).

Inleiding:van gegevens naar grafiek. een Web Jorney Met Flask en SQLite

In mijn vorige tutorial, Python WebServer With Flask en Raspberry Pi, leerden we hoe we met de fysieke wereld kunnen communiceren via een web-front-endpagina, gebouwd met Flask. De volgende natuurlijke stap is dus om gegevens uit de echte wereld te verzamelen en deze voor ons beschikbaar te hebben op een webpagina. Erg makkelijk! Maar wat gebeurt er als we willen weten hoe het bijvoorbeeld de dag ervoor was? Of een soort analyse maken met die gegevens? In die gevallen moeten we de gegevens ook in een database laten opslaan.

Kortom, in deze nieuwe tutorial zullen we:

Leg echte gegevens vast (luchttemperatuur en relatieve vochtigheid) met een DHT22-sensor; Laad die gegevens in een lokale database , gebouwd met SQLite; Maak afbeeldingen met historische gegevens met behulp van Matplotlib; Gegevens weergeven met geanimeerde "gages", gemaakt met JustGage; Maak alles online beschikbaar via een lokale webserver die is gemaakt met Python en Flask;

Het blokschema geeft ons een idee van het hele project:

Stap 1:Stuklijst – Stuklijst

  • Raspberry Pi V3 - US$ 32,00
  • DHT22 temperatuur- en relatieve vochtigheidssensor - USD 9,95
  • Weerstand 4K7 ohm

Stap 2:SQLite installeren

OK, het algemene idee is om gegevens van een sensor te verzamelen en op te slaan in een database.

Maar welke database "engine" moet worden gebruikt?

Er zijn veel opties op de markt en waarschijnlijk de 2 meest gebruikte met Raspberry Pi en sensoren zijn MySQL en SQLite. MySQL is zeer bekend, maar een beetje "zwaar" voor gebruik op eenvoudige Raspberry-gebaseerde projecten (bovendien is het eigendom van Oracle!). SQLite is waarschijnlijk de meest geschikte keuze. Omdat het serverloos, lichtgewicht, opensource is en de meeste SQL-code ondersteunt (de licentie is "Public Domain"). Een ander handig ding is dat SQLite gegevens opslaat in een enkel bestand dat overal kan worden opgeslagen.

Maar wat is SQLite?

SQLite is een relationeel databasebeheersysteem in een C-programmeerbibliotheek. In tegenstelling tot veel andere databasebeheersystemen is SQLite geen client-server database-engine. Het is eerder ingebed in het eindprogramma.

SQLite is een populair publiek domein keuze als embedded databasesoftware voor lokale/clientopslag in applicatiesoftware zoals webbrowsers. Het is misschien wel de meest gebruikte database-engine, omdat het tegenwoordig wordt gebruikt door verschillende wijdverbreide browsers, besturingssystemen en embedded systemen (zoals mobiele telefoons). SQLite heeft bindingen met veel programmeertalen zoals Python, degene die in ons project wordt gebruikt.

(Meer op Wikipedia)

We zullen hier niet te veel details geven, maar de volledige SQLite-documentatie is te vinden via deze link: https://www.sqlite.org/docs.html

Zo zal het zijn! Laten we SQLite op onze Pi installeren

Installatie:

Volg de onderstaande stappen om een ​​database aan te maken.

1. Installeer SQLite op Raspberry Pi met het commando:

sudo apt-get install sqlite3 

2. Maak een map om het project te ontwikkelen:

mkdir Sensors_Database 

3. Ga naar deze map:

cd mkdir Sensors_Database/ 

3. Geef een naam en maak een database zoals databaseName.db (in mijn geval “sensorsData.db”):

sqlite3 sensorsData.db 

Er verschijnt een "shell" waar u kunt invoeren met SQLite-commando's. We komen er later op terug.

sqlite> 

Commando's beginnen met een ".", zoals ".help", ".quit", enz.

4. Sluit de shell om terug te keren naar de Terminal:

sqlite> .quit 

Het bovenstaande Terminal-afdrukscherm laat zien wat er is uitgelegd.

De "sqlite>" hierboven is alleen bedoeld om te illustreren hoe de SQLite-shell eruit zal zien. U hoeft het niet te typen. Het zal automatisch verschijnen.

Stap 3:een tabel maken en vullen

Om de gemeten gegevens van de DHT-sensor in de database te loggen, moeten we een tabel  . maken (een database kan meerdere tabellen bevatten). Onze tabel krijgt de naam "DHT_data" en heeft drie kolommen, waarin we onze verzamelde gegevens zullen loggen:Datum en uur (kolomnaam: timestamp ), Temperatuur (kolomnaam: temp ), en Vochtigheid (kolomnaam: hum ).

Een tabel maken:

Om een ​​tabel te maken, kunt u het volgende doen:

  • Direct op de SQLite-shell, of
  • Een Python-programma gebruiken.

1. Shell gebruiken:

Open de database die in de laatste stap is aangemaakt:

sqlite3 sensorsData.db 

En invoeren met SQL-statements:

sqlite> BEGIN;sqlite> MAAK TABEL DHT_data (tijdstempel DATETIME, temp NUMERIC, brom NUMERIC);sqlite> COMMIT; 

Alle SQL-instructies moeten eindigen op ";". Ook worden die uitspraken meestal met hoofdletters geschreven. Het is niet verplicht, maar wel een goede gewoonte.

2. Python gebruiken

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

Open de bovenstaande code van mijn GitHub: createTableDHT.py

Voer het uit op uw Terminal:

python3 createTableDHT.py 

Waar de methode ook wordt gebruikt, de tabel moet worden gemaakt. U kunt het verifiëren op SQLite Shell met behulp van de opdracht ".table". Open de database-shell:

sqlite3> sensorsData.db 

In de shell, zodra u de .table . gebruikt commando, zullen de gemaakte tabelnamen verschijnen (in ons geval zal dit er maar één zijn:"DHT_table". Sluit de shell daarna af met de .quit  commando.

sqlite> .tableDHT_datasqlite> .quit 

Gegevens invoegen in een tabel:

Laten we in onze database 3 datasets invoeren, waarbij elke set elk 3 componenten heeft:(tijdstempel, temp en brom). De component tijdstempel zal echt zijn en uit het systeem worden gehaald, met behulp van de ingebouwde functie 'nu' en temp en hum zijn dummy-gegevens in respectievelijk oC en %.

Opmerking dat de tijd in "UTC" staat, wat goed is omdat u zich geen zorgen hoeft te maken over problemen met betrekking tot zomertijd en andere zaken. Als u de datum in gelokaliseerde tijd wilt weergeven, converteert u deze daarna gewoon naar de juiste tijdzone.

Dezelfde manier werd gedaan met het maken van tabellen, u kunt gegevens handmatig invoegen via SQLite-shell of via Python. In de shell zou je het doen, data voor data met behulp van SQL-statements zoals deze (in ons voorbeeld doe je het 3 keer):

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

En in Python zou je hetzelfde doen, maar tegelijk:

import sqlite3 as 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(' nu'), 30.3, 50)") 

Open de bovenstaande code van mijn GitHub: insertTableDHT.py

Voer het uit op Pi Terminal:

python3 insertTableDHT.py 

Om te bevestigen dat de bovenstaande code werkte, kunt u de gegevens in de tabel controleren via shell, met de SQL-instructie:

sqlite> SELECTEER * VAN DHT_DATA; 

Het bovenstaande Terminal-afdrukscherm laat zien hoe de rijen van de tabel eruit zullen zien.

Stap 4:Gegevens invoegen en verifiëren met Python

Laten we om te beginnen hetzelfde doen als voorheen (gegevens invoeren en ophalen), maar beide doen met python en ook de gegevens afdrukken op terminal:

import sqlite3import sysconn=sqlite3.connect('sensorsData.db')curs=conn.cursor()# functie om gegevens in te voegen op een tabledef add_data (temp, hum) :curs.execute("INSERT INTO DHT_data values(datetime('now'), (?), (?))", (temp, hum)) conn.commit()# roep de functie aan om dataadd_data in te voegen (20.5, 30 )add_data (25.8, 40)add_data (30.3, 50)# print database contentprint ("\nGehele database-inhoud:\n")voor rij in curs.execute("SELECT * FROM DHT_data"):print (rij)# sluit de database na useconn.close() 

Open de bovenstaande code van mijn GitHub: insertDataTableDHT.pyen voer het uit op uw Terminal:

python3 insertDataTableDHT.py 

Het bovenstaande Terminal-afdrukscherm toont het resultaat.

Stap 5:DHT22 temperatuur- en vochtigheidssensor

Tot nu toe hebben we een tabel in onze database gemaakt, waarin we alle gegevens opslaan die een sensor zal lezen. We hebben daar ook enkele dummy-gegevens ingevoerd. Nu is het tijd om echte gegevens te gebruiken die moeten worden opgeslagen in onze tabel, luchttemperatuur en relatieve vochtigheid. Daarvoor gebruiken we de oude en goede DHTxx (DHT11 of DHT22). De ADAFRUIT-site biedt geweldige informatie over die sensoren. Bellow, wat informatie daar vandaan gehaald:

Overzicht

De goedkope DHT-temperatuur- en vochtigheidssensoren zijn erg eenvoudig en traag, maar zijn geweldig voor hobbyisten die wat basisgegevens willen loggen. De DHT-sensoren bestaan ​​uit twee delen, een capacitieve vochtigheidssensor en een thermistor. Er zit ook een heel eenvoudige chip in die wat analoog naar digitaal omzet en een digitaal signaal uitspuugt met de temperatuur en vochtigheid. Het digitale signaal is vrij gemakkelijk te lezen met elke microcontroller.

DHT11 versus DHT22

We hebben twee versies van de DHT-sensor, ze lijken een beetje op elkaar en hebben dezelfde pinout, maar hebben verschillende kenmerken. Dit zijn de specificaties:

DHT11 (meestal blauw)

Goed voor 20-80% vochtigheidsmetingen met 5% nauwkeurigheid Goed voor 0-50°C temperatuurmetingen ±2°C nauwkeurigheid Niet meer dan 1 Hz bemonsteringsfrequentie (eenmaal per seconde)

  • Ultra lage kosten
  • 3 tot 5V voeding en I/O
  • 2,5mA max stroomverbruik tijdens conversie (tijdens het opvragen van gegevens)
  • Lichaamsgrootte 15,5 mm x 12 mm x 5,5 mm
  • 4 pinnen met een tussenruimte van 0,1″

DHT22 (meestal wit)

Goed voor 0-100% vochtigheidsmetingen met 2-5% nauwkeurigheid Goed voor -40 tot 125 °C temperatuurmetingen ±0,5 °C nauwkeurigheid Niet meer dan 0,5 Hz bemonsteringsfrequentie (eenmaal per 2 seconden)

  • Lage kosten
  • 3 tot 5V voeding en I/O
  • 2,5mA max stroomverbruik tijdens conversie (tijdens het opvragen van gegevens)
  • Lichaamsgrootte 15,1 mm x 25 mm x 7,7 mm
  • 4 pinnen met een tussenruimte van 0,1″

Zoals je kunt zien, is de DHT22 iets nauwkeuriger en goed over een iets groter bereik. Beide gebruiken een enkele digitale pin en zijn 'traag' omdat je ze niet vaker dan eens per seconde (DHT11) of twee (DHT22) kunt opvragen.

Beide sensoren werken prima om binnen-informatie op te slaan in onze database.

De DHTxx heeft 4 pinnen (naar de sensor gericht, pin 1 is de meest linkse):

  • VCC (we kunnen verbinding maken met externe 5V of 3,3V van RPi);
  • Gegevens uit;
  • Niet verbonden
  • Grond.

We zullen een DHT22 gebruiken in ons project.

Als u de sensor gewoonlijk gebruikt op afstanden van minder dan 20 m, moet een weerstand van 4K7 ohm worden aangesloten tussen de data- en VCC-pinnen. De DHT22-uitgangsgegevenspin wordt verbonden met Raspberry GPIO 16.

Controleer het bovenstaande elektrische schema om de sensor op de RPi-pinnen aan te sluiten, zoals hieronder:

  • Pin 1 – Vcc ==> 3.3V
  • Pin 2 – Gegevens ==> GPIO 16
  • Pin 3 – Niet verbinden
  • Pin 4 – Gnd ==> Gnd

Vergeet niet om de 4K7 ohm-weerstand tussen Vcc- en datapinnen te installeren. Nadat de sensor is aangesloten, moeten we ook de bibliotheek op onze RPi installeren. We zullen dit in de volgende stap doen.

Stap 6:DHT-bibliotheek installeren

Ga op je Raspberry, beginnend op /home, naar /Documenten:

cd-documenten  

Maak een map om de bibliotheek te installeren en ga daarheen:

mkdir DHT22_Sensorcd DHT22_Sensor 

Ga in je browser naar Adafruit GITHub: https://github.com/adafruit/Adafruit_Python_DHT

Download de bibliotheek door op de download-zip-link aan de rechterkant te klikken en pak het archief uit in de recent gemaakte map van uw Raspberry Pi. Ga dan naar de directory van de bibliotheek (submap die automatisch wordt aangemaakt als je het bestand uitpakt), en voer het commando uit:

sudo python3 setup.py install 

Open een testprogramma (DHT22_test.py) vanuit mijn GITHUB:

import Adafruit_DHTDHT22Sensor =Adafruit_DHT.DHT22DHTpin =16vochtigheid, temperatuur =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin)als de vochtigheid niet Geen is en de temperatuur niet Geen:print('Temp={0:0.1f}*C Vochtigheid={1:0.1f}%'.format(temperatuur, vochtigheid))else:print('Kan niet lezen. Probeer het opnieuw!') 

Voer het programma uit met het commando:

python3 DHT22_test.py 

Het bovenstaande Terminal-afdrukscherm toont het resultaat.

Stap 7:echte gegevens vastleggen

Nu we beide hebben, de sensor en onze database allemaal geïnstalleerd en geconfigureerd, is het tijd om echte gegevens te lezen en op te slaan.

Daarvoor gebruiken we de code:

import timeimport sqlite3import Adafruit_DHTdbname='sensorsData.db'sampleFreq =2 # time in seconds# get data from DHT sensordef getDHTdata():DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 hum, temp =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin) als brom niet Geen is en temp niet Geen:hum =round(hum) temp =round(temp, 1) logData (temp, hum)# log sensorgegevens op databasedef logData (temp, brom):conn=sqlite3.connect(dbname) curs=conn.cursor() curs.execute("INSERT INTO DHT_data values(datetime('now'), (?), (?))", (temp , brom)) conn.commit() conn.close()# database datadef displayData():conn=sqlite3.connect(dbname) curs=conn.cursor() print ("\nGehele database-inhoud:\n") voor rij in curs.execute ("SELECT * FROM DHT_data"):print (row) conn.close()# main functiondef main():for i binnen bereik (0,3):getDHTdata() time.sleep(sampleFreq) displayData ()# Voer programma main() uit 

Open het bovenstaande bestand vanaf mijn GitHub:appDHT.pyen voer het uit op uw Terminal:

python3 appDHT.py 

De functie getDHTdata() legt 3 monsters van de DHT-sensor vast, test ze op fouten en slaat, indien OK, de gegevens op in de database met de functie logData (temp, hum) . Het laatste deel van de code roept de functie aan displayData() die de volledige inhoud van onze tabel op Terminal afdrukt.

Bovenstaand printscreen toont het resultaat. Merk op dat de laatste 3 regels (rijen) de echte gegevens zijn die met dit programma zijn vastgelegd en dat de 3 vorige rijen degene waren die eerder handmatig werden ingevoerd.

In feite is appDHT.py geen goede naam. Over het algemeen wordt "appSomething.py" gebruikt met Python-scripts op webservers, zoals we verderop in deze tutorial zullen zien. Maar je kunt het natuurlijk hier gebruiken.

Stap 8:gegevens automatisch vastleggen

Wat we op dit moment moeten implementeren, is een mechanisme om automatisch gegevens in onze database te lezen en in te voegen, onze "Logger".

Open een nieuw Terminal-venster en voer in met de onderstaande Python-code:

import timeimport sqlite3import Adafruit_DHTdbname='sensorsData.db'sampleFreq =1*60 # time in seconds ==> Sample elke 1 min# haal data van DHT sensordef getDHTdata() :DHT22Sensor =Adafruit_DHT.DHT22 DHTpin =16 brom, temp =Adafruit_DHT.read_retry(DHT22Sensor, DHTpin) als brom niet Geen is en temp niet Geen:zoem =rond (brom) temp =rond (temp, 1) retourtemperatuur, zoem # log sensorgegevens op 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()# main functiondef main():while True:temp, hum =getDHTdata() logData (temp, hum) time.sleep(sampleFreq) # ------------ Programma main() uitvoeren 

Of haal het van mijn GitHub: logDHT.py. Voer het uit op de Terminal:

python3 logDHT.py 

Wat de functie main() doet is:

Roep de functie aan getDHTdata() , die de vastgelegde gegevens door de DHT22-sensor retourneert. Neem die gegevens (temperatuur en vochtigheid) en geef ze door aan een andere functie: logData(temp, hum) die ze samen met de werkelijke datum en tijd in onze tabel invoegen. En gaat slapen, wachtend tot de volgende geplande tijd om gegevens vast te leggen (gedefinieerd door sampleFreq , wat in dit voorbeeld 1 minuut is).

Laat het Terminal-venster geopend.

Totdat u het programma afsluit met bijvoorbeeld [Ctr+z], zal het programma continu gegevens vastleggen en deze in onze database invoeren. Ik liet het een tijdje draaien op een frequentie van 1 minuut om de database sneller te vullen en de frequentie na een paar uur te veranderen in 10 minuten.

Er zijn andere mechanismen die veel efficiënter zijn om dit soort "automatische logger" uit te voeren dan het gebruik van "time.sleep", maar de bovenstaande code zal hier prima werken voor ons doel. Hoe dan ook, als u een betere 'planner' wilt implementeren, kunt u Crontab gebruiken , wat een handig UNIX-hulpmiddel is om taken te plannen. Een goede uitleg van wat Crontab is, is te vinden in deze tutorial:“Schedule Tasks on Linux Using Crontab”, door Kevin van Zonneveld.

Stap 9:Query's

Nu onze database automatisch wordt gevoed, moeten we manieren vinden om met al die gegevens te werken. We doen het met vragen!

Wat is een zoekopdracht?

Een van de belangrijkste kenmerken van het werken met SQL-taal over databases is de mogelijkheid om "databasequery's" te maken. Met andere woorden, query's extraheren gegevens uit een database en formatteren ze in een leesbare vorm. Een zoekopdracht moet zijn geschreven in SQL-taal , die een SELECT . gebruikt statement om specifieke gegevens te selecteren.

We hebben het in feite op een "brede manier" gebruikt bij de laatste stap:"SELECT * FROM DHT_data".

Voorbeelden:

Laten we enkele query's maken over de gegevens in de tabel die we al hebben gemaakt. Voer daarvoor in met onderstaande code:

import sqlite3conn=sqlite3.connect('sensorsData.db')curs=conn.cursor()maxTemp =27.6print ("\nGehele database-inhoud:\n") for row in curs.execute("SELECT * FROM DHT_data"):print (row)print ("\nDatabase-items voor een specifieke vochtigheidswaarde:\n")for row in curs.execute("SELECT * FROM DHT_data WHERE hum='29'"):print (rij) print ("\nDatabase-items waar de temperatuur hoger is dan 30oC:\n")voor rij in curs.execute("SELECT * FROM DHT_data WHERE temp>
30.0"):print (rij) print ("\nDatabase-items waar de temperatuur hoger is dan x:\n")voor rij in curs.execute("SELECT * FROM DHT_data WHERE temp>
(?)", (maxTemp,)):print (rij)  

Of haal het van mijn GitHub: queryTableDHT.py, en voer het uit op Terminal:

python3 queryTableDHT.py 

U kunt het resultaat zien op het printscherm van de Terminal hierboven. Dit zijn eenvoudige voorbeelden om u een idee te geven van vragen. Neem de tijd om de SQL-instructies in bovenstaande code te begrijpen.

Als je meer wilt weten over SQL-taal, is een goede bron de W3School SQL Tutorial.

Stap 10:Laatst ingevoerde gegevens op een tabel:

Een zeer belangrijke vraag is die om de laatst ingevoerde gegevens op te halen (of ingelogd) op een tafel. We kunnen het rechtstreeks op de SQLite-shell doen, met het commando:

sqlite> SELECTEER * UIT DHT_data BESTELLEN OP tijdstempel DESC LIMIT 1; 

Of het uitvoeren van een eenvoudige python-code zoals hieronder:

import sqlite3conn =sqlite3.connect('sensorsData.db')curs=conn.cursor()print ("\nLaatste gegevens ingelogd op database:\n")voor rij in curs.execute ("SELECT * FROM DHT_data ORDER BY timestamp DESC LIMIT 1"):print (rij) 

U kunt het resultaat zien op het eerste Terminal-afdrukscherm hierboven.

Merk op dat het resultaat zal verschijnen als een "tupel van waarden":('timestamp', temp, hum).

De tuple retourneerde de laatste rij-inhoud van onze tabel, die is gevormd met 3 elementen erop:

  • rij[0] =tijdstempel [tekenreeks]
  • rij[1] =tijdelijk [zweven]
  • rij[2] =brom [float]

We kunnen onze code dus beter gebruiken om 'schone' gegevens uit de tabel op te halen, bijvoorbeeld:

import sqlite3conn=sqlite3.connect('sensorsData.db')curs=conn.cursor()print ("\nLaatste onbewerkte gegevens ingelogd op database:\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(rij[2])) 

Open het bestand van mijn GitHub:lastLogDataTableDHT.py en voer het uit op Terminal:

python3 lastLogDataTableDHT.py 

U kunt het resultaat zien op het printscherm van de 2e terminal hierboven.

Stap 11:een webfront-end voor gegevensvisualisatie

In mijn laatste tutorial:Python WebServer Met Flask en Raspberry Pi hebben we geleerd hoe we een webserver (met Flask) kunnen implementeren om gegevens van sensoren vast te leggen en hun status op een webpagina weer te geven.

Dat willen we hier ook bereiken. Het verschil zit in de gegevens die naar onze front-end moeten worden verzonden, die uit een database worden gehaald en niet rechtstreeks van sensoren zoals we deden in die tutorial.

Een webserveromgeving maken:

Het eerste dat u moet doen, is Flask op uw Raspberry Pi installeren. Als je het niet hebt, ga dan naar de Terminal en voer het volgende in:

sudo apt-get install python3-flask 

Wanneer u een nieuw project start, kunt u het beste een map maken waarin u uw bestanden kunt ordenen. Bijvoorbeeld:

Ga vanuit huis naar onze werkmap:

cd Documents/Sensors_Database 

Maak een nieuwe map aan, bijvoorbeeld:

mkdir dhtWebServer 

De bovenstaande opdracht zal een map maken met de naam "dhtWebServer", waar we onze python-scripts zullen opslaan:

/home/pi/Documents/Sensor_Database/rpiWebServer 

Laten we nu in deze map 2 submappen maken: statisch voor CSS- en eventueel JavaScript-bestanden en sjablonen  voor HTML-bestanden. Ga naar je nieuwere aangemaakte map:

cd dhtWebServer 

En maak de 2 nieuwe submappen aan:

mkdir statisch 

en

mkdir-sjablonen 

De uiteindelijke map "boom" ziet er als volgt uit:

├── Sensors_Database ├── sensorsData.db ├── logDHT.py ├── dhtWebSensor ├── sjablonen └── statisch 

We laten onze aangemaakte database in de /Sensor_Database directory staan, dus u zult SQLite moeten verbinden met “../sensorsData.db”.

OKE! Laten we met onze omgeving de onderdelen in elkaar zetten en onze Python WebServer Application maken . Het bovenstaande diagram geeft ons een idee van wat er moet gebeuren!

Stap 12:De Python WebServer-toepassing

Laten we, uitgaande van het laatste diagram, een python-webserver maken met Flask. Ik stel voor Geany als de te gebruiken IDE,  zodra u gelijktijdig met verschillende soorten bestanden kunt werken (.py, .html en .css).

De onderstaande code is het python-script dat op onze eerste webserver moet worden gebruikt:

from flask import Flask, render_template, requestapp =Flask(__name__)import sqlite3# Haal gegevens op uit databasedef getData():conn=sqlite3.connect('../sensorsData .db') curs=conn.cursor() voor rij 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# hoofdroute @app.route("/")def index():time, temp, hum =getData() templateData ={ 'time':time, ' temp':temp, 'hum':} return render_template('index.html', **templateData)if __name__ =="__main__":app.run(host='0.0.0.0', port=80, debug=Onwaar) 

U kunt het python-script appDhtWebServer.py ophalen van mijn GitHub. Wat de bovenstaande code doet is:

Met dit verzoek is het eerste dat in de code wordt gedaan om gegevens uit de database te halen met behulp van de functie time, temp, hum =getData(). Deze functie is in feite dezelfde query die eerder werd gebruikt om gegevens op te halen die in de tabel zijn opgeslagen. Met de gegevens bij de hand, keert ons script terug naar de webpagina (index.html ): tijdtemp  en hum als antwoord op het vorige verzoek.

  • Elke keer dat iemand "klikt"'op "/", dat is de hoofdpagina (index.html) van onze webpagina, wordt een GET-verzoek gegenereerd;

Laten we dus eens kijken naar de index.html en style.css bestanden die zullen worden gebruikt om onze front-end te bouwen:

index.html

  DHT-sensorgegevens     

DHT-sensorgegevens

TEMPERATUUR ==> {{ tempLab }} oC

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


Laatste sensorwaarde:{{ time }} ==> REFRESH


@2018 Ontwikkeld door MJRoBot.org

Je kunt het bestand index.html ophalen van mijn GitHub.

style.css

body{ background:blue; kleur geel; opvulling:1%}.button { lettertype:vet 15px Arial; tekstdecoratie:geen; achtergrondkleur:#EEEEEE; kleur:#333333; opvulling:2px 6px 2px 6px; border-top:1px solide #CCCCCC; grens-rechts:1px solide #333333; border-bottom:1px effen #333333; border-left:1px solide #CCCCCC;} 

Je kunt het bestand style.css van mijn GitHub halen. De bestanden moeten als volgt in uw directory worden geplaatst:

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

Voer nu het python-script uit op de Terminal:

sudo python3 appDhtWebServer.py 

Ga naar een willekeurige browser in uw netwerk en voer in met http://YOUR_RPI_IP (bijvoorbeeld in mijn geval: http://10.0.1.27)

Op bovenstaande printscreen ziet u wat u moet zien. OPMERKING:Als u niet zeker bent van uw RPi Ip-adres, voer dan uit op uw terminal:

 ifconfig 

Bij wlan0:sectie vind je het. In mijn geval:10.0.1.27

Stap 13:onze web front-end liefhebber maken!

Laten we enkele meters introduceren om de werkelijke temperatuur- en vochtigheidswaarden op een betere manier weer te geven. Houd er rekening mee dat ons Python-script niet zal veranderen, maar het gebruik van JustGage op onze html/css-bestanden zal de manier waarop gegevens worden gepresenteerd aanzienlijk verbeteren.

Wat is JustGage?

JustGage is een handige JavaScript-plug-in voor het genereren en animeren van mooie en schone meters. Het is gebaseerd op de Raphaël-bibliotheek voor vectortekenen, dus het is volledig resolutie-onafhankelijk en zelfaanpassend, en werkt in bijna elke browser.

Installatie:

  • Download JustGage v1.2.2 + voorbeelden van de JustGage-website ==> http://justgage.com/download/justgage-1.2.2.zip
  • Sla de 2 .js-bestanden op in de /static/ directory
  • Gebruik de nieuwe index.html hieronder:

justgage-1.2.2.zip

 DHT-gegevenssensor    

DHT-sensorgegevens


Laatste sensorwaarde:{{ time }} ==> REFRESH


@2018 Ontwikkeld door MJRoBot.org

Download van mijn GitHub het bestand: index_gage.html, en hernoem het als index.html (vergeet niet het vorige te hernoemen met een andere naam als je het wilt behouden, bijvoorbeeld index_txt.html).

De uiteindelijke directorystructuur zou er als volgt uit moeten zien:

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

Druk op [Crl-C] op uw terminal om appDhtWebServer.py af te sluiten en het gewoon opnieuw te starten. Wanneer u uw browser ververst, moet u het bovenstaande afdrukscherm zien.

Kijk naar de voorbeeldbestanden die u van de JustGage-website hebt gedownload. Probeer wijzigingen aan te brengen in uw meters. Het is heel eenvoudig.

Stap 14:Het volledige proces

Het bovenstaande diagram geeft weer wat we tot nu toe hebben bereikt:2 afzonderlijke scripts die parallel lopen en hun taken onafhankelijk uitvoeren:

Gegevens vastleggen met sensor en in een database laden (logDHT.py )Zoek naar gegevens in de database en presenteer ze op een webfront-end (appDhtWebServer.py ).

In het algemeen is ons project van het vastleggen van gegevens, het opslaan ervan in een database en het weergeven van die gegevens op een webpagina voltooid. Maar het heeft geen zin om een ​​database met historische gegevens te hebben en deze alleen te gebruiken voor de laatst vastgelegde gegevens. We moeten spelen met historische gegevens en het meest elementaire dat we moeten doen, is ze in een grafiek presenteren. Laten we ervoor gaan!

Step 15:Graphing the Historical Data

A very good library to graph data is 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


Productieproces

  1. Bewaar en beheer gevoelige gegevens met Secret Manager
  2. Microchip:24-bit en 16-bit ADC's met datasnelheden tot 153,6 kSPS
  3. Thuis (kamer) temperatuur- en vochtigheidsmonitor met webgebaseerde grafiek - Raspberry Pi
  4. Botten bouwen met Raspberry Pi en Python
  5. Digitale transformatie versnellen met IoT-gegevens, dankzij Cisco en IBM
  6. IoT-gegevens benutten van de edge naar de cloud en terug
  7. Het IIoT-traject begint met telemetrie op afstand
  8. Hoe IOT echt te maken met Tech Data en IBM Part 2
  9. Hoe maak je IoT echt met Tech Data en IBM Part 1
  10. Zakelijke resultaten behalen met big data-projecten en AI
  11. Realtime behoeften oplossen terwijl bedrijfsleiders vooroplopen met ML en AI