in src/Azure.IIoT.OpcUa.Publisher/src/Stack/Extensions/SessionEx.cs [437:615]
internal static async Task<ServiceResultModel?> ReadNodeStateAsync(
this IOpcUaSession session, RequestHeader requestHeader, NodeState nodeState,
NodeId rootId, RelativePath? relativePath = null, CancellationToken ct = default)
{
var valuesToRead = new List<ReadValueId>();
var objectsToBrowse = new List<BrowseDescription>();
var resolveBrowsePaths = session.GetBrowsePathFromNodeState(rootId,
nodeState, relativePath);
if (resolveBrowsePaths.Count == 0)
{
// Nothing to do
return ((StatusCode)StatusCodes.GoodNoData).CreateResultModel();
}
var limits = await session.GetOperationLimitsAsync(ct).ConfigureAwait(false);
var resolveBrowsePathsBatches = resolveBrowsePaths
.Batch(limits.GetMaxNodesPerTranslatePathsToNodeIds());
foreach (var batch in resolveBrowsePathsBatches)
{
// translate browse paths.
var response = await session.Services.TranslateBrowsePathsToNodeIdsAsync(
requestHeader, new BrowsePathCollection(batch), ct).ConfigureAwait(false);
var results = response.Validate(response.Results, s => s.StatusCode,
response.DiagnosticInfos, batch);
if (results.ErrorInfo != null)
{
return results.ErrorInfo;
}
foreach (var result in results)
{
if (result.Request.Handle is not NodeState node)
{
continue;
}
if (StatusCode.IsBad(result.StatusCode))
{
if (result.StatusCode.Code is StatusCodes.BadNodeIdUnknown or
StatusCodes.BadUnexpectedError)
{
return result.ErrorInfo;
}
if (node is BaseVariableState v)
{
// Initialize the variable
v.Value = null;
v.StatusCode = result.StatusCode;
}
continue;
}
if (result.Result.Targets.Count == 1 &&
result.Result.Targets[0].RemainingPathIndex == uint.MaxValue &&
!result.Result.Targets[0].TargetId.IsAbsolute)
{
node.NodeId = (NodeId)result.Result.Targets[0].TargetId;
}
else
{
if (node is BaseVariableState v)
{
// Initialize the variable
v.Value = null;
v.StatusCode = StatusCodes.BadNotSupported;
}
continue;
}
switch (node)
{
case BaseVariableState variable:
// Initialize the variable
variable.Value = null;
variable.StatusCode = StatusCodes.BadNotSupported;
valuesToRead.Add(new ReadValueId
{
NodeId = node.NodeId,
AttributeId = Attributes.Value,
Handle = node
});
break;
case FolderState folder:
// Save for browsing
objectsToBrowse.Add(new BrowseDescription
{
BrowseDirection = Opc.Ua.BrowseDirection.Forward,
Handle = folder,
IncludeSubtypes = true,
ReferenceTypeId = ReferenceTypeIds.Organizes,
NodeClassMask =
(uint)Opc.Ua.NodeClass.Variable |
(uint)Opc.Ua.NodeClass.Object,
NodeId = node.NodeId,
ResultMask = (uint)BrowseResultMask.All
});
break;
}
}
}
if (objectsToBrowse.Count > 0)
{
foreach (var batch in objectsToBrowse.Batch(limits.GetMaxNodesPerBrowse()))
{
// Browse folders with objects and variables in it
await foreach (var (description, references, errorInfo) in session.BrowseAsync(
requestHeader, null, new BrowseDescriptionCollection(batch),
ct).ConfigureAwait(false))
{
var obj = (BaseObjectState?)description?.Handle;
if (obj == null || references == null)
{
continue;
}
foreach (var reference in references)
{
switch (reference.NodeClass)
{
case Opc.Ua.NodeClass.Variable:
// Add variable to the folder and set it to be read.
var variable = new BaseDataVariableState(obj)
{
NodeId = (NodeId)reference.NodeId,
BrowseName = reference.BrowseName,
DisplayName = reference.DisplayName,
StatusCode = StatusCodes.BadNotSupported,
ReferenceTypeId = reference.ReferenceTypeId,
Value = null
};
obj.AddChild(variable);
valuesToRead.Add(new ReadValueId
{
NodeId = variable.NodeId,
AttributeId = Attributes.Value,
Handle = variable
});
break;
case Opc.Ua.NodeClass.Object:
// Add object
#pragma warning disable CA2000 // Dispose objects before losing scope
var child = new BaseObjectState(obj)
{
NodeId = (NodeId)reference.NodeId,
BrowseName = reference.BrowseName,
DisplayName = reference.DisplayName,
ReferenceTypeId = reference.ReferenceTypeId
};
#pragma warning restore CA2000 // Dispose objects before losing scope
obj.AddChild(child);
break;
}
}
}
}
}
if (valuesToRead.Count > 0)
{
foreach (var batch in valuesToRead.Batch(limits.GetMaxNodesPerRead()))
{
// read the values.
var readResponse = await session.Services.ReadAsync(
requestHeader, 0, Opc.Ua.TimestampsToReturn.Neither,
new ReadValueIdCollection(batch), ct).ConfigureAwait(false);
var readResults = readResponse.Validate(readResponse.Results,
s => s.StatusCode, readResponse.DiagnosticInfos,
batch);
if (readResults.ErrorInfo != null)
{
return readResults.ErrorInfo;
}
foreach (var readResult in readResults)
{
var variable = (BaseVariableState)readResult.Request.Handle;
variable.WrappedValue = readResult.Result.WrappedValue;
variable.DataType = TypeInfo.GetDataTypeId(readResult.Result.Value);
variable.StatusCode = readResult.Result.StatusCode;
}
}
return null;
}
return ((StatusCode)StatusCodes.BadUnexpectedError).CreateResultModel();
}