Project #15: Environment – C4002 – BME280 – ENS160 Air Quality – Mk49

——

#DonLucElectronics #DonLuc #C4002 #BME280 #ENS160 #Environment #FireBeetle2ESP32E #ESP32 #Display #IoT #Project #Fritzing #Programming #Electronics #Microcontrollers #Consultant

——

C4002 - BME280 - ENS160 Air Quality

——

C4002 - BME280 - ENS160 Air Quality

——

C4002 - BME280 - ENS160 Air Quality

——

C4002 – BME280 – ENS160 Air Quality

Capable of detecting individuals who are sitting, sleeping, or standing completely still. Ideal for bedrooms, offices, and bathrooms.

Motion Detection: Up to 11m (Walking / Running).
Static Detection: Up to 10m (Reading / Typing / Sleeping).
Smart Lighting Automation: Maintains lighting based on true presence (breathing/micro-motion) rather than large movements, solving the problem of lights turning off while reading or working.
Privacy-Friendly Elderly Care: Detects presence or prolonged inactivity in bedrooms or bathrooms without the need for invasive cameras or wearable devices.
Plug-and-Play Smart Home Integration: BME280 Environmental Compensation. Integrated barometric sensor automatically corrects ENS160 readings for altitude and weather effects, improving accuracy by 30% versus standalone sensors.

To prevent false triggers common in radar technology (e.g., swaying plants, moving curtains), the C4002 incorporates adaptive background noise learning. The module automatically establishes a noise model of the environment, filtering out non-human interference to ensure triggers occur only upon actual human presence.

DL2609Mk02

1 x DFRobot FireBeetle 2 ESP32-E
1 x Fermion: 3.5” 480×320 TFT LCD Capacitive
1 x GDL Line 10 CM
1 x Fermion: C4002 mmWave Human Presence Sensor
1 x Fermion: ENS160+BME280 Envirotal Sensor
1 x Gravity: IO Shield for FireBeetle 2
1 x Terminal Block Board for FireBeetle 2 ESP32-E IoT
1 x Lithium Ion Battery – 1000mAh
1 x USB 3.0 to Type-C Cable

DL2609Mk02p

DL2609Mk02p.ino

/****** Don Luc Electronics © ******
Software Version Information
Project #15: Environment – C4002 - BME280 - ENS160 Air Quality – Mk49
15-49
DL2609Mk02p.ino
DL2609Mk02
1 x DFRobot FireBeetle 2 ESP32-E
1 x Fermion: 3.5” 480x320 TFT LCD Capacitive
1 x GDL Line 10 CM
1 x Fermion: C4002 mmWave Human Presence Sensor
1 x Fermion: ENS160+BME280 Envirotal Sensor
1 x Gravity: IO Shield for FireBeetle 2
1 x Terminal Block Board for FireBeetle 2 ESP32-E IoT
1 x Lithium Ion Battery - 1000mAh
1 x USB 3.0 to Type-C Cable
*/

// Include the Library Code
// DFRobot Display GDL API
#include <DFRobot_GDL.h>
// C4002 mmWave Human Presence
#include "DFRobot_C4002.h"
// BME280 Environmental
#include <DFRobot_BME280.h>
// ENS160 Air Quality Sensor
#include <DFRobot_ENS160.h>

// ENS160 Air Quality Sensor
// I2C communication.
#define I2C_COMMUNICATION  
// I2C address is 0x53
DFRobot_ENS160_I2C ENS160(&Wire, 0x53);
// Status
uint8_t Status;
// AQI
uint8_t AQI;
// TVOC
uint16_t TVOC;
// ECO2
uint16_t ECO2;

// BME280 Environmental
typedef DFRobot_BME280_IIC BME;
// Wire
BME   bme(&Wire, 0x76);
// Sea Level Pressure
#define SEA_LEVEL_PRESSURE 1015.0f
// Temperature
float   temp = bme.getTemperature();
// Pressure
uint32_t    press = bme.getPressure();
// Altitude
float alti;
// Humidity
float humi;

// C4002 mmWave Human Presence
DFRobot_C4002 c4002(&Serial1, 115200, /*D0*/ D11, /*D1*/ D10);
//float light;
String sLight;
// Get Target State
String sTarget;
// Get Presence distance gate target info
String sPreDis;
// Get motion distance gate index
String sMot;

