node-opcua-client 2.118.0 → 2.119.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.
- package/dist/alarms_and_conditions/client_alarm_tools.d.ts +1 -1
- package/dist/alarms_and_conditions/client_alarm_tools.js +5 -8
- package/dist/alarms_and_conditions/client_alarm_tools.js.map +1 -1
- package/dist/alarms_and_conditions/client_tools.d.ts +1 -7
- package/dist/alarms_and_conditions/client_tools.js +15 -147
- package/dist/alarms_and_conditions/client_tools.js.map +1 -1
- package/dist/client_monitored_item_toolbox.js.map +1 -1
- package/dist/client_session.d.ts +9 -0
- package/dist/client_session_keepalive_manager.js.map +1 -1
- package/dist/client_subscription.d.ts +2 -1
- package/dist/client_subscription.js.map +1 -1
- package/dist/client_utils.js.map +1 -1
- package/dist/index.d.ts +3 -6
- package/dist/index.js +3 -6
- package/dist/index.js.map +1 -1
- package/dist/private/client_base_impl.js +2 -2
- package/dist/private/client_base_impl.js.map +1 -1
- package/dist/private/client_monitored_item_group_impl.js.map +1 -1
- package/dist/private/client_monitored_item_impl.js.map +1 -1
- package/dist/private/client_publish_engine.js +1 -1
- package/dist/private/client_publish_engine.js.map +1 -1
- package/dist/private/client_session_impl.d.ts +4 -0
- package/dist/private/client_session_impl.js +7 -3
- package/dist/private/client_session_impl.js.map +1 -1
- package/dist/private/client_subscription_impl.js.map +1 -1
- package/dist/private/opcua_client_impl.js.map +1 -1
- package/dist/private/performance.js.map +1 -1
- package/dist/reconnection.js.map +1 -1
- package/dist/tools/findservers.js.map +1 -1
- package/dist/tools/read_history_server_capabilities.js.map +1 -1
- package/dist/verify.js.map +1 -1
- package/package.json +32 -31
- package/source/alarms_and_conditions/client_alarm_tools.ts +2 -6
- package/source/alarms_and_conditions/client_tools.ts +21 -185
- package/source/client_session.ts +10 -1
- package/source/client_subscription.ts +3 -2
- package/source/index.ts +3 -6
- package/source/private/client_session_impl.ts +4 -0
- package/source/alarms_and_conditions/client_alarm.ts +0 -130
- package/source/alarms_and_conditions/client_alarm_list.ts +0 -112
- package/source/alarms_and_conditions/client_alarm_tools_acknowledge_all_conditions.ts +0 -187
- package/source/alarms_and_conditions/client_alarm_tools_dump_event.ts +0 -67
- package/source/alarms_and_conditions/client_alarm_tools_extractConditionFields.ts +0 -12
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from "events";
|
|
2
|
-
import { assert } from "node-opcua-assert";
|
|
3
|
-
import { DataType } from "node-opcua-basic-types";
|
|
4
|
-
import { NodeId } from "node-opcua-nodeid";
|
|
5
|
-
import { ClientAlarm, EventStuff } from "./client_alarm";
|
|
6
|
-
|
|
7
|
-
export interface ClientAlarmList {
|
|
8
|
-
on(eventName: "alarmChanged", handler: (alarm: ClientAlarm) => void): this;
|
|
9
|
-
on(eventName: "alarmDeleted", handler: (alarm: ClientAlarm) => void): this;
|
|
10
|
-
on(eventName: "newAlarm", handler: (alarm: ClientAlarm) => void): this;
|
|
11
|
-
|
|
12
|
-
emit(eventName: "alarmChanged", alarm: ClientAlarm): boolean;
|
|
13
|
-
emit(eventName: "newAlarm", alarm: ClientAlarm): boolean;
|
|
14
|
-
emit(eventName: "alarmDeleted", alarm: ClientAlarm): boolean;
|
|
15
|
-
}
|
|
16
|
-
// maintain a set of alarm list for a client
|
|
17
|
-
export class ClientAlarmList extends EventEmitter implements Iterable<ClientAlarm> {
|
|
18
|
-
private _map: { [key: string]: ClientAlarm } = {};
|
|
19
|
-
|
|
20
|
-
public constructor() {
|
|
21
|
-
super();
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
public [Symbol.iterator](): Iterator<ClientAlarm> {
|
|
25
|
-
let pointer = 0;
|
|
26
|
-
const components = Object.values(this._map);
|
|
27
|
-
return {
|
|
28
|
-
next(): IteratorResult<ClientAlarm> {
|
|
29
|
-
if (pointer >= components.length) {
|
|
30
|
-
return {
|
|
31
|
-
done: true,
|
|
32
|
-
value: components[pointer++]
|
|
33
|
-
};
|
|
34
|
-
} else {
|
|
35
|
-
return {
|
|
36
|
-
done: false,
|
|
37
|
-
value: components[pointer++]
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
public alarms(): ClientAlarm[] {
|
|
45
|
-
return Object.values(this._map);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
public update(eventField: EventStuff): void {
|
|
49
|
-
// Spec says:
|
|
50
|
-
// Clients shall check for multiple Event Notifications for a ConditionBranch to avoid
|
|
51
|
-
// overwriting a new state delivered together with an older state from the Refresh
|
|
52
|
-
// process.
|
|
53
|
-
|
|
54
|
-
const { conditionId, eventType } = eventField;
|
|
55
|
-
assert(conditionId, "must have a valid conditionId ( verify that event is a acknodweldgeable type");
|
|
56
|
-
const alarm = this.findAlarm(conditionId.value, eventType.value);
|
|
57
|
-
|
|
58
|
-
if (!alarm) {
|
|
59
|
-
const key = this.makeKey(conditionId.value, eventType.value);
|
|
60
|
-
const newAlarm = new ClientAlarm(eventField);
|
|
61
|
-
this._map[key] = newAlarm;
|
|
62
|
-
this.emit("newAlarm", newAlarm);
|
|
63
|
-
this.emit("alarmChanged", newAlarm);
|
|
64
|
-
} else {
|
|
65
|
-
alarm.update(eventField);
|
|
66
|
-
this.emit("alarmChanged", alarm);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
public removeAlarm(eventField: EventStuff): void {
|
|
70
|
-
const { conditionId, eventType } = eventField;
|
|
71
|
-
const alarm = this.findAlarm(conditionId.value, eventType.value);
|
|
72
|
-
if (alarm) {
|
|
73
|
-
alarm.update(eventField);
|
|
74
|
-
this._removeAlarm(alarm);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
public get length(): number {
|
|
79
|
-
return Object.keys(this._map).length;
|
|
80
|
-
}
|
|
81
|
-
public purgeUnusedAlarms(): void {
|
|
82
|
-
const alarms = this.alarms();
|
|
83
|
-
for (const alarm of alarms) {
|
|
84
|
-
if (!alarm.getRetain()) {
|
|
85
|
-
this._removeAlarm(alarm);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private _removeAlarm(alarm: ClientAlarm) {
|
|
91
|
-
this.emit("alarmDeleted", alarm);
|
|
92
|
-
this.deleteAlarm(alarm.conditionId, alarm.eventType);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private makeKey(conditionId: NodeId, eventType: NodeId) {
|
|
96
|
-
return conditionId.toString() + "|" + eventType.toString();
|
|
97
|
-
}
|
|
98
|
-
private findAlarm(conditionId: NodeId, eventType: NodeId): ClientAlarm | null {
|
|
99
|
-
const key = this.makeKey(conditionId, eventType);
|
|
100
|
-
const _c = this._map[key];
|
|
101
|
-
return _c || null;
|
|
102
|
-
}
|
|
103
|
-
private deleteAlarm(conditionId: NodeId, eventType: NodeId): boolean {
|
|
104
|
-
const key = this.makeKey(conditionId, eventType);
|
|
105
|
-
const _c = this._map[key];
|
|
106
|
-
if (_c) {
|
|
107
|
-
delete this._map[key];
|
|
108
|
-
return true;
|
|
109
|
-
}
|
|
110
|
-
return false;
|
|
111
|
-
}
|
|
112
|
-
}
|
|
@@ -1,187 +0,0 @@
|
|
|
1
|
-
import { resolveNodeId } from "node-opcua-nodeid";
|
|
2
|
-
import { constructEventFilter } from "node-opcua-service-filter";
|
|
3
|
-
import { AttributeIds, ReadValueIdOptions, TimestampsToReturn } from "node-opcua-service-read";
|
|
4
|
-
import { CreateSubscriptionRequestOptions, MonitoringParametersOptions } from "node-opcua-service-subscription";
|
|
5
|
-
import { StatusCode, StatusCodes } from "node-opcua-status-code";
|
|
6
|
-
import { DataType, Variant } from "node-opcua-variant";
|
|
7
|
-
import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
|
|
8
|
-
import { ClientSession } from "../client_session";
|
|
9
|
-
import { EventStuff, fieldsToJson } from "./client_alarm";
|
|
10
|
-
import { extractConditionFields } from "./client_alarm_tools_extractConditionFields";
|
|
11
|
-
import { callConditionRefresh } from "./client_tools";
|
|
12
|
-
|
|
13
|
-
const doDebug = checkDebugFlag(__filename);
|
|
14
|
-
const debugLog = make_debugLog(__filename);
|
|
15
|
-
const errorLog = make_errorLog(__filename);
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
*
|
|
19
|
-
* @param session
|
|
20
|
-
* @param eventStuff
|
|
21
|
-
* @param comment
|
|
22
|
-
*/
|
|
23
|
-
export async function acknowledgeCondition(session: ClientSession, eventStuff: EventStuff, comment: string): Promise<StatusCode> {
|
|
24
|
-
try {
|
|
25
|
-
const conditionId = eventStuff.conditionId.value;
|
|
26
|
-
const eventId = eventStuff.eventId.value;
|
|
27
|
-
return await session.acknowledgeCondition(conditionId, eventId, comment);
|
|
28
|
-
} catch (err) {
|
|
29
|
-
errorLog("Acknowledging alarm has failed !", err);
|
|
30
|
-
return StatusCodes.BadInternalError;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
export async function confirmCondition(session: ClientSession, eventStuff: EventStuff, comment: string): Promise<StatusCode> {
|
|
34
|
-
try {
|
|
35
|
-
const conditionId = eventStuff.conditionId.value;
|
|
36
|
-
const eventId = eventStuff.eventId.value;
|
|
37
|
-
return await session.confirmCondition(conditionId, eventId, comment);
|
|
38
|
-
} catch (err) {
|
|
39
|
-
errorLog("Acknowledging alarm has failed !", err);
|
|
40
|
-
return StatusCodes.BadInternalError;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Enumerate all events
|
|
46
|
-
* @param session
|
|
47
|
-
*/
|
|
48
|
-
export async function findActiveConditions(session: ClientSession): Promise<EventStuff[]> {
|
|
49
|
-
const request: CreateSubscriptionRequestOptions = {
|
|
50
|
-
maxNotificationsPerPublish: 10000,
|
|
51
|
-
priority: 6,
|
|
52
|
-
publishingEnabled: true,
|
|
53
|
-
requestedLifetimeCount: 1000,
|
|
54
|
-
requestedMaxKeepAliveCount: 100,
|
|
55
|
-
requestedPublishingInterval: 100
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const subscription = await session.createSubscription2(request);
|
|
59
|
-
|
|
60
|
-
const itemToMonitor: ReadValueIdOptions = {
|
|
61
|
-
attributeId: AttributeIds.EventNotifier,
|
|
62
|
-
nodeId: resolveNodeId("Server") // i=2253
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const fields = await extractConditionFields(session, "AcknowledgeableConditionType");
|
|
66
|
-
|
|
67
|
-
// note: we may want to have this select clause
|
|
68
|
-
// Or(OfType("AcknowledgeableConditionType"), OfType("RefreshStartEventType"), OfType("RefreshEndEventType"))
|
|
69
|
-
const eventFilter = constructEventFilter(fields);
|
|
70
|
-
|
|
71
|
-
const monitoringParameters: MonitoringParametersOptions = {
|
|
72
|
-
discardOldest: false,
|
|
73
|
-
filter: eventFilter,
|
|
74
|
-
queueSize: 100,
|
|
75
|
-
samplingInterval: 0
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
const event_monitoringItem = await subscription.monitor(itemToMonitor, monitoringParameters, TimestampsToReturn.Both);
|
|
79
|
-
|
|
80
|
-
const acknowledgeableConditions: EventStuff[] = [];
|
|
81
|
-
|
|
82
|
-
let refreshStartEventHasBeenReceived = false;
|
|
83
|
-
let RefreshEndEventHasBeenReceived = false;
|
|
84
|
-
|
|
85
|
-
const RefreshStartEventType = resolveNodeId("RefreshStartEventType").toString();
|
|
86
|
-
const RefreshEndEventType = resolveNodeId("RefreshEndEventType").toString();
|
|
87
|
-
|
|
88
|
-
const promise: Promise<void> = new Promise((resolve, reject) => {
|
|
89
|
-
// now create a event monitored Item
|
|
90
|
-
event_monitoringItem.on("changed", (_eventFields: any) => {
|
|
91
|
-
const eventFields = _eventFields as Variant[];
|
|
92
|
-
|
|
93
|
-
try {
|
|
94
|
-
if (RefreshEndEventHasBeenReceived) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// dumpEvent(session, fields, eventFields);
|
|
99
|
-
const pojo = fieldsToJson(fields, eventFields) as any;
|
|
100
|
-
|
|
101
|
-
// make sure we only start recording event after the RefreshStartEvent has been received
|
|
102
|
-
if (!refreshStartEventHasBeenReceived) {
|
|
103
|
-
if (pojo.eventType.value.toString() === RefreshStartEventType) {
|
|
104
|
-
refreshStartEventHasBeenReceived = true;
|
|
105
|
-
}
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
if (pojo.eventType.value.toString() === RefreshEndEventType) {
|
|
109
|
-
RefreshEndEventHasBeenReceived = true;
|
|
110
|
-
resolve();
|
|
111
|
-
return;
|
|
112
|
-
}
|
|
113
|
-
if (!pojo.conditionId.value) {
|
|
114
|
-
// not a Acknowledgeable condition
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (pojo.ackedState.id.dataType === DataType.Boolean) {
|
|
119
|
-
acknowledgeableConditions.push(pojo as EventStuff);
|
|
120
|
-
}
|
|
121
|
-
} catch (err) {
|
|
122
|
-
errorLog("Error !!", err);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
// async call without waiting !
|
|
126
|
-
try {
|
|
127
|
-
callConditionRefresh(subscription);
|
|
128
|
-
} catch (err) {
|
|
129
|
-
// it is possible that server do not implement conditionRefresh ...
|
|
130
|
-
debugLog("Server may not implement conditionRefresh", err);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
await promise;
|
|
135
|
-
|
|
136
|
-
// now shut down subscription
|
|
137
|
-
await subscription.terminate();
|
|
138
|
-
|
|
139
|
-
return acknowledgeableConditions;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export async function acknowledgeAllConditions(session: ClientSession, message: string): Promise<void> {
|
|
143
|
-
try {
|
|
144
|
-
let conditions = await findActiveConditions(session);
|
|
145
|
-
if (conditions.length === 0) {
|
|
146
|
-
debugLog("Warning: cannot find conditions ");
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// filter acknowledgeable conditions (no acked yet)
|
|
150
|
-
conditions = conditions.filter((pojo) => pojo.ackedState.id.value === false);
|
|
151
|
-
|
|
152
|
-
const promises: Array<Promise<StatusCode>> = [];
|
|
153
|
-
for (const eventStuff of conditions) {
|
|
154
|
-
promises.push(acknowledgeCondition(session, eventStuff, message));
|
|
155
|
-
}
|
|
156
|
-
const result = await Promise.all(promises);
|
|
157
|
-
// istanbul ignore next
|
|
158
|
-
if (doDebug) {
|
|
159
|
-
debugLog("Acked all results: ", result.map((e) => e.toString()).join(" "));
|
|
160
|
-
}
|
|
161
|
-
} catch (err) {
|
|
162
|
-
errorLog("Error", err);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
export async function confirmAllConditions(session: ClientSession, message: string): Promise<void> {
|
|
166
|
-
try {
|
|
167
|
-
let conditions = await findActiveConditions(session);
|
|
168
|
-
if (conditions.length === 0) {
|
|
169
|
-
debugLog("Warning: cannot find conditions ");
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// filter acknowledgeable conditions (no acked yet)
|
|
173
|
-
conditions = conditions.filter((pojo) => pojo.confirmedState.id.value === false);
|
|
174
|
-
|
|
175
|
-
const promises: Array<Promise<any>> = [];
|
|
176
|
-
for (const eventStuff of conditions) {
|
|
177
|
-
promises.push(confirmCondition(session, eventStuff, message));
|
|
178
|
-
}
|
|
179
|
-
const result = await Promise.all(promises);
|
|
180
|
-
// istanbul ignore next
|
|
181
|
-
if (doDebug) {
|
|
182
|
-
debugLog("Confirm all results: ", result.map((e) => e.toString()).join(" "));
|
|
183
|
-
}
|
|
184
|
-
} catch (err) {
|
|
185
|
-
errorLog("Error", err);
|
|
186
|
-
}
|
|
187
|
-
}
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
import chalk from "chalk";
|
|
2
|
-
import { AttributeIds } from "node-opcua-data-model";
|
|
3
|
-
import { NodeId } from "node-opcua-nodeid";
|
|
4
|
-
import { IBasicSessionReadAsyncSimple } from "node-opcua-pseudo-session";
|
|
5
|
-
import { DataType, Variant, VariantLike } from "node-opcua-variant";
|
|
6
|
-
|
|
7
|
-
import { make_warningLog } from "node-opcua-debug";
|
|
8
|
-
|
|
9
|
-
const warningLog = make_warningLog("ClientAlarmTool");
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
*
|
|
13
|
-
* @param session
|
|
14
|
-
* @param fields
|
|
15
|
-
* @param eventFields
|
|
16
|
-
*/
|
|
17
|
-
export async function dumpEvent(session: IBasicSessionReadAsyncSimple, fields: string[], eventFields: Variant[]): Promise<void> {
|
|
18
|
-
async function getBrowseName(_session: IBasicSessionReadAsyncSimple, nodeId: NodeId): Promise<string> {
|
|
19
|
-
const dataValue = await _session.read({
|
|
20
|
-
attributeId: AttributeIds.BrowseName,
|
|
21
|
-
nodeId
|
|
22
|
-
});
|
|
23
|
-
if (dataValue.statusCode.isGood()) {
|
|
24
|
-
const browseName = dataValue.value.value.name!;
|
|
25
|
-
return browseName;
|
|
26
|
-
} else {
|
|
27
|
-
return "???";
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function w(str: string, l: number): string {
|
|
31
|
-
return (str || "").toString().padEnd(l, " ").substring(0, l);
|
|
32
|
-
}
|
|
33
|
-
async function __dumpEvent1(_session: IBasicSessionReadAsyncSimple, _fields: any, variant: VariantLike, index: number) {
|
|
34
|
-
if (variant.dataType === DataType.Null) {
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (variant.dataType === DataType.NodeId) {
|
|
38
|
-
const name = await getBrowseName(_session, variant.value);
|
|
39
|
-
warningLog(
|
|
40
|
-
chalk.yellow(w(name, 30), w(_fields[index], 25)),
|
|
41
|
-
chalk.cyan(w(DataType[variant.dataType], 10).toString()),
|
|
42
|
-
chalk.cyan.bold(name),
|
|
43
|
-
"(",
|
|
44
|
-
w(variant.value, 20),
|
|
45
|
-
")"
|
|
46
|
-
);
|
|
47
|
-
} else {
|
|
48
|
-
// tslint:disable-next-line: no-console
|
|
49
|
-
warningLog(
|
|
50
|
-
chalk.yellow(w("", 30), w(_fields[index], 25)),
|
|
51
|
-
chalk.cyan(w(DataType[variant.dataType as number], 10).toString()),
|
|
52
|
-
variant.value
|
|
53
|
-
);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
async function __dumpEvent(_session: IBasicSessionReadAsyncSimple, _fields: string[], _eventFields: Variant[]) {
|
|
58
|
-
let index = 0;
|
|
59
|
-
const promises = [];
|
|
60
|
-
for (const variant of _eventFields) {
|
|
61
|
-
promises.push(__dumpEvent1(_session, _fields, variant, index));
|
|
62
|
-
index++;
|
|
63
|
-
}
|
|
64
|
-
await Promise.all(promises);
|
|
65
|
-
}
|
|
66
|
-
await __dumpEvent(session, fields, eventFields);
|
|
67
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { NodeIdLike } from "node-opcua-nodeid";
|
|
2
|
-
import { simpleBrowsePathsToString, extractFields, ISessionForExtractField } from "node-opcua-pseudo-session";
|
|
3
|
-
|
|
4
|
-
export async function extractConditionFields(session: ISessionForExtractField, conditionNodeId: NodeIdLike): Promise<string[]> {
|
|
5
|
-
// conditionNodeId could be a Object of type ConditionType
|
|
6
|
-
// or it could be directly a ObjectType which is a subType of ConditionType
|
|
7
|
-
const p = await extractFields(session, conditionNodeId);
|
|
8
|
-
const fields1 = simpleBrowsePathsToString(p.map((a) => a.path));
|
|
9
|
-
// add this field which will always be added
|
|
10
|
-
fields1.push("ConditionId");
|
|
11
|
-
return fields1;
|
|
12
|
-
}
|