ESP32 + SGP40 VOC Sensor with Home Assistant (ESPHome & MQTT) – Complete 2025 Guide

Indoor air quality is not just about CO₂. Volatile organic compounds (VOCs) from cleaning products, furniture, paints, cooking, and people can significantly affect comfort and health. The SGP40 is a modern VOC sensor designed specifically for indoor air quality applications, and when combined with an ESP32 and Home Assistant, it becomes a powerful monitoring tool.

This guide shows how to integrate the SGP40 VOC sensor with ESP32 and Home Assistant, using both ESPHome and MQTT.


1. What the SGP40 Measures

The SGP40 does not directly output “ppm” like CO₂ sensors. Instead, it produces a VOC index, typically in the range:

  • 0–100: Excellent air quality
  • 100–200: Normal indoor air
  • >200: Polluted / stuffy / cooking / chemicals

The exact scale depends on the library or ESPHome implementation, but the general principle is the same: higher index = worse air quality.


2. Hardware Required

  • ESP32 DevKit
  • SGP40 VOC sensor breakout
  • Jumper wires
  • USB cable
  • (Optional) Temperature/humidity sensor (e.g. SHT45) for compensated readings
  • (Optional) Ventilated enclosure

3. Wiring the ESP32 to SGP40

The SGP40 uses I2C.

I2C Wiring

ESP32 → SGP40
3.3V  → VIN
GND   → GND
GPIO21 → SDA
GPIO22 → SCL

If another I2C sensor (BME280, SHT45, etc.) is already connected, the SGP40 can share the same SDA/SCL lines.


4. Method 1 – ESPHome Integration

ESPHome provides native support for SGP40 through the sgp4x platform in newer builds (check ESPHome docs for exact availability). A typical configuration exposes a VOC index sensor.

4.1 Basic ESPHome YAML for SGP40

esphome:
  name: esp32-sgp40
  platform: ESP32
  board: esp32dev

wifi:
  ssid: "YOUR_WIFI"
  password: "YOUR_PASSWORD"

logger:
api:
ota:

i2c:
  sda: 21
  scl: 22
  scan: true

sensor:
  - platform: sgp4x
    voc_index:
      name: "SGP40 VOC Index"
    update_interval: 10s

This configuration:

  • Scans the I2C bus
  • Reads the VOC index every 10 seconds
  • Exposes a sensor.sgp40_voc_index entity in Home Assistant automatically

5. Method 2 – MQTT Integration

For setups that use MQTT for all ESP32 nodes, the SGP40 can be read via Arduino code and published as JSON to Home Assistant.

5.1 Home Assistant configuration.yaml – MQTT VOC Sensor

Add under the existing mqtt: section:

mqtt:
  sensor:
    - name: "Living Room VOC Index"
      state_topic: "home/air/voc"
      value_template: "{{ value_json.voc_index }}"
      unit_of_measurement: "index"

Home Assistant will then read messages published as JSON on the topic home/air/voc.


6. ESP32 Arduino MQTT Code for SGP40

The following sketch:

  • Connects the ESP32 to WiFi
  • Reads SGP40 VOC index
  • Publishes JSON to the MQTT broker
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include "SensirionI2CSgp40.h"

#define WIFI_SSID "YOUR_WIFI"
#define WIFI_PASS "YOUR_PASSWORD"
#define MQTT_SERVER "192.168.0.10"

WiFiClient espClient;
PubSubClient client(espClient);
SensirionI2CSgp40 sgp40;

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);

  sgp40.begin(Wire);

  WiFi.begin(WIFI_SSID, WIFI_PASS);
  while (WiFi.status() != WL_CONNECTED) delay(500);

  client.setServer(MQTT_SERVER, 1883);
}

