node-opcua-client 2.73.0 → 2.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/LICENSE +3 -1
  2. package/README.md +54 -0
  3. package/dist/alarms_and_conditions/client_alarm.d.ts +5 -1
  4. package/dist/alarms_and_conditions/client_alarm.js +23 -15
  5. package/dist/alarms_and_conditions/client_alarm.js.map +1 -1
  6. package/dist/alarms_and_conditions/client_alarm_list.js.map +1 -1
  7. package/dist/alarms_and_conditions/client_alarm_tools.js +22 -18
  8. package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
  9. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.js +4 -2
  10. package/dist/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.js.map +1 -1
  11. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.d.ts +0 -5
  12. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.js +8 -10
  13. package/dist/alarms_and_conditions/client_alarm_tools_extractConditionFields.js.map +1 -1
  14. package/dist/private/client_monitored_item_impl.js +3 -2
  15. package/dist/private/client_monitored_item_impl.js.map +1 -1
  16. package/dist/private/client_session_impl.js +1 -0
  17. package/dist/private/client_session_impl.js.map +1 -1
  18. package/dist/private/client_subscription_impl.js +7 -2
  19. package/dist/private/client_subscription_impl.js.map +1 -1
  20. package/package.json +43 -43
  21. package/source/alarms_and_conditions/client_alarm.ts +28 -17
  22. package/source/alarms_and_conditions/client_alarm_list.ts +1 -0
  23. package/source/alarms_and_conditions/client_alarm_tools.ts +33 -23
  24. package/source/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.ts +10 -4
  25. package/source/alarms_and_conditions/client_alarm_tools_extractConditionFields.ts +11 -11
  26. package/source/private/client_monitored_item_impl.ts +4 -3
  27. package/source/private/client_session_impl.ts +10 -2
  28. package/source/private/client_subscription_impl.ts +6 -2
@@ -1,10 +1,10 @@
1
1
  import { AttributeIds } from "node-opcua-data-model";
2
2
  import { resolveNodeId } from "node-opcua-nodeid";
3
- import { constructEventFilter } from "node-opcua-service-filter";
3
+ import { constructEventFilter, ofType } from "node-opcua-service-filter";
4
4
  import { ReadValueIdOptions, TimestampsToReturn } from "node-opcua-service-read";
5
5
  import { CreateSubscriptionRequestOptions, MonitoringParametersOptions } from "node-opcua-service-subscription";
6
- import { Variant } from "node-opcua-variant";
7
- import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
6
+ import { DataType, Variant } from "node-opcua-variant";
7
+ import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
8
8
 
9
9
  import { ClientMonitoredItem } from "../client_monitored_item";
10
10
  import { ClientSubscription } from "../client_subscription";
@@ -16,6 +16,7 @@ import { callConditionRefresh } from "./client_tools";
16
16
 
17
17
  const doDebug = checkDebugFlag("A&E");
18
18
  const debugLog = make_debugLog("A&E");
19
+ const warningLog = make_warningLog("A&E");
19
20
 
