In the past few years some really interesting hardware projects started getting more and more accessible to common mortals like me. Look at the Arduino platform and the entire ecosystem around it to see how different it is compared to a decade ago. There are pretty much sensors for anything you might want to measure and they are quite cheap too!
Bare esp8266 (no usb, DC converter, etc). Trying to run it on batteries is proving to be lots of fun!
By the end of this blog post you should be able to put together a temperature and humidity sensor that sends data to a home-assistant application running on a raspberry pi via MQTT.
You might ask, why would I want to record temperature and humidity in my house? Well, there are many things you could do with it. For examples you can:
- Create a smart thermostat and control your heating from anywhere.
- Evaluate your home energy efficiency in terms of heat dissipation.
- Evaluate how quickly your heating can raise the house temperature by 1°C when outside is -5°C .
- Figure out how daily activities like cooking or drying the laundry has an impact on how comfortable the home feels.
- Maybe create a little weather station outside your house and contribute data to your own locality ?
Looking for a good IoT controller
I started with Arduino and quite quickly looked for some cheap alternatives with WiFi support. That is when I found the esp8266. A super cheap micro controller with WiFi integrated and full TCP/IP stack. Having tiny WiFi devices like that really enables a lot of interesting use-cases.
Overview
Most of the IoT platforms would normally have three steps:
The hardware
What we are going to use in this post is:
- DHT22 temperature and humidity sensor
- The sensor will be controlled using a NodeMCU controller based on the ESP8266 to make USB connection and powering easier.
- Collection and analysis will be done on a Raspberry pi version 3 with home assistant.
You can easily get all the hardware above on eBay / Amazon.
Programming the controller
Let's start with the NodeMCU programming to read a sensor. For this purpose you need to either use the Arduino IDE or lately I started using platformio which has some great tools like CLI and IDE integrations.
Install platformio
For the rest of this tutorial we'll use platform.io, so go ahead and download the IDE or simply install the core using brew:
brew install platformio
Create a new folder for your sensor project. I will refer to it as ovo-sensors
.
The very next thing we are going to do is to use a handy little framework for the esp8266 called homie. Homie has some really handy features to deal with WiFi and MQTT connection / reconnection but also exposes a JSON API to configure the device and do other fancy things like OTA (Over The Air) updates of the firmware. Check the full list here
Initialize the project
So go back to the ovo-sensors
and initialize your project
platformio init --board nodemcuv2
Add the dependencies
After running the command above you should have a file called platformio.ini
. Add the lib_deps = Homie
line at the end of the section
[env:nodemcuv2]
platform = espressif8266
board = nodemcuv2
framework = arduino
lib_deps =
Homie
DHT sensor library@1.3.0
Create a main file
The last thing left to do is to tell the controller what to do 😀. Create a new file main.cpp
under src
.
The following is pretty much a copy and paste of this example from the homie library with some additional code to handle reading the temperature from the actual sensor and some logging.
#include <Homie.h>
#include <DHT.h>
#define WAIT_FOR_SENSOR_IN_MS 2500
#define DHTPIN D2
#define DHTTYPE DHT22
HomieNode temperatureNode("temperature", "temperature");
HomieNode humidityNode("humidity", "humidity");
DHT dht(DHTPIN, DHTTYPE);
void setupHandler() {
temperatureNode.setProperty("unit").send("c");
humidityNode.setProperty("unit").send("%");
}
void loopHandler() {
delay(WAIT_FOR_SENSOR_IN_MS);
float humidity = dht.readHumidity();
float temperature = dht.readTemperature();
if (isnan(temperature) || isnan(humidity)){
Homie.getLogger() << "Error reading. Temperature is " << temperature << " and humidity is " << humidity << endl;
return;
} else {
Homie.getLogger() << "Temperature: " << temperature << " °C" << endl;
Homie.getLogger() << "Humidity: " << humidity << " %" << endl;
temperatureNode.setProperty("degrees").send(String(temperature));
humidityNode.setProperty("percent").send(String(humidity));
}
}
void setup() {
Serial.begin(115200);
Serial << endl << endl;
Homie_setFirmware("sensors", "1.0.0");
Homie.setSetupFunction(setupHandler).setLoopFunction(loopHandler);
temperatureNode.advertise("unit");
temperatureNode.advertise("degrees");
humidityNode.advertise("unit");
humidityNode.advertise("percent");
dht.begin();
Homie.setup();
}
void loop() {
Homie.loop();
}
Setup the raspberry pi
Install the image
You can use the raspbian lite image for this as we don't really need any UI. There is a really handy trick to enable the raspbian ssh so you'll never need to plug in a screen / keyboard, just the network cable.
Install home-assistant
Home assistant runs on python 3. My preferred way to run it is using virtualenv. Here is a hacky script you can use for that.
# Installing python3 and virtualenv
sudo apt-get update
sudo apt-get -y install python-pip python3-dev
sudo pip install --upgrade virtualenv
# Create homeassistant user
sudo adduser --system homeassistant
sudo mkdir /srv/homeassistant
sudo chown homeassistant /srv/homeassistant
# Installs homeassistant as the user homeassistant
sudo -u homeassistant /bin/bash <<EOS
virtualenv -p python3 /srv/homeassistant
. /srv/homeassistant/bin/activate
pip3 install --upgrade homeassistant
EOS
Configure home assistant
Home assistant uses a yml
file to drive the entire system. Everything is defined in this one file. You can obviously split it into multiple smaller files but that is up to you. For our configuration we will need
- An MQTT server. You can either use the built in one or point to an external one. The passwords can be stored in an exernal file called
secrets.yml
and read using the!secret <key>
syntax. - MQTT sensors to read the data from.
- A database to store the data. I use postgres running locally but you can omit the
db_url
configuration and simply use the SQLite default database engine.
# hbmqtt server
mqtt:
client_id: hbmqtt
keepalive: 60
username: homeassistant
password: !secret mqtt_password
# Database
recorder:
db_url: postgres://@/homeassistant
# Sensor definition
sensor:
- platform: mqtt
name: "Room Temperature"
state_topic: "sensor/room/temperature/degrees"
unit_of_measurement: "°C"
- platform: mqtt
name: "Room Humidity"
state_topic: "sensor/room/humidity/percent"
unit_of_measurement: "%"
Conclusions
With this basic setup you can now easily add other sensors, create rules and complicated workflows to automate your home. I have a number of sensors in my house and control the heating and some lights using essentially this basic setup.
The next steps (maybe posts?) could be
- Expose home assistant to the internet using DDNS to access it when you are out of the house.
- Add some switches for lights / heaters / AC
- Integrate with Alexa to control everything using your voice.
- Create some super cool dashboards to display your sensors data.
- Run it on batteries?