Skip to main content

Overview

SensorModuleV2 is the modern container class that manages multiple BaseSensV2 sensors. It provides type-safe access, real-time filtering, threshold alerts, and advanced debugging capabilities. Header: lib/sensors/SensorModuleV2/SensorModule/SensorModuleV2.h

Class Definition

class SensorModuleV2 {
public:
    SensorModuleV2();
    ~SensorModuleV2();
    
    // Lifecycle
    void init();
    void update();
    
    // Sensor management
    void addSensor(const char *name, BaseSensV2 *sensor);
    void addSensor(const char *name, SensorCreateCallback callbackSensModule);
    
    // Access
    BaseSensV2 *getSensor(uint8_t index) const;
    BaseSensV2 *getSensorByName(const char *name) const;
    template<typename T>
    T getValue(const char *sensorName, const char *valueKey) const;
    
    // Filtering system
    bool attachFilter(const char *sensorName, const char *valueKey,
                      FilterType type, FilterParams params);
    float getFilteredValue(const char *sensorName, const char *valueKey);
    
    // Alert system
    bool setThreshold(const char *sensorName, const char *valueKey,
                      float lowThreshold, float highThreshold,
                      AlertType type = ALERT_OUTSIDE);
    void setGlobalAlertCallback(AlertCallback callback);
    
    // Debug
    void debugAll(bool showHeapMemory = false);
    void debugPretty(uint32_t time = 1000);
};

Lifecycle Methods

init()

Initializes all registered sensors.
void init();
Behavior:
  • Creates shared JSON document
  • Calls init() on each sensor
  • Prints initialization status to Serial
  • Stores initialization status for each sensor
Example:
SensorModuleV2 sensors;
sensors.addSensor("temp", new DHTSensV2(2, DHT22));
sensors.addSensor("gas", new MQSensV2(A0, MQ135));
sensors.init();
Serial Output:
| [NAME]: temp [INFO]: Init Success
| [NAME]: gas [INFO]: Init Success

update()

Updates all sensors and processes filters/alerts.
void update();
Behavior:
  1. Calls update() on each initialized sensor
  2. Updates all attached filters with new values
  3. Checks all threshold alerts
  4. Triggers alert callbacks if thresholds are violated
Example:
void loop() {
    sensors.update();
    
    // Access updated values
    float temp = sensors.getValue<float>("temp", "temperature");
    Serial.println(temp);
    
    delay(1000);
}

Sensor Management

addSensor()

Adds a sensor to the module.
void addSensor(const char *name, BaseSensV2 *sensor);
void addSensor(const char *name, SensorCreateCallback callbackSensModule);
name
const char*
required
Unique identifier for the sensor
sensor
BaseSensV2*
required
Pointer to the sensor instance
callbackSensModule
SensorCreateCallback
Factory function: BaseSensV2* (*)()
Example:
// Direct addition
sensors.addSensor("temp", new DHTSensV2(2, DHT22));

// Using factory function
BaseSensV2* createGasSensor() {
    return new MQSensV2(A0, MQ135);
}
sensors.addSensor("gas", createGasSensor);
Call addSensor() before init(). Sensors added after initialization will not be properly configured.

getSensor()

Retrieves a sensor by index or name.
BaseSensV2 *getSensor(uint8_t index) const;
BaseSensV2 *getSensorByName(const char *name) const;
const char *getSensorName(uint8_t index) const;
uint8_t getSensorCount() const;
index
uint8_t
Zero-based sensor index
name
const char*
Sensor name identifier
Example:
BaseSensV2* sensor = sensors.getSensorByName("temp");
if (sensor) {
    float temp = sensor->getFloatValue("temperature");
}

// Iterate all sensors
for (uint8_t i = 0; i < sensors.getSensorCount(); i++) {
    Serial.println(sensors.getSensorName(i));
}

Type-Safe Value Access

getValue()

Retrieves a typed value from a sensor.
template<typename T>
T getValue(const char *sensorName, const char *valueKey) const;
T
template
Value type (float, int, bool, const char*, etc.)
sensorName
const char*
required
Sensor identifier
valueKey
const char*
required
Value key within the sensor
return
T
The requested value with type safety
Example:
float temperature = sensors.getValue<float>("temp", "temperature");
int humidity = sensors.getValue<int>("temp", "humidity");
bool status = sensors.getValue<bool>("temp", "valid");

