module import { SessionContext , UAVariable , ContinuationPointManager , ContinuationPoint } from "node-opcua-address-space" ; import { NodeClass } from "node-opcua-data-model" ; import { DataValue } from "node-opcua-data-value" ; import { HistoryData , HistoryReadResult , ReadRawModifiedDetails } from "node-opcua-service-history" ; import { StatusCode } from "node-opcua-status-code" ; import { coerceNodeId } from "node-opcua-nodeid" ; import { getAggregateConfiguration } from "./aggregates" ; import { getInterval , Interval , AggregateConfigurationOptionsEx } from "./interval" ; internal param node param processingInterval param startDate param endDate param dataValues param lambda param callback function processAggregateData ( node , processingInterval , startDate , endDate , dataValues , lambda , callback ) { const aggregateConfiguration = getAggregateConfiguration ( node ) ; const results = [ ] ; const tstart = startDate . getTime ( ) ; const tend = endDate . getTime ( ) ; const indexHint = 0 ; for ( let t = tstart ; t < tend ; t += processingInterval ) { const sourceTimestamp = new Date ( ) ; sourceTimestamp . setTime ( t ) ; const interval = getInterval ( sourceTimestamp , processingInterval , indexHint , dataValues ) ; const dataValue = lambda ( interval , aggregateConfiguration ) ; if ( ! dataValue || ! dataValue . sourceTimestamp ) { throw Error ( "invalid DataValue" ) ; } results . push ( dataValue ) ; } setImmediate ( ( ) => { callback ( null , results ) ; } ) ; } export function getAggregateData ( node , processingInterval , startDate , endDate , lambda , callback ) { if ( node . nodeClass !== NodeClass . Variable ) { throw new Error ( "node must be UAVariable" ) ; } if ( processingInterval <= 0 ) { throw new Error ( "Invalid processing interval, shall be greater than 0" ) ; } const continuationPointManager = new ContinuationPointManager ( ) ; const context = new SessionContext ( { session : { continuationPointManager , getSessionId : ( ) => coerceNodeId ( "i=0" ) } } ) ; const historyReadDetails = new ReadRawModifiedDetails ( { endTime : endDate , startTime : startDate , isReadModified : false , numValuesPerNode : 0 } ) ; const indexRange = null ; const dataEncoding = null ; const continuationPoint = null ; node . historyRead ( context , historyReadDetails , indexRange , dataEncoding , { continuationPoint } , ( err , result ? ) => { if ( err ) { return callback ( err ) ; } const historyData = result ! . historyData as HistoryData ; const dataValues = historyData . dataValues || [ ] ; processAggregateData ( node , processingInterval , startDate , endDate , dataValues , lambda , callback ) ; } ) ; } export function interpolateValue ( dataValue1 , dataValue2 , date ) { const t0 = dataValue1 . sourceTimestamp ! . getTime ( ) ; const t = date . getTime ( ) ; const t1 = dataValue2 . sourceTimestamp ! . getTime ( ) ; const coef1 = ( t - t0 ) / ( t1 - t0 ) ; const coef2 = ( t1 - t ) / ( t1 - t0 ) ; const value = dataValue1 . value . clone ( ) ; value . value = coef2 * dataValue1 . value . value + coef1 * dataValue2 . value . value ; const statusCode = StatusCode . makeStatusCode ( dataValue1 . statusCode , "HistorianInterpolated" ) ; return new DataValue ( { sourceTimestamp : date , statusCode , value } ) ; }