Measuring CO2 levels using a Raspberry Pi, Python and the Senseair S8

Nick Doornekamp
4 min readJan 5, 2021

An even slightly elevated CO2 concentration can negatively impact cognitive capabilities. And inversely: reducing CO2 concentration in an office, may improve them. That’s not news: since 2012 Dutch building codes specify a maximum of 1000 ppm for schools - a value that is commonly mentioned as the threshold above which negative effects occur.

A modern office is likely to have this covered through central ventilation and airconditioning, but like many others I’ve mostly been working from home these days. Therefore I was curious: what’s the CO2 concentration in my home, specifically my home office? Commercial devices to measure CO2 aren’t cheap, and as I had recently acquired a hammer (Raspberry Pi) this problem looked like a nail to me, so I set out to measure CO2 using that.

Measuring CO2 with a Raspberry Pi and the Senseair S8

A Raspberry Pi alone can’t measure CO2: a specialised sensor is required. After reading this thread, I decided to go for the Senseair S8.

Interaction between the Senseair S8 and the Raspberry Pi happens via UART, using the Modbus protocol. In a nutshell, that means that to interact with the sensor, you send and receive sequences of bytes. Which bytes do what is all documented in the Modbus on Senseair S8. For example, and most importantly, the code below can be used to obtain a CO2-measurement:

Obtaining a CO2 measurement from the Senseair S8

I ended up writing a Python module to neatly wrap this, which you can find on my Github page. It is also published on PyPi, which turned out to be an adventure by itself but is properly documented for example here. As a result, it can now be installed using pip: pip install senseair-s8, and then used with a simple interface:

Obtaining a CO2 measurement from the Senseair S8 using the senseair-s8 module

Is the CO2 concentration in my home office OK?

Using the senseair-s8 module, I took measurements in my home office every minute during a regular working week and logged them to a CSV file. During these measurements, I was ventilating the space as usual (closed windows but open air vents). The following graph shows the CO2 concentration in parts per million (ppm):

CO2 concentration in parts per million (ppm) during a working week

For comparison: in 2019 the outdoors CO2 concentration was 412 ppm (and rising), which seems to be in line with the lowest measured values. There are peaks on Monday and Thursday that morning stand out, which can be explained by me closing the door to the office for an hour or so, as the vacuum robot does its job at that time (so closing the door has a clear impact).

In any case, my conclusion was that during this regular working week the CO2 concentration was well below the 1000 ppm threshold and therefore OK. If it wasn’t, this setup could be extended to, for example, light a LED or sound an alarm whenever the CO2 concentration exceeds a certain threshold (e.g. 1000 ppm), to remind you to open a window or stimulate ventilation otherwise.

CO2 levels vs. presence of a person

As a bonus, I measured not only the CO2, but also whether a person was present. Being the only source of CO2 in the room, this should have a strong influence.

After experimenting with an infrared motion sensor for a bit, I ended up using the HC-SR04 distance sensor to do so. This sensor emits ultrasonic pulses (i.e. sound waves with frequencies higher than humans can hear) which are reflected by solid objects (e.g. walls). By measuring the time between emission and the echo, one can estimate the distance to the object the pulse was reflected by. I had positioned the sensor so it faced the wall, but was blocked by my arms whenever I was at my desk. This way the distance measurement could tell me whether someone was present:

  • If the measured distance is approximately 170 cm (that’s how far the sensor was from the wall), then nobody is at the desk;
  • If the measured distance is either smaller than that (i.e. the pulse reflected on the person at the desk) or no echo was perceived (i.e. the pulse was absorbed or deflected by the person at the desk), then somebody is at the desk.

Despite requiring me to be thoughtful of where to place objects such as coffee mugs on my desk during measurements, this setup gave some pretty consistent results:

CO2 concentration (in ppm) and an indicator whether a person is present over time

Besides showing that, indeed, CO2 concentration strongly correlates to a person being present as expected, there are several other patterns to be recognised:

  • Lunch breaks in the middle of each workday, longer on Monday and Thursday to take a quick run outside;
  • Usually my girlfriend or I spent one or two hours at the desk after dinner, for studying, browsing the web, writing this blog, etc.



Nick Doornekamp

Software Engineer at Alliander | Cycling & speedskating enthusiast