isUpdated()

Checks if a sensor was updated in the last cycle.
bool isUpdated(const char *sensorName) const;
Example:
sensors.update();
if (sensors.isUpdated("temp")) {
    float temp = sensors.getValue<float>("temp", "temperature");
    Serial.println(temp);
}

Filtering System

attachFilter()

Attaches a real-time filter to a sensor value.
bool attachFilter(const char *sensorName, const char *valueKey,
                  FilterType type, FilterParams params);
sensorName
const char*
required
Sensor identifier
valueKey
const char*
required
Value to filter
type
FilterType
required
Filter algorithm type
params
FilterParams
required
Filter configuration parameters
return
bool
true if filter was attached successfully
FilterType Enum:
enum FilterType {
    FILTER_NONE,
    FILTER_MOVING_AVERAGE,
    FILTER_MEDIAN,
    FILTER_KALMAN,
    FILTER_EXPONENTIAL
};
FilterParams Structure:
struct FilterParams {
    union {
        struct { uint8_t windowSize; } movingAverage;
        struct { uint8_t windowSize; } median;
        struct {
            float processNoise;
            float measurementNoise;
            float estimateError;
        } kalman;
        struct { float alpha; } exponential;
    };
};
Example:
// Moving average filter (window size 10)
FilterParams maParams;
maParams.movingAverage.windowSize = 10;
sensors.attachFilter("temp", "temperature", FILTER_MOVING_AVERAGE, maParams);

// Kalman filter
FilterParams kalmanParams;
kalmanParams.kalman.processNoise = 0.01f;
kalmanParams.kalman.measurementNoise = 0.1f;
kalmanParams.kalman.estimateError = 1.0f;
sensors.attachFilter("accel", "x", FILTER_KALMAN, kalmanParams);

// Exponential filter (alpha = 0.2)
FilterParams expParams;
expParams.exponential.alpha = 0.2f;
sensors.attachFilter("sensor", "value", FILTER_EXPONENTIAL, expParams);

getFilteredValue()

Retrieves the filtered value.
float getFilteredValue(const char *sensorName, const char *valueKey);
float getLastFilteredValue(const char *sensorName, const char *valueKey);
sensorName
const char*
required
Sensor identifier
valueKey
const char*
required
Value key
return
float
Filtered sensor value
Example:
sensors.update();
float rawTemp = sensors.getValue<float>("temp", "temperature");
float filteredTemp = sensors.getFilteredValue("temp", "temperature");

Serial.printf("Raw: %.2f, Filtered: %.2f\n", rawTemp, filteredTemp);

Filter Management

bool updateFilter(const char *sensorName, const char *valueKey,
                  FilterType type, FilterParams params);
bool detachFilter(const char *sensorName, const char *valueKey);
void detachAllFilters();
void resetFilter(const char *sensorName, const char *valueKey);
void resetAllFilters();
bool hasFilter(const char *sensorName, const char *valueKey);
FilterType getFilterType(const char *sensorName, const char *valueKey);
Example:
// Check if filter exists
if (sensors.hasFilter("temp", "temperature")) {
    FilterType type = sensors.getFilterType("temp", "temperature");
}

// Reset filter state
sensors.resetFilter("temp", "temperature");

// Remove filter
sensors.detachFilter("temp", "temperature");

Alert System

setThreshold()

Configures a threshold alert for a sensor value.
bool setThreshold(const char *sensorName, const char *valueKey,
                  float lowThreshold, float highThreshold,
                  AlertType type = ALERT_OUTSIDE);
