philipp2604.VariableValueMonitor 1.1.0

dotnet add package philipp2604.VariableValueMonitor --version 1.1.0
                    
NuGet\Install-Package philipp2604.VariableValueMonitor -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="philipp2604.VariableValueMonitor" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="philipp2604.VariableValueMonitor" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="philipp2604.VariableValueMonitor" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add philipp2604.VariableValueMonitor --version 1.1.0
                    
#r "nuget: philipp2604.VariableValueMonitor, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package philipp2604.VariableValueMonitor@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=philipp2604.VariableValueMonitor&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=philipp2604.VariableValueMonitor&version=1.1.0
                    
Install as a Cake Tool

VariableValueMonitor 🚨

A flexible, modern .NET library for monitoring variable values and triggering alarms based on a rich set of configurable conditions. It's designed to be a lightweight, type-safe, and thread-safe core for any application that needs to react to state changes, such as in industrial automation, IoT, or system monitoring.

.NET 8 (LTS) Build & Test .NET 9 (Latest) Build & Test
Language License GitHub issues
NuGet Version Ask DeepWiki

✨ Key Features

  • ✅ Flexible Condition Engine: Define alarms using five powerful, type-safe condition types:
    • Thresholds: Trigger alarms when a numeric value goes above or below a set point (e.g., temperature > 80.0).
    • Predicates: Use custom logic (Predicate<T>) for complex state validation (e.g., status == "Error", isEmergencyStop == true).
    • Value Changes: React to the dynamics of a variable by comparing its old and new values (e.g., newValue > oldValue, Math.Abs(newValue - oldValue) > 10.0).
    • Delayed Conditions: Wrap any condition to only trigger alarms if the condition remains active for a specified duration (e.g., prevent nuisance alarms from brief spikes).
    • Hysteresis Thresholds: Use separate trigger and clear thresholds to prevent oscillating alarms (e.g., trigger at 85°C, clear at 75°C).
  • 🔧 Fluent Condition Builders: Use the static CommonConditions class for a clean, readable way to create common alarm logic like OnTrue(), OnValueJump(), OnStringEquals(), WithDelay(), and OnHighValueHysteresis().
  • ⏰ Time-Based Features: Advanced timing capabilities including delayed conditions for filtering transient spikes and hysteresis conditions for stable alarm behavior.
  • 🔔 Event-Driven Alarms: Subscribe to AlarmTriggered and AlarmCleared events to seamlessly integrate alarm logic into your application's workflow.
  • 🚀 Type-Safe & Generic: Monitor any IComparable or IEquatable type, from primitives (int, double, bool) and enums to your own custom record or class types.
  • 🎛️ Stateful Alarm Management: The monitor tracks the state of all active alarms, preventing duplicate triggers and providing Acknowledge functionality.
  • ⚡️ Thread-Safe by Design: Built with ConcurrentDictionary to ensure that registering variables and notifying value changes is safe across multiple threads.
  • 🏗️ Lightweight & Modern: A focused library with a minimal footprint, written in modern C# with clear, testable components.

🏛️ Architecture

The library is designed with a clear separation of concerns, making it easy to understand and extend.

  • The Monitor (ValueMonitor): The central engine and public API. It manages variable registrations, state, timing infrastructure, and orchestrates condition checking and event firing.
  • Conditions: Five types of declarative, type-safe "rules" that you define:
    • ThresholdCondition: Numeric threshold comparisons
    • PredicateCondition: Custom predicate logic
    • ValueChangeCondition: Old vs new value comparisons
    • DelayedCondition<T>: Wraps any condition with a time delay
    • HysteresisThresholdCondition: Separate trigger and clear thresholds
  • Common Conditions (CommonConditions): A static helper class that acts as a factory for creating the most frequently used conditions, including time-based helpers like WithDelay() and OnHighValueHysteresis().
  • Timing Infrastructure (ITimerProvider, TimerProvider, ConditionTimer): Manages time-based condition logic with testable abstractions.
  • Events (AlarmEventArgs, ValueChangedEventArgs): The primary output mechanism. These classes carry all the context about an alarm or value change to your event handlers.
  • Data Models (ActiveAlarm, VariableRegistration): Internal and public records/classes that represent the state of monitored variables and active alarms.

