module import { AggregateFunction } from "node-opcua-constants" ; import { makeNodeId } from "node-opcua-nodeid" ; import * as utils from "node-opcua-utils" ; import { DataType } from "node-opcua-variant" ; import { AddressSpace , BaseNode , UAHistoryServerCapabilities , UAObject , UAServerCapabilities , UAVariable } from "node-opcua-address-space" ; import { AddressSpacePrivate } from "node-opcua-address-space/src/address_space_private" ; import { AggregateConfigurationOptionsEx } from "./interval" ; import { readProcessedDetails } from "./read_processed_details" ; const historicalCapabilitiesDefaultProperties = { accessHistoryDataCapability : true , accessHistoryEventsCapability : true , deleteAtTimeCapability : false , deleteEventCapability : false , deleteRawCapability : false , insertAnnotationCapability : false , insertDataCapability : false , insertEventCapability : false , maxReturnDataValues : 0 , maxReturnEventValues : 0 , replaceDataCapability : false , replaceEventCapability : false , updateDataCapability : false , updateEventCapability : false } ; export function createHistoryServerCapabilities ( addressSpace , serverCapabilities ) { if ( serverCapabilities . browseName . toString ( ) !== "ServerCapabilities" ) { throw new Error ( "Expecting server Capabilities" ) ; } const historyServerCapabilitiesType = addressSpace . getNamespace ( 0 ) . findObjectType ( "HistoryServerCapabilitiesType" ) ! ; if ( ! historyServerCapabilitiesType ) { throw new Error ( "Cannot find HistoryServerCapabilitiesType" ) ; } return historyServerCapabilitiesType . instantiate ( { browseName : "HistoryServerCapabilities" , componentOf : serverCapabilities } ) ; } function setHistoricalServerCapabilities ( historyServerCapabilities , defaultProperties ) { function setBoolean ( propName ) { const lowerCase = utils . lowerFirstLetter ( propName ) ; if ( ! Object . prototype . hasOwnProperty . call ( defaultProperties , lowerCase ) ) { throw new Error ( "cannot find " + lowerCase ) ; } const value = defaultProperties [ lowerCase ] ; const prop = historyServerCapabilities . getChildByName ( propName ) ; if ( ! prop ) { throw new Error ( " Cannot find property " + propName ) ; } prop . setValueFromSource ( { dataType : DataType . Boolean , value } ) ; } function setUInt32 ( propName ) { const lowerCase = utils . lowerFirstLetter ( propName ) ; if ( ! Object . prototype . hasOwnProperty . call ( historyServerCapabilities , lowerCase ) ) { throw new Error ( "cannot find " + lowerCase ) ; } const value = defaultProperties [ lowerCase ] ; const prop = historyServerCapabilities . getChildByName ( propName ) ; prop . setValueFromSource ( { dataType : DataType . UInt32 , value } ) ; } setBoolean ( "AccessHistoryDataCapability" ) ; setBoolean ( "AccessHistoryEventsCapability" ) ; setUInt32 ( "MaxReturnDataValues" ) ; setUInt32 ( "MaxReturnEventValues" ) ; setBoolean ( "InsertDataCapability" ) ; setBoolean ( "ReplaceDataCapability" ) ; setBoolean ( "UpdateDataCapability" ) ; setBoolean ( "DeleteRawCapability" ) ; setBoolean ( "DeleteAtTimeCapability" ) ; setBoolean ( "InsertEventCapability" ) ; setBoolean ( "ReplaceEventCapability" ) ; setBoolean ( "UpdateEventCapability" ) ; setBoolean ( "DeleteEventCapability" ) ; } export type AggregateFunctionName = "AnnotationCount" | "Average" | "Count" | "Delta" | "DeltaBounds" | "DurationBad" | "DurationGood" | "DurationInStateNonZero" | "DurationInStateZero" | "EndBound" | "Interpolative" | "Maximum" | "Maximum2" | "MaximumActualTime" | "MaximumActualTime2" | "Minimum" | "Minimum2" | "MinimumActualTime" | "MinimumActualTime2" | "NumberOfTransitions" | "PercentBad" | "PercentGood" | "Range" | "Range2" | "StandardDeviationPopulation" | "StandardDeviationSample" | "Start" | "StartBound" | "TimeAverage" | "TimeAverage2" | "Total" | "Total2" | "VariancePopulation" | "VarianceSample" | "WorstQuality" | "WorstQuality2" ; interface UAHistoryServerCapabilitiesWithH extends UAServerCapabilities { historyServerCapabilities : UAHistoryServerCapabilities ; } function addAggregateFunctionSupport ( addressSpace , functionName ) { if ( ! functionName ) { throw new Error ( "Invalid function name" ) ; } const serverCapabilities = addressSpace . rootFolder . objects . server . serverCapabilities as UAHistoryServerCapabilitiesWithH ; if ( ! serverCapabilities . historyServerCapabilities ) { throw new Error ( "missing serverCapabilities.historyServerCapabilities" ) ; } const aggregateFunctions = serverCapabilities . aggregateFunctions ; const aggregateFunctionsInHist = serverCapabilities . historyServerCapabilities . aggregateFunctions ; const functionNodeId = makeNodeId ( functionName ) ; const functionNode = addressSpace . getNamespace ( 0 ) . findNode ( functionNodeId ) ; if ( ! functionNode ) { throw new Error ( "Cannot find node " + functionName + " in addressSpace" ) ; } aggregateFunctions . addReference ( { nodeId : functionNode . nodeId , referenceType : "Organizes" } ) ; aggregateFunctionsInHist . addReference ( { nodeId : functionNode . nodeId , referenceType : "Organizes" } ) ; } export function addAggregateSupport ( addressSpace ) { const aggregateConfigurationType = addressSpace . getNamespace ( 0 ) . findObjectType ( "AggregateConfigurationType" ) ; if ( ! aggregateConfigurationType ) { throw new Error ( "addressSpace do not expose AggregateConfigurationType" ) ; } const aggregateFunctionType = addressSpace . getNamespace ( 0 ) . findObjectType ( "AggregateFunctionType" ) ; if ( ! aggregateFunctionType ) { throw new Error ( "addressSpace do not expose AggregateFunctionType" ) ; } const serverObject = addressSpace . rootFolder . objects . getFolderElementByName ( "Server" ) ; if ( ! serverObject ) { throw new Error ( "addressSpace do not expose a ServerObject" ) ; } const serverCapabilities = serverObject . getChildByName ( "ServerCapabilities" ) ! as UAServerCapabilities ; let historyServerCapabilities = serverCapabilities . getChildByName ( "HistoryServerCapabilities" ) ; if ( ! historyServerCapabilities ) { historyServerCapabilities = createHistoryServerCapabilities ( addressSpace , serverCapabilities ) ; } setHistoricalServerCapabilities ( historyServerCapabilities , historicalCapabilitiesDefaultProperties ) ; addAggregateFunctionSupport ( addressSpace , AggregateFunction . Interpolative ) ; addAggregateFunctionSupport ( addressSpace , AggregateFunction . Minimum ) ; addAggregateFunctionSupport ( addressSpace , AggregateFunction . Maximum ) ; addAggregateFunctionSupport ( addressSpace , AggregateFunction . Average ) ; const addressSpaceInternal = addressSpace as unknown as AddressSpacePrivate ; addressSpaceInternal . _readProcessedDetails = readProcessedDetails ; } export function installAggregateConfigurationOptions ( node , options ) { const nodePriv = node as any ; const aggregateConfiguration = nodePriv . $historicalDataConfiguration . aggregateConfiguration ; aggregateConfiguration . percentDataBad . setValueFromSource ( { dataType : "Byte" , value : options . percentDataBad } ) ; aggregateConfiguration . percentDataGood . setValueFromSource ( { dataType : "Byte" , value : options . percentDataGood } ) ; aggregateConfiguration . treatUncertainAsBad . setValueFromSource ( { dataType : "Boolean" , value : options . treatUncertainAsBad } ) ; aggregateConfiguration . useSlopedExtrapolation . setValueFromSource ( { dataType : "Boolean" , value : options . useSlopedExtrapolation } ) ; nodePriv . $historicalDataConfiguration . stepped . setValueFromSource ( { dataType : "Boolean" , value : options . stepped } ) ; } export function getAggregateConfiguration ( node ) { const nodePriv = node as any ; if ( ! nodePriv . $historicalDataConfiguration ) { throw new Error ( "internal error" ) ; } const aggregateConfiguration = nodePriv . $historicalDataConfiguration . aggregateConfiguration ; const stepped = nodePriv . $historicalDataConfiguration . stepped . readValue ( ) . value . value ; return { percentDataBad : aggregateConfiguration . percentDataBad . readValue ( ) . value . value , percentDataGood : aggregateConfiguration . percentDataGood . readValue ( ) . value . value , stepped , treatUncertainAsBad : aggregateConfiguration . treatUncertainAsBad . readValue ( ) . value . value , useSlopedExtrapolation : aggregateConfiguration . useSlopedExtrapolation . readValue ( ) . value . value } ; }