Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [milo-dev] Alarm/Event Notifications triggers from OPC server

Milo client is creating the monitoringevent succesfully in the prosys server.How ever it does not send event notifications back to the milo client.
But it sent out notifications for the prosys client with same subscription and monitoring parameters.

Any clue on why Milo client does not receive notifications even though monitoring subscription is created successfully?
My client is attached here



On Sat, Nov 25, 2017 at 6:49 PM, Kevin Herron <kevinherron@xxxxxxxxx> wrote:
Yes, it seems the Bad_InternalError you got is some kind of bug or programming error in the Prosys server.

It seems you've already got it, but an example EventFilter might look like this:

EventFilter eventFilter = new EventFilter(
new SimpleAttributeOperand[]{
new SimpleAttributeOperand(
Identifiers.BaseEventType,
new QualifiedName[]{new QualifiedName(0, "EventId")},
AttributeId.Value.uid(),
null),
new SimpleAttributeOperand(
Identifiers.BaseEventType,
new QualifiedName[]{new QualifiedName(0, "Severity")},
AttributeId.Value.uid(),
null),
new SimpleAttributeOperand(
Identifiers.BaseEventType,
new QualifiedName[]{new QualifiedName(0, "Time")},
AttributeId.Value.uid(),
null),
new SimpleAttributeOperand(
Identifiers.BaseEventType,
new QualifiedName[]{new QualifiedName(0, "Message")},
AttributeId.Value.uid(),
null)
},
new ContentFilter(null)
);

On Sat, Nov 25, 2017 at 2:22 AM, Isuru Samaraweera <isuru@xxxxxxxx> wrote:
It seems after passing a EventFilter monitoredItem was created successfully.
Spec is not mandating a EventFilter as per my understanding.Might be this server I use mandates an EventFilter

Thanks

On Sat, Nov 25, 2017 at 11:19 AM, Isuru Samaraweera <isuru@xxxxxxxx> wrote:
I created a device node with ns=2;s=MyDevice with EventNotifier set to1 in a OPC server which supports alarms and events.
I am trying to intercept events from client.The code  I used is attached herewith. 

I am getting below error on server when I ran the code.It seems a configuration error on the client.

ServiceFault: Bad_InternalError (0x80020000) "An internal error occurred as a result of a programming or configuration error."
Diagnostic Info: java.lang.IllegalArgumentException: addItem called with EventNotifier, use addEventItme instead 
at com.prosysopc.ua.server.Subscription.addDataItem(Unknown Source)
at com.prosysopc.ua.server.SubscriptionManager.createMonitoredDataItem(Unknown Source)
at com.prosysopc.ua.server.SubscriptionManager.createMonitoredItem(Unknown Source)
at com.prosysopc.ua.server.SubscriptionServiceHandler.createMonitoredItems(Unknown Source)
at com.prosysopc.ua.server.SubscriptionServiceHandler.onCreateMonitoredItems(Unknown Source)



Can you please see what has gone wrong in the attached client code?

Thanks
Isuru

On Sat, Nov 25, 2017 at 12:23 AM, Kevin Herron <kevinherron@xxxxxxxxx> wrote:
Events are only supported in the client SDK right now.

Tentative milestone for support in the server is release 0.3.0.

On Fri, Nov 24, 2017 at 10:41 AM, Isuru Samaraweera <isuru@xxxxxxxx> wrote:
I did all the steps you mention to publish events like Creating objectnode with EventNotifier =1,Client changes etc..
How do we simulate triggering a event?Event triggering is supported by Milo server?
Please clarify

Thanks,
Isuru

On Fri, Nov 24, 2017 at 6:33 PM, Kevin Herron <kevinherron@xxxxxxxxx> wrote:
The SamplingInterval is supposed to be 0 when you subscribe to Events, so I assume you're talking about the PublishingInterval of the subscription.

