node-opcua-alarm-condition 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/LICENSE +22 -0
- package/dist/acknowledge_all_conditions.d.ts +10 -0
- package/dist/acknowledge_all_conditions.js +173 -0
- package/dist/acknowledge_all_conditions.js.map +1 -0
- package/dist/call_condition_refresh.d.ts +3 -0
- package/dist/call_condition_refresh.js +46 -0
- package/dist/call_condition_refresh.js.map +1 -0
- package/dist/call_method_condition.d.ts +8 -0
- package/dist/call_method_condition.js +65 -0
- package/dist/call_method_condition.js.map +1 -0
- package/dist/client_alarm.d.ts +30 -0
- package/dist/client_alarm.js +54 -0
- package/dist/client_alarm.js.map +1 -0
- package/dist/client_alarm_list.d.ts +26 -0
- package/dist/client_alarm_list.js +98 -0
- package/dist/client_alarm_list.js.map +1 -0
- package/dist/client_alarm_tools_dump_event.d.ts +9 -0
- package/dist/client_alarm_tools_dump_event.js +60 -0
- package/dist/client_alarm_tools_dump_event.js.map +1 -0
- package/dist/event_stuff.d.ts +23 -0
- package/dist/event_stuff.js +48 -0
- package/dist/event_stuff.js.map +1 -0
- package/dist/extract_condition_fields.d.ts +3 -0
- package/dist/extract_condition_fields.js +15 -0
- package/dist/extract_condition_fields.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
- package/source/acknowledge_all_conditions.ts +193 -0
- package/source/call_condition_refresh.ts +42 -0
- package/source/call_method_condition.ts +86 -0
- package/source/client_alarm.ts +73 -0
- package/source/client_alarm_list.ts +112 -0
- package/source/client_alarm_tools_dump_event.ts +66 -0
- package/source/event_stuff.ts +65 -0
- package/source/extract_condition_fields.ts +12 -0
- package/source/index.ts +8 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import { assert } from "node-opcua-assert";
|
|
3
|
+
import { NodeId } from "node-opcua-nodeid";
|
|
4
|
+
import { EventStuff } from "./event_stuff";
|
|
5
|
+
import { ClientAlarm } 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 acknowledgeable 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
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
import { make_traceLog } from "node-opcua-debug";
|
|
7
|
+
|
|
8
|
+
const traceLog = make_traceLog("ClientAlarmTool");
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
*
|
|
12
|
+
* @param session
|
|
13
|
+
* @param fields
|
|
14
|
+
* @param eventFields
|
|
15
|
+
*/
|
|
16
|
+
export async function dumpEvent(session: IBasicSessionReadAsyncSimple, fields: string[], eventFields: Variant[]): Promise<void> {
|
|
17
|
+
async function getBrowseName(_session: IBasicSessionReadAsyncSimple, nodeId: NodeId): Promise<string> {
|
|
18
|
+
const dataValue = await _session.read({
|
|
19
|
+
attributeId: AttributeIds.BrowseName,
|
|
20
|
+
nodeId
|
|
21
|
+
});
|
|
22
|
+
if (dataValue.statusCode.isGood()) {
|
|
23
|
+
const browseName = dataValue.value.value.name!;
|
|
24
|
+
return browseName;
|
|
25
|
+
} else {
|
|
26
|
+
return "???";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function w(str: string, l: number): string {
|
|
30
|
+
return (str || "").toString().padEnd(l, " ").substring(0, l);
|
|
31
|
+
}
|
|
32
|
+
async function __dumpEvent1(_session: IBasicSessionReadAsyncSimple, _fields: any, variant: VariantLike, index: number) {
|
|
33
|
+
if (variant.dataType === DataType.Null) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (variant.dataType === DataType.NodeId) {
|
|
37
|
+
const name = await getBrowseName(_session, variant.value);
|
|
38
|
+
traceLog(
|
|
39
|
+
chalk.yellow(w(name, 30), w(_fields[index], 25)),
|
|
40
|
+
chalk.cyan(w(DataType[variant.dataType], 10).toString()),
|
|
41
|
+
chalk.cyan.bold(name),
|
|
42
|
+
"(",
|
|
43
|
+
w(variant.value, 20),
|
|
44
|
+
")"
|
|
45
|
+
);
|
|
46
|
+
} else {
|
|
47
|
+
// tslint:disable-next-line: no-console
|
|
48
|
+
traceLog(
|
|
49
|
+
chalk.yellow(w("", 30), w(_fields[index], 25)),
|
|
50
|
+
chalk.cyan(w(DataType[variant.dataType as number], 10).toString()),
|
|
51
|
+
variant.value
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
async function __dumpEvent(_session: IBasicSessionReadAsyncSimple, _fields: string[], _eventFields: Variant[]) {
|
|
57
|
+
let index = 0;
|
|
58
|
+
const promises = [];
|
|
59
|
+
for (const variant of _eventFields) {
|
|
60
|
+
promises.push(__dumpEvent1(_session, _fields, variant, index));
|
|
61
|
+
index++;
|
|
62
|
+
}
|
|
63
|
+
await Promise.all(promises);
|
|
64
|
+
}
|
|
65
|
+
await __dumpEvent(session, fields, eventFields);
|
|
66
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { NodeId } from "node-opcua-nodeid";
|
|
2
|
+
import { lowerFirstLetter } from "node-opcua-utils";
|
|
3
|
+
import { Variant } from "node-opcua-variant";
|
|
4
|
+
|
|
5
|
+
import { make_warningLog } from "node-opcua-debug";
|
|
6
|
+
const warningLog = make_warningLog(__filename);
|
|
7
|
+
|
|
8
|
+
export interface TVariant<T> extends Variant {
|
|
9
|
+
value: T;
|
|
10
|
+
}
|
|
11
|
+
export interface TTwoStateStatus extends TVariant<string> {
|
|
12
|
+
id: TVariant<boolean>;
|
|
13
|
+
}
|
|
14
|
+
export interface EventStuff {
|
|
15
|
+
conditionId: TVariant<NodeId>;
|
|
16
|
+
eventType: TVariant<NodeId>;
|
|
17
|
+
eventId: TVariant<Buffer>;
|
|
18
|
+
retain: TVariant<boolean>;
|
|
19
|
+
activeState: TTwoStateStatus;
|
|
20
|
+
ackedState: TTwoStateStatus;
|
|
21
|
+
confirmedState: TTwoStateStatus;
|
|
22
|
+
conditionName?: TVariant<string>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
export function fieldsToJson(fields: string[], eventFields: Variant[], flat?: boolean): EventStuff {
|
|
30
|
+
|
|
31
|
+
function setProperty(_data: Record<string, unknown>, fieldName: string, value: Variant) {
|
|
32
|
+
let name: string;
|
|
33
|
+
if (!fieldName || value === null) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
if (!flat) {
|
|
37
|
+
const f = fieldName.split(".");
|
|
38
|
+
if (f.length === 1) {
|
|
39
|
+
fieldName = lowerFirstLetter(fieldName);
|
|
40
|
+
_data[fieldName] = value;
|
|
41
|
+
} else {
|
|
42
|
+
for (let i = 0; i < f.length - 1; i++) {
|
|
43
|
+
name = lowerFirstLetter(f[i]);
|
|
44
|
+
_data[name] = _data[name] || {};
|
|
45
|
+
_data = _data[name] as Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
name = lowerFirstLetter(f[f.length - 1]);
|
|
48
|
+
_data[name] = value;
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
const name = fieldName.split(".").map(lowerFirstLetter).join(".");
|
|
52
|
+
_data[name] = value;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (fields.length > eventFields.length) {
|
|
56
|
+
warningLog("warning fields.length !== eventFields.length", fields.length, eventFields.length);
|
|
57
|
+
}
|
|
58
|
+
const data: any = {};
|
|
59
|
+
for (let index = 0; index < fields.length; index++) {
|
|
60
|
+
const variant = eventFields[index];
|
|
61
|
+
setProperty(data, fields[index], variant);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return data;
|
|
65
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NodeIdLike } from "node-opcua-nodeid";
|
|
2
|
+
import { ISessionForExtractField, extractFields, simpleBrowsePathsToString } 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
|
+
}
|
package/source/index.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export * from "./acknowledge_all_conditions";
|
|
2
|
+
export * from "./call_condition_refresh";
|
|
3
|
+
export * from "./call_method_condition";
|
|
4
|
+
export * from "./client_alarm_list";
|
|
5
|
+
export * from "./client_alarm_tools_dump_event";
|
|
6
|
+
export * from "./client_alarm";
|
|
7
|
+
export * from "./event_stuff";
|
|
8
|
+
export * from "./extract_condition_fields";
|