04/14/2020
When following the sample code in the QuickStart sample "HistoricalAccess Server", in the method CreateAddressSpace() where it sets the history capabilities using this code:
lock (Server.DiagnosticsLock)
{
HistoryServerCapabilitiesState capabilities = Server.DiagnosticsNodeManager.GetDefaultHistoryCapabilities();
capabilities.AccessHistoryDataCapability.Value = true;
capabilities.InsertDataCapability.Value = true;
capabilities.ReplaceDataCapability.Value = true;
capabilities.UpdateDataCapability.Value = true;
capabilities.DeleteRawCapability.Value = true;
capabilities.DeleteAtTimeCapability.Value = true;
capabilities.InsertAnnotationCapability.Value = true;
}
This results in 2 instances of HistoryServerCapabilitiesState in the address space. Because the call to "GetDefaultHistoryCapabilities()" creates a new one even though there is already one in the address space.
04/14/2020
Randy Armstrong said
Sounds like a bug in the sample.GetDefaultHistoryCapabilities() should return the only instance.
It looks like a bug in the OPC Library from what I can tell. The GetDefaultHistoryCapabilities() stores the instance in the private member m_historyCapabilities. That private member is only ever initialized in that method, and it never attempts to find the existing instance in the address space.
The HistoryServerCapabilities node already exists in the address space as it is a predefined node from the model file for the Config/DiagnosticNodeManager.
However, in the address space, it is only a NodeState, not an instance of the derived class HistoryServerCapabilitiesState. Maybe what is missing in the OPC library code is to add a case for this node to AddBehaviourToPredefinedNode(), and initialize m_historyCapabilities with that instance when it is created.
Short of that OPC library fix, we found that this workaround seems to work to get the existing predefined node and update it:
var nodeHistoryServerCapabilities = FindNodeInAddressSpace(Opc.Ua.ObjectIds.HistoryServerCapabilities); if (nodeHistoryServerCapabilities == null) return; var qualAHDCName = new QualifiedName("AccessHistoryDataCapability"); nodeHistoryServerCapabilities.SetChildValue(SystemContext, qualAHDCName, true, true);
This is not ideal though, since the HistoryServerCapabilitiesState class isn't able to be used.
Also note that when HistoryServerCapabilities is created in GetDefaultHistoryCapabilities() it doesn't use the node ID constant that is provided with the OPC library, (Opc.Ua.ObjectIds.HistoryServerCapabilities), so the capabilities object would not be accessible using this nodeId.
05/30/2017
You report the bug on GitHub:
https://github.com/OPCFoundati.....ard/issues
Your workaround seems reasonable.
The default object after load is a BaseObjectState instance. The AddBehaviourToPredefinedNode on the DiagnosticNodeManager method should convert it to a HistoryServerCapabilitiesState. If you have the SDK source you could update AddBehaviourToPredefinedNode
1 Guest(s)