fix(site-runtime): fan tag updates out to every attribute sharing a tag path
InstanceActor._tagPathToAttribute was a Dictionary<string,string> — one tag path mapped to a single attribute. When two attributes reference the same PLC node (e.g. two composed cooling-tank modules both reading ns=3;s=Tank.Level, or a pump's TempSensor and AlarmSensor both reading ns=3;s=Sensor.Reading), SubscribeToDcl's map assignment overwrote, so only the last-registered attribute ever received values — the rest stayed permanently Uncertain. The map is now Dictionary<string,List<string>>; HandleTagValueUpdate fans each update out to every attribute referencing the tag path, and each distinct tag path is still subscribed only once per connection.
This commit is contained in:
@@ -52,8 +52,11 @@ public class InstanceActor : ReceiveActor
|
||||
|
||||
// DCL manager actor reference for subscribing to tag values
|
||||
private readonly IActorRef? _dclManager;
|
||||
// Maps tag paths back to attribute canonical names for DCL updates
|
||||
private readonly Dictionary<string, string> _tagPathToAttribute = new();
|
||||
// Maps each tag path to every attribute canonical name that references it.
|
||||
// A tag path can back more than one attribute (e.g. two composed modules
|
||||
// whose members reference the same PLC node), so a tag value update must
|
||||
// fan out to all of them — not just the last one registered.
|
||||
private readonly Dictionary<string, List<string>> _tagPathToAttributes = new();
|
||||
|
||||
public InstanceActor(
|
||||
string instanceUniqueName,
|
||||
@@ -350,13 +353,17 @@ public class InstanceActor : ReceiveActor
|
||||
/// </summary>
|
||||
private void HandleTagValueUpdate(TagValueUpdate update)
|
||||
{
|
||||
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;
|
||||
if (!_tagPathToAttributes.TryGetValue(update.TagPath, out var attrNames))
|
||||
return;
|
||||
|
||||
// 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;
|
||||
|
||||
// One tag path may back several attributes — update every one of them.
|
||||
foreach (var attrName in attrNames)
|
||||
{
|
||||
var changed = new AttributeValueChanged(
|
||||
_instanceUniqueName, update.TagPath, attrName,
|
||||
value, update.Quality.ToString(), update.Timestamp);
|
||||
@@ -414,11 +421,24 @@ public class InstanceActor : ReceiveActor
|
||||
string.IsNullOrEmpty(attr.BoundDataConnectionName))
|
||||
continue;
|
||||
|
||||
_tagPathToAttribute[attr.DataSourceReference] = attr.CanonicalName;
|
||||
// Record every attribute that references this tag path so a single
|
||||
// tag value update fans out to all of them.
|
||||
if (!_tagPathToAttributes.TryGetValue(attr.DataSourceReference, out var attrs))
|
||||
{
|
||||
attrs = new List<string>();
|
||||
_tagPathToAttributes[attr.DataSourceReference] = attrs;
|
||||
}
|
||||
attrs.Add(attr.CanonicalName);
|
||||
|
||||
if (!byConnection.ContainsKey(attr.BoundDataConnectionName))
|
||||
byConnection[attr.BoundDataConnectionName] = new List<string>();
|
||||
byConnection[attr.BoundDataConnectionName].Add(attr.DataSourceReference);
|
||||
if (!byConnection.TryGetValue(attr.BoundDataConnectionName, out var connTags))
|
||||
{
|
||||
connTags = new List<string>();
|
||||
byConnection[attr.BoundDataConnectionName] = connTags;
|
||||
}
|
||||
// Subscribe each distinct tag path once per connection — a tag shared
|
||||
// by several attributes still needs only one DCL subscription.
|
||||
if (!connTags.Contains(attr.DataSourceReference))
|
||||
connTags.Add(attr.DataSourceReference);
|
||||
}
|
||||
|
||||
// Send subscription requests to DCL for each connection
|
||||
|
||||
Reference in New Issue
Block a user