/// <summary> /// Get the delegate for an operator /// </summary> /// <param name="opCode">Operation</param> /// <returns>The delegate</returns> public static RDXOpCode GetOperator(ContosoOpcNodeOpCode opCode) { switch (opCode) { case ContosoOpcNodeOpCode.Nop: return(Nop); case ContosoOpcNodeOpCode.Diff: return(Diff); case ContosoOpcNodeOpCode.Avg: return(Avg); case ContosoOpcNodeOpCode.Sum: return(Sum); case ContosoOpcNodeOpCode.Last: return(Last); case ContosoOpcNodeOpCode.Count: return(Count); case ContosoOpcNodeOpCode.Max: return(Max); case ContosoOpcNodeOpCode.Min: return(Min); case ContosoOpcNodeOpCode.Const: return(Const); case ContosoOpcNodeOpCode.SubMaxMin: return(SubMaxMin); case ContosoOpcNodeOpCode.Timespan: return(Timespan); default: break; } return(null); }
/// <summary> /// Ctor for a Contoso OPC UA node, specifying alert related information. /// </summary> public ContosoOpcUaNode( string opcUaNodeId, string opcUaSymbolicName, List <ContosoPerformanceRelevance> opcUaNodeRelevance, ContosoOpcNodeOpCode opCode, string units, bool visible, double?constValue, double?minimum, double?maximum, List <ContosoAlertActionDefinition> minimumAlertActionDefinitions, List <ContosoAlertActionDefinition> maximumAlertActionDefinitions, ContosoPushPinCoordinates imagePushpin, string warning ) : base(opcUaNodeId, opcUaSymbolicName) { Relevance = opcUaNodeRelevance; OpCode = opCode; Units = units; Visible = visible; ConstValue = constValue; Minimum = minimum; Maximum = maximum; MinimumAlertActions = minimumAlertActionDefinitions; MaximumAlertActions = maximumAlertActionDefinitions; Last = new ContosoDataItem(); ImagePushpin = imagePushpin; WarningValue = warning; }
/// <summary> /// Get the value of an operation for OPC UA server Node Id /// </summary> /// <param name="opCode">Operation to get the value</param> /// <param name="appUri">The OPC UA server application Uri</param> /// <param name="nodeId">The node id in the OPC UA server namespace</param> /// <returns>The value</returns> private double GetValue(ContosoOpcNodeOpCode opCode, string appUri, string nodeId) { double?value = null; var appUriIndex = _result.Dimension.IndexOf(appUri); var nodeIdIndex = _result.Aggregate.Dimension.IndexOf(nodeId); if (appUriIndex >= 0 && nodeIdIndex >= 0) { if (opCode == ContosoOpcNodeOpCode.SubMaxMin) { double?max = _result.Aggregate.Aggregate.Measures.TryGetPropertyMeasure <double?>(new int[] { appUriIndex, nodeIdIndex, (int)RDXOpcUaQueries.AggregateIndex.Max }); if (max == null) { value = 0.0; } else { value = max - _result.Aggregate.Aggregate.Measures.TryGetPropertyMeasure <double?>(new int[] { appUriIndex, nodeIdIndex, (int)RDXOpcUaQueries.AggregateIndex.Min }); } } else { value = _result.Aggregate.Aggregate.Measures.TryGetPropertyMeasure <double?>(new int[] { appUriIndex, nodeIdIndex, RDXUtils.AggregatedOperatorIndex(opCode) }); } } // The node/station is inactive or there were no events in the searchspan! if (value == null) { value = 0.0; } return((double)value); }
/// <summary> /// Calls the delegate for an operator. /// </summary> /// <param name="opCode">Operation to execute</param> /// <param name="rdxQuery">Query info.</param> /// <param name="opcUaNode">Topology node.</param> public static Task CallOperator(ContosoOpcNodeOpCode opCode, RDXOeeKpiQuery rdxQuery, ContosoOpcUaNode opcUaNode) { RDXOpCode opCodeFunc = GetOperator(opCode); if (opCodeFunc == null) { return(Task.CompletedTask); } return(opCodeFunc(rdxQuery, opcUaNode)); }
/// <summary> /// Test if opcode requires a unique OPC UA Node Id. /// </summary> private static bool OpCodeRequiresOpcUaNode(ContosoOpcNodeOpCode opCode) { switch (opCode) { case ContosoOpcNodeOpCode.Const: case ContosoOpcNodeOpCode.Timespan: case ContosoOpcNodeOpCode.Nop: return(false); } return(true); }
/// <summary> /// Test if operator can be aggregated by RDX /// </summary> /// <param name="opCode"></param> /// <returns>True if operator is aggregated</returns> public static bool IsAggregatedOperator(ContosoOpcNodeOpCode opCode) { switch (opCode) { case ContosoOpcNodeOpCode.Avg: case ContosoOpcNodeOpCode.Sum: case ContosoOpcNodeOpCode.Count: case ContosoOpcNodeOpCode.Max: case ContosoOpcNodeOpCode.Min: case ContosoOpcNodeOpCode.SubMaxMin: return(true); } return(false); }
/// <summary> /// Return scale factor for opcode display in a time series. /// </summary> private static double OpCodeScaleFactor(ContosoOpcNodeOpCode opcode, TimeSpan interval, TimeSpan scaledInterval) { switch (opcode) { case ContosoOpcNodeOpCode.SubMaxMin: case ContosoOpcNodeOpCode.Sum: return(scaledInterval.TotalSeconds / interval.TotalSeconds); case ContosoOpcNodeOpCode.Max: case ContosoOpcNodeOpCode.Min: case ContosoOpcNodeOpCode.Avg: return(1.0); } throw new Exception("Invalid op code for operation"); }
/// <summary> /// Return the index of an operator result in a query measure. /// </summary> /// <param name="opCode">Operation</param> /// <returns>The index</returns> public static int AggregatedOperatorIndex(ContosoOpcNodeOpCode opCode) { switch (opCode) { case ContosoOpcNodeOpCode.Avg: return((int)RDXOpcUaQueries.AggregateIndex.Average); case ContosoOpcNodeOpCode.Sum: return((int)RDXOpcUaQueries.AggregateIndex.Sum); case ContosoOpcNodeOpCode.Count: return((int)RDXOpcUaQueries.AggregateIndex.Count); case ContosoOpcNodeOpCode.Max: return((int)RDXOpcUaQueries.AggregateIndex.Max); case ContosoOpcNodeOpCode.Min: return((int)RDXOpcUaQueries.AggregateIndex.Min); } return(0); }
/// <summary> /// Adds an OPC UA Node to this OPC UA server topology node. /// </summary> public void AddOpcServerNode( string opcUaNodeId, string opcUaSymbolicName, List <ContosoPerformanceRelevance> opcUaNodeRelevance, ContosoOpcNodeOpCode opCode, string units, bool visible, double?constValue, double?minimum, double?maximum, List <ContosoAlertActionDefinition> minimumAlertActionDefinitions, List <ContosoAlertActionDefinition> maximumAlertActionDefinitions, ContosoPushPinCoordinates imagePushpin, string warning) { foreach (var node in NodeList) { if (OpCodeRequiresOpcUaNode(opCode) && node.NodeId == opcUaNodeId ) { throw new Exception(string.Format("The OPC UA node with NodeId '{0}' and SymbolicName '{1}' does already exist. Please change.", opcUaNodeId, opcUaSymbolicName)); } } ContosoOpcUaNode opcUaNodeObject = new ContosoOpcUaNode( opcUaNodeId, opcUaSymbolicName, opcUaNodeRelevance, opCode, units, visible, constValue, minimum, maximum, minimumAlertActionDefinitions, maximumAlertActionDefinitions, imagePushpin, warning); NodeList.Add(opcUaNodeObject); }
/// <summary> /// Call the operator on a query and node. /// Gets value from cache if operation is supported, /// if not forwards the call to single query engine. /// </summary> /// <param name="opCode">Operation to get the value</param> /// <param name="rdxQuery">The query</param> /// <param name="opcUaNode">The Topology node </param> public async Task CallOperator(ContosoOpcNodeOpCode opCode, RDXOeeKpiQuery rdxQuery, ContosoOpcUaNode opcUaNode) { if (RDXUtils.IsAggregatedOperator(opCode) && _task != null) { _result = await _task; if (_result != null) { double?value = GetValue(opCode, rdxQuery.AppUri, opcUaNode.NodeId); if (value != null) { opcUaNode.Last.Value = (double)value; opcUaNode.Last.Time = rdxQuery.SearchSpan.To; opcUaNode.UpdateRelevance(rdxQuery.TopologyNode); } } return; } // issue a single query if the operator can not be handled from aggregated values await RDXContosoOpCodes.CallOperator(opCode, rdxQuery, opcUaNode); }