The internet of things (IoT) is everywhere now. And of course I’m into connecting all sort of electronic stuff to the internet as well. I think the equivalent of the famous “Hello World!” programming language example is the “Temperature Sensor” for IoT. And of course I’m interested in Temperature, Humidity and Pressure as well. Not only because I want to know how cold it is outside. I also want to know the temperature and especially the historical temperature in every room.
In the long term I’d hope to derive some learnings from these data to optimize our heating schedule and eventually control the heating from an automated systems.
To get started I wanted to build some cheap wireless sensors whose data are collected in a central place. Sure you can buy that stuff readymade. But where’s the fun in that?
To keep the wireless transfer part as low profile as possible (also in terms of power consumption) I picked the 868MHz Radio band that’s free to use and has a good range. Alternatives are LoRa Packet radio at 900Mhz which seems to emerge as a new standard for IoT connections. There is an affordable breakout module from Adafruit for this with the well supported RFM69HCW chipset.
As Sensor node I picked the Adafruid Feather M0 with the RFM69HCW module integrated. That’s a tiny Arduino-compatible Micro-Controller which has the packet radio module integrated on the same PCB. In addition it has a JTAG header and Lithium-Polymer battery loader circuit. This makes it flexible on the power supply.
For temperature and humidity I chose the really cheap Adafruit Si7021 breakout board with I2C interface. This allows to connect more sensors to the Feather M0 if needed.
On the receiver side I first tried to connect the RFM68HCW to the RaspberryPi. But I couldn’t find any reliable libraries talking to the chipset to get proper readings. And for things rather close to hardware the MicroControllers seems to be the weapon of choice. So I got myself a Gertduino. This is a full fledged Arduino UNO (and some other neat stuff) on a PCB that sits on top of a RaspberryPi and connects to its GPIO headers. You can program the Arduino from the RapsberryPi and read/write data from it via Serial line. So much on the hardware side.
On the software side my first goal was to collect and visualize the data. Recently I had to look into ElasticSearch and figured that it’s actually quite simple to setup. It also comes with a usual visualization web frontend named Kibana. ElasticSearch prefers JSON documents as input. So I configured the collector nodes to emit their sensor readings in JSON format.
The ElasticSearch and Kibana I raised with this simple Docker setup (docker-compose.yml):
Adafruit Feather nodes on the input side and ElasticSearch/Kibana on the visualization. But how to connect the dots? First I thought of writing myself some python code to read from the Gertduino serial line on the RaspberryPi and send it to the ElasticSearch. But my local IoT guru Chaosblog brought some new stuff to the table – Node Red.
This is a Node.js application which helps do the plumbing described above. It’s got little building blocks that you can drag to a canvas and connect with wires. Messages travel the wires and can be consumed and manipulated by the blocks. There are many predefined blocks which offer easy solutions to common problems.
My workflow in Node Red looks like this:
- read data from serial port
- try to parse as JSON object
- insert timestamp into JSON object
- HTTP POST document to ElasticSearch
Some things I learned along the way:
- do a Serial.flush(); to make sure data is written to the serial line
- The Feather M0 has a realtime clock than can be used in the power saving setup
- You can’t program the Gertduino from the RaspberryPi when using the serial connection (hardware jumpers … )
- The RFM69HCW needs an exactly 16 byte encryption key
- the RFM69HCW modules has got it’s own temperature sensor
- the RFM69HCW can only send packets of app. 61 bytes (might need to split messages)
- Interrupt Service Routines (ISR) are tricky:
- don’t use delay(); it will make your code hang
- you might not need any code in the ISR at all.
Source Code for the Weather Nodes (make sure you give each node a different Node: #define NODEID 1)
Source Code for the Weather Hub (on the Gertduino)