void loop() {
  if (!client.connected()) {
    while (!client.connected()) client.connect("ESP32_SGP40");
  }

  uint16_t vocIndex = 0;
  uint16_t srawVoc = 0;  // raw value, if needed

  // Simplified reading: some libs provide vocIndex directly,
  // in others you calculate from srawVoc via algorithm.
  // Example assuming direct vocIndex read:
  sgp40.measureRawSignal(srawVoc);
  // Here, a VOC algorithm would convert srawVoc → vocIndex.
  // For illustration, assume vocIndex = srawVoc / 10:
  vocIndex = srawVoc / 10;

  String json = "{";
  json += "\"voc_index\":" + String(vocIndex);
  json += "}";

  client.publish("home/air/voc", json.c_str());

  client.loop();
  delay(10000);
}

Note: Real-world implementations use Sensirion’s official VOC index algorithm on raw values (srawVoc). Library examples usually show how to compute this properly; the above is simplified for structure and MQTT integration.


7. Home Assistant Dashboard Example

A simple way to visualize the VOC index:

type: vertical-stack
cards:
  - type: sensor
    entity: sensor.living_room_voc_index
  - type: history-graph
    entities:
      - sensor.living_room_voc_index
    hours_to_show: 24

For a more intuitive display, thresholds can be added using custom cards (e.g. colored gauges).


8. Typical VOC Index Interpretation

While the precise mapping depends on implementation, a general guideline:

  • 0–100 → Excellent
  • 100–200 → Normal
  • 200–400 → Poor
  • >400 → Very poor

These levels can be used to drive automations.


9. Example Automations

9.1 Send a notification when VOC index is high

automation:
  - alias: "High VOC Alert"
    trigger:
      - platform: numeric_state
        entity_id: sensor.living_room_voc_index
        above: 200
    action:
      - service: notify.mobile_app
        data:
          message: "VOC levels are high. Consider opening a window or reducing chemicals."

9.2 Automatically turn on ventilation fan

  - alias: "Ventilation on High VOC"
    trigger:
      - platform: numeric_state
        entity_id: sensor.living_room_voc_index
        above: 250
    action:
      - service: fan.set_percentage
        target:
          entity_id: fan.cabinet_fan
        data:
          percentage: 100

9.3 Scale fan speed based on VOC index

  - alias: "Dynamic Ventilation by VOC"
    trigger:
      - platform: state
        entity_id: sensor.living_room_voc_index
    action:
      - choose:
          - conditions: "{{ states('sensor.living_room_voc_index') | float > 350 }}"
            sequence:
              - service: fan.set_percentage
                target:
                  entity_id: fan.cabinet_fan
                data:
                  percentage: 100
          - conditions: "{{ states('sensor.living_room_voc_index') | float > 250 }}"
            sequence:
              - service: fan.set_percentage
                target:
                  entity_id: fan.cabinet_fan
                data:
                  percentage: 70
          - conditions: "{{ states('sensor.living_room_voc_index') | float > 150 }}"
            sequence:
              - service: fan.set_percentage
                target:
                  entity_id: fan.cabinet_fan
                data:
                  percentage: 40
        default:
          - service: fan.turn_off
            target:
              entity_id: fan.cabinet_fan

10. Combining VOC with Other Sensors

The SGP40 works best when combined with:

  • Temperature sensor (e.g. SHT45)
  • Humidity sensor
  • CO₂ sensor (SCD30 / SCD41)

A complete air quality setup might include:

  • CO₂ levels
  • VOC index
  • Temperature
  • Humidity

These can be grouped on a single Home Assistant dashboard for a full indoor air quality overview.


11. Troubleshooting

Sensor not detected

  • Check I2C wiring (SDA/SCL pins)
  • Make sure 3.3V is used, not 5V
  • Enable scan: true in ESPHome’s i2c: section

VOC index stuck or unnatural

  • New sensors need burn-in time (several hours)
  • Avoid enclosing the sensor in an airtight box
  • Keep away from direct airflow from fans or windows

Values look noisy

  • Use longer update_interval (10–60 seconds)
  • Apply Home Assistant statistics or filter sensors for smoothing

Keywords

esp32 sgp40
home assistant voc sensor
esphome sgp40
mqtt voc index esp32
indoor air quality esp32
sgp40 esp32 wiring
voc index home assistant
esp32 air quality monitoring

Newsletter Updates

Enter your email address below and subscribe to our newsletter

Leave a Reply

Your email address will not be published. Required fields are marked *