I’ve been putting off home automation for a long time, but recently the planets aligned and I’ve built something. The main ingredients are Raspberry Pi 3B, Arduino Mega, MQTT and OpenHAB. RPi because WiFi, huge software support, Linux, file system, etc. Arduino Mega because low power, many, many libraries, huge I/O and cheap.
System Overview
Here’s the heart of the basic system:
12V 35W PSU with built-in lead-acid battery charger, DC-DC converter (3A @ 5V output), RPi 3B and Arduino Mega clone (with CH340 USB-serial, and micro USB connector for the #win). The Pi has a USB flash drive. All the interesting parts of the filesystem are backed up to the cloud nightly. I’ve also run a small fan to suck air through my case made from 2 Ikea picture frames with a hinge and some plywood backing. The support for the battery is 3D printed PLA. You’ll also see my first sensor which is a Dallas (now owned by Maxim) DS18B20 1-wire device that I have attached to the case of the switched-mode PSU.
By the way, MQTT reminds me a lot of SNMP which might mean something to older readers.
Software
Arduino
Let’s start at the bottom. The Arduino runs as a slave to the Pi and is connected via the USB cable which also powers it. Neat. The Arduino is slave to the Pi where the Pi sends commands to the Arduino periodically which include polling for status where it reads all the sensor values in a single hit.
Here’s the simple Arduino sketch (the Dallas temperature interface library is here):
#include <OneWire.h> #include <DallasTemperature.h> #define PIN_DALLAS_ONE_WIRE_BUS 3 #define PIN_LED 13 #define SEPARATOR ";" #define BLINK_DELAY 1000 OneWire dallasOneWireBus(PIN_DALLAS_ONE_WIRE_BUS); DallasTemperature temperatureSensors(&dallasOneWireBus); String inputMessage = ""; boolean inputMessageReceived = false; void setup() { pinMode(PIN_LED, OUTPUT); Serial.begin(9600); temperatureSensors.begin(); inputMessage.reserve(200); } void loop() { if(inputMessageReceived) { char command = inputMessage.charAt(0); if(command == 's') { sendMessageStatus(); } inputMessage = ""; inputMessageReceived = false; } } void serialEvent() { while(Serial.available()) { char inChar = (char)Serial.read(); inputMessage += inChar; if(inChar == '\n') { inputMessageReceived = true; } } } void sendMessageStatus() { temperatureSensors.requestTemperatures(); for(int i = 0; i < temperatureSensors.getDeviceCount(); i ++) { Serial.print("temp/"); Serial.print(i); Serial.print(":"); Serial.print(temperatureSensors.getTempCByIndex(i)); Serial.print(SEPARATOR); } Serial.println(""); }
In order to program the Arduino directly from the Raspberry Pi I used the Ino toolchain which is awesome but means that most library code needs a few tweaks before it will compile. One standard tweak is that in just about all cases you’ll need to delete the #include
of Arduino headers from the library’s .cpp source and move a #include
into the header file protected inside the usual #ifndef
re-inclusion section.
And a simple Python script to read the sensor(s) and write to the MQTT broker (Mosquitto) running on the very same RPi:
#!/usr/bin/python import paho.mqtt.client as mqtt import serial import time ser = serial.Serial('/dev/ttyUSB0', 9600) mqttc = mqtt.Client() mqttc.connect('localhost', port=1883, keepalive=60, bind_address="") while True: time.sleep(1) ser.write("s\n"); response = ser.readline().replace('\n', '') tags = response.split(';') for tag in tags: tag = tag.strip() if tag and len(tag.split(':')) == 2: (topic, value) = tag.split(':') print('{} = {}'.format(topic, value)) mqttc.publish('arduino/0/' + topic, value)
Once the MQTT broker is installed (see below), you can run a separate terminal and check that the Python script is indeed posting to MQTT:
mosquitto_sub -h localhost -v -t "arduino/#"
Here’s a nice introduction to MQTT.
The Pi
The Pi runs Raspbian Jessie.
The Pi has Mosquitto for the MQTT broker. It’s a cinch to install and run:
sudo apt-get install mosquitto mosquitto-clients
Regarding UI, the system is currently pretty much headless except for the pin 13 LED on the Arduino. So I’m using OpenHAB which has mobile app support and also cloud support. I’ve seen some tutorials out there for making OpenHAB installable via apt package manager, but links are already broken. So I’m back to suggesting that, at the time of writing, that you use downloads from the OpenHAB site and uncompress to somewhere like /opt/openhab. As root, or with lots of sudo’ing (noting that you should update the download links, don’t just copy-paste this):
mkdir /opt/openhab cd /opt/openhab wget https://bintray.com/artifact/download/openhab/bin/distribution-1.8.3-runtime.zip unzip distribution-1.8.3-runtime.zip rm distribution-1.8.3-runtime.zip mkdir all-addons cd all-addons wget https://bintray.com/artifact/download/openhab/bin/distribution-1.8.3-addons.zip unzip distribution-1.8.3-addons.zip rm distribution-1.8.3-addons.zip cd ../addons cp ../all-addons/*mqtt* . cd ../configurations
Edit openhab.cfg and look for the section MQT Transport where you will need to add the lines:
mqtt:local_broker.url=tcp://localhost:1883 mqtt:local_broker.clientId=openhab
Then edit sitemaps/default.sitemap (will be a new file) and add (sitemap files are documented here):
sitemap home label="Home" { Frame label="Central Control System" { Text item=psu_temp } }
And items/default.items add (items files are documented here):
Number psu_temp "PSU Temperature [%.1f °C]" <temperature> {mqtt="<[local_broker:arduino/0/temp/0:state:default]"}
The MQTT magic is documented here.
mkdir /usr/lib/systemd/system
Then, as root / sudo, edit /usr/lib/systemd/system/openhab.service and add the following:
[Unit] Description=openHAB Home Automation Bus Documentation=http://www.openhab.org Wants=network-online.target After=network-online.target [Service] Type=simple GuessMainPID=yes User=pi ExecStart=/opt/openhab/start.sh ExecStop=kill -SIGINT $MAINPID Restart=on-failure WorkingDirectory=/opt/openhab [Install] WantedBy=multi-user.target
Then, back as root or sudo’ing:
chown -R pi:pi /opt/openhab systemctl --system daemon-reload cd /usr/lib/systemd/system systemctl enable openhab.service
Shortly you should be able to go to http://myraspberrypi:8080/ and get to your OpenHAB UI.
To check the server logs for debugging, try (Ctrl-C to exit) (or just poke around in /opt/openhab/logs):
sudo journalctl -f -u openhab.service
You may also need to restart the openhab server after so much reconfiguration (although, in theory, it picks all changes up automagically):
sudo service openhab restart
It takes about 60 seconds on a RPi 3B to restart the service and while it’s restarting, you might see some errors if you try to look at the web UI.
If all goes well, you should get:
Access Away From Home
You could install your Raspberry Pi on your home network with a port opened on your router and directed through to your OpenHAB port. This may not be ideal for you if a) you’re nervous about opening ports on your home router’s internet-facing side or b) your ISP closes all outward facing ports and will only open them for a fee.
Another solution, if you happen to run a server somewhere out in the Cloud (e.g. Linode or Amazon AWS virtual machine) is to make use of an SSH tunnel with autossh. There’s a good article on setting such a thing up here. You would forward 8080 (not 22 as per the article) to your Cloud server. You can then use Apache’s proxy module and additional Apache user/password protection to expose the HTTP / web interface of your OpenHAB to the internet.
Future Improvements
More sensors:
- Smoke. Perhaps this could email the fire service
- Gas. (Carbon monoxide)
- 12V rail voltage monitoring with triggers for email when voltage shows mains has gone and then a trigger for a clean shutdown after about an hour
- Connection to remote station to report sunlight, rain and wind.
- Inductive ground loop in my driveway to advise of vehicles moving in/out.
- PIR as a feed into heuristics along with Bluetooth MAC scan and inductive loop triggers.
The PSU isn’t too efficient and gets rather warm. For the eagle-eyed amongst you, you’ll see that the earth isn’t connected – which is naughty.
Mutual reset capability for watchdogs on Pi and Arduino.
GSM/GPRS board for backup comms to outside world. Possibly also an APRS interface in case some jerk jams mobile frequencies.
PDP-Style front panel blinkenlights.
A bigger battery.
Integration to a satellite system running OpenSprinkler or something like it (simpler).