Skip to main content

Overview

The Sensor Module V2 includes a comprehensive alert system for monitoring sensor values against threshold limits. The system supports multiple alert types, customizable callbacks, debouncing, hysteresis, and alert acknowledgment.

Alert System Architecture

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 outside [lowThreshold, highThreshold]
};

enum AlertState {
    ALERT_INACTIVE,      // No alert condition
    ALERT_ACTIVE,        // Alert currently triggered
    ALERT_ACKNOWLEDGED   // Alert acknowledged by user
};

struct AlertInfo {
    char *sensorName;
    char *valueKey;
    float currentValue;
    float lowThreshold;
    float highThreshold;
    AlertType type;
    AlertState state;
    uint32_t timeTriggered;
    uint8_t repeatCount;
};

typedef void (*AlertCallback)(AlertInfo alertInfo);

Setting Threshold Alerts

Basic Alert Setup

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

SensorModuleV2 sensors;
DHTSensV2 dht(2, DHT22);

void setup() {
    Serial.begin(115200);
    
    dht.setUpdateInterval(2000);
    sensors.addSensor("climate", &dht);
    sensors.init();
    
    // Alert when temperature is outside 20-30°C range
    sensors.setThreshold("climate", "temperature", 
                        20.0, 30.0, ALERT_OUTSIDE);
    
    // Alert when humidity drops below 30%
    sensors.setThreshold("climate", "humidity", 
                        30.0, 100.0, ALERT_BELOW);
}

void loop() {
    sensors.update();
    
    // Check alert status
    if (sensors.isAlertActive("climate", "temperature")) {
        Serial.println("Temperature alert active!");
    }
}

Alert Types

ALERT_ABOVE

Triggers when value exceeds high threshold.
// Alert when temperature exceeds 35°C
sensors.setThreshold("temp", "temperature", 
                    0.0, 35.0, ALERT_ABOVE);

ALERT_BELOW

Triggers when value falls below low threshold.
// Alert when battery voltage drops below 3.3V
sensors.setThreshold("battery", "voltage", 
                    3.3, 5.0, ALERT_BELOW);

ALERT_BETWEEN

Triggers when value is within range.
// Alert when pH is in optimal range (6.5-7.5)
sensors.setThreshold("water", "ph", 
                    6.5, 7.5, ALERT_BETWEEN);

ALERT_OUTSIDE

Triggers when value is outside range (most common).
// Alert when temperature is outside safe range
sensors.setThreshold("fridge", "temperature", 
                    2.0, 8.0, ALERT_OUTSIDE);

Alert Callbacks

Global Alert Callback

Single callback for all alerts:
void alertHandler(AlertInfo info) {
    Serial.println("\n=== ALERT ===");
    Serial.print("Sensor: ");
    Serial.println(info.sensorName);
    Serial.print("Value: ");
    Serial.println(info.valueKey);
    Serial.print("Current: ");
    Serial.println(info.currentValue);
    Serial.print("Range: ");
    Serial.print(info.lowThreshold);
    Serial.print(" - ");
    Serial.println(info.highThreshold);
    Serial.print("State: ");
    Serial.println(info.state);
    Serial.print("Time: ");
    Serial.println(info.timeTriggered);
    Serial.print("Repeat Count: ");
    Serial.println(info.repeatCount);
}

void setup() {
    // ... sensor setup ...
    
    sensors.setGlobalAlertCallback(alertHandler);
}

Sensor-Specific Callbacks

Different callbacks for different sensors:
void temperatureAlert(AlertInfo info) {
    Serial.print("Temperature alert: ");
    Serial.print(info.currentValue);
    Serial.println("°C");
    
    // Take action
    if (info.type == ALERT_ABOVE) {
        activateCooling();
    } else {
        activateHeating();
    }
}

void humidityAlert(AlertInfo info) {
    Serial.print("Humidity alert: ");
    Serial.print(info.currentValue);
    Serial.println("%");
    
    activateDehumidifier();
}

void setup() {
    // ... sensor setup ...
    
    // Set sensor-specific callbacks
    sensors.setSensorAlertCallback("climate_temp", temperatureAlert);
    sensors.setSensorAlertCallback("climate_hum", humidityAlert);
}

Lambda Callbacks