Yes, there will be a delay, up to as much as the PublishingInterval, before the clients receive the notifications. There's no way around this - it's how subscriptions work in OPC UA. It's like this because schemes where changes are sent immediately don't scale when you have tens of thousands of changes happening. The PublishingInterval allows changes to be "batched" and sent to the client periodically (at the PublishingInterval). The QueueSize parameter when creating a MonitoredItem provides a mechanism to ensure multiple changes happening to an item within the PublishingInterval are not lost.

Perhaps the best thing you can do is create a Subscription you use just for Events with a fast PublishingInterval.



On Thu, Nov 23, 2017 at 9:25 PM, Isuru Samaraweera <isuru@xxxxxxxx> wrote:
For instance Alarm/Events might need to be notified to the client as it happens instead of waiting till PublishRequest arrives from a client after frequency is met.

Please clarify.

On Fri, Nov 24, 2017 at 10:45 AM, Isuru Samaraweera <isuru@xxxxxxxx> wrote:
When subscribing to events through subscription we set up  a sampling interval.
If we set the interval as 5 seconds.Event notifications are also sent out to the client in the same frequency by queuing them in the server instead of as soon as event happens.

Is there anyway events notifications are sentout to the client as the event transpires bypassing PublishRequest/Response which happens in the frequency set up during Subscription?

Thanks,
Isuru




On Fri, Nov 24, 2017 at 12:36 AM, Kevin Herron <kevinherron@xxxxxxxxx> wrote:
Subscribing to events work like this, assuming you have a Subscription already:

1. Find the ObjectNode in the server that is the source of events you're interested in. Its EventNotifier attribute will be set.

2. Create a MonitoredItem, pointing at that EventNotifier attribute, in MonitoringMode.Reporting, optionally specifying an EventFilter. How you define an EventFilter is talked about in part 4 of the spec, section 7.17.3. It's almost like you're building a SQL query with a select and where clause that determines what kinds of events and what fields from those events are delivered.

3. Set an EventConsumer on the UaMonitoredItem you created. That will be the callback invoked when the server delivers events that passed the EventFilter.

You shouldn't need to worry about receiving empty PublishResponses or null NotificationMessages (neither of those things should happen, except an empty PublishResponse when its a KeepAlive). If you're using the OpcUaClient then you don't ever interact directly with PublishRequest/PublishResponse in the first place - the subscription manager takes care of that and you just receive callbacks on the items you create.



On Thu, Nov 23, 2017 at 9:44 AM, Isuru Samaraweera <isuru@xxxxxxxx> wrote:
Hi All,

Normal procedure for receiving notification from server is

1.Create Subscription
2.Create MpnitoringParameters/MonitoredItemCreateRequest
3.createMonitoredItems

Once you do this PublishRequest/Response is used to receive notifications.

If we have to receive specific notifications/alarms instead of all the notifications from the server
The right way is to define a filter(DataChangeFilter,EventFilter etc) of type Extensible Parameter MonitoringFilter along with above 3 steps and
sentout notifications only if filter criteria is met?

If criteria is not met PublishResponse will be sent out with NotificationMessage set to null?

Or Is there a different way for condtionalNotifications/Alarms to be sent out without creating subscriptions,filters and monitoreditems and without sending empty PublishResponses ?

Please clarify.

Thanks,
Isuru

_______________________________________________
milo-dev mailing list
milo-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/milo-dev



_______________________________________________
milo-dev mailing list
milo-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/milo-dev




_______________________________________________
milo-dev mailing list
milo-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/milo-dev



_______________________________________________
milo-dev mailing list
milo-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/milo-dev



_______________________________________________
milo-dev mailing list
milo-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/milo-dev



_______________________________________________
milo-dev mailing list
milo-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/milo-dev




_______________________________________________
milo-dev mailing list
milo-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/milo-dev



_______________________________________________
milo-dev mailing list
milo-dev@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/milo-dev


package com.yukon.opc.testclient.ua;

