A gamified bad breath detector using BME680 VOC sensor with ESP8266/ESP32 microcontrollers and a companion web app. Measure your breath quality, track improvements over time, and unlock achievements!
BreathBuddy uses the BME680 environmental sensor to measure:
- IAQ (Indoor Air Quality) - Overall breath quality score (0-500)
- COβ Equivalent - Estimated COβ levels in ppm
- VOC Equivalent - Volatile organic compounds in ppm
- Temperature, Humidity, Pressure - Environmental conditions
- Gas Resistance - Raw sensor resistance (kΞ©)
The system supports two microcontroller platforms:
| Platform | Protocol | Features |
|---|---|---|
| ESP32 (Recommended) | WebSocket | BSEC library, persistent calibration, button + buzzer |
| ESP8266 | HTTP REST | Basic readings, EMA smoothing |
| Component | Qty | Notes |
|---|---|---|
| ESP32 DevKit or ESP8266 NodeMCU | 1 | ESP32 recommended for BSEC support |
| BME680 Breakout Board | 1 | IΒ²C interface (Adafruit, Pimoroni, or generic) |
| Tactile Push Button | 1 | ESP32 only - for triggering readings |
| Piezo Buzzer (Active) | 1 | ESP32 only - for audio feedback |
| Jumper Wires | ~8 | Male-to-female recommended |
| Breadboard | 1 | Optional, for prototyping |
The BME680 uses IΒ²C communication. Common breakout boards have these pins:
| Pin | Description |
|---|---|
| VCC / VIN | Power (3.3V) |
| GND | Ground |
| SDA | IΒ²C Data |
| SCL | IΒ²C Clock |
| SDO | IΒ²C Address Select (GND = 0x76, VCC = 0x77) |
| CS | SPI Chip Select (leave unconnected for IΒ²C) |
BME680 ESP32
βββββββ βββββ
VCC ββββββββ 3.3V
GND ββββββββ GND
SDA ββββββββ GPIO 21 (IΒ²C SDA)
SCL ββββββββ GPIO 22 (IΒ²C SCL)
SDO ββββββββ GND (for address 0x76)
Button ESP32
ββββββ βββββ
Pin 1 ββββββββ GPIO 33
Pin 2 ββββββββ GND
Buzzer ESP32
ββββββ βββββ
+ (Red) ββββββ GPIO 27
- (Black) ββββ GND
Schematic Diagram (ESP32):
ββββββββββββββββββ
β ESP32 β
β β
BME680 β 3.3V βββββββββΌββββ VCC
βββββββ β GND βββββββββΌββββ GND
β VCC βββββββββββ€ GPIO21 (SDA)βββΌββββ SDA
β GND βββββββββββ€ GPIO22 (SCL)βββΌββββ SCL
β SDA βββββββββββ€ β
β SCL βββββββββββ€ GPIO33 ββββββββΌββββ Button βββ GND
β SDO ββββββGND β GPIO27 ββββββββΌββββ Buzzer+ βββ Buzzer- βββ GND
βββββββ β β
ββββββββββββββββββ
BME680 ESP8266 NodeMCU
βββββββ βββββββββββββββ
VCC ββββββββ 3.3V
GND ββββββββ GND
SDA ββββββββ GPIO 4 (D2)
SCL ββββββββ GPIO 5 (D1)
SDO ββββββββ GND (for address 0x76)
Schematic Diagram (ESP8266):
ββββββββββββββββββ
β ESP8266 β
β NodeMCU β
BME680 β β
βββββββ β 3.3V βββββββββΌββββ VCC
β VCC βββββββββββ€ GND βββββββββΌββββ GND
β GND βββββββββββ€ GPIO4 (D2)βββββΌββββ SDA
β SDA βββββββββββ€ GPIO5 (D1)βββββΌββββ SCL
β SCL βββββββββββ€ β
β SDO ββββββGND β β
βββββββ ββββββββββββββββββ
-
Arduino IDE (v2.x recommended) or PlatformIO
-
Required Libraries (install via Library Manager):
Adafruit BME680 LibraryArduinoJson(v6.x)- ESP32 Only:
BSEC Software Libraryby BoschWebSockets_Generic
- ESP8266 Only:
ESP8266WiFi(bundled with ESP8266 core)ESP8266WebServer(bundled with ESP8266 core)
-
Board Support:
- ESP32: Add
https://dl.espressif.com/dl/package_esp32_index.jsonto Board Manager URLs - ESP8266: Add
http://arduino.esp8266.com/stable/package_esp8266com_index.json
- ESP32: Add
- Create
secrets.hin the appropriate folder (ESP32/orESP8266/):
#pragma once
#define WIFI_SSID "YourNetworkName"
#define WIFI_PASS "YourPassword"- Verify IΒ²C Address - If sensor isn't detected, try changing address:
0x76- SDO pin connected to GND (default)0x77- SDO pin connected to VCC
For ESP32:
# Select Board: ESP32 Dev Module
# Upload Speed: 115200
# Flash Frequency: 80MHzUpload ESP32/esp32-final-program.ino
For ESP8266:
# Select Board: NodeMCU 1.0 (ESP-12E Module)
# Upload Speed: 115200Upload ESP8266/bad-breadth.ino
The companion Next.js app provides a modern dashboard interface:
cd breathalyzer-app
pnpm install # or npm install
pnpm dev # Start dev server at http://localhost:3000Important: Update the WebSocket URL in components/websocket-provider.tsx:
const ws = new WebSocket('ws://YOUR_ESP32_IP:8080/')To find your ESP32's IP address, check the Serial Monitor after boot.
- Power on the device and wait for Wi-Fi connection (check Serial Monitor)
- Note the IP address displayed in Serial Monitor
- Start a test:
- Press the physical button on GPIO 33, OR
- Send
"start"command via WebSocket, OR - Click "Start Test" in the web app
- Follow the countdown (3-2-1 beeps from buzzer)
- Blow on the sensor for 10 seconds
- View results via WebSocket or Serial Monitor
WebSocket Response Format:
{
"iaq": 75.5,
"co2_eq": 650.2,
"voc_eq": 1.25,
"temp": 24.5,
"hum": 45.2,
"pres": 1013.25,
"gas_kOhm": 125.5
}- Power on and connect to Wi-Fi
- Navigate to
http://YOUR_ESP8266_IP/in a browser - Click "Get Reading" button to sample
- View JSON data at
http://YOUR_ESP8266_IP/data
HTTP Response Format:
{
"temperature": 24.5,
"humidity": 45.2,
"pressure": 1013.25,
"voc": 125.5,
"vocSmooth": 118.3
}| IAQ Range | Rating | Meaning |
|---|---|---|
| 0-50 | π Excellent | Fresh breath! |
| 51-100 | π Good | Normal, healthy |
| 101-150 | Slight odor detected | |
| 151-200 | π· Poor | Noticeable bad breath |
| 200+ | β Very Poor | Strong halitosis |
| Command | Response | Description |
|---|---|---|
Connect to ws://IP:8080/ |
"Connected to ESP32 BSEC server" |
Initial connection |
Send "start" |
JSON payload after 13s | Triggers 3-2-1 countdown + 10s sampling |
| Endpoint | Method | Response |
|---|---|---|
/ |
GET | HTML interface |
/data |
GET | JSON sensor reading |
- Check wiring - Ensure SDA/SCL connections are correct
- Verify IΒ²C address - Try both
0x76and0x77 - Run IΒ²C scanner to find connected devices:
#include <Wire.h>
void setup() {
Serial.begin(9600);
Wire.begin();
for (byte addr = 1; addr < 127; addr++) {
Wire.beginTransmission(addr);
if (Wire.endTransmission() == 0) {
Serial.printf("Found device at 0x%02X\n", addr);
}
}
}
void loop() {}- Check SSID/password in
secrets.h - Ensure 2.4GHz network (ESP8266/ESP32 don't support 5GHz)
- Move closer to router during initial setup
The BSEC library requires a burn-in period for accurate IAQ readings:
- First ~5 minutes: IAQ accuracy = 0 (unreliable)
- 30+ minutes: IAQ accuracy = 1-2 (improving)
- 24+ hours: IAQ accuracy = 3 (fully calibrated)
Calibration state is persisted to NVS flash and restored on reboot.
- Allow sensor to warm up for 2-3 minutes
- Avoid touching the sensor directly
- Test in a well-ventilated area first to establish baseline
- Keep sensor away from strong odors during calibration
MIT License - feel free to use and modify for your own projects!
- Bosch BSEC Library for advanced gas sensing algorithms
- Adafruit BME680 Library for sensor drivers