philipp2604.VariableValueMonitor
1.1.0
dotnet add package philipp2604.VariableValueMonitor --version 1.1.0
NuGet\Install-Package philipp2604.VariableValueMonitor -Version 1.1.0
<PackageReference Include="philipp2604.VariableValueMonitor" Version="1.1.0" />
<PackageVersion Include="philipp2604.VariableValueMonitor" Version="1.1.0" />
<PackageReference Include="philipp2604.VariableValueMonitor" />
paket add philipp2604.VariableValueMonitor --version 1.1.0
#r "nuget: philipp2604.VariableValueMonitor, 1.1.0"
#:package philipp2604.VariableValueMonitor@1.1.0
#addin nuget:?package=philipp2604.VariableValueMonitor&version=1.1.0
#tool nuget:?package=philipp2604.VariableValueMonitor&version=1.1.0
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.
✨ 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).
- Thresholds: Trigger alarms when a numeric value goes above or below a set point (e.g.,
- 🔧 Fluent Condition Builders: Use the static
CommonConditions
class for a clean, readable way to create common alarm logic likeOnTrue()
,OnValueJump()
,OnStringEquals()
,WithDelay()
, andOnHighValueHysteresis()
. - ⏰ 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
andAlarmCleared
events to seamlessly integrate alarm logic into your application's workflow. - 🚀 Type-Safe & Generic: Monitor any
IComparable
orIEquatable
type, from primitives (int
,double
,bool
) andenums
to your own customrecord
orclass
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 comparisonsPredicateCondition
: Custom predicate logicValueChangeCondition
: Old vs new value comparisonsDelayedCondition<T>
: Wraps any condition with a time delayHysteresisThresholdCondition
: 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 likeWithDelay()
andOnHighValueHysteresis()
. - 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.
- Fork the repository.
- Create a new branch for your feature or bug fix.
- Make your changes.
- Add or update unit/integration tests to cover your changes.
- 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 | Versions 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. |
-
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.