ESP32-C3 CO₂ & Environment Sensor Board

A small environmental monitoring board: ESP32-C3 module with a Sensirion S8 NDIR CO₂ sensor (UART) and a BME280 temperature / humidity / pressure sensor (I²C). Flashed with ESPHome and integrated into Home Assistant.

Status: prototype v1 — designed in KiCad, fabricated at PCBWay, hand assembled, powered up and running.

Board size 50.05 × 40.05 mm
Layers 2
Assembly through-hole / pin-header plug-in modules
Firmware ESPHome (see firmware/)
Schematic docs/esp-sensair-schematic.pdf
Fabrication data Gerber X2 + Excellon + job file — attached to the latest release (esp-sensair-v1.0.0-gerbers.zip)

3D render

Photos

Photos of the assembled prototype live in photos/, are embedded below, and are shown in the v1.0.0 release notes.

Assembled board, front side Assembled board, back side
Front side (assembled) Back side (assembled)
Front side, soldered Back side, soldered
Front side, soldered Back side, soldered

Running, with an active CO₂ measurement:

Active CO₂ measurement

Live values on the Home Assistant dashboard:

Home Assistant dashboard

Block diagram

                              +5 V
                                |
      +-------------------------+
      |                         |
      |              +----------v----------+
      |              |   ESP32-C3 module   |--- 3.3 V out --+
      |              | (onboard 3V3 LDO)   |                |
      +--------------+                     |                |
      |  UART 9600   +----------+----------+                |
      |                        |                            |
+-----v-------+         +------v-------+                    v
| Sensirion S8|         |    BME280    |<--- I2C (SDA/SCL) -+
|  NDIR CO2   |         |  T / RH / P  |
+-------------+         +--------------+

SW1 (calibration button) -- RC (1 k / 100 n) -- Sensirion S8 bCal_in (pin 8)
   5 V enters at the ESP32-C3 devkit's USB-C connector and is passed to the S8 via the 5 V net.

Connections

Signal ESP32-C3 module Sensirion S8 BME280
+5V pad 11 pad 0 (heater supply) —
GND pad 12 pad 1 pads 0, 4
+3V3 pad 13 (module output) — pads 1, 5
/TX pad 21 pad 6 (UART_RxD) —
/RX pad 20 pad 5 (UART_TxD) —
/SDA pad 7 — pad 2
/SCL pad 8 — pad 3
bCal_in — pad 8 (bCal_in) —

The calibration button SW1 is wired to the S8's own bCal_in input, not to the MCU: pulling bCal_in low starts the sensor's background calibration. C1 (100 nF) and R1 (1 kΩ to GND) form the debounce/RC network on that line.

Sensirion S8 pins Alarm_OC, PWM_1kHz, DVCC_out and UART_R/T are left unconnected.

Bill of materials

Ref Part Package Function
U1 ESP32-C3 Wi-Fi/BLE module (16 pads) custom esp_sensair_stuff:ESP32-C3 MCU, radio, 3.3 V regulator on module
U2 Sensirion S8 NDIR CO₂ sensor custom esp_sensair_stuff:Sensair S8 CO₂ measurement, UART, 5 V heater
U3 BME280 (plug-in breakout) custom esp_sensair_stuff:BME280 temperature, relative humidity, pressure, I²C
SW1 Tactile push button 6 mm Button_Switch_THT:SW_PUSH_6mm S8 manual (background) calibration trigger
R1 1 kΩ Resistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P7.62mm_Horizontal button debounce, low-pass to GND
C1 100 nF Capacitor_THT:C_Disc_D10.5mm_W5.0mm_P5.00mm button debounce / supply decoupling

Machine-readable BOM: bom/esp-sensair-bom.csv

Fabrication

Order data used for the v1 prototype:

Parameter Value
Fabricator PCBWay
Layers 2
Board size (ordered) 40 × 50 mm
Board size (design) 40.05 × 50.05 mm
Board material FR-4
Board thickness 1.6 mm
Finished copper weight 1 oz (35 µm)
Surface finish HASL with lead
Design rules used 0.15 mm track / 0.15 mm clearance, via 0.7 mm / 0.3 mm drill
Drill sizes present 0.8 mm, 1.0 mm, 1.1 mm (39 plated holes, 4 vias)
Non-plated holes none
Solder mask / silkscreen as ordered (see gerber/)
Stencil not ordered (THT assembly)
Qty / lead time / cost fill in from your order confirmation

Fabrication files are derived artifacts and are not committed to the tree. They are published as assets on the matching release:

  • esp-sensair-v1.0.0-gerbers.zip — Gerber X2 plot + Excellon drill files + job file, ready to upload (attached to the latest release)

To regenerate them from the design: open esp-sensair.kicad_pro in KiCad, plot Gerber X2 + drills with the project's stored export settings, and zip the result.

Note on the job file: the v1 project was started from a 4-layer KiCad stackup, so esp-sensair-job.gbrjob declares LayerNumber: 4 and labels the copper layers L1/L4 even though only the outer layers are used. The board was fabricated correctly as a 2-layer board. For the next revision: set the stackup to 2 layers in Board Setup → Stackup before exporting, so the job file is self-consistent for anyone re-ordering the board.

Assembly

All parts are through-hole or plug-in modules on pin headers; hand soldered with a soldering iron. The Sensirion S8 requires a 5 V supply (its NDIR heater draws current pulses of up to ~150 mA) and about 30 s of preheat time before it reports valid CO₂ values.

Grounding and copper

