Breadboard
docs
Example project · Sensors

Air-quality station (SEN55 + OLED)

A desk-ready monitor: the ESP32 polls a Sensirion SEN55 over I2C and renders live PM2.5, humidity, and temperature to the OLED once a second. Press Run, then ▶ Run script in the serial monitor, and the display updates like the real appliance.

The Air-quality station (SEN55 + OLED) circuit as rendered by the simulator

How it works

A Sensirion SEN55 read over I²C with its real command set: the script starts measurement by writing 0x0021 to address 0x69, then polls command 0x03C4 and unpacks the 24-byte reply into PM2.5 (scaled ÷10), humidity (÷100), and temperature (÷200), exactly like production firmware. The SEN55 sits on the 5 V rail because its fan is a real load; its data pins share the C3's I²C bus (SDA=G8, SCL=G9) with the SSD1306 that renders the station readout once a second.

What's on the bench

  • Battery
  • ESP32-C3
  • OLED 128×64
  • SEN55

How it's wired

  • hole a10hole B-5
  • hole a11hole B+5
  • hole a30hole B+9
  • hole a31hole B-9
  • hole a32hole a20
  • hole a33hole f11
  • hole a34hole B-9
  • hole a40hole B-9
  • hole a41hole f10
  • hole a42hole g11
  • hole a43hole b20

The code

This MicroPython script runs on the emulated board every boot; edit it in the Code tab.

from machine import I2C, Pin
import framebuf, time
i = I2C(0, scl=Pin(9), sda=Pin(8))
buf = bytearray(1024)
fb = framebuf.FrameBuffer(buf, 128, 64, framebuf.MONO_VLSB)
for c in b'\xae\xd5\x80\xa8\x3f\xd3\x00\x40\x8d\x14\x20\x00\xa1\xc8\xda\x12\x81\xcf\xd9\xf1\xdb\x40\xa4\xa6\xaf':
    i.writeto(0x3c, bytes([0, c]))
def show():
    i.writeto(0x3c, b'\x00\x21\x00\x7f\x22\x00\x07')
    i.writeto(0x3c, b'\x40' + buf)

# SEN55: start measurement, then poll (Sensirion I2C command set)
i.writeto(0x69, b'\x00\x21')
time.sleep(0.2)
for n in range(60):
    i.writeto(0x69, b'\x03\xc4')
    d = i.readfrom(0x69, 24)
    w = [(d[k*3] << 8) | d[k*3+1] for k in range(8)]
    fb.fill(0)
    fb.text('AIR QUALITY', 20, 2)
    fb.text('PM2.5 %.1f ug' % (w[1]/10), 0, 20)
    fb.text('RH    %.1f %%' % (w[4]/100), 0, 34)
    fb.text('TEMP  %.1f C' % (w[5]/200), 0, 48)
    show()
    print('PM2.5', w[1]/10, 'RH', w[4]/100, 'T', w[5]/200)
    time.sleep(1)

Try this

  • Select the SEN55 and drag its PM2.5 slider: the OLED and the serial line follow.
  • Two devices, one bus: run I2C(0, scl=Pin(9), sda=Pin(8)).scan() at the REPL and find 0x3c and 0x69.
  • Compare with the fume-extractor build, which turns these same readings into fan control.
  • Hover the SEN55 supply pin: 5 V, not 3V3 — the fan needs it.

Related projects