Skip to content

Commit

Permalink
refactor readUAAnalogItem
Browse files Browse the repository at this point in the history
  • Loading branch information
erossignon authored and sterfive committed Nov 3, 2023
1 parent 60864a0 commit 95439f3
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 132 deletions.
81 changes: 26 additions & 55 deletions packages/node-opcua-client/source/client_utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@
* @module node-opcua-client
*/

import { assert } from "node-opcua-assert";
import { AttributeIds } from "node-opcua-data-model";
import { DataValue } from "node-opcua-data-value";
import { NodeIdLike, resolveNodeId } from "node-opcua-nodeid";
import { ReadValueIdOptions } from "node-opcua-service-read";
import { BrowsePath, BrowsePathResult } from "node-opcua-service-translate-browse-path";
import { StatusCodes } from "node-opcua-status-code";
import { Variant } from "node-opcua-variant";
import { ClientSession } from "./client_session";
import { ClientSessionImpl } from "./private/client_session_impl";
import { ResponseCallback } from "node-opcua-pseudo-session";
import { IBasicSessionAsync } from "node-opcua-pseudo-session";

const hasPropertyRefId = resolveNodeId("HasProperty");

Expand Down Expand Up @@ -48,16 +44,7 @@ interface AnalogDataItemSnapshot {
* @param nodeId
* @param callback
*/
export function readUAAnalogItem(session: ClientSession, nodeId: NodeIdLike): Promise<AnalogDataItemSnapshot>;
export function readUAAnalogItem(
session: ClientSession,
nodeId: NodeIdLike,
callback: ResponseCallback<AnalogDataItemSnapshot>
): void;
export function readUAAnalogItem(session: ClientSession, nodeId: NodeIdLike, ...args: [any?, ...any[]]): any {
const callback = args[0] as ResponseCallback<AnalogDataItemSnapshot>;
assert(typeof callback === "function");

export async function readUAAnalogItem(session: IBasicSessionAsync, nodeId: NodeIdLike): Promise<AnalogDataItemSnapshot> {
const browsePath = [
browsePathPropertyRequest(nodeId, "EngineeringUnits"),
browsePathPropertyRequest(nodeId, "EURange"),
Expand All @@ -74,51 +61,35 @@ export function readUAAnalogItem(session: ClientSession, nodeId: NodeIdLike, ...
valuePrecision: null
};

session.translateBrowsePath(browsePath, (err: Error | null, browsePathResults?: BrowsePathResult[]) => {
if (err) {
return callback(err);
}
browsePathResults = browsePathResults || [];
const browsePathResults = await session.translateBrowsePath(browsePath);

const actions: any[] = [];
const nodesToRead: ReadValueIdOptions[] = [];
const actions: ( (readResult: DataValue) =>void)[] = [];
const nodesToRead: ReadValueIdOptions[] = [];

function processProperty(browsePathResult: BrowsePathResult, propertyName: string) {
if (browsePathResult.statusCode.isGood()) {
browsePathResult.targets = browsePathResult.targets || [];
nodesToRead.push({
attributeId: AttributeIds.Value,
nodeId: browsePathResult.targets[0].targetId
});
actions.push((readResult: DataValue) => ((analogItemData as any)[propertyName] = readResult.value.value));
}
function processProperty(browsePathResult: BrowsePathResult, propertyName: string) {
if (browsePathResult.statusCode.isGood()) {
browsePathResult.targets = browsePathResult.targets || [];
nodesToRead.push({
attributeId: AttributeIds.Value,
nodeId: browsePathResult.targets[0].targetId
});
actions.push(
(readResult: DataValue) =>
((analogItemData as unknown as Record<string, unknown>)[propertyName] = readResult.value.value)
);
}
}

processProperty(browsePathResults[0], "engineeringUnits");
processProperty(browsePathResults[1], "engineeringUnitsRange");
processProperty(browsePathResults[2], "instrumentRange");
processProperty(browsePathResults[3], "valuePrecision");
processProperty(browsePathResults[4], "definition");
processProperty(browsePathResults[0], "engineeringUnits");
processProperty(browsePathResults[1], "engineeringUnitsRange");
processProperty(browsePathResults[2], "instrumentRange");
processProperty(browsePathResults[3], "valuePrecision");
processProperty(browsePathResults[4], "definition");

session.read(nodesToRead, (err1: Error | null, dataValues?: DataValue[]) => {
if (err1) {
return callback(err1);
}
/* istanbul ignore next */
if (!dataValues) {
return callback(new Error("Internal Error"));
}

dataValues.forEach((result: DataValue, index: number) => {
actions[index].call(null, result);
});
const dataValues = await session.read(nodesToRead);

callback(err1, analogItemData);
});
dataValues.forEach((result: DataValue, index: number) => {
actions[index].call(null, result);
});
return analogItemData;
}
// tslint:disable:no-var-requires
// tslint:disable:max-line-length
const thenify = require("thenify");
const opts = { multiArgs: false };
(module as any).exports.readUAAnalogItem = thenify.withCallback((module as any).exports.readUAAnalogItem, opts);
Original file line number Diff line number Diff line change
@@ -1,36 +1,22 @@
"use strict";
const chalk = require("chalk");
const should = require("should");
const async = require("async");

const opcua = require("node-opcua");
const OPCUAClient = opcua.OPCUAClient;
const StatusCodes = opcua.StatusCodes;
const DataType = opcua.DataType;
const AttributeIds = opcua.AttributeIds;
const BrowseDirection = opcua.BrowseDirection;
const readUAAnalogItem = opcua.readUAAnalogItem;

const { make_debugLog, checkDebugFlag } = require("node-opcua-debug");
const debugLog = make_debugLog("TEST");
const doDebug = checkDebugFlag("TEST");
const { OPCUAClient, DataType, AttributeIds, readUAAnalogItem, BrowseDirection } = require("node-opcua");

const port = 2009;

const { build_server_with_temperature_device } = require("../../test_helpers/build_server_with_temperature_device");

// eslint-disable-next-line import/order
const describe = require("node-opcua-leak-detector").describeWithLeakDetector;
describe("testing AnalogItem on client side", function () {
let server, client, temperatureVariableId, endpointUrl;
describe("testing AnalogItem on client side", function() {
let server, client, endpointUrl;

this.timeout(Math.max(600000, this.timeout()));

let g_session = null;
before(async () => {
server = await build_server_with_temperature_device({ port });
endpointUrl = server.getEndpointUrl();
temperatureVariableId = server.temperatureVariableId;
});

beforeEach(async () => {
Expand All @@ -47,33 +33,28 @@ describe("testing AnalogItem on client side", function () {
await client.disconnect();
});

after(function (done) {
after(function(done) {
server.shutdown(done);
});

it("readUAAnalogItem should extract all properties of a UAAnalogItem ", function (done) {
it("readUAAnalogItem should extract all properties of a UAAnalogItem ", async () => {
const nodeId = "ns=1;s=TemperatureAnalogItem";
const data = await readUAAnalogItem(g_session, nodeId);
data.should.have.ownProperty("engineeringUnits");
data.should.have.ownProperty("engineeringUnitsRange");
data.should.have.ownProperty("instrumentRange");
data.should.have.ownProperty("valuePrecision");
data.should.have.ownProperty("definition");

readUAAnalogItem(g_session, nodeId, function (err, data) {
if (err) {
return done(err);
}

data.should.have.ownProperty("engineeringUnits");
data.should.have.ownProperty("engineeringUnitsRange");
data.should.have.ownProperty("instrumentRange");
data.should.have.ownProperty("valuePrecision");
data.should.have.ownProperty("definition");

done();
});
});
it("readUAAnalogItem should return an error if not doesn't exist", function (done) {

it("readUAAnalogItem should return an error if not doesn't exist", async () => {
const nodeId = "ns=4;s=invalidnode";
readUAAnalogItem(g_session, nodeId, function (err, data) {
should.exist(err);
done();
});
let err = null;
try {
await readUAAnalogItem(g_session, nodeId);
} catch (_err) { err = _err; }
should.exist(err);
});

/**
Expand All @@ -82,60 +63,43 @@ describe("testing AnalogItem on client side", function () {
* @param browseName
* @param callback
*/
function findProperty(g_session, nodeId, browseName, callback) {
async function findProperty(g_session, nodeId, browseName) {
const browseDescription = {
nodeId: nodeId,
referenceTypeId: "HasProperty",
browseDirection: BrowseDirection.Forward,
resultMask: 0x3f
};
g_session.browse(browseDescription, function (err, result) {
if (err) {
return callback(err);
}

if (result.statusCode.isNotGood()) {
return callback(null, null);
}

let tmp = result.references.filter((e) => e.browseName.name === browseName);

tmp = tmp.map(function (e) {
return e.nodeId;
});
const found = tmp.length === 1 ? tmp[0] : null;
callback(null, found);
});
const result = await g_session.browse(browseDescription);
if (result.statusCode.isNotGood()) {
return null;
}
let tmp = result.references.filter((e) => e.browseName.name === browseName);

tmp = tmp.map((e) => e.nodeId);
const found = tmp.length === 1 ? tmp[0] : null;
return found;
}

it("should read the EURange property of an analog item", function (done) {
it("should read the EURange property of an analog item", async () => {
const nodeId = "ns=1;s=TemperatureAnalogItem";

findProperty(g_session, nodeId, "EURange", function (err, propertyId) {
if (err) {
return done(err);
}
const propertyId = await findProperty(g_session, nodeId, "EURange");

should.exist(propertyId);
should.exist(propertyId);

const nodeToRead = {
nodeId: propertyId,
attributeId: AttributeIds.Value
};
//xx console.log("propertyId = ", propertyId.toString());
g_session.read(nodeToRead, function (err, dataValue) {
if (err) {
return done(err);
}
const nodeToRead = {
nodeId: propertyId,
attributeId: AttributeIds.Value
};
//xx console.log("propertyId = ", propertyId.toString());
const dataValue = await g_session.read(nodeToRead);

//xx console.log("result = ",result.toString());
dataValue.value.dataType.should.eql(DataType.ExtensionObject);
//xx console.log("result = ",result.toString());
dataValue.value.dataType.should.eql(DataType.ExtensionObject);

dataValue.value.value.low.should.eql(100);
dataValue.value.value.high.should.eql(200);
dataValue.value.value.low.should.eql(100);
dataValue.value.value.high.should.eql(200);

done(err);
});
});
});
});

0 comments on commit 95439f3

Please sign in to comment.