Enviro+ connected to an ESP32 for use with ESPHome

Hello! I want to be able to use my existing Enviro+ and particulate sensor combo with an ESP32 running ESPHome. The ESP32 is lower power usage than an RPI and less maintenance running something purpose built like ESPHome for sensor interfacing and data transmission.

Is there an electrical/circuit schematic for the Enviro+?
Does the Enviro+ have pull up/down resistors for the I2C and SPI buses? or would I need to add them for use with something other than a Raspberry Pi?

I’ve managed to - via a breadboard - get the ESP32 wired up using the pinout for the Enviro+ provided on pinout.xyz. So far I’ve managed to be able to get data flowing for:

  • PM5003 via UART
  • Turning on the screen’s backlight via a simple binary switch

Unfortunately I don’t appear to be able to get the following working:

  • I2C devices like the 0x49 ADS1015, 0x76: BME280, 0x23: LTR559 - I can see the addresses from a bus scan, but communication with the devices appears to fail due to the I2C lines staying low erroneously
  • The SPI screen displays corrupt static, rather than anything I rendered that I send it

We added schematics for our newer boards earlier this week but looks like we missed this one - I’ll nudge some engineers!

1 Like

Schematic is now linked on the shop page - here’s a direct link!

Oh awesome thanks!! Do you have it for the old-school Enviro+ for Raspberry Pi too? Sorry I wasn’t aware that the new round of Enviros has an Enviro+, too - otherwise I would’ve been more specific!

Ah sorry, missed that you were after the schematic for the HAT version, will put a request in for that one too!

1 Like

@hel any chance those schematics are about? :)

Not yet, sorry - I’ve applied another nudge though!

1 Like

Sorry it took us a while, but the schematic for Enviro+ for Raspberry Pi is now linked on the shop page - here’s a direct link!


No worries at all. Very pleased the effort was made. Thank you muchly :)

EDIT: wow generated today even - hot off the press!


hi @hel is there a guide to connect up the Enviro+ for Raspberry PI to an ESP32 and an example sketch that we can use to pull the readings from all the sensor and display on the display (but using an ESP32 instead of a raspberry pi)?

hi @WebAsh were you able to successfully wire up the ESP32 and capture readings from the sensors? If so could you please share the sketch or the code for the ESP32 that you used? Thank you so much.

No, sorry - ESP32 isn’t an ecosystem we have a lot of experience with at Pimoroni Towers :(

I think RP2040/Pico is now supported in ESPHome though and it looks like some of the Enviro + sensors are supported - could be worth giving that route a try? https://esphome.io/

EDIT: Oops - just realised you’re talking about the Raspberry Pi version of Enviro - ignore the bit about Pico/RP2040!

1 Like

Hey @maucyr . Yes I’ve got a RPI version of an Enviro+ hooked up to an ESP32 running ESPHome. Haven’t worked on getting the mic or the light sensor going yet, but all others are great!

I basically just used pinouts.xyz to map the Enviro+ to the ESP32 equivalent via a breadboard. I do need to redo it without the breadboard as a simple harness instead but haven’t got round to it.

I managed to get it right first time once I realised that I needed to use the espressif framework in ESPHome rather than the arduino, so that I could enable the in-built pull up resistors for the i2c interface.

Here’s my little monster

I can share my ESPHome conf if helpful!


Amazing! Yes please, could you also let me know which pins you mapped to the esp32 and the enviro+ raspberry pi hat?

Enviro+ RaspberryPI Pinout
from: Enviro Plus at Raspberry Pi GPIO Pinout

Envrio+ Phat ----> ESP32 Pin
Pin 2 (5V Power) ----> ??
Pin 6 (GND) ----> ??
Pin 3(GPIO 2 (I2C1 SDA)) ----> ??
Pin 5 (GPIO 3 (I2C1 SCL)) ----> ??
Pin 8 (GPIO 14 (PMS5003)) ----> ??
Pin 10 (GPIO 15 (PMS5003)) ----> ??
Pin 12 (GPIO 18 (MIc i2s clk)) ----> ??
Pin 13 (GPIO 27 PMS5003 Reset)) ----> ??
Pin 15 (GPIO 22 PMS5003 Enable)) ----> ??
Pin 16 (GPIO 23 (ADS1015 Alert)) ----> ??
Pin 18 (GPIO 24 (Gas Header Enable)) ----> ??
Pin 19 (GPIO 10 (SPI0 MOSI)) ----> ??
Pin 21 (GPIO 9 (LCD/DC)) ----> ??
Pin 23 (GPIO 11 (SPI0 SCLK)) ----> ??
Pin 26 (GPIO 7 (SPI CS)) ----> ??
Pin 32 (GPIO 12 (Backlight)) ----> ??
Pin 35 (GPIO 19 (Mic i2s fs)) ----> ??
Pin 38 (GPIO 20 (Mic 12c data)) ----> ??

