IoT party: installing InfluxDB (+Grafana) on a Raspberry PI for IoT sensors

Last year I upgraded my solar water panels with some temperature probes, and I scattered NodeMCU in my house (with some DHT22 and DHT11 sensors). At the time I had an old PC that was acting as a server: IoT devices were sending readings to RabbitMQ instance on that server, with a shell script that was bridging between MQTT and RRDTool database.

Of course, for me that was perfect. But I when I tried to share these tools with my family, quickly became clear that I had to make a nice interface. I ended up by sending the chart by Telegram with a bot.

Then, during last month, the old server died. I moved some things to the cloud, and some other things were archived. After some free-time during cleanup (I had two 1TB disks to cleanup...) I landed into Grafana home page. And I decided to give it a try.

Architecture

Using MQTT will improve the reliability and efficency of IoT devices that I'm going to (re)use((How? Because MQTT is lightweight, energy efficient and async)).

NTP: time is money!

The Time-Series database that we'll use rely on system clock. To keep the RPi clock in sync, we need to install a NTP client:

apt-get install ntp

Installing RabbitMQ

As I'm using Raspbian for RPi, I just need to download the *.deb package from RabbitMQ webpage and install it (as root):

wget https://github.com/rabbitmq/rabbitmq-server/releases/download/rabbitmq_v3_6_12/rabbitmq-server_3.6.12-1_all.deb
dpkg -i rabbitmq-server_3.6.12-1_all.deb

Most likely we don't have Erlang installed on RPi, so we may fix the "missing dependency error" by issuing:

apt-get install -f

Configuring RabbitMQ

First of all, we need to enable two plugins that we're going to use: the MQTT plugin, and the Management Interface plugin (for web management):

rabbitmq-plugins enable rabbitmq_mqtt
rabbitmq-plugins enable rabbitmq_management

This will install the web interface on port 15672. For security reasons (we don't want to end up with another MongoDB effect, do we?), the management interface default login (guest/guest) is available only on localhost. As we are in a headless RPi, we can use SSH for that:

ssh ip.address.of.raspberrypi -l pi -L15672:127.0.0.1:15672

Now you can browse (on the PC where was launched SSH client) http://localhost:15672/ and login with guest/guest. Go to "admin" section and create an user. Remember to set the user permissions. Now you can browse the RabbitMQ management interface with your PC (http://ip.address.of.raspberrypi:15672/).

Installing InfluxDB

As a backend for Grafana I'm using InfluxDB, a Time-Series database. You can download latest InfluxDB version on official website:

wget https://dl.influxdata.com/influxdb/releases/influxdb-1.3.5_linux_armhf.tar.gz
tar xvfz influxdb-1.3.5_linux_armhf.tar.gz
mv influxdb-1.3.5-1 /opt/influxdb

To start InfluxDB with RPi, we need to create a systemd unit file.

cat > /etc/systemd/system/influxdb.service <[Service]
ExecStart=/opt/influxdb/usr/bin/influxd run
Restart=on-failure
User=root
Group=root

[Install] WantedBy=multi-user.target EOF

We can save this file to /etc/systemd/system/influxdb.service, and update systemd:

systemctl enable influxdb.service
systemctl start influxdb.service

Installing Grafana

We need NodeJS for Grafana Grunt assets. We can use the official way:

curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash -
apt-get install nodejs

Then, we can install Grafana from @fg2it pre-builds (as the build process take too much memory and hours):

wget https://github.com/fg2it/grafana-on-raspberry/releases/download/v4.4.3/grafana_4.4.3_armhf.deb
dpkg -i grafana_4.4.3_armhf.deb
systemctl daemon-reload
systemctl enable grafana-server
systemctl start grafana-server

That's it!

Configuring Grafana

Grafana has a wizard for initial configuration (in this case you'll need to point to the InfluxDB instance): you can simply browse to http://ip.address.of.rpi:3000/

The bridge between MQTT and InfluxDB

As Telegraf (the "default" bridge between InfluxDB and MQTT) is heavy and rely on a fixed scheme for MQTT payloads (eg. the probe MQTT message should be formatted as one of the "supported payload format"), I wrote a bridge that parse the format that I'm using for sensors, and make the right HTTP requests to write into InfluxDB. This is an example:

import requests
import pika

def _listencallback(ch, method, properties, body): if method.routing_key == ‘internaltemp’ or method.routing_key == ’externaltemp’: # … extract some values from payload … r = requests.post(“http://127.0.0.1:8086/write?db=influxdbname”, data=“myserie temperature=%s,humidity=%s %s000000000” % (temperature, humidity, unixtimestamp)) if r.status_code > 299: print “Request error: %d %s” % (r.status_code, r.reason) else: print “Request OK”

Connect

credentials = pika.PlainCredentials(‘user’, ‘pass’) connection = pika.BlockingConnection(pika.ConnectionParameters(‘127.0.0.1’, 5672, “/”, credentials)) channel = connection.channel()

channel.exchange_declare(exchange=‘amq.topic’,exchange_type=‘topic’,durable=True) result = channel.queue_declare(exclusive=True) channel.queue_bind(exchange=‘amq.topic’, queue=result.method.queue, routing_key=“internaltemp”) channel.queue_bind(exchange=‘amq.topic’, queue=result.method.queue, routing_key=“externaltemp”) channel.basic_consume(_listencallback, queue=result.method.queue, no_ack=True) channel.start_consuming()

Happy coding!