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