locka99 / opcua

A client and server implementation of the OPC UA specification written in Rust
Mozilla Public License 2.0
496 stars 131 forks source link

Does this library support CreateMonitoredItem of Alarm and Events #101

Closed ekafe closed 3 years ago

ekafe commented 3 years ago

I tried to create a monitored item for getting alarm data of OPCU Server, no response is coming.While monitored items of data changes of particular node id is giving result. I want to know whether this library support subscribing to alarms and events or this is due to my lack of knowledge to implement with this library. I am asking this because, one C++ library i used before only supported monitoring of data changes.

locka99 commented 3 years ago

The OPC UA for Rust lib implemented event functionality in the last release although it may not be to spec yet. If you want to see how to do it, it refer to the web-client sample where it creates a monitored item with EventCallback encapsulated callback function. The demo-server sample also shows how a server can raise events.

Let me know if it isn't working when you follow the sample because OPC UA is a complex specification and I'm building outwards through nano, embedded to standard and some functionality may be lacking.

ekafe commented 3 years ago

Thanks for this information,sorry i forgot to mention, i am trying to implement a opcua client not a server.I will go through web client sample and will inform you if its working or not.

ekafe commented 3 years ago

I tried to test the demo server with web sample client, there also data changes are showing in the notification, but no events are showing in the notification.Do i have to implements some events in the demo-server or some event will automatically produce.

Since i cant complete the test with web-client, i still don't know the event problem is with the library or with my code. I haven't changed anything in the demo server or web-client.In HTML page i have to change the url from localhost to 127.0.0.1 for to connect successfully, otherwise its not connecting.

So i tried testing the web-client with an open OPCUA URL. There also events are showing in the page. I have been using this URL for testing Alarms and Events : opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer

locka99 commented 3 years ago

Can you test with a 3rd party OPC client such as dataFEED OPC UA Client and see that you can:

a) Subscribe to events (e.g. ns=2;s=0:East/Red) b) Trigger an event / alarm c) Observe the event / alarm happening with the events log.

Assuming this then I should be able to repro the behaviour web-client. For the time being I can confirm I can connect to the OPC server and I can subscribe to data values, but I don't know how to trigger anything for the event notification.

locka99 commented 3 years ago

Btw the http interface for web-client when you run it is on http://localhost:8686/. It's a very simple JS client that communicates over a websocket to a backend http server that is an OPC client. For events it allows you to subscribe to an event type and specify some filtering criteria. I have had it working with the demo-server.

ekafe commented 3 years ago

I have been testing with "Unified Automation UaExpert" Client software with the URL i mentioned Above. I can give you the screenshot of the events and alarms with this client. You can use Server node for event subscription, here it is "i=2253" or "ns=2;s=0:Green/East" I have also tried with "dataFeed OPCUA client". From it also i can subscribe to the events.

So if u can reproduce the events in the server on the webclient, then i can use that code for my application. The URL i used is an open OPCUA server : "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer" Capture Capture2

locka99 commented 3 years ago

I've run Wireshark on this and I can see there is an issue but not what is causing it. I can see the Rust OPC UA client correctly subscribing / monitoring for events but the server isn't returning any. One difference to other clients is the publish request behaviour so I may look at that next.

ekafe commented 3 years ago

Thanks again, Please let me know, if any improvement has happened.

locka99 commented 3 years ago

I'm still investigating. I have made improvements to the subscription publish request mechanism to make it easier to debug this issue. There is something very odd about that OPC server in that even if I use dataFEED client to connect to it, it sometimes does not trigger events unless I modify the monitored item, e.g change queue size from 1 to 2. So even not using my client, it can be odd so perhaps there are server side issues to it too.

ekafe commented 3 years ago

Yes i also encountered problem of queue size of that opcua server. So i was searching for a demo server which implements Alarms and Condition.I tried nodejs opcua server, i couldn't run or compile it successfully, (https://github.com/node-opcua/node-opcua). You can try and use that as a sample server.

