UNPKG

node-opcua-aggregates

Version:

pure nodejs OPCUA SDK - module aggregates

143 lines 9.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.readProcessedDetails = readProcessedDetails; const node_opcua_constants_1 = require("node-opcua-constants"); const node_opcua_status_code_1 = require("node-opcua-status-code"); const node_opcua_service_history_1 = require("node-opcua-service-history"); const minmax_1 = require("./minmax"); const interpolate_1 = require("./interpolate"); const average_1 = require("./average"); const count_1 = require("./count"); const percent_bad_1 = require("./percent_bad"); const percent_good_1 = require("./percent_good"); const duration_good_1 = require("./duration_good"); const duration_bad_1 = require("./duration_bad"); function _buildResult(err, dataValues, callback2) { if (err) { return callback2(null, new node_opcua_service_history_1.HistoryReadResult({ statusCode: node_opcua_status_code_1.StatusCodes.BadInternalError })); } const result = new node_opcua_service_history_1.HistoryReadResult({ historyData: new node_opcua_service_history_1.HistoryData({ dataValues }), statusCode: node_opcua_status_code_1.StatusCodes.Good }); return callback2(null, result); } function applyAggregate(variable, processingInterval, startTime, endTime, aggregateType, callback2) { if (!startTime || !endTime) { return _buildResult(new Error("Invalid date time"), undefined, callback2); } const buildResult = (err, dataValues) => { _buildResult(err, dataValues, callback2); }; if (aggregateType.namespace === 0) { switch (aggregateType.value) { case node_opcua_constants_1.AggregateFunction.Minimum: (0, minmax_1.getMinData)(variable, processingInterval, startTime, endTime, buildResult); break; case node_opcua_constants_1.AggregateFunction.Maximum: (0, minmax_1.getMaxData)(variable, processingInterval, startTime, endTime, buildResult); break; case node_opcua_constants_1.AggregateFunction.Interpolative: (0, interpolate_1.getInterpolatedData)(variable, processingInterval, startTime, endTime, buildResult); break; case node_opcua_constants_1.AggregateFunction.Average: (0, average_1.getAverageData)(variable, processingInterval, startTime, endTime, buildResult); break; case node_opcua_constants_1.AggregateFunction.DurationGood: (0, duration_good_1.getDurationGoodData)(variable, processingInterval, startTime, endTime, buildResult); break; case node_opcua_constants_1.AggregateFunction.DurationBad: (0, duration_bad_1.getDurationBadData)(variable, processingInterval, startTime, endTime, buildResult); break; case node_opcua_constants_1.AggregateFunction.PercentBad: (0, percent_bad_1.getPercentBadData)(variable, processingInterval, startTime, endTime, buildResult); break; case node_opcua_constants_1.AggregateFunction.PercentGood: (0, percent_good_1.getPercentGoodData)(variable, processingInterval, startTime, endTime, buildResult); break; case node_opcua_constants_1.AggregateFunction.Count: (0, count_1.getCountData)(variable, processingInterval, startTime, endTime, buildResult); break; default: // todo provide correct implementation return callback2(null, new node_opcua_service_history_1.HistoryReadResult({ statusCode: node_opcua_status_code_1.StatusCodes.BadAggregateNotSupported })); } } else { // custom aggregate added by some companion specification // to do return callback2(null, new node_opcua_service_history_1.HistoryReadResult({ statusCode: node_opcua_status_code_1.StatusCodes.BadAggregateNotSupported })); } } function readProcessedDetails(variable, context, historyReadDetails, indexRange, dataEncoding, continuationData, callback) { // OPC Unified Architecture, Part 11 27 Release 1.03 // // This structure is used to compute Aggregate values, qualities, and timestamps from data in // the history database for the specified time domain for one or more HistoricalDataNodes. The // time domain is divided into intervals of duration ProcessingInterval. The specified Aggregate // Type is calculated for each interval beginning with startTime by using the data within the next // ProcessingInterval. // For example, this function can provide hourly statistics such as Maximum, Minimum , and // Average for each item during the specified time domain when ProcessingInterval is 1 hour. // The domain of the request is defined by startTime, endTime, and ProcessingInterval. All three // shall be specified. If endTime is less than startTime then the data shall be returned in reverse // order with the later data coming first. If startTime and endTime are the same then the Server // shall return Bad_InvalidArgument as there is no meaningful way to interpret such a case. If // the ProcessingInterval is specified as 0 then Aggregates shall be calculated using one interval // starting at startTime and ending at endTime. // The aggregateType[] parameter allows a Client to request multiple Aggregate calculations per // requested NodeId. If multiple Aggregates are requested then a corresponding number of // entries are required in the NodesToRead array. // For example, to request Min Aggregate for NodeId FIC101, FIC102, and both Min and Max // Aggregates for NodeId FIC103 would require NodeId FIC103 to appear twice in the // NodesToRead array request parameter. // aggregateType[] NodesToRead[] // Min FIC101 // Min FIC102 // Min FIC103 // Max FIC103 // If the array of Aggregates does not match the array of NodesToRead then the Server shall // return a StatusCode of Bad_AggregateListMismatch. // The aggregateConfiguration parameter allows a Client to override the Aggregate configuration // settings supplied by the AggregateConfiguration Object on a per call basis. See Part 13 for // more information on Aggregate configurations. If the Server does not support the ability to // override the Aggregate configuration settings then it shall return a StatusCode of Bad_ // AggregateConfigurationRejected. If the Aggregate is not valid for the Node then the // StatusCode shall be Bad_AggregateNotSupported. // The values used in computing the Aggregate for each interval shall include any value that // falls exactly on the timestamp at the beginning of the interval, but shall not include any value // that falls directly on the timestamp ending the interval. Thus, each value shall be included // only once in the calculation. If the time domain is in reverse order then we consider the later // timestamp to be the one beginning the sub interval, and the earlier timestamp to be the one // ending it. Note that this means that simply swapping the start and end times will not result in // getting the same values back in reverse order as the intervals being requested in the two // cases are not the same. // If an Aggregate is taking a long time to calculate then the Server can return partial results // with a continuation point. This might be done if the calculation is going to take more time th an // the Client timeout hint. In some cases it may take longer than the Client timeout hint to // calculate even one Aggregate result. Then the Server may return zero results with a // continuation point that allows the Server to resume the calculation on the next Client read // call. const startTime = historyReadDetails.startTime; const endTime = historyReadDetails.endTime; if (!startTime || !endTime) { return callback(null, new node_opcua_service_history_1.HistoryReadResult({ statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument })); } if (startTime.getTime() === endTime.getTime()) { // Start = End Int = Anything No intervals. Returns a Bad_InvalidArgument StatusCode, // regardless of whether there is data at the specified time or not return callback(null, new node_opcua_service_history_1.HistoryReadResult({ statusCode: node_opcua_status_code_1.StatusCodes.BadInvalidArgument })); } const aggregateTypes = historyReadDetails.aggregateType || []; // If the ProcessingInterval is specified as 0 then Aggregates shall be calculated using one interval // starting at startTime and ending at endTime. const processingInterval = historyReadDetails.processingInterval || endTime.getTime() - startTime.getTime(); // tslint:disable-next-line: prefer-for-of if (!historyReadDetails.aggregateType || historyReadDetails.aggregateType.length !== 1) { return callback(null, new node_opcua_service_history_1.HistoryReadResult({ statusCode: node_opcua_status_code_1.StatusCodes.BadInternalError })); } return applyAggregate(variable, processingInterval, startTime, endTime, aggregateTypes[0], callback); } //# sourceMappingURL=read_processed_details.js.map