Raspberry Pi IOT
Geef het een naam: Internet Of Things, REST API. Op mijn webserver wil ik informatie van sensors aangesloten op de GPIO van de Raspberry Pi kunnen gebruiken om deze te presenteren in RRD grafieken. Eerst iets geprobeerd met een NFS mount op de webserver, maar ik kwam er al snel achter dat ik dan de informatie opgeslagen in een RRD 1.x data formaat niet kan gebruiken omdat deze CPU en OS specifiek is. Dan maar iets met een REST API op de Raspberry Pi. Hierbij kwam ik uit op het WebIOPi framework.
Om WebIOPi te kunnen gebruiken voor de Pi B+ en Pi 2 moet deze worden gepatcht.
Wel eerst even Python 3 installeren op de Pi omdat dit standaard wordt gebruikt door WebIOPi.
$ sudo apt install python3 $ mkdir webiopi $ cd webiopi/ $ wget http://sourceforge.net/projects/webiopi/files/WebIOPi-0.7.1.tar.gz $ tar xvzf WebIOPi-0.7.1.tar.gz $ cd WebIOPi-0.7.1/ $ wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi-pi2bplus.patch $ patch -p1 -i webiopi-pi2bplus.patch $ sudo ./setup.sh $ cd /etc/systemd/system/ $ sudo wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi.service $ sudo systemctl enable webiopi $ sudo systemctl start webiopi $ sudo systemctl status webiopi
De config file van webIOPi aanpassen naar behoefte.
$ sudo vi /etc/webiopi/config
In dit voorbeeld heb ik een DS1820 temperatuursensor gebruikt.
[DEVICES] #temp0 = TMP102 #temp1 = TMP102 slave:0x49 #temp2 = DS18B20 #temp3 = DS18B20 slave:28-0000049bc218 woonkamer = DS18B20 slave:28-0315613197ff
Zorg er ook voor dat de 1-wire module geladen wordt.
$ sudo echo w1-gpio >> /etc/modules $ sudo echo w1-therm >> /etc/modules
Vanaf Raspbian Jessie wordt device tree gebruikt pas hiervoor de boot.txt aan.
$ sudo vi /boot/config.txt # Additional overlays and parameters are documented /boot/overlays/README dtoverlay=w1-gpio,gpiopin=4 $ sudo shutdown -r now
Zet een gebruikersnaam en wachtwoord voor de webIOPi web interface.
$ sudo webiopi-passwd $ sudo systemctl restart webiopi
Test met curl of de REST API werkt.
$ curl -X GET -u user:password localhost:8000/devices/woonkamer/sensor/temperature/c 20.00
Onze DS1820 1-wire temperatuursensor aangesloten op de GPIO aansluiting van de Raspberry Pi is nu beschikbaar via een REST API. Om de temperatuur in een mooie grafiek te plotten maken we gebruik van de RRDtool. Op de webserver maken we nu een RRD database aan met rrdtool. Hiervoor maak ik gebruik van het voorbeeld op http://blog.kugelfish.com.
$ sudo mkdir -p /opt/templog/data $ sudo mkdir -p /opt/templog/python $ sudo chown -R webpi:webpi /opt/templog
$ cd templog/data $ sudo -u webpi rrdtool create templog.rrd --step 300 \ DS:internal:GAUGE:600:-55:125 \ RRA:AVERAGE:0.5:1:576 \ RRA:AVERAGE:0.5:3:1344 \ RRA:AVERAGE:0.5:12:1488 \ RRA:AVERAGE:0.5:72:1984 \ RRA:MIN:0.5:72:1984 \ RRA:MAX:0.5:72:1984
Het templogger.py script van kugelfish heb ik aangepast om de temperatuur via de REST API van de Raspberry Pi op te halen en weg te schrijven naar de RRD database.
$ cd templog/python $ sudo -u webpi vi templogger.py
#!/usr/bin/python
import logging
import logging.handlers
import rrdtool
import time
import sys
import requests
url = 'http://ip-raspberry-pi:8000/devices/woonkamer/sensor/temperature/c'
username = 'user'
password = 'password'
def do_update():
timestamp = time.time()
internal = requests.get(url, auth=(username, password)).content
# in case of error, retry after 5 seconds
for retry in (5, 1):
try:
rrdtool.update("/opt/templog/data/templog.rrd",
"%d:%s" % (timestamp,
float(internal)))
return
except:
logging.exception("retry in %is because of: ", retry)
time.sleep(retry * 1000)
# set up logging to syslog to avoid output being captured by cron
syslog = logging.handlers.SysLogHandler(address="/dev/log")
syslog.setFormatter(logging.Formatter("templogger: %(levelname)s %(message)s"))
logging.getLogger().addHandler(syslog)
do_update()
En voeg toe aan crontab. /etc/cron.d/templogger
*/4 * * * * webpi /opt/templog/python/templogger.py
Om de RRD grafiek te laten presenteren door de webserver heb ik het app.py script van kugelfish gebruikt en iets aangepast voor mijn webserver. In directory /var/www/templogger/
!/usr/bin/python
import os
import rrdtool
import tempfile
import web
# web.py app URL routing setup
URLS = ('/graph.png', 'Graph',
'/view', 'Page')
RRD_FILE = '/opt/templog/data/templog.rrd'
SCALES = ('day', 'week', 'month', 'quarter', 'half', 'year')
RESOLUTIONS = {'day': '-26hours', 'week':'-8d', 'month':'-35d', 'quarter':'-90d',
'half':'-6months', 'year':'-1y'}
class Page:
def GET(self):
scale = web.input(scale='day').scale.lower()
if scale not in SCALES:
scale = SCALES[0]
result = '<html><head><title>Temp Logger</title></head><h4>'
for tag in SCALES:
if tag == scale:
result += '| %s |' % (tag,)
else:
result += '| <a href="./view?scale=%s">%s</a> |' % (tag, tag)
result += '</h4>'
result += '<img src="./graph.png?scale=%s">' % (scale, )
result += '</html>'
web.header('Content-Type', 'text/html')
return result
class Graph:
def GET(self):
scale = web.input(scale='day').scale.lower()
if scale not in SCALES:
scale = SCALES[0]
fd,path = tempfile.mkstemp('.png')
rrdtool.graph(path,
'-w 900', '-h', '400', '-a', 'PNG',
'--slope-mode',
'--start', ',%s' % (RESOLUTIONS[scale], ),
'--end', 'now',
'--vertical-label', 'temperature (C)',
'DEF:in=%s:internal:AVERAGE' % (RRD_FILE, ),
'LINE2:in#00ff00:inside ',
'GPRINT:in:LAST:Cur\:%8.2lf',
'GPRINT:in:AVERAGE:Avg\: %8.2lf',
'GPRINT:in:MAX:Max\:%8.2lf',
r'GPRINT:in:MIN:Min\:%8.2lf\j')
data = open(path, 'r').read()
os.unlink(path)
web.header('Content-Type', 'image/png')
return data
if __name__ == "__main__":
web.application(URLS, globals()).run()
Voeg het volgende toe aan de apache config file om het mogelijk te maken om Python scripts te kunnen draaien.
<Directory /var/www/templogger>
Options +ExecCGI
AddHandler cgi-script .py
</Directory>
En de website met de RRD grafiek van de DS1820 temperatuursensor is beschikbaar op onze webserver.
https://ip-webserver/templogger/app.py/view