import static com.google.common.collect.Lists.newArrayList;
import static com.yukon.opc.stack.core.types.builtin.unsigned.Unsigned.uint;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.BiConsumer;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import com.yukon.opc.sdk.client.OpcUaClient;
import com.yukon.opc.sdk.client.api.subscriptions.UaMonitoredItem;
import com.yukon.opc.sdk.client.api.subscriptions.UaSubscription;
import com.yukon.opc.stack.core.AttributeId;
import com.yukon.opc.stack.core.Identifiers;
import com.yukon.opc.stack.core.types.builtin.DataValue;
import com.yukon.opc.stack.core.types.builtin.ExtensionObject;
import com.yukon.opc.stack.core.types.builtin.NodeId;
import com.yukon.opc.stack.core.types.builtin.QualifiedName;
import com.yukon.opc.stack.core.types.builtin.Variant;
import com.yukon.opc.stack.core.types.builtin.unsigned.UInteger;
import com.yukon.opc.stack.core.types.enumerated.MonitoringMode;
import com.yukon.opc.stack.core.types.enumerated.TimestampsToReturn;
import com.yukon.opc.stack.core.types.structured.ContentFilter;
import com.yukon.opc.stack.core.types.structured.EventFilter;
import com.yukon.opc.stack.core.types.structured.MonitoredItemCreateRequest;
import com.yukon.opc.stack.core.types.structured.MonitoringParameters;
import com.yukon.opc.stack.core.types.structured.ReadValueId;
import com.yukon.opc.stack.core.types.structured.SimpleAttributeOperand;
import com.yukon.opc.testclient.ClientExample;
import com.yukon.opc.testclient.ClientExampleRunner;

public class SubscriptionExampleUA implements ClientExample {

	public static void main(String[] args) throws Exception{
		// TODO Auto-generated method stub
		SubscriptionExampleUA example = new SubscriptionExampleUA();

	        new ClientExampleRunner(example).run();
	}
	private final Logger logger = LoggerFactory.getLogger(getClass());

    private final AtomicLong clientHandles = new AtomicLong(1L);

    @Override
    public void run(OpcUaClient client, CompletableFuture<OpcUaClient> future) throws Exception {
        // synchronous connect
        client.connect().get();

        // create a subscription @ 1000ms
        UaSubscription subscription = client.getSubscriptionManager().createSubscription(0.0).get();

     
        NodeId n=NodeId.parse("ns=2;s=MyDevice");
        
        // subscribe to the Value attribute of the server's CurrentTime node
        ReadValueId readValueId = new ReadValueId(
            n,
            AttributeId.EventNotifier.uid(), null, QualifiedName.NULL_VALUE);
        

        // important: client handle must be unique per item
        UInteger clientHandle = uint(clientHandles.getAndIncrement());
//EventFilter ds = new EventFilter();
ExtensionObject eo = createEF2();
        //eo=createEventFilter();
        MonitoringParameters parameters = new MonitoringParameters(
            clientHandle,
            0.0,     // sampling interval
            eo,       // filter, null means use default
            uint(10),   // queue size
            true        // discard oldest
        );

        MonitoredItemCreateRequest request = new MonitoredItemCreateRequest(
            readValueId, MonitoringMode.Reporting, parameters);

        // when creating items in MonitoringMode.Reporting this callback is where each item needs to have its
        // value/event consumer hooked up. The alternative is to create the item in sampling mode, hook up the
        // consumer after the creation call completes, and then change the mode for all items to reporting.
        BiConsumer<UaMonitoredItem, Integer> onItemCreated =
            (item, id) -> item.setEventConsumer(this::onEventReceived);

        List<UaMonitoredItem> items = subscription.createMonitoredItems(
            TimestampsToReturn.Both,
            newArrayList(request),
            onItemCreated
        ).get();

        for (UaMonitoredItem item : items) {
            if (item.getStatusCode().isGood()) {
                logger.info("item created for nodeId={}", item.getReadValueId().getNodeId());
            } else {
                logger.warn(
                    "failed to create item for nodeId={} (status={})",
                    item.getReadValueId().getNodeId(), item.getStatusCode());
            }
        }

        // let the example run for 5 seconds then terminate
        Thread.sleep(5000000);
        future.complete(client);
    }

    private void onSubscriptionValue(UaMonitoredItem item, DataValue value) {
        logger.info(
            "subscription value received: item={}, value={}",
            item.getReadValueId().getNodeId(), value.getValue());
    }
    
