node.jseventsopc-uanode-opcua

monitor node-opc-ua events


I'm trying to monitor events (instead of variables) from a OPC-UA server using node-opcua.

I did not found any example of monitoring events in the client tutorial and found some old issues like this online and some sample code

Based on what I see it seems like "monitoring" an event should be quite similar to monitor variables: I need to change the attributeId from AttributeIds.Value to AttributeIds.EventNotifier in the ReadValueIdOptions parameter, add a filter variable in MonitoringParametersOptions object and then call a method like ClientMonitoredItem.create, passing a subscription, or directly calling monitor method on the subscription itself.

I'm testing code with an online demo server opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer, and I'm able to monitor a variable like "LastSeverity" by its nodeid, which I found by using the UAExpert client. :

UA Expert screenshot

I get the following output if I run the source code posted below

PS PATH_TO_DIRECTORY> node out/main2.js
17:46:03.763Z :opcua_client_impl             :248
Warning: endpoint_must_exist is now deprecated, use endpointMustExist instead
session created !
Monitored item value (LastSeverity) changed:  300
Monitored item value (LastSeverity) changed:  500
Monitored item value (LastSeverity) changed:  700
Monitored item value (LastSeverity) changed:  900
Monitored item value (LastSeverity) changed:  100

main2.ts source code:

import {
    AttributeIds,
    ClientMonitoredItem,
    ClientSubscription,
    DataValue,
    MessageSecurityMode,
    MonitoringParametersOptions,
    OPCUAClient,
    OPCUAClientOptions,
    ReadValueIdOptions,
    SecurityPolicy,
    TimestampsToReturn,
} from "node-opcua-client";

async function main(): Promise<void> {
    try {
        const options: OPCUAClientOptions = {
            connectionStrategy: {
                initialDelay: 1000,
                maxRetry: 100000,
            },
            securityMode: MessageSecurityMode.None,
            securityPolicy: SecurityPolicy.None,
            endpoint_must_exist: false,
        };
        const client = OPCUAClient.create(options);
        await client.connect("opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer");
        const session = await client.createSession();
        console.log("session created !");
        const subscription = ClientSubscription.create(session, {
            requestedPublishingInterval: 1000,
            maxNotificationsPerPublish: 100,
            publishingEnabled: true,
            priority: 10
        });
        const itemToMonitor: ReadValueIdOptions = {
            nodeId: "ns=2;s=1:Metals/WestTank?Bronze/LastSeverity",
            attributeId: AttributeIds.Value
        };
        const parameters: MonitoringParametersOptions = {
            samplingInterval: 100,
            discardOldest: true,
            queueSize: 10
        };
        const monitoredItem = ClientMonitoredItem.create(
            subscription,
            itemToMonitor,
            parameters,
            TimestampsToReturn.Both
        );
        monitoredItem.on("changed", (dataValue: DataValue) => {
            const value = dataValue.value.value;
            console.log("Monitored item value (LastSeverity) changed: ", value);
        });
    }
    catch (err) {
        console.log("Execution failed: ", err);
    }
}

main();

So the variable monitoring is fine, but I can't succeed in monitoring an event. If I add Event View in UAExpert I can see a lot of events:

UA Expert events description

By changing the code in something like the following (I also tried a very similar code to the first I posted, by changing AttributeIds.EventNotifier and stuff like that as I said above), nothing happens and no events are logged on console:

import {
    AttributeIds,
    ClientSubscription,
    DataValue,
    MessageSecurityMode,
    OPCUAClient,
    OPCUAClientOptions,
    SecurityPolicy,
    TimestampsToReturn,
} from "node-opcua-client";

import * as opcua from "node-opcua";

async function main(): Promise<void> {
    try {
        const options: OPCUAClientOptions = {
            connectionStrategy: {
                initialDelay: 1000,
                maxRetry: 100000,
            },
            securityMode: MessageSecurityMode.None,
            securityPolicy: SecurityPolicy.None,
            endpoint_must_exist: false,
        };
        const client = OPCUAClient.create(options);
        await client.connect("opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer");
        const session = await client.createSession();
        console.log("session created !");
        const subscription = ClientSubscription.create(session, {
            requestedPublishingInterval: 1000,
            maxNotificationsPerPublish: 100,
            publishingEnabled: true,
            priority: 10
        });
        var fields = [
            "EventId",
            "EventType",
            "SourceNode",
            "SourceName",
            "Time",
            "ReceiveTime",
            "Message",
            "Severity"
        ];
        var eventFilter = opcua.constructEventFilter(fields);
        var event_monitoringItem = await subscription.monitor(
            {
                nodeId: "ns=0;i=9764",
                attributeId: AttributeIds.EventNotifier
            },
            {
                queueSize: 100000,
                filter: eventFilter,
                discardOldest: true
            },
            TimestampsToReturn.Both
        );
        event_monitoringItem.on("changed", (dataValue: DataValue) => {
            const value = dataValue.value.value;
            console.log("Monitored item value (Event) changed: ", value);
        });
    }
    catch (err) {
        console.log("Execution failed: ", err);
    }
}

main();

I've tried different node ids like ns=0;i=9764 and i=9764 but it's not working.

What am I missing? Is it just a node id issue (how should I get it from the event?) or I need to change the code in something different?

Thanks for the attention.


Solution

  • For anyone interested, i opened a new issue in the official project github page. The accepted solution shows how to directly point to the "Server" nodeid (ObjectIds.Server) in monitoring events.

    I paste the solution code below:

    import {
      AttributeIds,
      constructEventFilter,
      ObjectIds,
      OPCUAClient,
      TimestampsToReturn,
      Variant,
    } from "node-opcua-client";
    
    async function main(): Promise<void> {
    
      const client = OPCUAClient.create({});
    
      const endpointUrl = "opc.tcp://opcua.demo-this.com:62544/Quickstarts/AlarmConditionServer";
    
      const subscriptionParamters = {
        requestedPublishingInterval: 1000,
        maxNotificationsPerPublish: 100,
        publishingEnabled: true,
        priority: 10,
      };
    
      await client.withSubscriptionAsync(endpointUrl, subscriptionParamters, async (session, subscription) => {
          const fields = [
            "EventId",
            "EventType",
            "SourceNode",
            "SourceName",
            "Time",
            "ReceiveTime",
            "Message",
            "Severity",
          ];
          const eventFilter = constructEventFilter(fields);
          const event_monitoringItem = await subscription.monitor(
            {
              nodeId: ObjectIds.Server,
              attributeId: AttributeIds.EventNotifier,
            },
            {
              queueSize: 10,
              filter: eventFilter,
              discardOldest: true,
            },
            TimestampsToReturn.Both
          );
    
          event_monitoringItem.on("changed", (events: Variant[]) => {
            for(let i=0;i<events.length;i++) {
                console.log(fields[i],"=", events[i].toString());
            }
            console.log("----------------\n\n")
          });
    
          console.log("CTRL+C to stop");
          await new Promise<void>((resolve) => process.once("SIGINT", resolve));
    
        }
      );
    }
    main();