20
21
  function r(_key: string, o: { dataType?: unknown; value?: unknown }) {
21
22
  if (o && o.dataType === "Null") {
@@ -67,7 +68,7 @@ export async function installAlarmMonitoring(session: ClientSession): Promise<Cl
67
68
  _sessionPriv.$clientAlarmList = clientAlarmList;
68
69
 
69
70
  const request: CreateSubscriptionRequestOptions = {
70
- maxNotificationsPerPublish: 10000,
71
+ maxNotificationsPerPublish: 100,
71
72
  priority: 6,
72
73
  publishingEnabled: true,
73
74
  requestedLifetimeCount: 10000,
@@ -84,21 +85,20 @@ export async function installAlarmMonitoring(session: ClientSession): Promise<Cl
84
85
 
85
86
  const fields = await extractConditionFields(session, "AlarmConditionType");
86
87
 
87
- const eventFilter = constructEventFilter(fields, [resolveNodeId("AcknowledgeableConditionType")]);
88
+ const AcknowledgeableConditionType = resolveNodeId("AcknowledgeableConditionType");
89
+
90
+ const eventFilter = constructEventFilter(fields, ofType(AcknowledgeableConditionType));
88
91
 
89
92
  const monitoringParameters: MonitoringParametersOptions = {
90
93
  discardOldest: false,
91
94
  filter: eventFilter,
92
- queueSize: 10000,
95
+ queueSize: 1000,
93
96
  samplingInterval: 0
94
97
  };
95
98
 
96
99
  // now create a event monitored Item
97
100
  const eventMonitoringItem = await subscription.monitor(itemToMonitor, monitoringParameters, TimestampsToReturn.Both);
98
101
 
99
- const RefreshStartEventType = resolveNodeId("RefreshStartEventType").toString();
100
- const RefreshEndEventType = resolveNodeId("RefreshEndEventType").toString();
101
-
102
102
  const queueEvent: EventStuff[] = [];
103
103
  function flushQueue() {
104
104
  const q = [...queueEvent];
@@ -110,17 +110,25 @@ export async function installAlarmMonitoring(session: ClientSession): Promise<Cl
110
110
 
111
111
  let inInit = true;
112
112
  eventMonitoringItem.on("changed", (eventFields: Variant[]) => {
113
- debugLog("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ---- ALARM RECEIVED");
114
- const pojo = fieldsToJson(fields, eventFields) as EventStuff;
113
+
114
+ const pojo = fieldsToJson(fields, eventFields);
115
+ const { eventType, eventId, conditionId, conditionName } = pojo;
116
+
117
+ debugLog(
118
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ---- ALARM RECEIVED " +
119
+ eventType.value.toString() +
120
+ " " +
121
+ eventId.value?.toString("hex")
122
+ );
115
123
  try {
116
- if (pojo.eventType.value.toString() === RefreshStartEventType) {
117
- return;
118
- }
119
- if (pojo.eventType.value.toString() === RefreshEndEventType) {
120
- return;
121
- }
122
- if (!pojo.conditionId || !pojo.conditionId.value || pojo.conditionId.dataType === 0) {
124
+ if (!conditionId || !conditionId.value || conditionId.dataType === DataType.Null) {
123
125
  // not a acknowledgeable condition
126
+ warningLog(
127
+ " not acknowledgeable condition ---- " + eventType.value.toString() + " ",
128
+ conditionId,
129
+ conditionName?.value,
130
+ " " + eventId.value?.toString("hex")
131
+ );
124
132
  return;
125
133
  }
126
134
  queueEvent.push(pojo);
@@ -128,10 +136,8 @@ export async function installAlarmMonitoring(session: ClientSession): Promise<Cl
128
136
  setTimeout(() => flushQueue(), 10);
129
137
  }
130
138
  } catch (err) {
131
- // tslint:disable-next-line: no-console
132
- console.log(JSON.stringify(pojo, r, " "));
133
- // tslint:disable-next-line: no-console
134
- console.log("Error !!", err);
139
+ warningLog(JSON.stringify(pojo, r, " "));
140
+ warningLog("Error !!", err);
135
141
  }
136
142
 
137
143
  // Release 1.04 8 OPC Unified Architecture, Part 9
@@ -150,7 +156,11 @@ export async function installAlarmMonitoring(session: ClientSession): Promise<Cl
150
156
  try {
151
157
  await callConditionRefresh(subscription);
152
158
  } catch (err) {
153
- console.log("Server may not implement condition refresh", (<Error>err).message);
159
+ if ((err as Error).message.match(/BadNothingToDo/)) {
160
+ /** fine! nothing to do */
161
+ } else {
162
+ warningLog("Server may not implement condition refresh", (<Error>err).message);
163
+ }
154
164
  }
155
165
  _sessionPriv.$monitoredItemForAlarmList = eventMonitoringItem;
156
166
 
@@ -5,7 +5,6 @@ import { CreateSubscriptionRequestOptions, MonitoringParametersOptions } from "n
5
5
  import { StatusCode, StatusCodes } from "node-opcua-status-code";
6
6
  import { DataType, Variant } from "node-opcua-variant";
7
7
  import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
8
- import { ClientMonitoredItem } from "../client_monitored_item";
9
8
  import { ClientSession } from "../client_session";
10
9
  import { EventStuff, fieldsToJson } from "./client_alarm";
11
10
  import { extractConditionFields } from "./client_alarm_tools_extractConditionFields";
@@ -22,6 +21,7 @@ const errorLog = make_errorLog(__filename);
22
21
  * @param comment
23
22
  */
24
23
  export async function acknowledgeCondition(session: ClientSession, eventStuff: EventStuff, comment: string): Promise<StatusCode> {
24
+
25
25
  try {
26
26
  const conditionId = eventStuff.conditionId.value;
27
27
  const eventId = eventStuff.eventId.value;
@@ -65,7 +65,9 @@ export async function findActiveConditions(session: ClientSession): Promise<Even
65
65
 
66
66
  const fields = await extractConditionFields(session, "AcknowledgeableConditionType");
67
67
 
68
- const eventFilter = constructEventFilter(fields, [resolveNodeId("AcknowledgeableConditionType")]);
68
+ // note: we may want to have this select clause
69
+ // Or(OfType("AcknowledgeableConditionType"), OfType("RefreshStartEventType"), OfType("RefreshEndEventType"))
70
+ const eventFilter = constructEventFilter(fields);
69
71
 
70
72
  const monitoringParameters: MonitoringParametersOptions = {
71
73
  discardOldest: false,
@@ -88,13 +90,17 @@ export async function findActiveConditions(session: ClientSession): Promise<Even
88
90
  // now create a event monitored Item
89
91
  event_monitoringItem.on("changed", (_eventFields: any) => {
90
92
  const eventFields = _eventFields as Variant[];
93
+
91
94
  try {
92
95
  if (RefreshEndEventHasBeenReceived) {
93
96
  return;
94
97
  }
98
+
99
+
95
100
  // dumpEvent(session, fields, eventFields);
96
101
  const pojo = fieldsToJson(fields, eventFields) as any;
97
- // console.log(pojo.eventType.value.toString(), RefreshEndEventType, RefreshStartEventType);
102
+
103
+ // console.log(pojo.eventType.value.toString({ addressSpace}), RefreshEndEventType, RefreshStartEventType);
98
104
 
99
105
  // make sure we only start recording event after the RefreshStartEvent has been received
100
106
  if (!refreshStartEventHasBeenReceived) {
@@ -147,7 +153,7 @@ export async function acknwoledgeAllConditions(session: ClientSession, message:
147
153
  // filter acknowledgable conditions (no acked yet)
148
154
  conditions = conditions.filter((pojo) => pojo.ackedState.id.value === false);
149
155
 
150
- const promises: Array<Promise<any>> = [];
156
+ const promises: Array<Promise<StatusCode>> = [];
151
157
  for (const eventStuff of conditions) {
152
158
  promises.push(acknowledgeCondition(session, eventStuff, message));
153
159
  }
@@ -2,15 +2,11 @@ import { BrowseDirection, NodeClassMask, QualifiedName } from "node-opcua-data-m
2
2
  import { NodeId, NodeIdLike, resolveNodeId } from "node-opcua-nodeid";
3
3
  import { IBasicSession } from "node-opcua-pseudo-session";
4
4
  import { BrowseDescriptionOptions } from "node-opcua-service-browse";
5
+ import { NodeClass } from "node-opcua-types";
5
6
 
6
- /**
7
- *
8
- * @param session
9
- * @param conditionNodeId
10
- */
11
7
  export async function extractConditionFields(session: IBasicSession, conditionNodeId: NodeIdLike): Promise<string[]> {
12
8
  // conditionNodeId could be a Object of type ConditionType
13
- // or it could be directly a ObhectType which is a subType of ConditionType
9
+ // or it could be directly a ObjectType which is a subType of ConditionType
14
10
 
15
11
  const _duplicateMap: any = {};
16
12
  const fields1: string[] = [];
@@ -63,7 +59,9 @@ export async function extractConditionFields(session: IBasicSession, conditionNo
63
59
 
64
60
  for (const ref of result.references) {
65
61
  const n = name + "." + ref.browseName.toString();
66
- addField(n);
62
+ if (ref.nodeClass === NodeClass.Variable) {
63
+ addField(n);
64
+ }
67
65
  deferObjectOrVariableInvestigation(ref.nodeId, n);
68
66
  }
69
67
  }
@@ -83,8 +81,10 @@ export async function extractConditionFields(session: IBasicSession, conditionNo
83
81
  const nodeToBrowse2: BrowseDescriptionOptions = {
84
82
  browseDirection: BrowseDirection.Forward,
85
83
  includeSubtypes: true,
84
+
86
85
  // tslint:disable-next-line: no-bitwise
87
86
  nodeClassMask: NodeClassMask.Object | NodeClassMask.Variable,
87
+
88
88
  nodeId: conditionNodeId,
89
89
  referenceTypeId: resolveNodeId("HasChild"),
90
90
  resultMask: 63
@@ -92,12 +92,11 @@ export async function extractConditionFields(session: IBasicSession, conditionNo
92
92
  const nodesToBrowse = [nodeToBrowse1, nodeToBrowse2];
93
93
  const browseResults = await session.browse(nodesToBrowse);
94
94
 
95
- // console.log(browseResults[0].toString());
96
- // console.log(browseResults[1].toString());
97
-
98
95
  if (browseResults[1] && browseResults[1].references) {
99
96
  for (const ref of browseResults[1].references) {
100
- addField(ref.browseName.toString());
97
+ if (ref.nodeClass === NodeClass.Variable) {
98
+ addField(ref.browseName.toString());
99
+ }
101
100
  deferObjectOrVariableInvestigation(ref.nodeId, ref.browseName.toString());
102
101
  }
103
102
  }
@@ -115,5 +114,6 @@ export async function extractConditionFields(session: IBasicSession, conditionNo
115
114
 
116
115
  // add this field which will always be added
117
116
  addField("ConditionId");
117
+
118
118
  return fields1;
119
119
  }
@@ -8,7 +8,7 @@ import { assert } from "node-opcua-assert";
8
8
 
9
9
  import { AttributeIds } from "node-opcua-data-model";
10
10
  import { DataValue, coerceTimestampsToReturn } from "node-opcua-data-value";
11
- import { checkDebugFlag, make_debugLog } from "node-opcua-debug";
11
+ import { checkDebugFlag, make_debugLog, make_warningLog } from "node-opcua-debug";
12
12
  import { ExtensionObject } from "node-opcua-extension-object";
13
13
  import { EventFilter } from "node-opcua-service-filter";
14
14
  import { ReadValueId, ReadValueIdOptions, TimestampsToReturn } from "node-opcua-service-read";
@@ -29,6 +29,7 @@ import { ClientSubscription } from "../client_subscription";
29
29
  import { ClientMonitoredItem_create, ClientSubscriptionImpl } from "./client_subscription_impl";
30
30
 
31
31
  const debugLog = make_debugLog(__filename);
32
+ const warningLog = make_warningLog(__filename);
32
33
  const doDebug = checkDebugFlag(__filename);
33
34
 
34
35
  export type PrepareForMonitoringResult =
@@ -216,8 +217,8 @@ export class ClientMonitoredItemImpl extends EventEmitter implements ClientMonit
216
217
  try {
217
218
  this.emit("changed", eventFields);
218
219
  } catch (err) {
219
- debugLog("Exception raised inside the event handler called by ClientMonitoredItem.on('change')", err);
220
- debugLog("Please verify the application using this node-opcua client");
220
+ warningLog("Exception raised inside the event handler called by ClientMonitoredItem.on('change')", err);
221
+ warningLog("Please verify the application using this node-opcua client");
221
222
  }
222
223
  }
223
224
 
@@ -10,7 +10,7 @@ import {
10
10
  ExtraDataTypeManager,
11
11
  getExtensionObjectConstructor,
12
12
  getExtraDataTypeManager,
13
- promoteOpaqueStructure,
13
+ promoteOpaqueStructure
14
14
  } from "node-opcua-client-dynamic-extension-object";
15
15
  import { Certificate, Nonce } from "node-opcua-crypto";
16
16
  import { attributeNameById, BrowseDirection, LocalizedTextLike } from "node-opcua-data-model";
@@ -82,7 +82,13 @@ import {
82
82
  import { WriteRequest, WriteResponse, WriteValue } from "node-opcua-service-write";
83
83
  import { StatusCode, StatusCodes, Callback, CallbackT } from "node-opcua-status-code";
84
84
  import { ErrorCallback } from "node-opcua-status-code";
85
- import { BrowseNextRequest, BrowseNextResponse, HistoryReadValueIdOptions, WriteValueOptions } from "node-opcua-types";
85
+ import {
86
+ BrowseNextRequest,
87
+ BrowseNextResponse,
88
+ HistoryReadValueIdOptions,
89
+ ServiceFault,
90
+ WriteValueOptions
91
+ } from "node-opcua-types";
86
92
  import { buffer_ellipsis, getFunctionParameterNames, isNullOrUndefined, lowerFirstLetter } from "node-opcua-utils";
87
93
  import { DataType, Variant, VariantLike } from "node-opcua-variant";
88
94
 
@@ -1540,6 +1546,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1540
1546
  if (err && err.message.match(/BadSessionIdInvalid/) && request.constructor.name !== "ActivateSessionRequest") {
1541
1547
  debugLog("Transaction on Invalid Session ", request.constructor.name);
1542
1548
  request.requestHeader.requestHandle = requestHandleNotSetValue;
1549
+ warningLog("client is now attempting to recreate a session");
1543
1550
  this.recreate_session_and_reperform_transaction(request, callback);
1544
1551
  return;
1545
1552
  }
@@ -1595,6 +1602,7 @@ export class ClientSessionImpl extends EventEmitter implements ClientSession {
1595
1602
  }
1596
1603
  return callback(err);
1597
1604
  }
1605
+
1598
1606
  /* istanbul ignore next */
1599
1607
  if (!response) {
1600
1608
  return callback(new Error("internal Error"));
@@ -471,8 +471,12 @@ export class ClientSubscriptionImpl extends EventEmitter implements ClientSubscr
471
471
  });
472
472
  session.setTriggering(setTriggeringRequest, (err: Error | null, response?: SetTriggeringResponse) => {
473
473
  if (err) {
474
- // use soft error, no exceptions
475
- return callback(null, response);
474
+ if (response) {
475
+ // use soft error, no exceptions
476
+ return callback(null, response);
477
+ } else {
478
+ return callback(err);
479
+ }
476
480
  }
477
481
  // istanbul ignore next
478
482
  if (!response) {