Indoor sensor ESPhome software integration

4 minute read

Introduction

As usual this blog post took longer to finish than anticipated, but it is finally there. I integrated my design for an affordable indoor sensor that can accurate measure CO2 levels, temperature, humidity and air pressure with EPShome. And I must say I was delighted how easy it was to generate the software using ESPhome and a configuration file without having to write a single line of code.

Considerations

One of the obvious but important requirements of an indoor sensor is that it can accurately measure within the context of the intended use. For a smart indoor sensor that is not trivial (especially for measuring temperature) as there a couple of heat sources that can not be ignored on the PCB:

  • ESP8266
  • MHZ19 sensor
  • SSD1306 OLED display
  • Red/green LED

Even though the PCB was designed in such a way that these heat sources are moved as far away as possible to the BME280 sensor, the compact size of the PCB causes these heat sources to affect the BME280 temperature sensor anyway. The effect of the heat sources has to be reduced using a carefully designed housing as the behaviour in a housing differs from open-air operation. But also during the ESPhome software integration this is important by having the option to calibrate the temperature offsets.

Housing

The housing was designed using FreeCAD. It is pretty straightforward and consists of two parts:

  • Bottom part where the PCB is attached. It contains ventilation slots at left, top and right side to allow free air flow. The USB-C connection is accesible from the bottom. The rear side has holes for mounting it to a wall.
  • Top part that holds the display and can be clicked on the bottom part

Using a 3D printer the housing parts can be printed without the need of supports. It takes about 2 hours in total to print.

Some pictures of the finished prototype:

Prototype of the housing

ESPhome

I am not afraid of writing a few lines of source code. In this project however, I tried ESPhome and I was impressed. Using only ESPhome and a .yaml configuration file, a working smart indoor sensor can be made that:

  • reads all sensors
  • controls the LED and display
  • connects over WIFI
  • makes all measurements easily available in e.g. Home Assistant

Using the indoorsensor.yaml configuration file the firmware can be created and flashed to the target with only this command:

esphome run indoorsensor

The first time, you have to connect it using USB. Once the sensor is connected to your Wifi network, further updates can be done over-the-air.

The full indoorsensor.yaml file can be found in the Indoor sensor Github repo. To give a sneak preview of how it looks like I listed a few sections below.

Substitutions

Substitutions allow keeping the configuration organized and their default values can be adjusted from the command line, e.g.

substitutions:
    devicename: "indoor"
    wifi_ssid: "SSID"
    wifi_password: "Password"
    bme280_temperature_offset: "-8.0"

This way, the Wifi password does not have to be stored in the .yaml file and multiple sensors each with their own device name can be flashed using only one configuration file. Simply run esphome as:

esphome -s devicename indoor-main -s wifi_ssid SSID -s wifi_password PASSWD run indoorsensor

Device/board name

The device and board name have to be added (note how devicename is substituted):

esphome:
  name: ${devicename}

esp8266:
  board: d1_mini

WIFI settings

The WIFI has to be configured and a fallback hotspot will be created in case WIFI connection fails

wifi:
  ssid: ${wifi_ssid}
  password: ${wifi_password}

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Indoor sensor Fallback Hotspot"
    password: "Pass1234"

captive_portal:

PIN settings

The LED digital outputs:

output:
  - platform: gpio
    pin: GPIO14
    id: led_red

  - platform: gpio
    pin: GPIO16
    id: led_green

The UART and I2C bus configuration:

uart:
  tx_pin: GPIO0
  rx_pin: GPIO2
  baud_rate: 9600

i2c:
  sda: GPIO4
  scl: GPIO5
  scan: true

Sensor settings

And finally the sensors are all already supported by ESPhome:

sensor:
  - platform: mhz19
    co2:
      name: "CO2 value"
      id: "co2"
    temperature:
      name: "MHZ19 Temperature"
    update_interval: 5s
    automatic_baseline_calibration: false

  - platform: bme280
    temperature:
      name: "BME280 Temperature"
      id: "temp"
    pressure:
      name: "BME280 Pressure"
      id: "pressure"
    humidity:
      name: "BME280 Humidity"
      id: "humidity"
    address: 0x76
    update_interval: 5s

And that is the basic configuration (apart from the display) enough to send the sensor values to Home Assistant.

Functionality

Now some functionality can be added. As an example I want the LED to show:

  • green when the CO2 value is below 800ppm
  • orange when it is between 800ppm and 1400ppm
  • red when the CO2 value is above 1400ppm

This can be easily achieved in the .yaml file by adding the following under the co2: section.

    co2:
      name: "CO2 value"
      id: "co2"
      on_value_range:
        - above: 1400
          then:
            - output.turn_on: led_red
            - output.turn_off: led_green
        - below: 1400
          above: 800
          then:
            - output.turn_on: led_red
            - output.turn_on: led_green
        - below: 800
          then:
            - output.turn_on: led_green
            - output.turn_off: led_red

Other functionality related to sensor offset calibration is found below. Also a 128x64 OLED display was integrated to show the main sensor values.

Offset calibration

The BME280 sensor is relatively accurate. The temperature measurement however is severely affected by the various internal heat sources. To cope with that at least some temperature offset compensation has to be used. In the .yaml file this can be added by applying a filter to the sensor values. For example at the BME280 temperature: section you can add:

      filters:
        - offset: ${bme280_temperature_offset}

Keep the sensor powered on long enough for the inside temperature to have stabilised. Then use a known reference temperature source to adjust the offset until both sensors indicate roughly the same temperature.

Of course this process can be repeated for the other sensors (humidity and air pressure) if you have a good reference available. For air pressure the METAR data of a nearby airport can be used. The air pressure reported by the BME280 I was using was typically within 1hPa of this already.

References

Indoor sensor project
Indoor sensor housing
Indoor sensor sofware
ESPhome