void setup() {
    // ... sensor setup ...
    
    // Inline lambda callback
    sensors.setGlobalAlertCallback([](AlertInfo info) {
        digitalWrite(LED_PIN, info.state == ALERT_ACTIVE ? HIGH : LOW);
        
        if (info.state == ALERT_ACTIVE) {
            Serial.print("ALERT: ");
            Serial.print(info.sensorName);
            Serial.print(".");
            Serial.print(info.valueKey);
            Serial.print(" = ");
            Serial.println(info.currentValue);
        }
    });
}

Alert Parameters

Hysteresis

Prevents alert oscillation at threshold boundaries.
// Set default hysteresis for all alerts
sensors.setDefaultHysteresis(1000);  // 1.0 unit (value * 1000)

// Set specific threshold with hysteresis
sensors.setThreshold("temp", "temperature", 20.0, 30.0, ALERT_OUTSIDE);
sensors.setThresholdParams("temp", "temperature", 
                          2000,     // Hysteresis: 2.0°C
                          0);       // Debounce time: 0ms
How Hysteresis Works:
  • Alert triggers at threshold
  • Alert clears only when value moves beyond threshold + hysteresis
  • Prevents rapid on/off cycling
Example:
Threshold: 30°C
Hysteresis: 2°C

Trigger ALERT_ABOVE: When temp >= 30°C
Clear alert: When temp < 28°C (30 - 2)

Prevents alerts oscillating when temp hovers around 30°C

Debouncing

Delay alert trigger to avoid false alarms from noise.
// Set default debounce time
sensors.setDefaultDebounceTime(5000);  // 5 seconds

// Set specific debounce
sensors.setThreshold("sensor", "value", 100.0, 200.0, ALERT_OUTSIDE);
sensors.setThresholdParams("sensor", "value",
                          0,        // No hysteresis
                          10000);   // 10 second debounce
How Debouncing Works:
  • Threshold condition must remain true for debounce period
  • Alert only triggers after continuous violation
  • Filters out brief spikes and noise
Example:
Threshold: > 100
Debounce: 5 seconds

Value exceeds 100 at t=0s
- Alert doesn't trigger yet
- System waits 5 seconds
At t=5s, if value still > 100:
- Alert triggers
If value drops below 100 before t=5s:
- Alert does not trigger

Alert Management

Checking Alert Status

void loop() {
    sensors.update();
    
    // Check if specific alert is active
    if (sensors.isAlertActive("temp", "temperature")) {
        Serial.println("Temperature alert!");
    }
    
    // Get detailed alert state
    AlertState state = sensors.getAlertState("temp", "temperature");
    switch (state) {
        case ALERT_INACTIVE:
            Serial.println("No alert");
            break;
        case ALERT_ACTIVE:
            Serial.println("Alert active!");
            break;
        case ALERT_ACKNOWLEDGED:
            Serial.println("Alert acknowledged");
            break;
    }
}

Acknowledging Alerts

Acknowledge alerts to prevent repeated notifications:
void loop() {
    sensors.update();
    
    if (sensors.isAlertActive("temp", "temperature")) {
        AlertState state = sensors.getAlertState("temp", "temperature");
        
        if (state == ALERT_ACTIVE) {
            // First time alert triggered
            notifyUser();
            
            // Acknowledge to prevent repeated notifications
            sensors.acknowledgeAlert("temp", "temperature");
        }
    }
    
    // Button press to acknowledge all alerts
    if (digitalRead(ACK_BUTTON) == LOW) {
        sensors.acknowledgeAllAlerts();
        Serial.println("All alerts acknowledged");
    }
}

Resetting Alerts

Clear alert state manually:
// Reset specific alert
sensors.resetAlert("temp", "temperature");

// Reset all alerts
sensors.resetAllAlerts();

Removing Alerts

// Remove specific threshold
sensors.removeThreshold("temp", "temperature");

// Remove all thresholds
sensors.removeAllThresholds();

// Clear all callbacks
sensors.clearAlertCallbacks();

Complete Alert Example

#define ENABLE_SENSOR_MODULE_V2
#define ENABLE_SENSOR_ALERT_SYSTEM_V2
#define ENABLE_SENSOR_DHT_V2
#define ENABLE_SENSOR_BME680_V2
#define ENABLE_SENSOR_ANALOG_V2
#include "Kinematrix.h"

SensorModuleV2 sensors;
DHTSensV2 dht(2, DHT22);
BME680SensV2 bme680;
AnalogSensV2 battery(A0, 5.0, 1023);

const int BUZZER_PIN = 13;
const int LED_RED = 12;
const int LED_YELLOW = 11;
const int ACK_BUTTON = 10;

bool buzzerActive = false;

