fix: wire DCL tag value delivery, alarm evaluation, and snapshot timestamps
Three runtime bugs fixed: - DataConnectionActor: TagValueReceived/TagResolutionSucceeded/Failed not handled in any Become state — OPC UA values went to dead letters. Added initial read after subscribe to seed current values immediately. - AlarmActor: ParseEvalConfig expected "attributeName"/"matchValue"/"min"/ "max" keys but seed data uses "attribute"/"value"/"high"/"low". Added support for both conventions and !=prefix for not-equal matching. - InstanceActor: snapshots reported all alarms (including unevaluated) with correct priorities and source timestamps instead of current UTC. Removed bogus Vibration template attribute that shadowed Speed's tag mapping.
This commit is contained in:
@@ -184,8 +184,18 @@ public class AlarmActor : ReceiveActor
|
||||
private bool EvaluateValueMatch(object? value)
|
||||
{
|
||||
if (_evalConfig is not ValueMatchEvalConfig config) return false;
|
||||
if (value == null) return config.MatchValue == null;
|
||||
return string.Equals(value.ToString(), config.MatchValue, StringComparison.Ordinal);
|
||||
if (config.MatchValue == null) return value == null;
|
||||
|
||||
var valueStr = value?.ToString() ?? "";
|
||||
|
||||
// Support "!=X" for not-equal matching
|
||||
if (config.MatchValue.StartsWith("!="))
|
||||
{
|
||||
var expected = config.MatchValue[2..];
|
||||
return !string.Equals(valueStr, expected, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
return string.Equals(valueStr, config.MatchValue, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private bool EvaluateRangeViolation(object? value)
|
||||
@@ -268,24 +278,36 @@ public class AlarmActor : ReceiveActor
|
||||
try
|
||||
{
|
||||
var doc = JsonDocument.Parse(triggerConfigJson);
|
||||
var attr = doc.RootElement.TryGetProperty("attributeName", out var attrEl)
|
||||
? attrEl.GetString() ?? "" : "";
|
||||
var root = doc.RootElement;
|
||||
|
||||
// Support both "attributeName" and "attribute" keys
|
||||
var attr = root.TryGetProperty("attributeName", out var attrEl)
|
||||
? attrEl.GetString() ?? ""
|
||||
: root.TryGetProperty("attribute", out var attrEl2)
|
||||
? attrEl2.GetString() ?? ""
|
||||
: "";
|
||||
|
||||
return _triggerType switch
|
||||
{
|
||||
AlarmTriggerType.ValueMatch => new ValueMatchEvalConfig(
|
||||
attr,
|
||||
doc.RootElement.TryGetProperty("matchValue", out var mv) ? mv.GetString() : null),
|
||||
root.TryGetProperty("matchValue", out var mv) ? mv.GetString()
|
||||
: root.TryGetProperty("value", out var mv2) ? mv2.GetString()
|
||||
: null),
|
||||
|
||||
AlarmTriggerType.RangeViolation => new RangeViolationEvalConfig(
|
||||
attr,
|
||||
doc.RootElement.TryGetProperty("min", out var minEl) ? minEl.GetDouble() : double.MinValue,
|
||||
doc.RootElement.TryGetProperty("max", out var maxEl) ? maxEl.GetDouble() : double.MaxValue),
|
||||
root.TryGetProperty("min", out var minEl) ? minEl.GetDouble()
|
||||
: root.TryGetProperty("low", out var lowEl) ? lowEl.GetDouble()
|
||||
: double.MinValue,
|
||||
root.TryGetProperty("max", out var maxEl) ? maxEl.GetDouble()
|
||||
: root.TryGetProperty("high", out var highEl) ? highEl.GetDouble()
|
||||
: double.MaxValue),
|
||||
|
||||
AlarmTriggerType.RateOfChange => new RateOfChangeEvalConfig(
|
||||
attr,
|
||||
doc.RootElement.TryGetProperty("thresholdPerSecond", out var tps) ? tps.GetDouble() : 10.0,
|
||||
doc.RootElement.TryGetProperty("windowSeconds", out var ws)
|
||||
root.TryGetProperty("thresholdPerSecond", out var tps) ? tps.GetDouble() : 10.0,
|
||||
root.TryGetProperty("windowSeconds", out var ws)
|
||||
? TimeSpan.FromSeconds(ws.GetDouble())
|
||||
: TimeSpan.FromSeconds(1)),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user