ESPHome: CO2 Sensors

I am using an SCD30 connected to a Raspberry PI Zero W to send CO2 measurements every 2 seconds to my Homeassistant. The current value of the SCD30 together with the difference of the last minute is shown in my statusbar, see a previous blog post about this.

But before I migrate the SCD30 to ESPHome I want to try a MH-Z19B I have bought a while ago and never used. First I soldered pins on the sensor and connected them to a Raspberry PI Pico W. For this I used Pins GP0 and GP1 to connect to RX/TX of the sensor. There are a lot of alternative UART pins on the Pico. A common alternative here would be GP21/GP22. The sensor needs 4.5~5.5 V DC so connect to 5V and of course connect GND.

The wiring setup looks like this:


My ESPHome config (ESPHome reference for MHZ19):

  tx_pin: 0
  rx_pin: 1
  baud_rate: 9600

  - platform: mhz19
      name: MH-Z19 CO2 Value
      name: MH-Z19 Temperature

When booting the sensor is warming up and after this we get CO2 values and temperature:

[20:02:29][W][mhz19:035]: MHZ19 warming up, 30s left
[20:03:29][W][component:170]: Component mhz19.sensor cleared Warning flag
[20:03:29][D][mhz19:065]: MHZ19 Received CO₂=756ppm Temperature=23°C Status=0x00
[20:03:29][D][sensor:093]: 'MH-Z19 CO2 Value': Sending state 756.00000 ppm with 0 decimals of accuracy
[20:03:29][D][sensor:093]: 'MH-Z19 Temperature': Sending state 23.00000 °C with 0 decimals of accuracy

On the Homeassistant dashboard the sensor works as expected:


Next the SCD30, which has a lot better accuracy, but costs more than twice as much. The sensor uses I2C which we used before for a BME280. We connect the SCD30 to GP0/GP1 (the same pins as for UART for the MHZ19). Important here is to connect SDA to GP0 and SCL to GP1 and not crosswise as for RX/TX.

Addionally I added a BME280 the same way my Raspberry PI Zero had used before. Because we have two devices that use I2C but can only specify one pin pair per bus we use the second bus for the BME280. We connected the BME280 to GP26 and GP27 for SDA and SCL and for power to the 3.3V pin.

My ESPHome config for the SCD30 (ESPHome reference) and a BME280:

  - id: bus0
    sda: 0
    scl: 1
  - id: bus1
    sda: 26
    scl: 27

  - platform: scd30
    i2c_id: bus0
      name: "Desk CO2"
      accuracy_decimals: 1
      name: "Desk Temperature"
      accuracy_decimals: 2
      name: "Desk Humidity"
      accuracy_decimals: 1
    address: 0x61
    update_interval: 2s
  - platform: bme280_i2c
    i2c_id: bus1
      name: "Desk BME280 Temperature"
      name: "Desk BME280 Pressure"
      name: "Desk BME280 Humidity"
    address: 0x76
    update_interval: 60s

Bootup is a lot faster and there is no initialization wait for the CO2 sensor:

[20:53:29][D][scd30:186]: Got CO2=962.24ppm temperature=25.13°C humidity=50.12%
[20:53:29][D][sensor:093]: 'Desk CO2': Sending state 962.23608 ppm with 1 decimals of accuracy
[20:53:29][D][sensor:093]: 'Desk Temperature': Sending state 25.13084 °C with 2 decimals of accuracy
[20:53:29][D][sensor:093]: 'Desk Humidity': Sending state 50.12207 % with 1 decimals of accuracy
[20:53:34][D][sensor:093]: 'Desk BME280 Temperature': Sending state 22.73586 °C with 1 decimals of accuracy
[20:53:34][D][sensor:093]: 'Desk BME280 Pressure': Sending state 959.16943 hPa with 1 decimals of accuracy
[20:53:34][D][sensor:093]: 'Desk BME280 Humidity': Sending state 53.44043 % with 1 decimals of accuracy

In Homeassistant the card looks like this:


The temperature of the SCD30 is a bit off. This can be corrected with the temperature_offset parameter in the sensor config. But because I have an additional BME280, I don't care about the offset.

Positives of migrating the SCD30 to ESPHome: one Raspberry Pi Zero shut off (no OS updates anymore, less power consumption for a Pico than for a Zero). Addionally I can update the Pico via OTA every few months with probably less issues.