Skip to content

Repository files navigation

mmWaveKit

Arduino library for the Seeed MR60BHA2 mmWave sensor kit.

Description

This library wraps the MR60BHA2 breathing and heart rate sensor, a BH1750 ambient light sensor, and a WS2812 RGB LED with a Button2-style callback API.

  • Breathing rate, heart rate, presence, distance, and ambient light readings
  • Edge-triggered callbacks for all alert conditions — no polling needed
  • Three age-specific vital profiles: ADULT, CHILD, TODDLER
  • Debounced alert edges (20 s zero-signal, 15 s threshold violation)
  • Irregular breathing detection (60-sample rolling standard deviation)
  • Light-gated tracking: pause vital monitoring when a room is lit/dark
  • LED control via setLedColor() / setLedOff()
  • Sensor firmware version query

It has been tested with the Seeed XIAO ESP32-C6.

If you are looking for a lower-level driver for the Seeed mmWave sensors, take a look at the mmWave library.

To see the latest changes to the library please take a look at the Changelog.

If you find this library helpful please consider giving it a ⭐️ at GitHub and/or buy me a ☕️.

Thank you!

Hardware

Designed for the Seeed XIAO ESP32-C6 with the MR60BHA2 kit:

Component Connection
MR60BHA2 sensor Serial0 (D6/D7)
BH1750 light sensor I2C (D4/D5)
WS2812 RGB LED D1 (GPIO 1)

How To Use

Quick Start

  • Include the library and create an mmWaveKit instance.
#include <mmWaveKit.h>

mmWaveKit kit;
  • Configure and start the sensor in setup() using a VitalConfig struct.
void setup() {
  Serial.begin(115200);

  mmWaveKit::VitalConfig vc;
  vc.profile = mmWaveKit::ADULT;

  kit.begin(vc, {});
}
  • Call update() in your loop() to process sensor data.
void loop() {
  kit.update();

  static unsigned long last = 0;
  if (millis() - last >= 1000) {
    last = millis();
    Serial.printf("BR: %d  HR: %d  present: %s\n",
      kit.getBreathingRate(), kit.getHeartRate(),
      kit.isPresent() ? "yes" : "no");
  }
}

Callback Handlers

  • Instead of polling readings in loop(), you can assign callback functions that fire when alert conditions are detected.
  • All callbacks share the same signature:
void handler(mmWaveKit& kit, mmWaveKit::Event e, int value)
  • value carries the relevant reading at fire time (BR in rpm, HR in bpm, lux; 0 for presence events).
Registration Event value
onEvent(cb) all events (fires before the specific handler) varies
onPresenceOn(cb) EVT_PRESENCE_ON 0
onPresenceOff(cb) EVT_PRESENCE_OFF 0
onNoBreathing(cb) EVT_NO_BREATHING 0
onBreathingLow(cb) EVT_LOW_BREATHING BR
onBreathingHigh(cb) EVT_HIGH_BREATHING BR
onBreathingIrregular(cb) EVT_IRREGULAR_BREATHING BR
onNoHeartRate(cb) EVT_NO_HEART_RATE 0
onHeartRateLow(cb) EVT_LOW_HEART_RATE HR
onHeartRateHigh(cb) EVT_HIGH_HEART_RATE HR
onBecameLight(cb) EVT_BECAME_LIGHT lux
onBecameDark(cb) EVT_BECAME_DARK lux
onLightSituationChanged(cb) both light events lux
  • Please take a look at the included examples (see below) to get an overview of the different callback handlers and their usage.

Config Structs

  • VitalConfig controls the vital sign monitoring behaviour:
struct VitalConfig {
  VitalProfile profile          = mmWaveKit::ADULT;
  uint32_t     zeroDebounceMs   = 20000;   // ms before "no signal" alert fires
  uint32_t     threshDebounceMs = 15000;   // ms before threshold alert fires
};
  • LightConfig controls the ambient light sensor and LED:
