Skip to content

Commit

Permalink
factor out node-opcua-alarm-condition module
Browse files Browse the repository at this point in the history
  • Loading branch information
erossignon committed Nov 25, 2023
1 parent 1cba6e9 commit ee7b7e3
Show file tree
Hide file tree
Showing 32 changed files with 616 additions and 418 deletions.
2 changes: 1 addition & 1 deletion extractModules.js
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,7 @@ async function test2() {
const source = `
import sinon = require("sinon");
import * as foo from "foo1";
import * as path from "path";
import path from "path";
const a = require("foo2");
const b = require("foo3/folder");
const c = require("@foo4/foo4");
Expand Down
19 changes: 19 additions & 0 deletions packages/node-opcua-alarm-condition/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
out/
out1/
out2/
documentation/
test/
test_to_fix/
test_fixtures/
certificates/
.vscode/
_test_generated/
schemas/
pki/
tmp/
test/
tsconfig.json
*.tsbuildinfo
pnpm-lock.yaml
tslint.*
.mocharc.*
22 changes: 22 additions & 0 deletions packages/node-opcua-alarm-condition/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
The MIT License (MIT)

Copyright (c) 2022-2023 Sterfive SAS - 833264583 RCS ORLEANS - France (https://www.sterfive.com)

Copyright (c) 2014-2022 Etienne Rossignon

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51 changes: 51 additions & 0 deletions packages/node-opcua-alarm-condition/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "node-opcua-alarm-condition",
"version": "2.118.0",
"description": "pure nodejs OPCUA SDK - module pseudo-session",
"scripts": {
"clean": "npx rimraf node_modules dist *.tsbuildinfo",
"build": "tsc -b",
"lint": "eslint source/**/*.ts",
"test": "echo mocha test"
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"dependencies": {
"node-opcua-assert": "2.105.0",
"node-opcua-basic-types": "2.118.0",
"node-opcua-data-model": "2.118.0",
"node-opcua-debug": "2.118.0",
"node-opcua-nodeid": "2.118.0",
"node-opcua-pseudo-session": "2.118.0",
"node-opcua-service-filter": "2.118.0",
"node-opcua-service-read": "2.118.0",
"node-opcua-service-browse": "2.118.0",
"node-opcua-service-subscription": "2.118.0",
"node-opcua-service-translate-browse-path": "2.118.0",
"node-opcua-status-code": "2.117.0",
"node-opcua-types": "2.118.0",
"node-opcua-utils": "2.117.0",
"node-opcua-variant": "2.118.0",
"thenify": "^3.3.1"
},
"author": "Etienne Rossignon",
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/node-opcua/node-opcua.git"
},
"keywords": [
"OPCUA",
"opcua",
"m2m",
"iot",
"opc ua",
"internet of things"
],
"homepage": "http://node-opcua.github.io/",
"gitHead": "50cfa07779d4c07b299176ac9c27527fcd97d079",
"files": [
"dist",
"source"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@ import { CreateSubscriptionRequestOptions, MonitoringParametersOptions } from "n
import { StatusCode, StatusCodes } from "node-opcua-status-code";
import { DataType, Variant } from "node-opcua-variant";
import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
import { ClientSession } from "../client_session";
import { EventStuff, fieldsToJson } from "./client_alarm";
import { extractConditionFields } from "./client_alarm_tools_extractConditionFields";
import { callConditionRefresh } from "./client_tools";

import { IBasicSessionAsync } from "node-opcua-pseudo-session";
import { IBasicSessionEx } from "node-opcua-pseudo-session";

import { EventStuff, fieldsToJson } from "./event_stuff";
import { extractConditionFields } from "./extract_condition_fields";
import { acknowledgeCondition, confirmCondition } from "./call_method_condition";
import { callConditionRefresh } from "./call_condition_refresh";

const doDebug = checkDebugFlag(__filename);
const debugLog = make_debugLog(__filename);
Expand All @@ -20,32 +24,35 @@ const errorLog = make_errorLog(__filename);
* @param eventStuff
* @param comment
*/
export async function acknowledgeCondition(session: ClientSession, eventStuff: EventStuff, comment: string): Promise<StatusCode> {

async function acknowledgeConditionEV(session: IBasicSessionAsync, eventStuff: EventStuff, comment: string): Promise<StatusCode> {
try {
const conditionId = eventStuff.conditionId.value;
const eventId = eventStuff.eventId.value;
return await session.acknowledgeCondition(conditionId, eventId, comment);
return await acknowledgeCondition(session, conditionId, eventId, comment);
} catch (err) {
errorLog("Acknowledging alarm has failed !", err);
errorLog("Acknowledging Condition has failed !", err);
return StatusCodes.BadInternalError;
}
}
export async function confirmCondition(session: ClientSession, eventStuff: EventStuff, comment: string): Promise<StatusCode> {
async function confirmConditionEV(session: IBasicSessionAsync, eventStuff: EventStuff, comment: string): Promise<StatusCode> {
try {
const conditionId = eventStuff.conditionId.value;
const eventId = eventStuff.eventId.value;
return await session.confirmCondition(conditionId, eventId, comment);
return await confirmCondition(session, conditionId, eventId, comment);
} catch (err) {
errorLog("Acknowledging alarm has failed !", err);
errorLog("Confirming Condition has failed !", err);
return StatusCodes.BadInternalError;
}
}

export type FindActiveConditions = () => Promise<EventStuff[]>;

/**
* Enumerate all events
* @param session
*/
export async function findActiveConditions(session: ClientSession): Promise<EventStuff[]> {
export async function findActiveConditions(session: IBasicSessionEx): Promise<EventStuff[]> {
const request: CreateSubscriptionRequestOptions = {
maxNotificationsPerPublish: 10000,
priority: 6,
Expand All @@ -59,7 +66,7 @@ export async function findActiveConditions(session: ClientSession): Promise<Even

const itemToMonitor: ReadValueIdOptions = {
attributeId: AttributeIds.EventNotifier,
nodeId: resolveNodeId("Server") // i=2253
nodeId: resolveNodeId("Server") // i=2253session
};

const fields = await extractConditionFields(session, "AcknowledgeableConditionType");
Expand All @@ -85,7 +92,7 @@ export async function findActiveConditions(session: ClientSession): Promise<Even
const RefreshStartEventType = resolveNodeId("RefreshStartEventType").toString();
const RefreshEndEventType = resolveNodeId("RefreshEndEventType").toString();

const promise: Promise<void> = new Promise((resolve, reject) => {
await new Promise<void>((resolve, reject) => {
// now create a event monitored Item
event_monitoringItem.on("changed", (_eventFields: any) => {
const eventFields = _eventFields as Variant[];
Expand Down Expand Up @@ -124,34 +131,33 @@ export async function findActiveConditions(session: ClientSession): Promise<Even
});
// async call without waiting !
try {
callConditionRefresh(subscription);
callConditionRefresh(session, subscription.subscriptionId);
} catch (err) {
// it is possible that server do not implement conditionRefresh ...
debugLog("Server may not implement conditionRefresh", err);
errorLog("Server may not implement conditionRefresh", (err as Error).message);
}
});

await promise;

// now shut down subscription
await subscription.terminate();

return acknowledgeableConditions;
}

export async function acknowledgeAllConditions(session: ClientSession, message: string): Promise<void> {
try {
let conditions = await findActiveConditions(session);
if (conditions.length === 0) {
debugLog("Warning: cannot find conditions ");
}
// let conditions = await findActiveConditions(session);
// if (conditions.length === 0) {
// debugLog("Warning: cannot find conditions ");
// }

export async function acknowledgeAllConditions(session: IBasicSessionEx, message: string): Promise<void> {
try {
let conditions: EventStuff[] = await findActiveConditions(session);
// filter acknowledgeable conditions (no acked yet)
conditions = conditions.filter((pojo) => pojo.ackedState.id.value === false);

const promises: Array<Promise<StatusCode>> = [];
for (const eventStuff of conditions) {
promises.push(acknowledgeCondition(session, eventStuff, message));
promises.push(acknowledgeConditionEV(session, eventStuff, message));
}
const result = await Promise.all(promises);
// istanbul ignore next
Expand All @@ -162,19 +168,16 @@ export async function acknowledgeAllConditions(session: ClientSession, message:
errorLog("Error", err);
}
}
export async function confirmAllConditions(session: ClientSession, message: string): Promise<void> {
try {
let conditions = await findActiveConditions(session);
if (conditions.length === 0) {
debugLog("Warning: cannot find conditions ");
}

export async function confirmAllConditions(session: IBasicSessionEx, message: string): Promise<void> {
try {
let conditions: EventStuff[] = await findActiveConditions(session);
// filter acknowledgeable conditions (no acked yet)
conditions = conditions.filter((pojo) => pojo.confirmedState.id.value === false);

const promises: Array<Promise<any>> = [];
for (const eventStuff of conditions) {
promises.push(confirmCondition(session, eventStuff, message));
promises.push(confirmConditionEV(session, eventStuff, message));
}
const result = await Promise.all(promises);
// istanbul ignore next
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import assert from "node-opcua-assert";
import { DataType, StatusCode, StatusCodes } from "node-opcua-basic-types";
import { resolveNodeId } from "node-opcua-nodeid";
import { makeBrowsePath } from "node-opcua-service-translate-browse-path";
import { CallMethodRequest } from "node-opcua-types";
import { Variant } from "node-opcua-variant";
import { make_debugLog, make_warningLog } from "node-opcua-debug";
import { IBasicSessionAsync, CallMethodRequestLike } from "node-opcua-pseudo-session";

const doDebug = false;
const debugLog = make_debugLog("A&E");
const warningLog = make_warningLog("A&E");

export async function callConditionRefresh(session: IBasicSessionAsync, subscriptionId: number): Promise<StatusCode> {
assert(isFinite(subscriptionId), "May be subscription is not yet initialized");
const conditionTypeNodeId = resolveNodeId("ConditionType");
let conditionRefreshId = resolveNodeId("ConditionType_ConditionRefresh");
// find conditionRefreshId
const browsePath = makeBrowsePath(conditionTypeNodeId, ".ConditionRefresh");
const translateResult = await session.translateBrowsePath(browsePath);

// istanbul ignore next
if (translateResult.targets && translateResult.targets.length > 0) {
conditionRefreshId = translateResult.targets[0].targetId;
} else {
// cannot find conditionRefreshId
return StatusCodes.BadInternalError;
}
const methodToCall: CallMethodRequestLike = {
inputArguments: [new Variant({ dataType: DataType.UInt32, value: subscriptionId })],
methodId: conditionRefreshId,
objectId: conditionTypeNodeId
};

doDebug && debugLog("Calling method ", new CallMethodRequest(methodToCall).toString());
const callResult = await session.call(methodToCall);
// istanbul ignore next
if (callResult.statusCode.isNotGood()) {
warningLog(new CallMethodRequest(methodToCall).toString());
}
return callResult.statusCode;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import assert from "node-opcua-assert";
import { LocalizedText, LocalizedTextLike } from "node-opcua-data-model";
import { NodeId, NodeIdLike, coerceNodeId } from "node-opcua-nodeid";
import { StatusCode, StatusCodes } from "node-opcua-status-code";
import { CallMethodRequest } from "node-opcua-types";
import { Variant } from "node-opcua-variant";
import { IBasicSessionAsync, findMethodId } from "node-opcua-pseudo-session";


export async function callMethodCondition(
session: IBasicSessionAsync,
methodName: string,
conditionId: NodeIdLike,
eventId: Buffer,
comment: LocalizedTextLike,

): Promise<StatusCode>
{
conditionId = coerceNodeId(conditionId);
assert(conditionId instanceof NodeId);
assert(eventId instanceof Buffer);
assert(typeof comment === "string" || comment instanceof LocalizedText);

comment = LocalizedText.coerce(comment) || new LocalizedText();
const r = await findMethodId(session, conditionId, methodName);
if (!r.methodId) {
return StatusCodes.BadNodeIdUnknown;
}
const methodId = r.methodId;
const methodToCalls = [];

methodToCalls.push(
new CallMethodRequest({
inputArguments: [
/* eventId */ new Variant({ dataType: "ByteString", value: eventId }),
/* comment */ new Variant({ dataType: "LocalizedText", value: comment })
],
methodId,
objectId: conditionId
})
);

const results = await session.call(methodToCalls);
const statusCode = results![0].statusCode;
return statusCode;
}


export async function acknowledgeCondition(
session: IBasicSessionAsync,
conditionId: NodeIdLike,
eventId: Buffer,
comment: LocalizedTextLike
): Promise<StatusCode> {
return await callMethodCondition(session, "Acknowledge", conditionId, eventId, comment);
}
export async function confirmCondition(
session: IBasicSessionAsync,
conditionId: NodeIdLike,
eventId: Buffer,
comment: LocalizedTextLike
): Promise<StatusCode> {
return await callMethodCondition(session, "Confirm", conditionId, eventId, comment);
}

0 comments on commit ee7b7e3

Please sign in to comment.