In de verschillende projecten heb ik gemerkt dat het belangrijk is om te meten en te monitoren. Als hij dan stuk gaat of iets onverwachts optreed kan je je met data achter halen wat er verkeerd is gegaan en daar op in spelen. Het is daarbij niet alleen belangrijk om te meten maar ook deze meetresultaten op te slaan en daarbij te presenteren.
In het verleden hebben wij (als team) wel eens log-files gehad van een systeem dat binnen 40 minuten meer dan 60 Mb aan data had verzameld, in de vorm van een txt file. Hiermee konden we dus ook de locatie aanwijzen (via gps) waar het verkeerd ging met ons systeem. Mijn idee is daarom ook maak een meet systeem met daarbij een verwerkingssysteem er achter. Het verwerkingssysteem is niet alleen voor het opslaan van de data maar ook om de data te presenteren, het liefst live. Een txt file van 60 Mb is leuk maar als een live grafiek of kaart voor je getekend wordt kan je sneller conclusies trekken.
Ik wil een systeem maken waar ik gemakkelijk, wat voor data dan ook, kan opslaan en presenteren. Met de data bedoel ik dan ook Heel Veel Data, een paar gigabyte zou mogelijk moeten zijn. Dat zou ook een beetje snel moeten kunnen. Het systeem moet geschikt zijn om 24×7 data van sensoren uit te lezen en op te slaan en dan ook energie zuinig(de sensoren dan). He dit klink als The-Internet-of-things, dat is het ook. Ik wil het ontwikkelen als bouwblok of Tool, zodat ik het ook in andere projecten kan gebruiken of aansluiten. Zodat ik bijvoorbeeld mijn MPPT de logs opslaat en overal waar ik ben uit kan lezen. Maar begin vooral simpel en bouw het dan uit. Hou het daarbij goedkoop hierdoor kan de hoeveelheid sensoren makkelijk toenemen.
Onderzoek
Als je onderzoek gaat doen naar The-Internet-of-Things, kom je al snel op de Raspberry Pi uit, die dan sensoren uit leest en dan op standaard systemen opslaat. Ik ben zelf een grote fan van de raspberry pi, maar ik vind dit een overkill. Een keer per seconden de temperatuur meten en dan op thingspeak wegschrijven, de Rasperry Pi kan een complete programmeer omgeving draaien. Dit kan beter en zuiniger, dat betekent niet dat ik de Raspberry Pi buiten beschouwing hou. Ik zie hem dan meer als server kant, hij kan de data opslaan en een website hosten. Thingspeak is een leuk systeem maar limiteert snel het aantal punten, een eigen systeem wordt dat gelimiteerd door de schijfruimte.
Het meten van temperatuur is wel een goed begin, wat simpel is en nuttig. Het is wel leuk om te weten hoeveel het ’s nachts heeft gevroren. De Pi niet als sensor kant; wat dan wel, het is niet dat er een ethernet controller in de Atmega8A zit gebouwd. Je hebt wel externe ethernet controllers die je via SPI kan aansluiten, zo als de bekende ENC28J60. Dan mag ik door het hele huis kabels gaan trekken. Er is nu een enorme trend gaande met de ESP8266. Toen ik begon met onderzoek kwam ik ze tegen voor 5 euro. Toen dacht ik al dat is goedkoop voor een wifi module die je via uart kan aansloten. Ik had er toen gelijk een gekocht, ik had alleen nog geen tijd voor om er mee te werken. Nu zijn ze zelf goedkoper geworden, 2 euro 30.