// Defined ESP32
#define TFT_DC  D2
#define TFT_CS  D6
#define TFT_RST D3

/*dc=*/ /*cs=*/ /*rst=*/
// DFRobot Display 320x480
DFRobot_ILI9488_320x480_HW_SPI screen(TFT_DC, TFT_CS, TFT_RST);

// Software Version Information
String sver = "15-49";

void loop() {
  
  // isBME280
  isBME280();

  // isENS160
  isENS160();
  
  // isC4002
  isC4002();
  
  // isDisplay C4002
  isDisplayC4002();

  // Delay 0.1 Second
  delay( 100 );
  
}

getBME280.ino

// BME280 Environmental
// isBME280
void isBME280(){

  // Temperature
  temp = bme.getTemperature();
  // Pressure
  press = bme.getPressure();
  // Altitude
  alti = bme.calAltitude(SEA_LEVEL_PRESSURE, press);
  // Humidity
  humi = bme.getHumidity();

}

getC4002.ino

// C4002 mmWave Human Presence
// isSetupC4002
void isSetupC4002(){

  // C4002 mmWave Human Presence
  // Initialize the C4002 sensor
  while (c4002.begin() != true) {
    Serial.println("C4002 begin failed!");
    delay(1000);
  }
  //Serial.println("C4002 begin success!");
  delay(50);

  // Set the run led to On

  if (c4002.setRunLedState(eLedOn)) {
    //Serial.println("Set run led success!");
  } else {
    Serial.println("Set run led failed!");
  }
  delay(50);

  // Set the out led to On
  if (c4002.setOutLedState(eLedOn)) {
    //Serial.println("Set out led success!");
  } else {
    Serial.println("Set out led failed!");
  }
  delay(50);

  // Set the Resolution mode to 20cm.
  // eResolution20Cm: This indicates that the resolution of the "distance gate"
  // is 20cm. With a resolution of 20 cm, it supports up to 25 distance gates, 
  //with a maximum distance of 4.9 meters
  //c4002.setResolutionMode(eResolution20Cm);
  if (c4002.setResolutionMode(eResolution20Cm)) {
    //Serial.println("Set resolution mode success!");
  } else {
    Serial.println("Set resolution mode failed!");
  }
  delay(50);

  // Set the detect range to 0-200 cm
  uint16_t clostRange = 0;
  uint16_t farRange   = 200;
  if (c4002.setDetectRange(clostRange, farRange)) {    // Max detect range(0-1100cm)
    //Serial.println("Set detect range success!");
  } else {
    Serial.println("Set detect range failed!");
  }

  // Set the light threshold to 0 lux.range: 0-50 lux
  if (c4002.setLightThresh(0)) {
    //Serial.println("Set light threshold success!");
  } else {
    Serial.println("Set light threshold failed!");
  }
  delay(50);

  // Resolution mode:eResolution20Cm
  // Enable the 'distance gate'
  // Resolution mode:eResolution20Cm,This means that the number of 'distance gates' 
  // we can operate is 25
  //disable : C4002_DISABLE, enable: C4002_ENABLE
  uint8_t gateState[25] = { C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, 
  C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE,
   C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, 
   C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE,
   C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE, C4002_ENABLE };

  // Operation motion distance gate
  if (c4002.configureGate(eMotionDistGate, gateState)) { 
    //Serial.println("Enable motion distance gate success!");
  }

  // Delay
  delay(50);

  // Operation presence distance gate
  if (c4002.configureGate(ePresenceDistGate, gateState)) { 
    //Serial.println("Enable presence distance gate success!");
  }
  
  // Delay
  delay(50);

  // Set the target disappear delay time to 1s,range: 0-65535s
  if (c4002.setTargetDisappearDelay(1)) {
    //Serial.println("Set target disappear delay time success!");
  } else {
    Serial.println("Set target disappear delay time failed!");
  }
 
  // Delay
  delay(50);

  // Set the report period to 10 * 0.1s = 1s
  if (c4002.setReportPeriod(10)) {
    //Serial.println("Set report period success!");
  } else {
    Serial.println("Set report period failed!");
  }

}
// isC4002
void isC4002(){

  // Get all the results of the C4002 sensor
  sRetResult_t retResult = c4002.getNoteInfo();

  if (retResult.noteType == eResult) {
    //Serial.println("------- Get all results --------");
    // get the light intensity
    float light = c4002.getLightIntensity();
    //Serial.print("Light: ");
    //Serial.print(light);
    //Serial.println(" lux");
    sLight = light;

    // get Target state
    eTargetState_t targetState = c4002.getTargetState();
    //Serial.print("Target state: ");
    if (targetState == eNoTarget) {

      //Serial.println("No Target");
      sTarget = "No Target";

    } else if (targetState == ePresence) {
      
      //Serial.println("Static Presence");
      sTarget = "Static Presence";

    } else if (targetState == eMotion) {
      
      //Serial.println("Motion");
      sTarget = "Motion";

    }

    // Get Presence distance gate target info
    sPresenceTarget_t presenceTarget = c4002.getPresenceTargetInfo();
    //Serial.print("Presence distance: ");
    //Serial.print(presenceTarget.distance);
    sPreDis = presenceTarget.distance;
    //Serial.println(" m");

    // Get motion distance gate index
    sMotionTarget_t motionTarget = c4002.getMotionTargetInfo();

    //Serial.print("Motion direction: ");
    if (motionTarget.direction == eAway) {
      
      //Serial.println("Away!");
      sMot = "Away!";

    } else if (motionTarget.direction == eNoDirection) {
      
      //Serial.println("No Direction!");
      sMot = "No Direction!";

    } else if (motionTarget.direction == eApproaching) {
      
      //Serial.println("Approaching!");
      sMot = "Approaching!";

    }
  }

}