    private void onEventReceived(UaMonitoredItem item, Variant[] var) {
    	System.out.println("Receive");
        logger.info(
            "subscription value received: item={}, value={}",
            item.getReadValueId().getNodeId(),var );
    }
    
    
    
    
    private ExtensionObject createEF2( ) {
    	
    	EventFilter eventFilter = new EventFilter(
    		    new SimpleAttributeOperand[]{
    		        new SimpleAttributeOperand(
    		            Identifiers.BaseEventType,
    		            new QualifiedName[]{new QualifiedName(0, "EventId")},
    		            AttributeId.Value.uid(),
    		            null),
    		        new SimpleAttributeOperand(
    		            Identifiers.BaseEventType,
    		            new QualifiedName[]{new QualifiedName(0, "Severity")},
    		            AttributeId.Value.uid(),
    		            null),
    		        new SimpleAttributeOperand(
    		            Identifiers.BaseEventType,
    		            new QualifiedName[]{new QualifiedName(0, "Time")},
    		            AttributeId.Value.uid(),
    		            null),
    		        new SimpleAttributeOperand(
    		            Identifiers.BaseEventType,
    		            new QualifiedName[]{new QualifiedName(0, "Message")},
    		            AttributeId.Value.uid(),
    		            null)
    		    },
    		    new ContentFilter(null)
    		);
    	
    	ExtensionObject eo = ExtensionObject.encode(eventFilter);
    	return eo;
    }
    
    
    private ExtensionObject createEventFilter() {
    	
    	
    	QualifiedName[] eventFields = { new QualifiedName(2,"EventType"), new QualifiedName(2,"Message"),
    			new QualifiedName(2,"SourceName"), new QualifiedName(2,"Time"), new QualifiedName(2,"Severity")
    			 };
    	
    	NodeId eventTypeId = Identifiers.BaseEventType;
		UInteger eventAttributeId =AttributeId.Value.uid();
		String indexRange = null;
		SimpleAttributeOperand[] selectClauses = new SimpleAttributeOperand[eventFields.length + 1];
		for (int i = 0; i < eventFields.length; i++) {
			QualifiedName[] browsePath = createBrowsePath(eventFields[i]);
			selectClauses[i] = new SimpleAttributeOperand(eventTypeId, browsePath, eventAttributeId, indexRange);
		}
		// Add a field to get the NodeId of the event source
		selectClauses[eventFields.length] = new SimpleAttributeOperand(eventTypeId, null, AttributeId.NodeId.uid(), null);
    	
    	
    	
    
    	
		//filter..setSelectClauses(selectClauses);

		// Event filtering: the following sample creates a
		// "Not OfType GeneralModelChangeEventType" filter
	/*	ContentFilterBuilder fb = new ContentFilterBuilder(client.getEncoderContext());		
		fb.add(FilterOperator.Not, new ElementOperand(UnsignedInteger.valueOf(1)));
		final LiteralOperand filteredType = new LiteralOperand(new Variant(Identifiers.GeneralModelChangeEventType));
		fb.add(FilterOperator.OfType, filteredType);*/
    	
		// The element operand refers to another operand -
				// operand #1 in this case which is the next,
				// LiteralOperand
		
		EventFilter filter = new EventFilter(selectClauses,null);
    	
    	ExtensionObject eo = ExtensionObject.encode(filter);
    	return eo;
    }
    
    protected QualifiedName[] createBrowsePath(QualifiedName qualifiedName) {
    	
    	System.out.println(qualifiedName.getName());
		if (!qualifiedName.getName().contains("/"))
			return new QualifiedName[] { qualifiedName };
		int namespaceIndex = qualifiedName.getNamespaceIndex().intValue();
		String[] names = qualifiedName.getName().split("/");
		QualifiedName[] result = new QualifiedName[names.length];
		for (int i = 0; i < names.length; i++)
			result[i] = new QualifiedName(namespaceIndex, names[i]);
		return result;
	}


}

Back to the top