rpine lab Tech Blog

Tech blog covering a wide range of topics, including my hobby of programming (web and backend), setting up a home lab, and electronics projects using microcontrollers.

🪟Connecting a CO2 Sensor to StackChan for Ventilation Advice

Connecting a CO2 Sensor to StackChan for Ventilation Advice
Table of contents
🤖
This article was AI-translated. Some nuances may differ from the original Japanese version.

Introduction

I connected an SCD41-based CO2 sensor to M5StackChan and enabled it to report real-time CO2 concentration, temperature, and humidity through conversation using a built-in MCP tool.

When you ask StackChan "Should I ventilate the room?", it retrieves sensor data via the get_co2_data MCP tool and responds with ventilation advice. CO2 concentration is a useful indicator of air quality, and 1000 ppm is commonly cited as a guideline for when to ventilate. This article configures StackChan to reference this threshold and judge ventilation timing.

This article covers CO2L Unit assembly and wiring, firmware customization with SCD41 support, and verification.

Equipment

Item Notes Purchase URL
M5StackChan (M5Stack official version) Main robot body M5Stack Store
M5Stack Unit CO2L (SCD41) CO2/temperature/humidity sensor M5Stack Store
M5Stack GROVE-compatible cable 5 cm (10-pack) For Port.A connection (optional) M5Stack Store
LEGO Technic fixing peg ×2 For sensor mounting (optional) -
Equipment: from left, M5StackChan body, Unit CO2L (CO2 sensor), Grove cable included with the unit (unused), separately purchased Grove cable (5 cm), and LEGO fixing pegs ×2 (reused from an M5Stack servo kit)
Equipment: from left, M5StackChan body, Unit CO2L (CO2 sensor), Grove cable included with the unit (unused), separately purchased Grove cable (5 cm), and LEGO fixing pegs ×2 (reused from an M5Stack servo kit)

Wiring & Assembly

The SCD41 by Sensirion uses photoacoustic sensing technology and measures CO2 concentration along with temperature and humidity. The CO2L Unit is an M5Stack Grove module built around this sensor with I2C address 0x62. Measurement ranges are 400–5000 ppm for CO2, -10–60°C for temperature, and 0–95% RH for humidity.

Connect the CO2L Unit to StackChan's Port.A (the red connector on the left side) via a Grove cable. While the 20 cm cable included with the unit works fine, the separately available 5 cm cable results in less cable slack.

Port.A (Grove) pin assignments:

Grove Pin Color Signal CoreS3 GPIO
1 Yellow SCL G1
2 White SDA G2
3 Red 5 V
4 Black GND

Both StackChan and M5Stack units have LEGO-compatible mounting holes, so you can use fixing pegs for a secure and clean installation. (I reused pegs from an M5Stack servo kit I already had.)

Left side of StackChan before mounting — insert fixing pegs into the LEGO holes at the top to secure the sensor
Left side of StackChan before mounting — insert fixing pegs into the LEGO holes at the top to secure the sensor
LEGO fixing peg
LEGO fixing peg
Completed assembly
Completed assembly

Custom Firmware

What Was Customized

I customized the M5StackChan firmware to add SCD41 support, with implementation assistance from Codex and Claude Code using the official documentation.

Due to the scope of changes, I forked the official repository and published the modified source code on GitHub. The changes are in the feature/scd41-co2-unit branch of pinelibg/StackChan:

  • Added I2C driver for SCD41
  • Added I2C initialization function for Port.A
  • Sensor initialization and periodic data acquisition via a background task
  • Added a CO2 monitor display app
  • Added built-in MCP tool get_co2_data for fetching CO2 sensor readings
  • All additions can be enabled/disabled via build config (CONFIG_HAL_SCD41_ENABLED, enabled by default)

The MCP tool description includes a ventilation guideline (recommending ventilation when CO2 exceeds 1000 ppm), so the AI interprets the data and generates natural responses. Note that the display app uses 800/1200 ppm color thresholds, while the MCP tool description uses the simpler 1000 ppm threshold for the AI.

If the sensor is not connected, the tool returns {"error": "SCD41 not available"} and the AI will inform the user accordingly.

Build & Flash

See the previous article (🔧 Building the M5StackChan Firmware Development Environment) for build environment setup.

Clone the feature/scd41-co2-unit branch and build:

git clone https://github.com/pinelibg/StackChan.git
cd StackChan/firmware
git checkout feature/scd41-co2-unit

After that, follow the standard build and flash procedure.

Verification

One important note: the sensor does not operate on battery power alone — USB power is required. It should be possible to enable Grove port power via software by controlling CoreS3's PMIC, but this is currently unverified. All tests below were performed with USB connected.

CO2 Monitor App

After flashing, a "CO2" app is added to the menu. Launching it displays real-time sensor readings updated every 5 seconds. The meter color changes based on CO2 concentration:

メニュー画面に追加されたCO2アプリ
メニュー画面に追加されたCO2アプリ
Level Color Status
Below 800 ppm Green Good
800–1200 ppm Yellow Caution
1200 ppm and above Red Ventilate
センサー値の表示アプリ
センサー値の表示アプリ

AI Conversation

During a conversation, StackChan calls the self.robot.get_co2_data tool and provides advice based on current sensor readings.

These tests used the local LLM (Gemma 4 E4B model) from the previous article (🤖 Running M5StackChan AI.AGENT with a Local LLM).

🧑
Tell me the air quality in the room.
🤖
CO2 is at 960 ppm, temperature around 26°C — feeling comfortable.
StackChan's response when CO2 is below threshold (960 ppm)
StackChan's response when CO2 is below threshold (960 ppm)
🧑
Should I ventilate?
🤖
CO2 is at 1023 ppm — a bit high. Ventilating would be a good idea.
StackChan's response at 1023 ppm
StackChan's response at 1023 ppm
🧑
Can you measure the CO2 level for me?
🤖
CO2 is at 1446 ppm — that's quite high. You should ventilate thoroughly.
StackChan's response when CO2 is high (1446 ppm)
StackChan's response when CO2 is high (1446 ppm)

Summary

By connecting the SCD41 CO2 sensor to StackChan and registering get_co2_data as a built-in MCP tool, the AI can now suggest ventilation timing based on real-time CO2 data.

The same pattern can be extended to other sensors — I have a barometric pressure sensor I haven't connected yet.

Currently, StackChan only responds about ventilation when asked. Adding sensor data to each conversation context, or periodically passing sensor data to the AI for evaluation, could enable proactive ventilation alerts in the future.

References

If you found this article helpful, please consider supporting me!