void criticalAlert(AlertInfo info) {
    // Critical alerts: activate buzzer
    Serial.println("\n*** CRITICAL ALERT ***");
    Serial.print(info.sensorName);
    Serial.print(".");
    Serial.print(info.valueKey);
    Serial.print(": ");
    Serial.println(info.currentValue);
    
    digitalWrite(LED_RED, HIGH);
    buzzerActive = true;
}

void warningAlert(AlertInfo info) {
    // Warning alerts: LED only
    Serial.println("\n- Warning -");
    Serial.print(info.sensorName);
    Serial.print(".");
    Serial.print(info.valueKey);
    Serial.print(": ");
    Serial.println(info.currentValue);
    
    digitalWrite(LED_YELLOW, HIGH);
}

void setup() {
    Serial.begin(115200);
    
    pinMode(BUZZER_PIN, OUTPUT);
    pinMode(LED_RED, OUTPUT);
    pinMode(LED_YELLOW, OUTPUT);
    pinMode(ACK_BUTTON, INPUT_PULLUP);
    
    // Configure sensors
    dht.setUpdateInterval(2000);
    bme680.setUpdateInterval(5000);
    battery.setUpdateInterval(10000);
    
    sensors.addSensor("climate", &dht);
    sensors.addSensor("air", &bme680);
    sensors.addSensor("power", &battery);
    sensors.init();
    
    // Configure alert system
    sensors.setDefaultHysteresis(1000);   // 1.0 unit hysteresis
    sensors.setDefaultDebounceTime(3000); // 3 second debounce
    
    // Critical alerts
    sensors.setThreshold("climate", "temperature", 15.0, 35.0, ALERT_OUTSIDE);
    sensors.setSensorAlertCallback("climate", criticalAlert);
    
    sensors.setThreshold("power", "volt", 3.3, 5.0, ALERT_BELOW);
    sensors.setSensorAlertCallback("power", criticalAlert);
    
    // Warning alerts
    sensors.setThreshold("climate", "humidity", 30.0, 70.0, ALERT_OUTSIDE);
    sensors.setSensorAlertCallback("air", warningAlert);
    
    sensors.setThreshold("air", "pressure", 980.0, 1050.0, ALERT_OUTSIDE);
    
    Serial.println("Alert system initialized");
    Serial.println("Press button to acknowledge alerts");
}

void loop() {
    sensors.update();
    
    // Handle buzzer
    if (buzzerActive) {
        // Beep pattern
        static unsigned long lastBeep = 0;
        if (millis() - lastBeep > 1000) {
            tone(BUZZER_PIN, 2000, 200);
            lastBeep = millis();
        }
    }
    
    // Acknowledge button
    static bool lastButtonState = HIGH;
    bool buttonState = digitalRead(ACK_BUTTON);
    
    if (buttonState == LOW && lastButtonState == HIGH) {
        sensors.acknowledgeAllAlerts();
        buzzerActive = false;
        digitalWrite(LED_RED, LOW);
        digitalWrite(LED_YELLOW, LOW);
        Serial.println("\nAll alerts acknowledged");
    }
    lastButtonState = buttonState;
    
    // Display status
    static unsigned long lastDisplay = 0;
    if (millis() - lastDisplay > 5000) {
        Serial.println("\n=== Status ===");
        
        float temp = sensors.getValue<float>("climate", "temperature");
        Serial.print("Temperature: ");
        Serial.print(temp);
        Serial.print("°C ");
        if (sensors.isAlertActive("climate", "temperature")) {
            Serial.println("[ALERT]");
        } else {
            Serial.println("[OK]");
        }
        
        float humidity = sensors.getValue<float>("climate", "humidity");
        Serial.print("Humidity: ");
        Serial.print(humidity);
        Serial.print("% ");
        if (sensors.isAlertActive("climate", "humidity")) {
            Serial.println("[ALERT]");
        } else {
            Serial.println("[OK]");
        }
        
        float pressure = sensors.getValue<float>("air", "pressure");
        Serial.print("Pressure: ");
        Serial.print(pressure);
        Serial.print(" hPa ");
        if (sensors.isAlertActive("air", "pressure")) {
            Serial.println("[ALERT]");
        } else {
            Serial.println("[OK]");
        }
        
        float battery = sensors.getValue<float>("power", "volt");
        Serial.print("Battery: ");
        Serial.print(battery);
        Serial.print(" V ");
        if (sensors.isAlertActive("power", "volt")) {
            Serial.println("[ALERT]");
        } else {
            Serial.println("[OK]");
        }
        
        lastDisplay = millis();
    }
}