From what I can see from the schematic that @hel posted earlier there seems to be certain pins that can be used but I’m not sure if we can also use the Breakout Garden Pinouts to capture all the sensor data :

  • BME280 temperature, pressure, humidity sensor -->> Uses I2C Address: 0x76
  • LTR-559 light and proximity sensor → Uses I2C Address: 0x23
  • MICS6814 analog gas sensor → Appears to use the ADS1015 & Pin 18 (GPIO 24 (Gas Header Enable))?
  • ADS1015 analog to digital converter (ADC) → Uses i2c addr = 0x49
  • MEMS microphone → Uses Pin 35 (GPIO 19 (Mic i2s fs)), Pin 38 (GPIO 20 (Mic 12c data)), & Pin 12 (GPIO 18 (MIc i2s clk))
  • 0.96" colour LCD (160x80) → Not sure what pins to use (the SPI & the LCD ones?)
  • Connector for particulate matter (PM5003) sensor → Pin 8 (GPIO 14 (PMS5003)) , Pin 10 (GPIO 15 (PMS5003)) , Pin 12 (GPIO 18 (MIc i2s clk)), Pin 13 (GPIO 27 PMS5003 Reset)) , Pin 15 (GPIO 22 PMS5003 Enable))

Hi @WebAsh would you be able to share your esphome config and the pins you used on the esp32? Thank you so much.

I think there is one other user @Pineapple-Jake who was looking at connecting up an esp32

Oh gosh, I’m so sorry I didn’t respond. Do you still need this?

Here yah go - note that I use the esp-idf framework, as it allows me to use the built-in pull up/down resistors via a config line, rather than having to wire up any actual resistors.

I’ve also included my crude code for outputting the values to the screen, which includes the weirdness that the colours are off somehow 🤷‍♂️, so I’ve worked out how to get the colours I wanted and that’s in there.

  name: env0

  board: az-delivery-devkit-v4
#   framework:
#     type: arduino
    type: esp-idf
    version: recommended

# Enable Home Assistant API
    key: ""

  password: ""

  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
    ssid: "Fallback Hotspot"
    password: ""
  domain: ""


    sda: GPIO21
    scl: GPIO22
    scan: true
    scl_pullup_enabled: True
    sda_pullup_enabled: True

    clk_pin: GPIO18
    mosi_pin: GPIO23 # MasterOutSlaveIn - data sent from ESP32 to LCD
    #miso_pin: .. # screen doesn't return data, so DOUT/MasterInSlaveOut isn't required

  rx_pin: GPIO16
  tx_pin: GPIO17
  baud_rate: 9600

# https://esphome.io/cookbook/bme280_environment.html
  - platform: bme280
      name: "BME280 Temperature"
      id: bme280_temperature
      name: "BME280 Pressure"
      id: bme280_pressure
      name: "BME280 Relative Humidity"
      id: bme280_humidity
    address: 0x76
    update_interval: 60s
  - platform: pmsx003
    type: PMSX003
      name: "Particulate Matter <1.0µm Concentration"
      id: pms5003_1um
      name: "Particulate Matter <2.5µm Concentration"
      id: pms5003_2dot5um
      name: "Particulate Matter <10.0µm Concentration"
      id: pms5003_10um
    update_interval: 60000ms

  # gfonts://family[@weight]
  - file: "gfonts://Roboto@light"
    id: roboto20
    size: 20
  - file: "gfonts://Roboto@light"
    id: roboto30
    size: 30
  - file: "gfonts://Roboto@light"
    id: roboto40
    size: 40

  - id: graph_red
    red: 100%
    green: 0%
    blue: 0%
  - id: graph_green
    red: 0%
    green: 100%
    blue: 0%
  - id: graph_blue
    red: 0%
    green: 0%
    blue: 100%
  - id: white
    red: 100%
    green: 100%
    blue: 100%
  - id: colour_text_gray
    red: 60%
    green: 60%
    blue: 60%
  - id: colour_text_red
    red: 17% # red and blue swapped
    green: 25%
    blue: 82%
    white: 0%
  - id: colour_text_blue
    red: 82% # red and blue swapped
    green: 38%
    blue: 0%
    white: 0%

