Note: This post was originally posted on my personal blog. I have copied the content to this blog.
I wanted to measure temperature and humidity and the options to do so in pre-built packages that integrate with Home Assistant all fell short, so I made my own. Why would you want to do something like this? Here are some examples of things you can create:
To achieve this, you need:
First, disconnect the Pi and solder the 40 pin header to it. Now connect the DHT22 to your Pi. Mine already had a pulldown resister installed on a small circuit board so I connected it directly to the Pi.
In this image, positive is orange, out is red and negative is brown. Also note that they are connected on the higher pins (which correspond to the inner side). This board is rotated a little more than 90 degrees clockwise compared to the schematic above.
Now that the sensor is connected (you made sure to test connectivity on your soldering, right?), hook your Pi back up, boot it and SSH into it. This guide assumes you will not be using Docker, but Docker may be an option (which means you can skip the next section).
Install Python 3.6+. Depending on your installation you may already have this (python3 --version
). If not, try to install it via the package manager (sudo apt-get install python3.6
). If this doesn’t work, you might have to compile from source (this is what I had to do). I would follow this gist, but I would run sudo apt-get install libffi-dev
first, before you compile Python. Then I would recommend using checkinstall
to install it as a package rather than directly onto your system. This didn’t work for me, so I ended up running make and then sudo make install
.
Once you have python 3.6 or higher installed, install mqtt-io
. In my case, I ran python3.9 -m venv mqtt-io
and then in the directory that was created, source bin/activate
, then pip3.9 install mqtt-io
. Once installed, I created a config for it with the following contents:
mqtt:
host: 192.168.1.68 # update this to your MQTT broker's IP
topic_prefix: office/pizero # change this as you see fit, I like [room]/[device]
status_payload_running: available
status_payload_stopped: unavailable
status_payload_dead: unavailable
sensor_modules:
- name: dht22_sensor
module: dht22
type: dht22
pin: 4 # this may change if you add additional sensors or don't use pin 4 from above
sensor_inputs:
- name: office_temperature
module: dht22_sensor
digits: 2
interval: 5
type: temperature
- name: office_humidity
module: dht22_sensor
digits: 2
interval: 5
type: humidity
Now try to run with your config: python3.9 -m mqtt_io config.yaml
. Watch the logs and MQTT to see the messages get pushed. You should see something like this:
With a humidity of 80%, you can see why I wanted to monitor it.
If it doesn’t work, check your config, your soldering, and how you wired up the sensor. It’s also possible the sensor is bad, apparently they have high failure rates.
If everything works, you can set this up to run as a service on your Pi:
sudo vi /etc/systemd/system/mqttio.service
[Unit]
Description=MQTT-IO
After=network.target
Wants=network-online.target
[Service]
Restart=always
Type=simple
ExecStart=/home/pi/mqtt-io/bin/python3 -m mqtt_io /home/pi/mqtt-io/config.yaml
User=pi
Environment=
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable mqttio
sudo systemctl start mqttio
Now time to configure Home Assistant. You can use autodiscovery, but in my experience that didn’t include a unit of measure, so the values ended up showing up like this:
By manually configuring the sensors, I was able to specify the unit of measurement, which fixed that.
Add the following to your configuration.yaml:
sensor:
- platform: mqtt
name: "Office Temperature"
unique_id: 889d6c50-41a3-48f9-9f3f-c23e2b709670 # this can be anything unique
state_topic: "office/pizero/sensor/office_temperature" # change this accordingly
unit_of_measurement: "°C"
- platform: mqtt
name: "Office Humidity"
unique_id: 990cf7c2-4d84-4cd0-b46d-a6a7efb313e0 # this can be anything unique
state_topic: "office/pizero/sensor/office_humidity" # change this accordingly
unit_of_measurement: "%"
Restart Home Assistant and you should see your data coming in:
The “_2” came came from the first sensor using autodiscovery and not having units.
From here, you can see historical values or create automations based off the data.
Update: I let this run for a little bit and I did notice some data errors:
I think this is just fluctuations in the sensor itself. I would recommend you take blips like this into account when making automations. For example instead of triggering when any reading is below a certain value, trigger when it has been below a certain value for X seconds or minutes.
Alternatively, instead of using the sensor directly, you can create a filtered sensor (add this to your home assistant config in the same sensor block as above):
- platform: filter
name: "Office Humidity Filtered"
entity_id: sensor.office_humidity
filters:
- filter: outlier
window_size: 5 # looks at the latest 5 data points
radius: 2.0 # this removes values that are more than 2 away from the median
- filter: lowpass
time_constant: 10
- filter: time_simple_moving_average
window_size: "00:01" # increase this to make your sensor slower to change
precision: 2 # 2 digits of precision
- platform: filter
name: "Office Temperature Filtered"
entity_id: sensor.office_temperature
filters:
- filter: outlier
window_size: 5
radius: 2.0
- filter: lowpass
time_constant: 10
- filter: time_simple_moving_average
window_size: "00:01"
precision: 2
Now you can use the mean to smooth out any spikes of the default attribute for the sensors. Because the config I provided pings every 5 seconds (which ends up being every 10-20 seconds, really), I recommend a low radius if you’re using DHT-22s.