Arduino-mini-pro
De gebrekkige informatie over de ESP8266 module of chip heb ik eerst een module besteld en daarbij een microcontroller die in een breadboard past. Standaard gebruik in de Atmega8A in SMD, deze past niet in een breadboard, dus is ging ik opzoek naar goedkope ontwikkel printjes en ben uiteindelijk uitgekomen op een met de Atmega328p. Of anders gezegd de Arduino-mini-pro. Dat betekent niet dat ik gelijk in Arduino moet programeren, het blijft gewoon een atmega dus kan gewoon in C blijven programmeren. Het belangrijkste om deze te kiezen is omdat hij pin compatible is, dat betekent dat ik een PCB voor de een kan ontwerpen en de andere er later toch op solderen. (bron: AVR094, weet het is de 88 maar dat is alleen het kleine flash versie van de 328)
Om wat te proberen had ik gelijk een paar verschillende temperatuur sensoren gekocht. De sensoren kunnen vaak naast temperature (temperatuur) ook humidity (luchtvochtigheid in RH) of Pressure (luchtdruk) meten.
- DHT11, Resolutie; 1°C , 1%RH, Communicatie; One-Wire*
- DTH22, Resolutie; 0.1°C , 0.1%RH, Communicatie One-Wire*
- DS18B20, Resolutie; 0.0625°C, Communicatie One-Wire**
- HTU21D***, Resolutie; 0.01°C , 0.1%RH, Communicatie I²c
- BMP180, Resolutie; 0.1°C , 0.01 hPa of 0.01 mbar, Communicatie I²c
* Maken gebruik van een eigen versie en kan dus niet zo als bij de originele one-wire in een lus worden aangesloten.
** Sensor is gekozen omdat hij in een lus aangesloten en deze waterdicht verkrijgbaar is.
*** lijkt compatibele met de SHT21, inc. het I²c adres.
Experimenteren
Temperatuur sensoren genoeg om mee te experimenteren. Liep gelijk al tegen een hobbel aan de ESP8266 heeft 3.3V min 250 mA nodig (dat vond ik ook al veel) en de DHT11 en DTH22 3.5 t/m 5 V dus die vielen al af voor het eindontwerp. Ik had geen zin om ook nog een 5 V voeding te bouwen.
Voor het schrijven van de microcontroller software is het lastig te debug-en zonder uart, de uart wordt namelijk gebruikt voor de ESP8266 module. Dus had ik een sw-uart bij gebouwd op basis van de application note van atmel, de AVR304. Deze werkt redelijk en was zeer nuttig bij het schrijven van de library voor de ESP8266 module.
Voor de server kant op de computer maak ik gebruik van Python (op ubuntu, linux), door middel van een simpel TCP socket kan ik de waardes om mijn computer opslaan. Over de socket wordt (zo als ik ander met uart ook doe) CSV of komma gescheiden waardes verstuurt. Simpel en zo min mogelijk overige informatie. Om deze data dan in een database op te slaan was simpel, door gebruik te maken van sqlite.
#!/usr/bin/python
import socket
import datetime
import time
import sqlite3
import sys
TCP_IP = "0.0.0.0"
TCP_PORT = 8080
try:
#connectie sqlite database
database = sqlite3.connect('test.db', check_same_thread=False)
d = database.cursor()
#timezone correctie
offset = datetime.datetime.now() - datetime.datetime.utcnow()
#starten van tcp/ip socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((TCP_IP, TCP_PORT))
sock.listen(1)
#wachten op een inkomende verbinding
conn, addr = sock.accept()
databaseName = "db" + str(datetime.datetime.now()).translate(None, " -,!.:;")
print 'Connection address:', addr, 'database', databaseName
d.execute("CREATE TABLE '%s'(ID INT PRIMARY KEY NOT NULL, var1 TEXT, var2 TEXT, var3 REAL, var4 REAL)" % databaseName)
id = 0
conn.setblocking(False)
conn.settimeout(10)
while True:
try:
data = ""
data = conn.recv(1024)
print str(datetime.datetime.now().time()), "@", addr, ":", data.rstrip('\r\n')
#Controlleer of het een voledige zin is, door de commas te tellen.
if data.count(',') == 2:
id=id+1
#uncomment deze line voor meer debug info
#print """INSERT INTO %s VALUES(%d,"%s",%s)""" % (databaseName, id, str(datetime.datetime.now()).translate(None, " ,!.:;"), data.rstrip('\r\n'))
d.execute("""INSERT INTO %s VALUES(%d,"%s",%s)""" % (databaseName, id, str(datetime.datetime.now()), data.rstrip('\r\n')))
except socket.error, socket.timeout:
#als er een probleem is met de verbinding of timeout wacht op nieuwe connectie
print 'Connection close:', addr
if conn:
conn.close()
conn, addr = sock.accept()
print 'Connection address:', addr
conn.setblocking(False)
conn.settimeout(10)
except sqlite3.OperationalError, sqlite3.IntegrityError:
#bij fouten in het schrijven in de database
print "database ERROR"
pass
except (KeyboardInterrupt, SystemExit):
print 'except exit'
conn.close()
sock.close()
database.commit()
finally:
print 'closing socket'
conn.close()
sock.close()
database.commit()
Iedere keer dat dit python script op start maakt hij een data base aan. De velden die hij aan maakt zijn:
- ID, nummer dan de data
- Var1, is de datum en tijd.
- Var2, Hex waarde van een andere status.
- Var3, Temperature in REAL
- Var4, Humidity in REAL
Sqlite heeft niet veel datatypes, ik was daarom genoodzaakt om text voor hex en REAL voor een FLOAT of DOUBLE te gebruiken. In het Filmpje hieronder is te zien de microcontroller de data verzend. De zwarte terminal is aangesloten op de TX van de ESP8266. De paarse (ubuntu) terminal is het draaien van het python script.
https://youtu.be/bhTNZVhVB0g
Dat werk en was niet zo moeilijk, alleen als je uit dezelfde database wil lezen als je aan het schrijven ben werkt niet makkelijk met Sqlite. Daarom heb ik het aangepast aan MySQL, zodat de database bijvoorbeeld uitgelezen kan worden met PHP. Ik heb het script nu aangepast dat als er meerdere zinnen in één keer binnen komen (kan gebeuren als het wegschrijven langer duurt dan verwacht) er per zin wordt weggeschreven. Per keer dat er een zin wordt geschreven print hij een “.”. Ook heb ik hem geschikt gemaakt om met dezelfde database verder te gaan en meerdere waardes (dit geval te Pressure en tweede temperatuur)
sprintf_P(buffer, PSTR("%02x,%3d.%02d,%3d.%02d,%3d.%01d,%4d.%02d\r\n"), temp, Temperature_H, Temperature_L, Humidity_H, Humidity_L, Temperature_bmp180_H, Temperature_bmp180_L, Pressure_H, Pressure_L);
ESP8266_send_data(1, buffer, false);
#!/usr/bin/python
import threading
import socket
import datetime
import time
import MySQLdb
import sys
TCP_IP = "0.0.0.0"
TCP_PORT = 8080
database = MySQLdb.connect('localhost', 'username', 'passdatiknietgavertellen', 'testdb')
d = database.cursor()
try:
#Deze weg halen voor het maken van een andere database
#databaseName = "db" + str(datetime.datetime.now()).translate(None, " -,!.:;")
#deze latenstaan voor de zelfde database
databaseName = "Weather"
offset = datetime.datetime.now() - datetime.datetime.utcnow()
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind((TCP_IP, TCP_PORT))
sock.listen(1)
conn, addr = sock.accept()
print 'Connection address:', addr, 'database', databaseName
#Voor het maken van een database
d.execute("CREATE TABLE %s (ID INT PRIMARY KEY AUTO_INCREMENT, var1 TEXT, var2 TEXT, var3 FLOAT, var4 FLOAT, var5 FLOAT, var6 FLOAT)" % databaseName)
id = 0
conn.setblocking(False)
conn.settimeout(10)
while True:
try:
data = ""
data = conn.recv(1024)
print str(datetime.datetime.now().time()), "@", addr, ":", data.rstrip('\r\n')
for datasplit in data.splitlines():
#het aantal commas aanpassan als het nodig is, dit is mijn check op geldige data
if datasplit.count(',') == 4:
#een punt voor iedere zin dat hij wegschrijft,
print ".",
#nieuwe waardes in een tabel, de tijd wordt de lokaale tijd beruikt om dat er geen rtc op mijn uc draait
d.execute("""INSERT INTO %s(var1,var2,var3,var4,var5,var6) VALUES("%s",%s)""" % (databaseName, str(datetime.datetime.now()), datasplit.rstrip('\r\n')))
database.commit()
except socket.error, socket.timeout:
print 'Connection close:', addr
if conn:
conn.close()
conn, addr = sock.accept()
print 'Connection address:', addr
conn.setblocking(False)
conn.settimeout(10)
except (MySQLdb.ProgrammingError, MySQLdb.OperationalError, MySQLdb.IntegrityError):
print "database ERROR"
pass
except (KeyboardInterrupt, SystemExit):
print 'except exit'
conn.close()
sock.close()
database.commit()
finally:
print 'closing socket'
conn.close()
sock.close()
database.commit()
Met dank aan highcharts demo kan ik eenvoudig een grafiek tekenen dat live is. Een php pagina leest de data uit de database. De webpagina wheater.html haalt highcharts de data en zorgt dat hij dat blijft doen.
Toen had ik data, 668266 data punten over de temperatuur van mijn kamer, dat niet meer dan 2 °C verschilt. Zucht…. Nu nog een print maken dat moet gaan zorgen voor zinnige data. Zoals constant de temperatuur buiten gaat meten.
Hier zijn de files voor de webpagina. Het is wel belangrijk om de juiste python 2.7 modules te installeren en mysql en apache te draaien, voor het draaien van het mysql script moet de “testdb” zijn aangemaakt. De ESP8266 library komt nog op github.
