This repository contains the firmware for SAMBA v2, a low-cost indoor environmental quality (IEQ) monitor developed by the IEQ Lab at The University of Sydney. SAMBA runs on ESPHome, an open-source firmware framework for ESP32 microcontrollers. The minimum supported version of ESPHome is 2026.8.1.
ESPHome devices are configured using YAML. This repository is structured so that each sensor or function has its own config file in config/, which are imported as packages by the main samba.yaml.
├── samba.yaml # main config
├── config/
| ├── adc.yaml # analog-to-digital converter
| ├── airspeed.yaml # anemometers
| ├── co2.yaml # CO2 sensor
| ├── diagnostics.yaml # device diagnostics
| ├── esp32.yaml # ESP32 board and framework
| ├── globals.yaml # global variables
| ├── homeassistant.yaml # Home Assistant API
| ├── illuminance.yaml # illuminance sensor
| ├── influx.yaml # InfluxDB connection
| ├── led.yaml # status LED
| ├── ota.yaml # over-the-air updates
| ├── pm25.yaml # PM2.5 sensor
| ├── rtc.yaml # real-time clock
| ├── sample.yaml # sampling loop
| ├── sd.yaml # SD card logging
| ├── spl.yaml # sound pressure level
| ├── substitutions.yaml # secrets and substitutions
| ├── tair.yaml # air temperature and RH
| ├── tglobe.yaml # globe temperature
| ├── tvoc.yaml # TVOC and NOx sensor
| └── wifi.yaml # wireless networking
├── components/ # custom ESPHome components
| ├── influxdb/ # InfluxDB v2 HTTP upload
| ├── sd_spi_card/ # SPI SD card read/write
| ├── senseair_i2c/ # K30/K33 CO2 over I2C
| └── sound_level_meter/ # I2S audio DSP for SPL
├── firmware/ # compiled binaries for OTA
└── pcb/ # hardware design files (Altium)
The components/ directory contains four external components that extend ESPHome:
sound_level_meter— audio DSP for sound pressure level (LAeq, LA90, LA10)senseair_i2c— I2C driver for the K30 CO2 sensorinfluxdb— HTTP upload to an InfluxDB v2 bucketsd_spi_card— FAT32 SD card logging via SPI
| Parameter | Sensor | Config | Component |
|---|---|---|---|
| Temperature / RH | Sensirion SHT40 | tair.yaml | sht4x |
| Globe Temperature | NTC Thermistor | tglobe.yaml | ntc |
| Air Speed | Thermal Anemometer | airspeed.yaml | ads1115 |
| CO2 | CO2Meter K30 | co2.yaml | senseair_i2c |
| PM2.5 | Plantower PMS5003T | pm25.yaml | pmsx003 |
| VOC / NOx Index | Sensirion SGP40 | tvoc.yaml | sgp4x |
| Illuminance | TI OPT3001 | illuminance.yaml | opt3001 |
| Sound Pressure Level | ICS-43434 Microphone | spl.yaml | sound_level_meter |
Most sensors are natively supported by ESPHome. The CO2 sensor and sound pressure level measurement use custom external components in components/.
SAMBA continuously measures environmental parameters, applies quality filters and a moving median, then publishes a summary every 5 minutes. The routine is:
- Each sensor measures at its own frequency (see table below).
- Raw readings pass through filters — NaN rejection, clamping, moving median — and calibration functions.
- Every 5 minutes, a cron task on the RTC triggers the
sensor_samplescript. - The script updates all template sensors, then publishes to Home Assistant, InfluxDB, and/or the SD card. The LED flashes white with each upload.
- Publishing is skipped during the first 2 minutes after boot (sensor warm-up).
| Measure | Frequency | Filters |
|---|---|---|
| Air Temperature | 30s | clamp; moving median; linear calibration |
| Relative Humidity | 30s | clamp; moving median; linear calibration |
| Globe Temperature | 30s | clamp; moving median; linear calibration |
| Air Speed | 2s | clamp; moving median; multivariate calibration; clamp |
| CO2 | 30s | filter; clamp; moving median; linear calibration; clamp |
| PM2.5 | ~1s | clamp; moving median |
| VOC Index | 30s | moving median |
| NOx Index | 30s | moving median |
| Illuminance | 20s | clamp; moving median; linear calibration; clamp |
| Sound Pressure Level | 500ms | sos; moving median; quantile (LA90, LA10) |
Published measurements are sent every 5 minutes to one or more of the following backends:
Home Assistant — An open-source home automation platform. Easy to use but requires additional hardware (e.g. Raspberry Pi) and some configuration to retain raw data beyond 10 days. Best suited for projects that also collect other measurements (e.g. energy, window/door state). Communication uses the native ESPHome API component.
InfluxDB — An open-source time series database optimised for IoT. Can be self-hosted or used via InfluxData's cloud service. Requires an active internet connection. Best suited for field deployments of multiple SAMBAs. Communication uses the custom influxdb component with building, level, and zone IDs as tags (set as global variables). See the InfluxDB key concepts for background.
SD Card — Local CSV logging via the sd_spi_card component. Files are named using the device MAC address and UTC timestamp. No network connection required.
A single RGB LED on the board reports device state. One rule covers the whole scheme: colour identifies the subsystem, and pulsing versus solid identifies severity. A slow pulse is a warning the device expects to recover from on its own; a steady light means the fault is sustained. Only the ADS1115 and K30 escalate to a restart, and only after an hour of uptime. Brightness is deliberately low throughout so a rack of units is not distracting in an occupied office.
| LED | Meaning | What to do |
|---|---|---|
| Green, flashing | Booting | Nothing — clears after startup |
| White, brief flash | 5-minute sample taken and uploaded | Nothing — this is the healthy heartbeat |
| Off | Running normally | Nothing |
| Amber, pulsing | Globe temperature / air speed unresponsive ~3 min | Watch — often transient |
| Amber, solid | Same, ~5 min. Restarts once the fault has covered 35% of the last hour (about 25 min continuous) | Check the RJ45 cable to the remote board, then reseat both ends |
| Blue, pulsing | CO2 (K30) failed 3 consecutive reads | Watch — usually self-recovers |
| Blue, solid | CO2 failed 4 or more; restarts once it has failed 67% of the last hour (about 65 min of near-total failure) | Check the K30; a persistent fault is often board-specific rather than the sensor |
| Magenta, pulsing | VOC / NOx (SGP4x) failed 4 consecutive reads | Watch — usually self-recovers |
| Magenta, solid | VOC / NOx failed 6 or more. Never restarts: the sensor keeps retrying itself, and a reboot would discard its month-long baseline | Check the sensor |
The LED is applied from a single 10-second poll of the error counters rather than from each sensor's error handler, so it survives the sample heartbeat and returns to off within about ten seconds of the sensor recovering. If two subsystems are in trouble at once, the more severe one shows, and the ADS1115 wins a tie.
A lit LED does not mean the device has stopped working. A failed sensor is reported as
nan and left out of the upload, while every other measurement continues to be sampled and
sent. Restarts are rate-limited to at most one per hour precisely so that one dead sensor
cannot take the whole unit off the air.
Amber is the one worth attention in the field: the remote board connects over an RJ45 lead, and a marginal cable is the most common cause of it.
Users are free to modify the SAMBA firmware to suit their needs. We recommend familiarity with ESPHome and microcontroller programming before doing so. To get started:
- Define your project-specific parameters in
secrets.yaml. - Modify the relevant
.yamlfiles inconfig/. - Compile and upload via USB-C with
esphome run samba.yaml, or wirelessly withesphome run samba.yaml --device <IP_ADDRESS>.
Calibration coefficients are stored as persistent global variables and can be updated either by editing the lambda functions in the relevant config files or by modifying the globals directly.
The user is responsible for managing any device running modified firmware.
SAMBA devices check for firmware updates every Monday at 4 am by comparing against firmware/manifest.json. If a new version is available, the update is applied automatically with random jitter to avoid fleet-wide simultaneous downloads. Automatic updates can be disabled with the Automatic Updates switch (see Deployment).
SAMBA devices are shipped pre-calibrated, with their location tags (building, level, zone) and calibration coefficients already set by the IEQ Lab. Follow these steps to connect a new SAMBA to your network and start sampling:
- Power on the SAMBA. The status LED will strobe red, green, and blue to indicate it is in setup mode.
- Connect to the hotspot. Using a phone or laptop, join the
samba_connectWiFi network and open the captive portal at http://192.168.4.1. - Enter WiFi credentials. Select the target 2.4 GHz network from the list and enter the password. The SAMBA will connect and begin sampling automatically. The LED will blink green during the warm-up period and then turn off once it enters the normal sampling routine.
There is no web interface on the device. The location tags, the InfluxDB Upload / SD Card Write / Automatic Updates switches and the calibration coefficients are exposed over the ESPHome native API, so they can be viewed and changed from Home Assistant or with the IEQ Lab's samba_app laptop client (its Identify SAMBA button blinks the LED to pick one unit out of a batch). If you need a SAMBA recalibrated or re-tagged, please reach out — see Project Maintenance below.
This is an active project to build an open research platform for healthy, high-performance buildings. If you're interested in using SAMBA in your project or contributing to its development, start a Github discussion or email Tom.