Alert Use Cases

Environmental Monitoring

// Greenhouse monitoring
sensors.setThreshold("greenhouse", "temperature", 18.0, 28.0, ALERT_OUTSIDE);
sensors.setThreshold("greenhouse", "humidity", 50.0, 80.0, ALERT_OUTSIDE);
sensors.setThreshold("greenhouse", "soilMoisture", 30.0, 70.0, ALERT_OUTSIDE);

sensors.setGlobalAlertCallback([](AlertInfo info) {
    if (strcmp(info.valueKey, "temperature") == 0) {
        if (info.currentValue < info.lowThreshold) {
            activateHeater();
        } else {
            activateVentilation();
        }
    } else if (strcmp(info.valueKey, "soilMoisture") == 0) {
        if (info.currentValue < info.lowThreshold) {
            activateIrrigation();
        }
    }
});

Equipment Protection

// Server room monitoring
sensors.setThreshold("server_room", "temperature", 18.0, 25.0, ALERT_OUTSIDE);
sensors.setThreshold("server_room", "humidity", 40.0, 60.0, ALERT_OUTSIDE);

// Immediate shutdown on critical temperature
sensors.setSensorAlertCallback("server_room", [](AlertInfo info) {
    if (strcmp(info.valueKey, "temperature") == 0 && 
        info.currentValue > 30.0) {
        emergencyShutdown();
        sendAlertEmail("Critical temperature!");
    }
});

Process Control

// Fermentation tank
sensors.setThreshold("tank", "temperature", 20.0, 22.0, ALERT_OUTSIDE);
sensors.setThreshold("tank", "ph", 4.5, 5.5, ALERT_OUTSIDE);
sensors.setThreshold("tank", "pressure", 0.9, 1.1, ALERT_OUTSIDE);

sensors.setThresholdParams("tank", "temperature", 500, 2000);  // 0.5°C hysteresis, 2s debounce
sensors.setThresholdParams("tank", "ph", 100, 5000);           // 0.1 pH hysteresis, 5s debounce

Safety Systems

// Gas leak detection
sensors.setThreshold("gas", "ppm", 0.0, 1000.0, ALERT_ABOVE);

sensors.setSensorAlertCallback("gas", [](AlertInfo info) {
    if (info.state == ALERT_ACTIVE) {
        // Immediate action
        closeGasValve();
        activateAlarm();
        notifyEmergency();
    }
});

Best Practices

Use Hysteresis: Always set hysteresis to prevent alert oscillation, especially for noisy sensors.
sensors.setDefaultHysteresis(1000);  // 1.0 unit
Debounce for Safety: Use debouncing for non-critical alerts to avoid false alarms, but minimize or disable for safety-critical alerts.
// Non-critical: use debounce
sensors.setThresholdParams("temp", "temperature", 1000, 5000);

// Critical: no debounce
sensors.setThresholdParams("gas", "ppm", 0, 0);
Combine with Filtering: Use filtered values for alerts to reduce noise:
FilterParams params;
params.movingAverage.windowSize = 5;
sensors.attachFilter("sensor", "value", FILTER_MOVING_AVERAGE, params);
sensors.setThreshold("sensor", "value", 10.0, 20.0, ALERT_OUTSIDE);
// Alert system automatically uses filtered values

Troubleshooting

Alerts Not Triggering

// Check if alert system is enabled
if (!sensors.hasAlertSystem()) {
    Serial.println("Alert system not initialized!");
}

// Verify threshold is set
AlertState state = sensors.getAlertState("sensor", "value");
if (state == ALERT_INACTIVE) {
    // Check sensor value
    float value = sensors.getValue<float>("sensor", "value");
    Serial.print("Current value: ");
    Serial.println(value);
}

Too Many False Alarms

// Increase debounce time
sensors.setDefaultDebounceTime(10000);  // 10 seconds

// Add filtering
FilterParams params;
params.median.windowSize = 7;  // Remove spikes
sensors.attachFilter("sensor", "value", FILTER_MEDIAN, params);

Alerts Not Clearing

// Increase hysteresis
sensors.setThresholdParams("sensor", "value", 
                          5000,   // Larger hysteresis
                          0);

// Or manually reset
sensors.resetAlert("sensor", "value");

Next Steps

Filtering

Reduce noise before alert detection

Calibration

Ensure accurate threshold detection

Build docs developers (and LLMs) love