sensorName
const char*
required
Sensor identifier
valueKey
const char*
required
Value to monitor
lowThreshold
float
required
Lower threshold value
highThreshold
float
required
Upper threshold value
type
AlertType
default:"ALERT_OUTSIDE"
Alert trigger condition
AlertType Enum:
enum AlertType {
    ALERT_ABOVE,      // Trigger when value > highThreshold
    ALERT_BELOW,      // Trigger when value < lowThreshold
    ALERT_BETWEEN,    // Trigger when lowThreshold < value < highThreshold
    ALERT_OUTSIDE     // Trigger when value < lowThreshold OR value > highThreshold
};
Example:
// Alert if temperature outside 20-30°C range
sensors.setThreshold("temp", "temperature", 20.0f, 30.0f, ALERT_OUTSIDE);

// Alert if humidity below 40%
sensors.setThreshold("temp", "humidity", 40.0f, 100.0f, ALERT_BELOW);

// Alert if CO2 above 1000 ppm
sensors.setThreshold("air", "co2", 0.0f, 1000.0f, ALERT_ABOVE);

setGlobalAlertCallback()

Sets a callback for all alert events.
void setGlobalAlertCallback(AlertCallback callback);
bool setSensorAlertCallback(const char *sensorName, AlertCallback callback);
void clearAlertCallbacks();
AlertCallback Type:
typedef void (*AlertCallback)(AlertInfo alertInfo);

struct AlertInfo {
    char *sensorName;
    char *valueKey;
    float currentValue;
    float lowThreshold;
    float highThreshold;
    AlertType type;
    AlertState state;
    uint32_t timeTriggered;
    uint8_t repeatCount;
};
AlertState Enum:
enum AlertState {
    ALERT_INACTIVE,      // No alert condition
    ALERT_ACTIVE,        // Alert triggered
    ALERT_ACKNOWLEDGED   // Alert acknowledged by user
};
Example:
void onAlert(AlertInfo info) {
    Serial.printf("ALERT! %s/%s = %.2f (threshold: %.2f-%.2f)\n",
                  info.sensorName, info.valueKey, info.currentValue,
                  info.lowThreshold, info.highThreshold);
    
    if (info.state == ALERT_ACTIVE) {
        // Trigger alarm, send notification, etc.
        digitalWrite(ALARM_PIN, HIGH);
    }
}

sensors.setGlobalAlertCallback(onAlert);

// Sensor-specific callback
sensors.setSensorAlertCallback("temp", [](AlertInfo info) {
    Serial.println("Temperature alert!");
});

Alert Management

AlertState getAlertState(const char *sensorName, const char *valueKey);
bool isAlertActive(const char *sensorName, const char *valueKey);
void acknowledgeAlert(const char *sensorName, const char *valueKey);
void acknowledgeAllAlerts();
void resetAlert(const char *sensorName, const char *valueKey);
void resetAllAlerts();
bool removeThreshold(const char *sensorName, const char *valueKey);
void removeAllThresholds();
Example:
if (sensors.isAlertActive("temp", "temperature")) {
    AlertState state = sensors.getAlertState("temp", "temperature");
    
    if (state == ALERT_ACTIVE) {
        // User acknowledged the alert
        sensors.acknowledgeAlert("temp", "temperature");
    }
}

Alert Configuration

bool setThresholdParams(const char *sensorName, const char *valueKey,
                        uint32_t hysteresis, uint32_t debounceTime);
void setDefaultHysteresis(uint32_t hysteresis);
void setDefaultDebounceTime(uint32_t debounceTime);
hysteresis
uint32_t
Hysteresis value to prevent rapid toggling (in same units as threshold)
debounceTime
uint32_t
Minimum time in milliseconds before triggering alert
Example:
// Set defaults for all new thresholds
sensors.setDefaultHysteresis(2);       // 2 units
sensors.setDefaultDebounceTime(5000);  // 5 seconds

// Override for specific threshold
sensors.setThreshold("temp", "temperature", 20.0f, 30.0f);
sensors.setThresholdParams("temp", "temperature", 1, 3000);

Debug Methods

debugAll()

Prints all sensor values to Serial.
void debugAll(bool showHeapMemory = false);
void debugHorizontal(bool showHeapMemory = false);
void debugHorizontalWithTime(uint32_t time, bool showHeapMemory = false);
showHeapMemory
bool
default:"false"
Include free heap memory in output
time
uint32_t
Debug interval in milliseconds (for timed variants)
Example:
// Print all values
sensors.debugAll();

