13:09, EEST
October 4, 2013
Hello,
Question 1:
Is there a way during a recursive browse of the OPC UA address room to generically detect which nodes are events? Right now we are using getNodeClass().toString() on nodes, however, this only returns “Variable”, “Method”, “Object” and “ObjectType”. Does “ObjectType” represent events? Are events in the OPC UA address room located at specific locations, such as “/Types/EventTypes/BaseEventType/”?
Question 2:
Right now we are browsing browsing the entire address room and listening for data changes on all variables, and attempting to listen to all types of events. Is this against best practices, or is it a feasible approach? The motivation for browsing the entire address room is that we do not adhere to a strict data model. Is this against best practices too? Perhaps a more common approach is to know exactly which nodes to subscribe to before connecting to the OPC UA server?
Thank you.
14:26, EEST
December 21, 2011
1: Any object may send events. The ones that do, define SubscribeToEvents in the EventNotifier attribute, e.g.
where object is an UaObject.
2. You can listen to all events by listening to the Server object. For variables, in general you should know which data you are interested in. If you really want to listen to everything, then you really need to browse the address space, but note that in theory the address space may contain loops. Also it may be quite demanding, if the server has a huge number of nodes available.
11:16, EEST
October 4, 2013
Thank you for your response. Hopefully you can help us out with these follow-up questions:
Question 1:
The code you posted:
object.getEventNotifier().contains(EventNotifierClass.SubscribeToEvents);
where object is an UaObject.
Detects, in our case, the Server object and objects under Server. However, it does not detect a custom event created in our server address space. Our custom event type is created in the same way as “MyEventType” in the sample client in the Prosys Java SDK, and is located under Types/EventTypes/BaseEventType/. Is this expected behavior? If so, how can you generically detect custom events, such as “MyEventType”, created by the server?
Question 2:
Is the Server object an address space node required by the OPC-UA standard? What would normally be the interesting information in the Server object?
Question 3:
What is the proper way to detect variables that allows listening to data changes? Right now, we detect such variables the following way
if (referenceDescription.getNodeClass().toString().equals(“Variable”)) {
// setup subscription
}
where referenceDescription is of type ReferenceDescription.
This works, however, is there a better way? In the sample client in the Prosys SDK there is the following code:
UaNode node = client.getAddressSpace().getNode(nodeId);
if (node instanceof UaVariable) {
// Validate that history is readable for the node
…
When using the conditional above, only some variables are detected in our server address space, NOT including custom created variables of type PlainVariables by the server:
final NodeId temperatureId = new NodeId(nodeManager.getNamespaceIndex(), “temperature”);
temperatureVariableSensor1 = new PlainVariable(nodeManager, temperatureId, “temperature”, Locale.ENGLISH);
temperatureVariableSensor1.setDataTypeId(Identifiers.Double);
temperatureVariableSensor1.setCurrentValue(99.);
device.addReference(temperatureVariableSensor1, Identifiers.HasComponent, false);
Is this expected behavior that these variables are not detected by checking for type of UaVariable?
By the way, how do you get code highlighting in the posts?
13:06, EEST
December 21, 2011
Good questions
1. All objects that can provide events should also be linked to the Server object using HasEventSource, HasNotifier or HasCondition references. See for example the SampleConsoleServer on how it adds these references. In practice it is enough to have these references from the Objects folder down to the nodes that provide events. The Java SDK uses these references to provide events from all nodes in the hierarchy. Some other servers may just send notifications for the server object anyway.
2. Yes, the Server object is a compulsory object for every server. It contains information about the server status, versions, capabilities, diagnostics, etc.
3. All variables in the server should also appear as UaVariable nodes on the client side. AddressSpace.getNode() reads the NodeClass attribute and creates the node objects based on that. I would say that there must be something odd, if it is not UaVariable, but still has NodeClass Variable.
You can use code-tags to highlight code. But it removes all indentation in general. So another option is to use pre-tags, which gives a bit different style, though.
9:10, EEST
October 4, 2013
Thank you.
You are correct, all variables do appear is UaVariable nodes. I have two additional follow-up questions
1. Exactly how do you link the custom event type to the Server object in order to have the event type detected by:
We tried the following without any luck:
Where server is of type UaServer and customEventType is of type UaObjectType. Does Identifiers.Server refer to the server Object?
2. What is the proper way to clean up resources after a connection failure is detected on the client side? Right now, on the client-side, we only call disconnect() on the the UaClient object. Is this sufficient? Should we also explicitly unsubscribe to all subscriptions, or will all resources related to subscriptions be released when the subscriptions time out?
10:07, EEST
December 21, 2011
1. Do not add reference from Server to the type. Add a reference to the objects. For example,
Defines that myObjectsFolder will generate events. It will also set the EventNotifier property for myObjectsFolder.
Note that if you add an HasEventSource reference (HasNotifier, HasCondition) to any node, the SDK will make sure that the reference chain is initialized all the way up to the Server object. Therefore the above line is not in SampleConsoleServer, as it is defining references to the MyLevelAlarm node.
2. The UaClient will handle normal connection errors automatically, if you have AutoReconnect property set to true (as is by default). When you want to close the connection, you only need to call disconnect(). The subscriptions will be kept in the client side, so that they are easily regenerated into the server as necessary (in next connect).
UaClient.setKeepSubscriptions() will define whether disconnect() will remove the subscriptions also from the server. If you keep them, it will enable you to disconnect and connect without losing data in the server as well. But as I mentioned, AutoReconnect will handle normal connection error situations and will recover from that properly, so you don’t need to do this “manually”.
12:21, EEST
October 4, 2013
Thank you.
If you choose to keep the connections on the server side with UaClient.setKeepSubscriptions(true), does this mean that when the client connects to the server again there is no need to browse the address room and actively create subscriptions?
Moreover, we have a few questions regarding timestamps:
1. For events, there is a default attribute, “time”, that provides a server-side timestamp. In our OPC-UA server, based on the sample server, this attribute appears to always be set. However, for data changes on data variables, such as PlainVariable, is there an associated server-side timestamp? The DatainnMonitoredDataItemListener provides a onDataChange() callback with a parameter of type DataValue. This parameter has a getServerTimestamp(), which appears to be null all the time. Should we be using this timestamp? Is there a miss configuration on our OPC-UA server since it is always null?
2. In addition to getServerTimestamp(), the DataValue parameter mentioned above also has a getSourceTimestamp() method. What kind of timestamp is this? A timestamp representing when the client SDK received the message from the server?
12:31, EEST
December 21, 2011
Yes, the subscription has a life time of it’s own separate from the session. So it can be transferred to the new session as it is. The UaClient does this automatically, whenever you connect/reconnect.
1. Yes the ServerTimestamp is similar to the Time field of Events. You need to set Subscription.setTimestampsToReturn(TimestampsToReturn.Both) to also get the ServerTimestamp. It is initialized to Source only by default.
2. The source timestamp should reflect the time when the value changed in the device or sensor (source). ServerTimestamp defines when the server was notified of the value.
12:39, EET
October 4, 2013
Thanks, exactly what we needed. We have stumbled upon three more questions:
1. Is it possible for the server (of type UaServer) to bind to a arbitrary available port, and then retrieve that port for the client to connect to? We tried binding to port 0 using server.setPort(), but server.getPort() returns 0 and the server fails. We would like this functionality during integration tests.
2. During browsing of the address space, we encounter several nodes that have the same path in the address space, but different NodeId. For example, we encounter two UaVariables at “Types/ObjectTypes/BaseObjectType/NamespacesType/AddressSpaceFile/GetPosition/InputArguments/OutputArguments”, one with NodeId 11691, and the other with 11692. We assume this node path is default provided by the UaServer. Is this expected behavior by the UaServer? If so, then the node path is not unique by itself?
The code we use for browsing is:
where client is of type UaClient, and nodId of type NodeId.
For detecting data variables that provide data change events, we use:
where node is of type UaNode.
3. Given the path in question 2., what would be the usefulness listening to data variable changes under that path? I guess it will not give us much. Is there any specific address room paths that are especially useful to listen to in the OPC UA standard, including both events and data variable changes? Events under the Server object at root is probably useful?
14:18, EET
December 21, 2011
1. That is not supported, so you will need to generate port numbers yourself.
2. Yes it is possible that there are several nodes with the same path. TranslateBrowsePathsToNodeIds can also provide several results for each BrowsePath. But the nodes that you mention should only be there once, InputArguments and OutputArguments are different nodes of GetPosition (or any method node, in practice).
3. There is no data or events in the Type address space. They are only available from the Objects (and Views).
Server object is typically listened to for events – you will get all events of the server by definition from it. Events are only available from objects. And Data is only available from Variables.
14:38, EET
October 4, 2013
Thanks. 3 more questions
1. Can TranslateBrowsePathsToNodeIds() be used to directly look up a node in the address space? For example, let’s say I want to directly look up an event at the path “/Objects/MyNode/MyEvent”, how would I do that in code? Or do you have to find that node by traversing from a known root node, such as Identifiers.Server.
2. Could you comment on our current method of browsing the server address space? Our approach is as follows. We have a generic depth-first traversal of the entire address space. Initially, every path in the address space is ignored (not traversed), however, we can configure the traversal using a “whitelist”, which defines which absolute paths (including leaf and sub-trees) should be included in the traversal. If a traversed node in the address space is either a data variable or event node, a subscription will be created for it. This way it is easy to include data variable and event nodes that are know before the traversal, as well include sub-trees that might have interesting nodes that we would like to create subscriptions for. Does our approach sound like a complete overkill, or reasonable? Would it be more sane to look up individual nodes using absolute paths, instead of a generic traversal?
3. Related to the above questions. We have experienced significant delay when traversing nodes in the address space when communication is over GSM. Our guess is that the network latency is the primary cause. Are we correct? What kind of actions would you suggest in such a case? Perhaps using TranslateBrowsePathsToNodeIds() to directly access nodes, if that is possible, and hence avoiding traversal latency?
Thank you.
13:48, EET
December 21, 2011
1. Yes, that is exactly what TranslateBrowsePathsToNodeIds does. Look at the SampleConsoleClient.browse(), which has an example of converting the string path to a browsePath that you need to provide as an argument. You can use Identifiers.RootFolder as the startingNodeId.
2. That depends on what you need. Note that if your server has a huge address space that can be a real overkill. But if you know that the server has a small address space, it may be viable.
3. Yes, it is better to limit the number of message calls. You can also request several nodeIds at the same time, using AddressSpace.translateBrowsePathsToNodeIds() instead of AddressSpace.translateBrowsePathToNodeId() (which is used in SampleConsoleClient.browse())
Most Users Ever Online: 1919
Currently Online:
50 Guest(s)
Currently Browsing this Page:
1 Guest(s)
Top Posters:
Heikki Tahvanainen: 402
hbrackel: 144
rocket science: 88
pramanj: 86
Francesco Zambon: 83
Ibrahim: 78
Sabari: 62
kapsl: 57
gjevremovic: 49
Xavier: 43
Member Stats:
Guest Posters: 0
Members: 726
Moderators: 7
Admins: 1
Forum Stats:
Groups: 3
Forums: 15
Topics: 1525
Posts: 6456
Newest Members:
forrestdilke5, ernestoportus31, martin123, rickie5305, shaylamaggard4, rickyjuarez140, jonathonmcintyre, fannielima, kristiewinkle8, rustModerators: Jouni Aro: 1026, Pyry: 1, Petri: 0, Bjarne Boström: 1028, Jimmy Ni: 26, Matti Siponen: 346, Lusetti: 0
Administrators: admin: 1