Beige Air Quality Sensor, sitting on bench, nice plant background

DIY Air Quality Sensor for Home Assistant Using an ESP32-C5

Indoor air quality is one of those things you usually do not think about until a room starts feeling off.

Maybe the air feels heavy. Maybe you have been sitting in a closed office for a few hours and cannot work out why you feel flat. Maybe you have just cooked dinner, used a cleaning spray, or lit a candle, and the room suddenly feels different.

The problem is that most of what affects indoor air is invisible. Fine particles, stale air, and fumes can all build up without much obvious warning. You notice the feeling before you know the cause.

That is what led me to build this DIY air quality sensor for Home Assistant.

This project is an always-on indoor air monitor built around a Seeed Studio XIAO ESP32-C5, a few different sensors, and Home Assistant. It tracks particulate matter, CO2, gas changes, temperature, humidity, and pressure, then sends everything into Home Assistant over MQTT so I can graph it, monitor it, and use it for alerts.

This is not a lab-grade instrument, and that was never the goal. I wanted something practical that could sit in the house full time, quietly collect useful data, and help explain what the air in a room is actually doing.

Don’t Miss the Next Build
Get new build ideas, code snippets, and project updates straight to your inbox!

What this build does

This air quality monitor measures:

  • PM1.0, PM2.5, and PM10
  • CO2
  • gas changes from sprays, fumes, and general air quality events
  • temperature
  • humidity
  • pressure

It is designed to be:

  • mains powered
  • always on
  • connected to Home Assistant
  • useful for long-term trends, not just one-off readings

If you want a small indoor sensor that gives you more than a single air quality number, this kind of setup works really well.

Parts used

These are the main parts I used in this build:

Before you build

Before putting everything together, there are a few things worth checking.

First, this is best treated as an always-on indoor monitor, not a battery device. Some of these sensors benefit from stable power and time to settle, so mains power makes a lot more sense here.

Second, check the voltage requirements for each sensor. Do not assume everything is happy on the same rail just because it uses I2C. Some modules are fine on 3.3 V, while others are built around 5 V.

Third, make sure you know the I2C addresses of each device before final assembly. If two devices share the same address and neither can be changed, that becomes a problem very quickly.

And finally, keep the physical layout in mind from the start. Airflow, heat from the board, and sensor placement all affect how useful the readings are.

Why I chose these sensors

I wanted a build that could tell me more than just whether the air was “good” or “bad.” Different sensors pick up different kinds of events, and that extra context is what makes the data useful.

PM sensor

The particulate sensor measures PM1.0, PM2.5, and PM10.

This is useful for spotting things like dust, smoke, cooking particles, aerosols, and anything else that adds fine particles to the air. In day-to-day use, PM2.5 is usually one of the most useful readings because it gives a good picture of the smaller particles that build up during normal indoor life.

DIY Air Quality Sensor Monitor
Source: California Air Resources Board

CO2 sensor

The SCD41 is one of the most useful sensors in the build because it tells you about ventilation.

This is not carbon monoxide. It is a way of seeing whether a room is getting stuffy because people are breathing in a space without enough fresh air coming in. Bedrooms, offices, and closed rooms are where this becomes most useful.

Source: Health Canada

Gas sensor

The multichannel gas sensor is best treated as a trend sensor, not a precision instrument.

I do not use it to chase exact gas concentrations. I use it to spot changes. If the readings jump after using cleaner, deodorant, fly spray, candles, or while cooking, that tells me something in the room changed.

Temperature, humidity, and pressure

The BME280 adds extra context.

Temperature affects comfort. Humidity matters for how a room feels and can also be useful for things like condensation risk. Pressure is less important for everyday air quality decisions, but it is still handy to log alongside the rest of the data.

Why I built it this way

A lot of smart sensors are designed around battery life first. That makes sense for some devices, but not for this one.

I wanted this monitor to be powered all the time, with no sleep cycles, no flat batteries, and no gaps in the data. That suits the sensors better and makes the readings more consistent.

For Home Assistant, it is a much better fit too. The monitor can just sit there in the background, always feeding in fresh data instead of only checking the air every now and then.

Main controller and hardware choice

At the centre of the build is the Seeed Studio XIAO ESP32-C5.

It is a compact board, but it has more than enough power for a project like this. One of the things I like about it here is the connectivity. It supports both 2.4 GHz and 5 GHz Wi-Fi, which gives a bit more flexibility depending on the network and where the device ends up being placed.

DIY air quality sensor using the ESP32-C5

I mounted it on the Seeeduino XIAO Expansion Board because it makes the build easier to wire, easier to test, and generally neater to work with.

I also added LEDs so the device can give quick at-a-glance feedback without needing to open Home Assistant every time. They work well, although I would still improve the enclosure in the next revision so the infill pattern is less visible when the LEDs are lit.

Wiring the build

Most of the sensors in this project use I2C, which helps keep the wiring fairly simple. In most cases, that means power, ground, SDA, and SCL.

That said, this is one of those builds where clean wiring matters. Temporary sensor builds have a habit of becoming permanent, and messy wiring is one of the easiest ways to create problems later.

When wiring a setup like this, keep these things in mind:

  • check the voltage requirement for each sensor
  • confirm the I2C address of each device
  • keep wiring runs neat and as short as practical
  • avoid putting unnecessary strain on headers or jumper leads
  • test one sensor at a time before closing the enclosure

Pin map

On the way!

Enclosure and airflow

The enclosure matters more than a lot of people expect.

These sensors only measure the air that reaches them. That means placement and airflow have a real effect on how useful the readings are.