As an end-user, you will primarily interact with the ValueMonitor class and define your logic using the various Condition types.

🚀 Getting Started

Installation

VariableValueMonitor will be available on NuGet. You can install it using the .NET CLI:

dotnet add package philipp2604.VariableValueMonitor 

Or via the NuGet Package Manager in Visual Studio.

Quick Start

Here's a practical example demonstrating how to monitor multiple variables with different types of conditions.

using VariableValueMonitor.Alarms.Conditions;
using VariableValueMonitor.Enums;
using VariableValueMonitor.Events;
using VariableValueMonitor.Monitor;

// 1. Initialize the ValueMonitor
var monitor = new ValueMonitor();

// 2. Subscribe to the alarm events
monitor.AlarmTriggered += OnAlarmTriggered;
monitor.AlarmCleared += OnAlarmCleared;

Console.WriteLine("--- Registering Variables for Monitoring ---");

// 3. Register variables with various conditions
// A temperature sensor with a high-temperature warning
monitor.RegisterVariable<double>("temp_sensor_1", "Main Boiler Temperature", 25.0,
    new ThresholdCondition(AlarmType.Warning, AlarmDirection.UpperBound, 85.0, "High temperature detected!"));

// An emergency stop button (boolean)
monitor.RegisterVariable<bool>("emergency_stop_1", "Main Conveyor E-Stop", false,
    CommonConditions.OnTrue(AlarmType.Alarm, "Emergency stop has been activated!"));

// A pressure sensor that alarms on a sudden jump
monitor.RegisterVariable<double>("pressure_sensor_1", "Hydraulic Pressure", 120.0,
    CommonConditions.OnValueJump(AlarmType.Info, 20.0, "Rapid pressure change detected."));

// A machine state monitor using enums
monitor.RegisterVariable<MachineState>("machine_1", "CNC Machine State", MachineState.Running,
    [CommonConditions.OnEnumEquals(AlarmType.Alarm, MachineState.Error, "Machine has entered an error state!")]);
monitor.RegisterVariable<MachineState>("machine_1", "CNC Machine State", MachineState.Running,
    [CommonConditions.OnEnumChange(AlarmType.Info, MachineState.Running, MachineState.Maintenance, "Machine is now under maintenance.")]);

// A delayed condition - only triggers after temperature is high for 30 seconds
monitor.RegisterVariable<double>("temp_delayed", "Oven Temperature", 60.0,
    CommonConditions.OnHighValueDelayed(200.0, TimeSpan.FromSeconds(30), "Sustained high temperature detected!"));

// A hysteresis condition - triggers at 85°C, clears at 75°C
monitor.RegisterVariable<double>("temp_hysteresis", "Reactor Temperature", 70.0,
    CommonConditions.OnHighValueHysteresis(85.0, 75.0, "Reactor temperature alarm"));

Console.WriteLine("--- Simulating Value Changes ---\n");

// 4. Notify the monitor of new values
monitor.NotifyValueChanged("temp_sensor_1", 90.0);       // Triggers "High temperature"
monitor.NotifyValueChanged("pressure_sensor_1", 155.5);  // Triggers "Rapid pressure change"
monitor.NotifyValueChanged("emergency_stop_1", true);    // Triggers "E-Stop activated"
monitor.NotifyValueChanged("machine_1", MachineState.Error); // Triggers "Error state"

// Demonstrate hysteresis behavior
monitor.NotifyValueChanged("temp_hysteresis", 90.0);     // Triggers at 85°C threshold
monitor.NotifyValueChanged("temp_hysteresis", 80.0);     // Stays active (above 75°C clear threshold)
monitor.NotifyValueChanged("temp_hysteresis", 74.0);     // Clears at 75°C threshold

// Demonstrate delayed condition (would need to wait 30 seconds for actual trigger)
monitor.NotifyValueChanged("temp_delayed", 220.0);       // Starts delay timer, no immediate alarm

monitor.NotifyValueChanged("temp_sensor_1", 80.0);       // Clears the temperature alarm

Console.WriteLine($"\n--- Final State ---");
Console.WriteLine($"There are {monitor.GetActiveAlarms().Count} active alarms.");

