Negar Rafieedolatabadi
Published

Smart Occupancy Detector with SCD41 CO₂ Sensor and ML

A compact ML-powered device that detects room occupancy using CO₂ and temperature data, ideal for smart environments.

BeginnerProtip2 hours149
Smart Occupancy Detector with SCD41 CO₂ Sensor and ML

Things used in this project

Hardware components

Arduino tiny ML
×1
Sensirion SEK-SCD41
Sensirion SEK-SCD41
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Edge Impulse Studio
Edge Impulse Studio
Arduino IDE
Arduino IDE

Story

Read more

Schematics

ML model Statistics

Details on the trained ML model

ML model Statistics

Code

Reading SCD41 Output and showing ML results on serial monitor

C#
You should firstly install the Edge impulse ML model Arduino library
#include <Wire.h>
#include <SensirionI2cScd4x.h>
#include <Occupancy_Detector_inferencing.h>

SensirionI2cScd4x scd4x;
float features[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = {0};

static bool debug_nn = false;

void setup() {
    Serial.begin(115200);
    while (!Serial);

    Serial.println("Starting occupancy detection with SCD41...");

    Wire.begin();
    scd4x.begin(Wire, 0x62);  // SCD41 I2C address is usually 0x62

    // Stop any previous measurement
    scd4x.stopPeriodicMeasurement();
    delay(500);

    // Start new measurement
    int16_t error = scd4x.startPeriodicMeasurement();
    if (error) {
        Serial.print("Failed to start periodic measurement: ");
        Serial.println(error);
    } else {
        Serial.println("Measurement started. Waiting for first reading...");
    }

    // Give it some time to warm up and produce valid data
    delay(5000);
}

void loop() {
    bool dataReady = false;
    if (scd4x.getDataReadyStatus(dataReady) != 0 || !dataReady) {
        Serial.println("Waiting for data...");
        delay(1000);
        return;
    }

    // Read sensor values
    uint16_t co2;
    float temperature, humidity;
    int16_t error = scd4x.readMeasurement(co2, temperature, humidity);

    if (error) {
        Serial.print("Error reading measurement: ");
        Serial.println(error);
        delay(1000);
        return;
    }

    Serial.print("CO2: ");
    Serial.print(co2);
    Serial.print(" ppm, Temp: ");
    Serial.print(temperature);
    Serial.println(" °C");

    // Format features for the model
    features[0] = (float)co2;
    features[1] = temperature;

    // Wrap data as Edge Impulse signal
    signal_t signal;
    int create_signal = numpy::signal_from_buffer(features, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
    if (create_signal != 0) {
        Serial.println("Failed to create signal from features!");
        delay(1000);
        return;
    }

    // Run classification
    ei_impulse_result_t result = { 0 };
    EI_IMPULSE_ERROR infer_result = run_classifier(&signal, &result, debug_nn);

    if (infer_result != EI_IMPULSE_OK) {
        Serial.print("Classifier failed: ");
        Serial.println((int)infer_result);
        delay(1000);
        return;
    }

    // Print inference result
    Serial.println("Predictions:");
    for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
        ei_printf("  %s: %.5f\n", result.classification[ix].label, result.classification[ix].value);
    }

    delay(1000);  // Optional: Wait 1s before next inference
}

Credits

Negar Rafieedolatabadi
6 projects • 5 followers

Comments