getDisplay.ino

// DFRobot Display 320x480
// DFRobot Display 320x480 - UID
void isDisplayUID(){

  // DFRobot Display 240x320
  // Text Display
  // Text Wrap
  screen.setTextWrap(false);
  // Rotation
  screen.setRotation(3);
  // Fill Screen => black
  screen.fillScreen(0x0000);
  // Text Color => white
  screen.setTextColor(0xffff);
    // Font => Free Sans Bold 12pt
  screen.setFont(&FreeSansBold12pt7b);
  // TextSize => 1.5
  screen.setTextSize(1.5);
  // Don Luc Electronics
  screen.setCursor(0, 30);
  screen.println("Don Luc Electronics");
  // BME280 Environmental
  screen.setCursor(0, 60);
  screen.println("C4002 - BME280 - ENS160 Air Quality");
  // Version
  screen.setCursor(0, 90);
  screen.println("Version");
  screen.setCursor(0, 120);
  screen.println( sver );

}
// isDisplay C4002
void isDisplayC4002(){

  // DFRobot Display 320x480
  // Text Display
  // Text Wrap
  screen.setTextWrap(false);
  // Rotation
  screen.setRotation(3);
  // Fill Screen => white
  screen.fillScreen(0xffff);
  // Text Color => blue
  screen.setTextColor(0x001F);
    // Font => Free Sans Bold 12pt
  screen.setFont(&FreeSansBold12pt7b);
  // TextSize => 1.5
  screen.setTextSize(1.5);
  // ENS160 Air Quality Sensor
  screen.setCursor(0, 30);
  screen.println("C4002 - BME280 - ENS160 Air Quality");
  // Status
  screen.setCursor(0, 60);
  screen.print("Light ");
  screen.setCursor(70, 60);
  screen.print( sLight );
  screen.setCursor(250, 60);
  screen.println("lux");
  // Target
  screen.setCursor(0, 90);
  screen.print("Target ");
  screen.setCursor(90, 90);
  screen.println( sTarget );
  // Presence
  screen.setCursor(0, 120);
  screen.print("Presence: ");
  screen.setCursor(130, 120);
  screen.println( sPreDis );
  screen.setCursor(250, 120);
  screen.println( "CM" );
  // Motion
  screen.setCursor(0, 150);
  screen.print("Motion: ");
  screen.setCursor(110, 150);
  screen.println( sMot );
  // Temperature
  screen.setCursor(0, 180);
  screen.print("Temperature: ");
  screen.setCursor(170, 180);
  screen.println( temp );
  screen.setCursor(250, 180);
  screen.println( "C" );
  // Humidity
  screen.setCursor(0, 210);
  screen.print("Humidity: ");
  screen.setCursor(170, 210);
  screen.println( humi );
  screen.setCursor(250, 210);
  screen.println( "%" );
  // TVOC - Return value range: 0–65000, unit: ppb
  screen.setCursor(0, 240);
  screen.print("TVOC: ");
  screen.setCursor(140, 240);
  screen.println( TVOC );
  screen.setCursor(250, 240);
  screen.println( "ppb" );
  // ECO2 = Return value range: 400–65000, unit: ppm
  // Five levels: Excellent(400 - 600), Good(600 - 800), Moderate(800 - 1000), 
  // Poor(1000 - 1500), Unhealthy(> 1500)
  screen.setCursor(0, 270);
  screen.print("ECO2: ");
  screen.setCursor(140, 270);
  screen.println( ECO2 );
  screen.setCursor(250, 270);
  screen.println( "ppb" );

}