Then i tried freeware opcua demo server - Prosys OPCUA Simulation Software (https://www.prosysopc.com/products/opc-ua-simulation-server/). I am running this on debian and i can see alarms and events from this Server on my UAExpert Client Software.

I hope you can use this server for testing of alarms and condition events. I don't know enough about the rust and opcua to edit your existing libraries to test with this server.

For my application i am using a Siemens controller with OPCUA Server, URL of which i cant share publicly.It doesn't have the queue size problem u mentioned above.

locka99 commented 3 years ago

Okay, I'm getting better luck with that other server. As of now on master, the following is generating events:

$ cd opcua/samples/event-client
$ cargo run -- --url opc.tcp://foo:53530/OPCUA/SimulationServer --event-source "ns=6;s=MyDevice"

The object "ns=6;s=MyDevice" is an event source on the server and "foo" is your server's hostname.

Created a subscription with id = 11
Creating a subscription to events from the event source ns=6;s=MyDevice
Result of subscribing to event = [MonitoredItemCreateResult { status_code: HISTORICAL_RAW | Good, monitored_item_id: 1, revised_sampling_interval: 0.0, revised_queue_size: 2, filter_result: ExtensionObject { node_id: NodeId { namespace: 0, identifier: Numeric(736) }, body: ByteString(ByteString { value: Some([3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 255]) }) } }]
Event from server:
Event handle = 1000
0: ByteString(ByteString { value: Some([0, 0, 0, 0, 0, 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, 80]) })
1: NodeId(NodeId { namespace: 0, identifier: Numeric(9482) })
2: LocalizedText(LocalizedText { locale: UAString { value: Some("") }, text: UAString { value: Some("Level exceeded") } })
Event from server:
Event handle = 1000
0: ByteString(ByteString { value: Some([0, 0, 0, 0, 0, 0, 0, 82, 0, 0, 0, 0, 0, 0, 0, 81]) })
1: NodeId(NodeId { namespace: 0, identifier: Numeric(9482) })
2: LocalizedText(LocalizedText { locale: UAString { value: Some("") }, text: UAString { value: Some("Level exceeded") } })
Event from server:
Event handle = 1000
0: ByteString(ByteString { value: Some([0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 0, 0, 0, 0, 0, 82]) })
1: NodeId(NodeId { namespace: 0, identifier: Numeric(9482) })
2: LocalizedText(LocalizedText { locale: UAString { value: Some("") }, text: UAString { value: Some("Level exceeded") } })
Event from server:
Event handle = 1000
0: ByteString(ByteString { value: Some([0, 0, 0, 0, 0, 0, 0, 84, 0, 0, 0, 0, 0, 0, 0, 83]) })
1: NodeId(NodeId { namespace: 0, identifier: Numeric(9482) })
2: LocalizedText(LocalizedText { locale: UAString { value: Some("") }, text: UAString { value: Some("Level exceeded") } })
Event from server:
Event handle = 1000
0: ByteString(ByteString { value: Some([0, 0, 0, 0, 0, 0, 0, 85, 0, 0, 0, 0, 0, 0, 0, 84]) })
1: NodeId(NodeId { namespace: 0, identifier: Numeric(9482) })
2: LocalizedText(LocalizedText { locale: UAString { value: Some("") }, text: UAString { value: Some("Level exceeded") } })
ekafe commented 3 years ago

Its good to see it working. I am sorry if i am asking too much, but the event is only giving message, i.e "Level Exceeded". To use this data - i need timestamp or severity of alarm or its active or not. Which should be included with notifier.

Timestamp i can adjust by creating a time when this event is triggered. But Severity,Source Name,active/not are missing. Is it something that i have to add in the code or this only gives the message from server.

I didn't try this code with actual server, i will run it and inform you.Can you check that, is it possible to get timestamp and severity also from the events

Thank You

ekafe commented 3 years ago

OK i got it, i didn't read code properly, I got the time, active state and severity.

I will check the code with my real server and inform if its working or not. I want to ask one more thing, accessing the event history, whether will you implement this in the future or not.

For me getting alarms and condition is very helpful Thanks for implementing it.

locka99 commented 3 years ago

You should be able to call history_read() to get historical events if the server supports that. The api of this function is a little opaque and complex because the HistoryRead service in OPC takes in different commands and has things called continuation points

Look at the link for the details, but basically you'd fill in a ReadEventDetails saying what you want and then serialise it into the history_read_details parameter. Then you would supply a e.g.

let read_event_details = ExtensionObject::from_encodable(
  ObjectId::ReadEventDetails_Encoding_DefaultBinary,
  &ReadEventDetails {
    // fill in your time range & event filter here
  }
);
let node_to_read_history_for = NodeId::new(2, "Some Node With Events");
let results = session.history_read(read_event_details, TimestampsToReturn::Neither, false, &[node_to_read_history_for]);

The results should be your events although the server may require you to call it multiple times with continuation points to retrieve them all.

locka99 commented 3 years ago

I might make the history_read() a little simpler by using an enum for the read_event_details param so the caller doesn't have to encode the struct but you should be able to use it like it is for now.

ekafe commented 3 years ago

Currently my server doesn't support history read. So i will test when its possible.

I tried alarms and conditions in real server , its working perfectly fine.So i am closing the issue. Thanks for the help.