// Clean up event handlers
monitor.AlarmTriggered -= OnAlarmTriggered;
monitor.AlarmCleared -= OnAlarmCleared;


// --- Event Handlers ---

void OnAlarmTriggered(object? sender, AlarmEventArgs e)
{
    Console.ForegroundColor = ConsoleColor.Red;
    Console.WriteLine($"ALARM TRIGGERED for '{e.VariableName}' ({e.VariableId})");
    Console.WriteLine($"   - Type: {e.AlarmType}, Message: {e.Message}");
    Console.WriteLine($"   - Value changed from '{e.PreviousValue}' to '{e.CurrentValue}'");
    Console.ResetColor();
}

void OnAlarmCleared(object? sender, AlarmEventArgs e)
{
    Console.ForegroundColor = ConsoleColor.Green;
    Console.WriteLine($"ALARM CLEARED for '{e.VariableName}' ({e.VariableId})");
    Console.WriteLine($"   - Message: {e.Message}");
    Console.WriteLine($"   - Current value is now '{e.CurrentValue}'");
    Console.ResetColor();
}

public enum MachineState { Stopped, Running, Maintenance, Error }

⏰ Time-Based Features

Delayed Conditions

Delayed conditions wrap existing conditions and only trigger alarms after the condition has been active for a specified duration. This prevents nuisance alarms from brief spikes or transient conditions.

// Only trigger after temperature exceeds 85°C for 5 seconds
var delayedCondition = CommonConditions.OnHighValueDelayed(85.0, TimeSpan.FromSeconds(5), "Sustained high temperature");
monitor.RegisterVariable("temp_sensor", "Temperature", 70.0, delayedCondition);

// You can wrap any condition type with a delay
var delayedPredicate = CommonConditions.WithDelay(
    CommonConditions.OnTrue(AlarmType.Alarm, "Emergency stop activated"),
    TimeSpan.FromSeconds(2));
monitor.RegisterVariable("e_stop", "Emergency Stop", false, delayedPredicate);

Hysteresis Thresholds

Hysteresis conditions use separate trigger and clear thresholds to prevent oscillating alarms around a single threshold value.

// Trigger alarm at 85°C, but don't clear until temperature drops to 75°C
var hysteresisCondition = CommonConditions.OnHighValueHysteresis(85.0, 75.0, "High temperature with hysteresis");
monitor.RegisterVariable("temp_sensor", "Temperature", 70.0, hysteresisCondition);

// Sequence of events:
monitor.NotifyValueChanged("temp_sensor", 90.0);  // Alarm triggered (>= 85°C)
monitor.NotifyValueChanged("temp_sensor", 82.0);  // Alarm stays active (> 75°C clear threshold)
monitor.NotifyValueChanged("temp_sensor", 74.0);  // Alarm cleared (<= 75°C)

Custom Timer Provider

For testing or specialized timing needs, you can provide your own timer implementation:

// Use custom timer provider (useful for unit testing)
var customTimerProvider = new MyCustomTimerProvider();
var monitor = new ValueMonitor(customTimerProvider);

📖 Documentation

  • ValueMonitor API Reference: The ValueMonitor interface is the primary entry point for all operations. Its public methods define the library's capabilities.
  • Common Conditions Reference: Explore this static class to see the available pre-built condition helpers, including time-based features.
  • Time-Based Conditions: Examples and tests for delayed conditions and hysteresis thresholds.
  • Unit Tests: The unit tests provide comprehensive, focused examples for every feature and condition type.
  • Integration Tests: These tests showcase how to handle more complex, multi-alarm scenarios.

🤝 Contributing

Contributions are welcome! Whether it's bug reports, feature requests, or pull requests, your help is appreciated.

  1. Fork the repository.
  2. Create a new branch for your feature or bug fix.
  3. Make your changes.
  4. Add or update unit/integration tests to cover your changes.
  5. Submit a Pull Request with a clear description of your changes.

Please open an issue first to discuss any major changes.

⚖️ License

This project is licensed under the MIT License. This is a permissive license that allows for reuse in both open-source and proprietary software. You are free to use, modify, and distribute this library as you see fit. See the LICENSE file for full details.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 506 7/22/2025
1.0.1 117 7/17/2025
1.0.0 121 7/17/2025