feat: add JoeAppEngine OPC UA nodes, fix DCL auto-reconnect and quality push

- Add JoeAppEngine folder to OPC UA nodes.json (BTCS, AlarmCntsBySeverity, Scheduler/ScanTime)
- Fix DataConnectionActor: capture Self in PreStart for use from non-actor threads,
  preventing Self.Tell failure in Disconnected event handler
- Implement InstanceActor.HandleConnectionQualityChanged to mark attributes Bad on disconnect
- Fix LmxFakeProxy TagMapper to serialize arrays as JSON instead of "System.Int32[]"
- Allow DataType and DataSourceReference updates in TemplateService.UpdateAttributeAsync
- Update test_infra_opcua.md with JoeAppEngine documentation
This commit is contained in:
Joseph Doherty
2026-03-19 13:27:54 -04:00
parent ffdda51990
commit 7740a3bcf9
70 changed files with 2684 additions and 541 deletions

View File

@@ -284,17 +284,36 @@ public class InstanceActor : ReceiveActor
{
if (_tagPathToAttribute.TryGetValue(update.TagPath, out var attrName))
{
// Normalize array values to JSON strings so they survive Akka serialization
var value = update.Value is Array
? System.Text.Json.JsonSerializer.Serialize(update.Value, update.Value.GetType())
: update.Value;
var changed = new AttributeValueChanged(
_instanceUniqueName, update.TagPath, attrName,
update.Value, update.Quality.ToString(), update.Timestamp);
value, update.Quality.ToString(), update.Timestamp);
HandleAttributeValueChanged(changed);
}
}
private void HandleConnectionQualityChanged(ConnectionQualityChanged qualityChanged)
{
_logger.LogInformation("Connection {Connection} quality changed to {Quality}",
qualityChanged.ConnectionName, qualityChanged.Quality);
_logger.LogWarning("Connection {Connection} quality changed to {Quality} for instance {Instance}",
qualityChanged.ConnectionName, qualityChanged.Quality, _instanceUniqueName);
if (_configuration == null) return;
// Mark all attributes bound to this connection with the new quality
var qualityStr = qualityChanged.Quality.ToString();
foreach (var attr in _configuration.Attributes)
{
if (attr.BoundDataConnectionName == qualityChanged.ConnectionName &&
!string.IsNullOrEmpty(attr.DataSourceReference))
{
_attributeQualities[attr.CanonicalName] = qualityStr;
_attributeTimestamps[attr.CanonicalName] = qualityChanged.Timestamp;
}
}
}
/// <summary>