If you put the device in a dead corner, it may respond slowly. If you put it behind a monitor, it may mostly read warm monitor air. If you place it directly under an air conditioning vent, that can skew the readings the other way.

For this build, I wanted an enclosure that allowed natural airflow without forcing direct airflow across the sensors. I also wanted the internal layout to make sense. In the updated version, I refined the fit, adjusted the layout, and gave the BME280 its own small compartment to help separate it from the heat of the rest of the electronics.

That matters most for temperature readings. There is not much point measuring room temperature if the sensor is mostly reading the warmth of its own board.

I did consider adding a fan, but I left it out. A fan would add noise, pull in more dust, and make the build more complicated. For this project, passive airflow made more sense.

Software and Home Assistant integration

On the software side, the build is fairly simple.

The device connects to Wi-Fi, reads the sensors on a schedule, handles warm-up and filtering, publishes the values, and drives the LEDs for local status feedback.

In my setup, I read the sensors every 5 seconds and publish values every 30 seconds. That gives reasonably quick response without flooding Home Assistant with unnecessary updates.

Once the data is in Home Assistant, the project becomes much more useful. This is where I can graph everything over time, compare readings, and create alerts that actually make sense.

The long-term trends are where the value really shows up. A single reading does not always tell you much, but patterns do.

A simple dashboard showing some of the data I have captured.

Code

On the way!

Warm-up and sensor behaviour

One of the easiest ways to make a project like this feel better in real use is handling sensor behaviour properly instead of just dumping raw values everywhere.

The PM sensor needs a short warm-up period after boot, so the first readings are not always reliable. It makes more sense to let it settle before treating the data as valid.

The SCD41 also benefits from sensible placement and stable operation. If it is boxed in badly or not given time to settle, the readings will be less useful than they should be.

The gas sensor needs the most context of all. I do not use it as an exact measurement tool. I use it as a way to spot when the air changes.

This is how I think about the whole sensor mix:

  • PM and CO2 are the strongest core readings
  • the gas sensor helps spot events
  • temperature and humidity add context

What the data looks like in real life

This is where a build like this gets interesting.

For CO2, one of the easiest tests is simply sitting in a small room with the door closed for a while. In that kind of space, the readings will usually climb over time. Open a window or improve ventilation, and they should start to drop again.

For particulate matter, cooking is a good test. Vacuuming and dusting are useful too. These can push PM readings up quickly, and then you can watch how long it takes for the room to clear.

For the gas sensor, sprays and fumes are where it becomes most useful. Cleaning products, deodorant, fly spray, candles, and cooking fumes can all create obvious changes in the readings.

That is one of the biggest benefits of combining multiple sensor types in one device. Different activities show up in different ways, and having that extra context makes it much easier to work out what is actually happening.

Measuing CO2 levels over the span of about a week in my office

How I interpret the readings

For me, the most useful part of a setup like this is not just seeing numbers. It is learning what normal looks like in your own house.

A brief spike is not always a problem. Indoor air changes constantly during normal life. Cooking, cleaning, vacuuming, opening doors, and even just sitting in a small room for a while can all shift the readings.

With PM, I care more about what caused the increase and how long it lasts.

With CO2, I see it as one of the clearest indicators of whether a room is getting enough fresh air.

With the gas sensor, I focus on sudden changes rather than the absolute number.

The longer the monitor runs, the more useful it becomes. Over time, you start to recognise patterns in your own home and understand what pushes the readings up, what clears the air quickly, and which rooms need more ventilation than you thought.

That is really the point of the build. It turns that vague feeling of “the air feels off” into something you can actually see and respond to.

What I would improve next time

Even though this version is already useful, there is still plenty I would refine in a future revision.

A small display for live readings would be a nice addition. A light sensor so the device could dim itself at night would also make sense. The LEDs work well for quick visual status, but I would like to improve the enclosure so the infill pattern is less visible when they are lit.

On the software side, there is always room to keep refining thresholds, dashboards, and alert logic. That is one of the nice things about a build like this. Once the hardware is working well, the software side can keep improving over time.

Final thoughts

This project ended up being exactly what I wanted it to be: a practical, always-on indoor air quality monitor that gives useful data and integrates neatly into Home Assistant.

It is not about chasing perfect lab-grade accuracy. It is about making indoor air easier to understand in a way that is actually useful day to day.

If a room feels stale, I can check CO2. If cooking fills the air with particles, I can see it. If a spray or cleaner changes the air, the sensor usually catches that too.

More than anything, it removes the guesswork.

And once you can see what the air in a room is actually doing, it becomes much easier to know when to open a window, improve ventilation, or simply understand why a space feels off.

FAQ

What does a DIY air quality sensor measure?

A DIY air quality sensor can measure things like PM2.5, PM10, CO2, temperature, humidity, pressure, and general gas changes depending on the sensors used.

Is CO2 useful for indoor air quality monitoring?

Yes. CO2 is one of the most useful readings for understanding ventilation in bedrooms, offices, and other closed rooms.

Can I use an ESP32 with Home Assistant for air quality monitoring?

Yes. An ESP32 is a good fit for a DIY Home Assistant air quality sensor because it can collect sensor data and send it to Home Assistant over Wi-Fi using MQTT or ESPHome.

Is this build meant to be lab accurate?

No. This build is designed to be practical and useful for trends, events, and general indoor air monitoring rather than certified scientific measurement.

Some of the links in this post may be affiliate links. If you buy through them, I may earn a small commission at no extra cost to you.

Leave a Reply

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