# graph:
#   - id: particulates_simple_graph
#     sensor: pms5003_10um
#     duration: 8h
#     width: 150
#     height: 50
#   - id: particulates_graph
#     duration: 8h
#     x_grid: 1h
#     y_grid: 1.0     # degC/div
#     width: 150
#     height: 60
#     traces:
#       - sensor: pms5003_1um
#         line_type: DOTTED
#         line_thickness: 2
#         color: graph_green
#       - sensor: pms5003_2dot5um
#         line_type: DASHED
#         line_thickness: 2
#         color: graph_red
#       - sensor: pms5003_10um
#         line_type: SOLID
#         line_thickness: 2
#         color: graph_blue

  - platform: st7735
    model: "INITR_MINI160X80"
    cs_pin: GPIO5
    dc_pin: GPIO19
    device_width: 80
    device_height: 160
    rotation: 90
    col_start: 26
    row_start: 1
    eight_bit_color: true
    invert_colors: true
    update_interval: 30s
    lambda: |-
      auto red = Color(255, 0, 0);
      auto green = Color(0, 255, 0);
      auto blue = Color(0, 0, 255);
      auto white = Color(255, 255, 255);
      auto black = Color(0, 0, 0);
      auto black_fucked_inverted = Color(255, 255, 255);
      auto white_fucked_inverted = Color(0, 0, 0);

      // R and B colours swapped - because fuck knows??
      auto colour_eu_aqi_good = Color(230, 240, 80);
      auto colour_eu_aqi_fair = Color(170, 204, 80);
      auto colour_eu_aqi_moderate = Color(65, 230, 240);
      auto colour_eu_aqi_poor = Color(80, 80, 255);
      auto colour_eu_aqi_vpoor = Color(50, 0, 150);
      auto colour_eu_aqi_expoor = Color(129, 33, 125);
      auto twodotfiveum_colour_text = colour_eu_aqi_good;
      auto tenum_colour_text = colour_eu_aqi_good;

      //it.graph(5, 20, id(particulates_simple_graph));
      //it.rectangle(0, 0, 30, 30, red);
      //it.rectangle(10, 10, 30, 30, green);
      //it.rectangle(20, 20, 30, 30, blue);
      //it.rectangle(5, 5, 30, 30, white);
      // Syntax is always: it.print(<x>, <y>, <font>, [color=COLOR_ON], [align=TextAlign::TOP_LEFT], <text>)
      //it.print(0, 30, id(roboto20), white, TextAlign::TOP_LEFT, "Hello World!");

      it.printf(0, 0, id(roboto40), colour_text_red, TextAlign::TOP_LEFT, "%2.1f", id(bme280_temperature).state);
      it.printf(160, 0, id(roboto40), colour_text_blue, TextAlign::TOP_RIGHT, "%2.0f%%", id(bme280_humidity).state);

      if ( !isnan( id(pms5003_1um).state ) ) {
        it.printf(0, 40, id(roboto30), colour_text_gray, TextAlign::TOP_LEFT, "%2.0f", id(pms5003_1um).state);

        if ( id(pms5003_2dot5um).state > 25 ) {
          twodotfiveum_colour_text = colour_eu_aqi_poor;
        } else if ( id(pms5003_2dot5um).state > 20 ) {
          twodotfiveum_colour_text = colour_eu_aqi_moderate;
        } else if ( id(pms5003_2dot5um).state > 10 ) {
          twodotfiveum_colour_text = colour_eu_aqi_fair;
        it.printf(100, 40, id(roboto30), twodotfiveum_colour_text, TextAlign::TOP_RIGHT, "%2.0f", id(pms5003_2dot5um).state);

        if ( id(pms5003_10um).state > 50 ) {
          tenum_colour_text = colour_eu_aqi_poor;
        } else if ( id(pms5003_10um).state > 40 ) {
          tenum_colour_text = colour_eu_aqi_moderate;
        } else if ( id(pms5003_10um).state > 20 ) {
          tenum_colour_text = colour_eu_aqi_fair;
        it.printf(160, 40, id(roboto30), tenum_colour_text, TextAlign::TOP_RIGHT, "%2.0f", id(pms5003_10um).state);

  - platform: gpio
    pin: GPIO32
    name: "LCD Backlight"
    id: backlight
1 Like

If your handy with a soldering iron, you could mount them to this, then solder jumpers from one to the other.
Adafruit Perma-Proto Breadboard PCB - 3 Pack! - Full size (pimoroni.com)


I am trying to get this to work with ESP Easy and managed to get the particulate sensor working but unfortunately I am not able to get anything working via the I2C chipset such as the BME280 or LTR559. Someone mentioned having to use pull up resistors? Does your implementation on your breadboard make use of these? or are they all just wired directly to the ESP32 device?


Does espeasy use the esp-idf framework as its base? If so, there might be a configuration item for enabling the pull resistors