Both copper layers carry a GND copper pour (one zone on F.Cu + B.Cu, filled, thermal-relief connection to pads with 0.5 mm gap, 0.5 mm thermal bridge). Four rule-area keep-outs (pads and footprints excluded, copper pour allowed) mark the module areas, including the ESP32-C3 antenna region.

Firmware

ESPHome on esp32-c3-devkitm-1, framework esp-idf. Config template: firmware/esp-sensair.yaml.example, secrets template: firmware/secrets.yaml.example. The flashed config and secrets.yaml are git-ignored — never commit live keys.

Item Value
I²C SDA = GPIO7, SCL = GPIO8, bus scan enabled
BME280 I²C address 0x76, temperature / pressure / humidity, 60 s interval
Sensirion S8 UART TX = GPIO21, RX = GPIO20, 9600 baud, 60 s interval
Home Assistant native ESPHome API with noise encryption, OTA updates
Network static IP, fast_connect, fallback hotspot + captive portal

Known issues and lessons learned (v1 → v2)

  1. Power comes in through the ESP32-C3 devkit's USB-C 5 V pin. The Sensirion S8 heater draws current pulses of up to ~150 mA, and that current travels through the module's USB connector, its 5 V rail and its onboard regulator path. v2: a dedicated 5 V power input (2.54 mm header, screw terminal or DC barrel jack) wired straight to the 5 V net, independent of the module's USB-C, which then stays a programming/debug connection. Add to that: 220–470 µF bulk plus 100 nF at the S8 supply pins, reverse-polarity protection (series Schottky or P-MOSFET), a jumper to back-feed 5 V from the module's USB for programming-only setups, and a power-good LED. Before changing anything: measure the ripple and droop on the 5 V rail with an oscilloscope while the S8 heater fires, so v2 fixes a quantified problem.
  2. Single 100 nF decoupling capacitor for the whole board. v2: 100 nF per supply pin, bulk capacitance at each sensor, and supply stitching vias into the ground pour.
  3. No mounting holes. The board is held by its connectors only. v2: four M2.5 holes.
  4. No I²C pull-ups populated. The design relies on the pull-ups of the BME280 breakout. v2: add 4.7 kΩ pull-up footprints on SDA/SCL.
  5. Schematic is not annotated (references U, U, U), so KiCad BOM export is unusable. v2: annotate, set MPNs, and export the BOM from the schematic.
  6. Leaded HASL is not RoHS-compliant. v2: HASL lead-free, and ENIG for any impedance-controlled design.
  7. Project name contained +. It propagated into the Gerber file names (esp+sensair-Front.gbr), which some fabricator upload portals and drill parsers reject. Fixed: the project and all fabrication files are now named esp-sensair.
  8. Antenna keep-out for the ESP32-C3 module is defined as a rule area (pads and footprints excluded, copper pour allowed). v2: verify it against the module datasheet's antenna keep-out figure, and check the pour's clearance to the antenna region specifically.

Repository layout

.
├── esp-sensair.kicad_pro        KiCad project
├── esp-sensair.kicad_sch        schematic
├── esp-sensair.kicad_pcb        board layout
├── esp_sensair_stuff.kicad_sym  custom symbols (ESP32-C3, Sensirion S8, BME280)
├── esp_sensair_stuff.pretty/    custom footprints, drawn from component datasheets
├── fp-lib-table                 project-local footprint library table (${KIPRJMOD})
├── sym-lib-table                project-local symbol library table (${KIPRJMOD})
├── bom/                         bill of materials (CSV)
├── docs/                        schematic PDF, layer plots, 3D render
├── firmware/                    ESPHome config templates, secrets templates, notes
├── photos/                      photographs of the assembled board (also release assets)
├── CHANGELOG.md                 release history
├── LICENSE                      CERN-OHL-S-2.0 (hardware)
└── LICENSE.MIT                  MIT (firmware config, BOM, docs)

(Fabrication outputs — Gerber X2, Excellon drills, job file, upload zip — are generated
from the design and published as release assets, not committed to the tree.)

Rebuilding the board

  1. Open esp-sensair.kicad_pro in KiCad 10.
  2. Run DRC; fix anything you change.
  3. Export Gerbers/drill (the settings are stored in the project) and upload the resulting zip to your fabricator with the parameters from the fabrication table.
  4. Order parts per BOM, solder through-hole parts and pin headers.
  5. Flash the ESPHome configuration and add the device to Home Assistant.

License

Dual licensed, SPDX identifiers:

Scope Licence File
Hardware: schematic, layout, symbols, footprints, fabrication data CERN-OHL-S-2.0 (CERN Open Hardware Licence v2, strongly reciprocal) LICENSE
Firmware configuration, BOM, scripts, documentation MIT LICENSE.MIT

SPDX notices to keep in derived files:

SPDX-License-Identifier: CERN-OHL-S-2.0
SPDX-FileCopyrightText: 2026 Hannes Gehrmann

Making a board from these files and distributing it is explicitly allowed; if you modify the design and convey it, CERN-OHL-S requires you to publish the modified design under the same licence and to mark what you changed (sections 3.2 and 3.3).

Acknowledgements

The hardware design — schematic, layout, symbols, footprints, fabrication data — and the firmware configuration are by Hannes Gehrmann.

The documentation and repository tooling in the v1.0.0 release — this README, CHANGELOG.md, the project-local library tables (fp-lib-table, sym-lib-table), the .gitignore, and the release packaging (project rename, moving fabrication outputs to release assets) — were drafted with OpenCode running the Qwen3.8 Flash Next model, and reviewed by the maintainer.

S
Description
No description provided
Readme
61 MiB
0 Stars 1 Watchers 0 Forks
Languages
CSV 100%