getENS160.ino

// ENS160 Air Quality Sensor
// isENS160
void isENS160(){

  // Status - Return value: 0-Normal operation 1-Warm-Up phase 
  // 2-Initial Start-Up phase
  Status = ENS160.getENS160Status();

  // AQI - Return value: 1-Excellent, 2-Good, 3-Moderate, 4-Poor, 5-Unhealthy
  AQI = ENS160.getAQI();

  // TVOC - Return value range: 0–65000, unit: ppb
  TVOC = ENS160.getTVOC();

  // ECO2 = Return value range: 400–65000, unit: ppm
  // Five levels: Excellent(400 - 600), Good(600 - 800), Moderate(800 - 1000), 
  // Poor(1000 - 1500), Unhealthy(> 1500)
  ECO2 = ENS160.getECO2();

}

setup.ino

// Setup
void setup()
{
 
  // Delay
  delay(100);

  Serial.begin(115200);

    // Delay
  delay( 100 );

  // C4002 mmWave Human Presence
  isSetupC4002();

  // Delay
  delay(100);

  // BME280 Environmental
  bme.begin();

  // Delay
  delay(100);

  // ENS160 Air Quality Sensor
  ENS160.begin();
  /**
   * Set power mode
   * mode Configurable power mode:
   * ENS160_SLEEP_MODE: DEEP SLEEP mode (low power standby)
   * ENS160_IDLE_MODE: IDLE mode (low-power)
   * ENS160_STANDARD_MODE: STANDARD Gas Sensing Modes
   */
  ENS160.setPWRMode(ENS160_STANDARD_MODE);

  /**
   * Users write ambient temperature and relative humidity into ENS160 for
   * calibration and compensation of the measured gas data.
   * ambientTemp Compensate the current ambient temperature, float type, unit: C
   * relativeHumidity Compensate the current ambient humidity, float type, unit: %rH
   * Temperature
   * Humidity=
   */
  ENS160.setTempAndHum(temp, humi);

  // Delay
  delay( 100 );

  // DFRobot Display 320x480
  screen.begin();

  // Delay
  delay( 100 );

  // DFRobot Display 320x480 - UID
  // Don Luc Electronics
  // Versioc
  isDisplayUID();
  
  // Delay
  delay( 5000 );

}

——

People can contact us: https://www.donluc.com/?page_id=1927

Consultant, R&D, Electronics, IoT, Teacher and Instructor

  • Programming Language
  • Single-Board Microcontrollers (PIC, Arduino, Raspberry Pi, Arm, Silicon Labs, Espressif, Etc…)
  • IoT
  • Wireless (Radio Frequency, Bluetooth, WiFi, Etc…)
  • Robotics
  • Automation
  • Camera and Video Capture Receiver Stationary, Wheel/Tank , Underwater and UAV Vehicle
  • Unmanned Vehicles Terrestrial, Marine and UAV
  • Machine Learning
  • Artificial Intelligence (AI)
  • RTOS
  • Sensors, eHealth Sensors, Biosensor, and Biometric
  • Research & Development (R & D)
  • Consulting

Follow Us

Luc Paquin – Curriculum Vitae – 2026
https://www.donluc.com/luc/LucPaquinCVEng2026Mk01.pdf
https://www.donluc.com/luc/

Web: https://www.donluc.com/
Web: https://www.jlpconsultants.com/
Facebook: https://www.facebook.com/neosteam.labs.9/
YouTube: https://www.youtube.com/@thesass2063
DFRobot: https://learn.dfrobot.com/user-10186.html
TikTok: https://www.tiktok.com/@luc.paquin8
Hackster: https://www.hackster.io/luc-paquin
LinkedIn: https://www.linkedin.com/in/jlucpaquin/

Don Luc