// Horizontal format with memory
sensors.debugHorizontal(true);

// Periodic debug (in loop)
sensors.debugHorizontalWithTime(1000, true);

debugPretty()

Prints formatted JSON output.
void debugPretty(uint32_t time = 1000);
time
uint32_t
default:"1000"
Output interval in milliseconds
Example:
void loop() {
    sensors.update();
    sensors.debugPretty(2000);  // Print every 2 seconds
}
Output:
{
  "temp": {
    "temperature": 25.5,
    "humidity": 65.2
  },
  "gas": {
    "ppm": 450.3
  }
}

debug()

Debug specific sensor/value.
void debug(const char *sensorName, const char *valueKey, bool showHeapMemory = false);
Example:
sensors.debug("temp", "temperature", true);

System Control

enableAlertSystem() / enableFilterSystem()

Enables or disables subsystems.
void enableAlertSystem(bool enable = true);
bool hasAlertSystem() const;

void enableFilterSystem(bool enable = true);
bool hasFilterSystem() const;
Example:
// Disable alerts temporarily
sensors.enableAlertSystem(false);

// Re-enable
sensors.enableAlertSystem(true);

if (sensors.hasAlertSystem()) {
    Serial.println("Alerts active");
}

Complete Usage Example

#define ENABLE_SENSOR_MODULE_V2
#define ENABLE_SENSOR_DHT_V2
#define ENABLE_SENSOR_MQ_V2
#include "Kinematrix.h"

SensorModuleV2 sensors;

void onTemperatureAlert(AlertInfo info) {
    Serial.printf("⚠️ Temperature alert: %.1f°C\n", info.currentValue);
    digitalWrite(LED_PIN, HIGH);
}

void setup() {
    Serial.begin(115200);
    pinMode(LED_PIN, OUTPUT);
    
    // Add sensors
    sensors.addSensor("climate", new DHTSensV2(2, DHT22));
    sensors.addSensor("airquality", new MQSensV2(A0, MQ135));
    
    // Initialize
    sensors.init();
    
    // Configure moving average filter for temperature
    FilterParams maParams;
    maParams.movingAverage.windowSize = 10;
    sensors.attachFilter("climate", "temperature", FILTER_MOVING_AVERAGE, maParams);
    
    // Configure Kalman filter for gas sensor
    FilterParams kalmanParams;
    kalmanParams.kalman.processNoise = 0.01f;
    kalmanParams.kalman.measurementNoise = 0.5f;
    kalmanParams.kalman.estimateError = 1.0f;
    sensors.attachFilter("airquality", "ppm", FILTER_KALMAN, kalmanParams);
    
    // Set temperature alert (20-30°C safe range)
    sensors.setThreshold("climate", "temperature", 20.0f, 30.0f, ALERT_OUTSIDE);
    sensors.setSensorAlertCallback("climate", onTemperatureAlert);
    
    // Set air quality alert (CO2 > 1000 ppm)
    sensors.setThreshold("airquality", "ppm", 0.0f, 1000.0f, ALERT_ABOVE);
    
    Serial.println("System ready!");
}

void loop() {
    // Update all sensors (also updates filters and checks alerts)
    sensors.update();
    
    // Get raw and filtered values
    float rawTemp = sensors.getValue<float>("climate", "temperature");
    float filteredTemp = sensors.getFilteredValue("climate", "temperature");
    
    Serial.printf("Temp: %.1f°C (filtered: %.1f°C)\n", rawTemp, filteredTemp);
    
    // Check if updated
    if (sensors.isUpdated("climate")) {
        int humidity = sensors.getValue<int>("climate", "humidity");
        Serial.printf("Humidity: %d%%\n", humidity);
    }
    
    // Pretty debug every 5 seconds
    sensors.debugPretty(5000);
    
    delay(2000);
}

Key Features

Type Safety

Template-based getValue() with compile-time type checking

Real-Time Filtering

Moving Average, Median, Kalman, and Exponential filters

Threshold Alerts

Configurable alerts with callbacks and hysteresis

Metadata

Labels, units, precision for each sensor value

See Also

Build docs developers (and LLMs) love