This article will explain how to setup a Pimoroni Enviro+ attached to a Raspberry Pi Zero WH and collect the data in Home Assistant using MQTT.
To do this I am using:
I chose to use the Enviro+ so that I could add the particulate sensor for additional sensor recording, however this tutorial can be followed by using the Enviro on its own or the Enviro+ without the additional sensor.
Be sure to order the Zero with the pre-soldered header unless you fancy soldering on your own header. You could use the Raspberry Pi Zero 2 WH but the original Zero is just fine for this purpose.
First connect your hardware together. Push the Enviro+ onto the 40pin IDC. If you are mounting this more permanently then I would advise using 2 (preferably 4) 10mm M2.5 spacers between the two boards. Then, if you are using one, attach the particulate sensor to the Enviro+.
Next you need to put you raspberry pi image on the SD card using Raspberry Pi imager, By default I always choose the standard desktop install as it is useful to be able to connect an HDMI pad to a raspberry pi and use the desktop environment in case of problems. You can always use raspy-config to boot into the CLI environment afterwards if you prefer as I find it makes little difference to performance.
Next ensure your raspberry Pi is up-to-date
sudo apt update
sudo apt upgrade -y
Reboot your Raspberry Pi
Now we can move onto setting up the Enviro+ with the following:
sudo apt install git
git clone https://github.com/pimoroni/enviroplus-python
cd enviroplus-python
./install.sh
Reboot the Raspberry Pi and then run one of the included examples. These run in their own Pimoroni virtual environment. To start the virtual environment enter the following:
source ~/.virtualenvs/pimoroni/bin/activate
Then we can start the script in the virtual environment:
cd enviroplus-python/examples
python all-in-one.py
You should see data output on the screen and on the small screen on the Enviro+ to confirm we have everything working. Press <ctrl-c> to stop this.
Now we want to publish the data via MQTT. The included examples provide a way to do this so on the command line enter the following. Make sure you are still within your virtual python environment and be sure to enter the correct broker IP address or hostname along with the login credentials. You will need to remember the topic name:
python mqtt-all.py --broker <broker hostname or IP here> --topic enviro --username <broker username> --password <broker password> --interval 5
Now exit from your virtual python environment and run the following from the command line. This should perfom correctly and is what we are going to use next to automate the script at boot time.
~/.virtualenvs/pimoroni/bin/python3 ~/enviroplus-python/examples/mqtt-all.py --broker <broker hostname or IP here> --topic enviro --username <broker username> --password <broker password> --interval 5
Unfortunately the script does not display the information correctly on the Enviro+ display. I made a few tweaks to this here to fix this and in addition added and additional line that updated each time the data is published via MQTT to give a visual indication to assist in debugging. If you choose to use this version then the Enviro+ display will correctly show you the serai lnumber, wifi status, mqtt-broker name and additionally the last time MQTT data was published. If you are not interested in this then simply proceed with the included mqtt-all.py
I updated the display_status function as below:
# Display Raspberry Pi serial and Wi-Fi status on LCD
def display_status(disp, mqtt_broker):
# Width and height to calculate text position
WIDTH = disp.width
HEIGHT = disp.height
# Text settings
font_size = 12
font = ImageFont.truetype(UserFont, font_size)
# Generate update time
updated = datetime.datetime.now().strftime("%X")
wifi_status = "connected" if check_wifi() else "disconnected"
text_colour = (255, 255, 255)
back_colour = (0, 170, 170) if check_wifi() else (85, 15, 15)
device_serial_number = get_serial_number()
# Add updated to output
message = f"{device_serial_number}\nWi-Fi: {wifi_status}\nmqtt-broker: {mqtt_broker}\nupdated: {updated}"
img = Image.new("RGB", (WIDTH, HEIGHT), color=(0, 0, 0))
draw = ImageDraw.Draw(img)
# fix from pull request 144
x1, y1, x2, y2 = draw.textbbox((0,0), message, font=font)
size_x = x2 - x1
size_y = y2 - y1
x = (WIDTH - size_x) / 2
y = (HEIGHT / 2) - (size_y / 2)
draw.rectangle((0, 0, 160, 80), back_colour)
draw.text((x, y), message, font=font, fill=text_colour)
disp.display(img)
Be sure to add at the top of mqtt-all.py the following line
import datetime
Now we want to make sure the python script is run at boot so to do this we need to add a crontab entry
sudo crontab -e
Then add the following line to your crontab. You will need to change the path of your home directory in both instances below. The @reboot means this will be run at boot time. Note for the actual implementation I have changes the script interval to 300 seconds rather than the 5 seconds we were using previously to test. If you power on the device rather than reboot it you may need to wait 5 minutes for the screen to update:
@reboot /home/martin/.virtualenvs/pimoroni/bin/python3 /home/martin/enviroplus-python/examples/mqtt-all.py --broker <broker hostname or IP here> --topic enviro --username <broker username> --password <broker password> --interval 300 &
Once we have setup the Raspberry pi to publish our data via MQTT we then need to setup some sensors in Home Assistant to consume and display this data. To do so add the following action to your configuration.yaml
mqtt:
sensor:
- name: "enviro_pm1"
state_topic: "enviro"
value_template: "{{ value_json.pm1 }}"
unit_of_measurement: 'pm'
icon: "mdi:thought-bubble-outline"
- name: "enviro_pm10"
state_topic: "enviro"
value_template: "{{ value_json.pm10 }}"
unit_of_measurement: 'pm'
icon: "mdi:thought-bubble-outline"
- name: "enviro_pm2.5"
state_topic: "enviro"
value_template: "{{ value_json.pm25 }}"
unit_of_measurement: 'pm'
icon: "mdi:thought-bubble-outline"
- name: "enviro_humidity"
state_topic: "enviro"
value_template: "{{ value_json.humidity }}"
unit_of_measurement: '%'
icon: "mdi:water-percent"
- name: "enviro_pressure"
state_topic: "enviro"
value_template: "{{ value_json.pressure }}"
unit_of_measurement: 'Pa'
icon: "mdi:arrow-down-bold"
- name: "baro_pressure"
state_topic: "enviro"
value_template: "{{ value_json.pressure|int /100 }}"
unit_of_measurement: 'mb'
icon: "mdi:arrow-down-bold"
- name: "msl_pressure"
state_topic: "enviro"
value_template: >-
{% set temperature_gradient = 0.0065 %}
{% set exponent = 0.03416 / temperature_gradient %}
{% set altitude_meters = 130 %} {# Set this to your local elevation (in metres) #}
{% set temperature_celsius = value_json.temperature | float %}
{% set temperautre_at_sealevel_kelvin = temperature_celsius + (temperature_celsius * temperature_gradient) + 273.15 %}
{% set air_pressure_hpa = (value_json.pressure | float / 100) | round(1) %}
{{ (air_pressure_hpa / (1 - ((temperature_gradient * altitude_meters) / temperautre_at_sealevel_kelvin)) ** exponent) | round(1) }}
unit_of_measurement: 'mb'
icon: "mdi:arrow-down-bold"
- name: "enviro_temperature"
state_topic: "enviro"
value_template: "{{ value_json.temperature }}"
unit_of_measurement: 'C'
icon: "mdi:thermometer"
- name: "enviro_lux"
state_topic: "enviro"
value_template: "{{ value_json.lux }}"
unit_of_measurement: 'lx'
icon: "mdi:weather-sunny"
- name: "enviro_nh3"
state_topic: "enviro"
value_template: "{{ value_json.nh3 }}"
unit_of_measurement: 'nh3'
icon: "mdi:thought-bubble"
- name: "enviro_reduced"
state_topic: "enviro"
value_template: "{{ value_json.reduced }}"
unit_of_measurement: 'CO'
icon: "mdi:thought-bubble"
- name: "enviro_oxidised "
state_topic: "enviro"
value_template: "{{ value_json.oxidised }}"
unit_of_measurement: 'no2'
icon: "mdi:thought-bubble"
The topic will need to match the topic in the python script. I created 3 separate entries for the pressure sensor. Feel free to chooser the one you prefer. Normally air pressure from weather stations is referred to as barometric pressure at mean sea level. I created a sensor to calculate this, however the calculation will require you to update your altitude (in metres) above sea level. There is the option in Home Assistant to enter this in the Setup section however I could not find a way to use this value so you will need to edit the value in configuration.yaml.
To show this in Home Assistant we need to create an entitites card and add all the required entitites:

I also used the code editor to rename each entity to a more tidy name
type: entities
entities:
- entity: sensor.enviro_temperature
name: Temperature
- entity: sensor.enviro_humidity
name: humidity
- entity: sensor.baro_pressure
name: barometric pressure
- entity: sensor.msl_pressure
name: pressure (mean sea level)
- entity: sensor.enviro_pressure
name: Pressure (Pa)
- entity: sensor.enviro_pm1
name: pm1
- entity: sensor.enviro_pm2_5
name: pm2.5
- entity: sensor.enviro_pm10
name: pm10
- entity: sensor.enviro_nh3
name: NH3
- entity: sensor.enviro_oxidised
name: NO2
- entity: sensor.enviro_reduced
name: CO
- entity: sensor.enviro_lux
name: Lux
state_color: true