Node.js / TypeScript · recipe
Subscribe to alarms and events in Node.js
Monitor the EventNotifier attribute of the Server object with an event filter that selects the fields you need. Selecting server-side keeps the volume down, and ConditionClassId is the field that makes a downtime reason portable.
| Stack | node-opcua |
|---|---|
| Version | 2.181.1 |
The code
const {
OPCUAClient, AttributeIds, TimestampsToReturn,
constructEventFilter, ObjectIds,
} = require("node-opcua");
(async () => {
const client = OPCUAClient.create({ endpointMustExist: false });
await client.connect("opc.tcp://milo.digitalpetri.com:62541/milo");
const session = await client.createSession();
const subscription = await session.createSubscription2({
requestedPublishingInterval: 500,
requestedLifetimeCount: 100,
requestedMaxKeepAliveCount: 10,
publishingEnabled: true,
});
const fields = ["EventId", "EventType", "SourceName", "Time", "Severity", "Message"];
const eventFilter = constructEventFilter(fields);
const item = await subscription.monitor(
{ nodeId: ObjectIds.Server, attributeId: AttributeIds.EventNotifier },
{ samplingInterval: 0, queueSize: 100, filter: eventFilter },
TimestampsToReturn.Both
);
item.on("changed", (values) => {
const e = {};
fields.forEach((f, i) => (e[f] = values[i].value));
console.log(`[${e.Severity}] ${e.SourceName}: ${e.Message && e.Message.text}`);
});
setTimeout(async () => {
await subscription.terminate();
await session.close();
await client.disconnect();
}, 10000);
})();
What it prints
[500] MachineTool_1: Tool life below threshold
[800] MachineTool_1: Tool breakage detected
[100] Server: Session activated
Notes
- The field order in the select clause is the order values arrive in. Zip them back to names yourself, as above: positional arrays are easy to get subtly wrong.
- samplingInterval: 0 means report as fast as events occur, which is what you want for events rather than values.
- Add ConditionClassId to the field list for OEE work. It gives you a standardised reason taxonomy.
- Call ConditionRefresh after reconnecting, or you will miss alarms that were already active.
What breaks first
The subscription is created but no events ever arrive
A field in your select clause does not exist on the event types the server emits. Reduce to the base fields, confirm events flow, then add fields back one at a time.
BadEventFilterInvalidA field in your select clause does not exist on the event types the server emits. Reduce to the base fields, confirm events flow, then add fields back one at a time.
Other recipes in this stack
Concepts on this page
Last verified 7 September 2026 against OPC UA 1.05.07. OPC UA Connect is an educational resource and is not affiliated with the OPC Foundation.