struct LightConfig {
  int     threshold = 10;              // lux boundary
  uint8_t trackMode = LIGHT_TRACK_ALWAYS;
  uint8_t ledPin    = 1;               // NeoPixel data pin
};

Vital Profiles

  • The library ships with three age-specific profiles that set normal ranges for breathing rate and heart rate.
Profile Breathing Heart Rate Sensitivity
ADULT 10–20 rpm 40–100 bpm most sensitive
CHILD 16–30 rpm 60–120 bpm moderate
TODDLER 16–45 rpm 60–160 bpm least sensitive
  • Narrower normal ranges fire alerts at smaller deviations — ADULT is most sensitive.

Light Track Modes

  • You can gate vital alert evaluation based on ambient light levels using the trackMode field in LightConfig.
Constant Behaviour
LIGHT_TRACK_ALWAYS always evaluate vital alerts (default)
LIGHT_TRACK_DARK only evaluate when lux < threshold
LIGHT_TRACK_LIGHT only evaluate when lux >= threshold

Notes

  • Only one mmWaveKit instance per program is supported (file-scope statics).
  • update() evaluates alerts in 1-second buckets; call it every loop().
  • Irregular breathing detection requires 60 consecutive 1-second samples.

Examples

  • BasicReadings.ino – polls sensor readings every second and prints them to Serial
  • Callbacks.ino – shows how to assign event handlers for vital sign alerts
  • LightTracking.ino – demonstrates light-gated vital monitoring with LightConfig

Class Definition

See below the constructors and member functions the library provides:

mmWaveKit();

bool begin(const VitalConfig& vc, const LightConfig& lc);
bool begin(HardwareSerial& serial, const VitalConfig& vc, const LightConfig& lc);
void update();

int   getBreathingRate();
int   getHeartRate();
float getDistance();
int   getLux();
bool  isPresent();
bool  isLight();
bool  isDark();
bool  isTrackingActive();
int   getThreshold();
const AlertState& getAlerts();

bool getFirmwareVersion(uint8_t& major, uint8_t& sub, uint8_t& modified);
bool getFirmwareVersion(char* buf, size_t len);

void setLedColor(uint8_t r, uint8_t g, uint8_t b);
void setLedOff();

void onEvent(CallbackFunction cb);
void onPresenceOn(CallbackFunction cb);
void onPresenceOff(CallbackFunction cb);
void onNoBreathing(CallbackFunction cb);
void onBreathingLow(CallbackFunction cb);
void onBreathingHigh(CallbackFunction cb);
void onBreathingIrregular(CallbackFunction cb);
void onNoHeartRate(CallbackFunction cb);
void onHeartRateLow(CallbackFunction cb);
void onHeartRateHigh(CallbackFunction cb);
void onBecameLight(CallbackFunction cb);
void onBecameDark(CallbackFunction cb);
void onLightSituationChanged(CallbackFunction cb);

Installation

Open the Arduino IDE, choose "Sketch > Include Library" and search for "mmWaveKit". Or download the ZIP archive (https://github.com/LennartHennigs/mmWaveKit/zipball/master), and choose "Sketch > Include Library > Add .ZIP Library..." and select the downloaded file.

For PlatformIO, add the following to your platformio.ini:

lib_deps =
    LennartHennigs/mmWaveKit @ ^1.0.0

Dependencies are installed automatically:

Note: The Seeed Arduino mmWave library is not available in the Arduino Library Manager. Install it manually via "Sketch > Include Library > Add .ZIP Library..." or for PlatformIO add https://github.com/Love4yzp/Seeed-mmWave-library to your lib_deps.

License

MIT License

Copyright (c) 2026 Lennart Hennigs

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

Arduino library for the Seeed MR60BHA2 mmWave sensor kit. Wraps the sensor, a BH1750 ambient light sensor, and a WS2812 LED with a callback API.

Topics

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages