/// <summary> /// 读取历史数据 /// </summary> /// <param name="context"></param> /// <param name="details"></param> /// <param name="timestampsToReturn"></param> /// <param name="releaseContinuationPoints"></param> /// <param name="nodesToRead"></param> /// <param name="results"></param> /// <param name="errors"></param> public override void HistoryRead(OperationContext context, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, IList <HistoryReadValueId> nodesToRead, IList <HistoryReadResult> results, IList <ServiceResult> errors) { ReadProcessedDetails readDetail = details as ReadProcessedDetails; //假设查询历史数据 都是带上时间范围的 if (readDetail == null || readDetail.StartTime == DateTime.MinValue || readDetail.EndTime == DateTime.MinValue) { errors[0] = StatusCodes.BadHistoryOperationUnsupported; return; } for (int ii = 0; ii < nodesToRead.Count; ii++) { int sss = readDetail.StartTime.Millisecond; double res = sss + DateTime.Now.Millisecond; //这里 返回的历史数据可以是多种数据类型 请根据实际的业务来选择 Opc.Ua.KeyValuePair keyValue = new Opc.Ua.KeyValuePair() { Key = new QualifiedName(nodesToRead[ii].NodeId.Identifier.ToString()), Value = res }; results[ii] = new HistoryReadResult() { StatusCode = StatusCodes.Good, HistoryData = new ExtensionObject(keyValue) }; errors[ii] = StatusCodes.Good; //切记,如果你已处理完了读取历史数据的操作,请将Processed设为true,这样OPC-UA类库就知道你已经处理过了 //不需要再进行检查了 nodesToRead[ii].Processed = true; } }
/// <summary> /// Saves a continuation point for later use. /// </summary> private void SaveContinuationPoint(HistoryReadDetails details, HistoryReadValueId nodeToRead, byte[] continuationPoint) { // clear existing continuation point. if (m_nodeToContinue != null) { HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection(); nodesToRead.Add(m_nodeToContinue); HistoryReadResultCollection results = null; DiagnosticInfoCollection diagnosticInfos = null; m_session.HistoryRead( null, new ExtensionObject(m_details), TimestampsToReturn.Neither, true, nodesToRead, out results, out diagnosticInfos); ClientBase.ValidateResponse(results, nodesToRead); ClientBase.ValidateDiagnosticInfos(diagnosticInfos, nodesToRead); } m_details = null; m_nodeToContinue = null; // save new continutation point. if (continuationPoint != null && continuationPoint.Length > 0) { m_details = details; m_nodeToContinue = nodeToRead; m_nodeToContinue.ContinuationPoint = continuationPoint; } // update controls. if (m_nodeToContinue != null) { GoBTN.Visible = false; NextBTN.Visible = true; NextBTN.Enabled = true; StopBTN.Enabled = true; } else { GoBTN.Visible = true; GoBTN.Enabled = true; NextBTN.Visible = false; StopBTN.Enabled = false; } }
/// <summary> /// Initializes a new instance of the <see cref="HdaHistoryReadRequest"/> class. /// </summary> /// <param name="itemId">The item id.</param> /// <param name="details">The details.</param> /// <param name="nodeToRead">The node to read.</param> public HdaHistoryReadRequest(string itemId, HistoryReadDetails details, HistoryReadValueId nodeToRead) { ItemId = itemId; IndexRange = nodeToRead.ParsedIndexRange; DataEncoding = nodeToRead.DataEncoding; }
/// <summary> /// Validates the nodes and reads the values from the underlying source. /// </summary> protected virtual void HistoryRead( ServerSystemContext context, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors, List<NodeHandle> nodesToProcess, IDictionary<NodeId, NodeState> cache) { // check if continuation points are being released. if (releaseContinuationPoints) { HistoryReleaseContinuationPoints( context, nodesToRead, errors, nodesToProcess, cache); return; } // check timestamps to return. if (timestampsToReturn < TimestampsToReturn.Source || timestampsToReturn > TimestampsToReturn.Neither) { throw new ServiceResultException(StatusCodes.BadTimestampsToReturnInvalid); } // handle raw data request. ReadRawModifiedDetails readRawModifiedDetails = details as ReadRawModifiedDetails; if (readRawModifiedDetails != null) { // at least one must be provided. if (readRawModifiedDetails.StartTime == DateTime.MinValue && readRawModifiedDetails.EndTime == DateTime.MinValue) { throw new ServiceResultException(StatusCodes.BadInvalidTimestampArgument); } // if one is null the num values must be provided. if (readRawModifiedDetails.StartTime == DateTime.MinValue || readRawModifiedDetails.EndTime == DateTime.MinValue) { if (readRawModifiedDetails.NumValuesPerNode == 0) { throw new ServiceResultException(StatusCodes.BadInvalidTimestampArgument); } } HistoryReadRawModified( context, readRawModifiedDetails, timestampsToReturn, nodesToRead, results, errors, nodesToProcess, cache); return; } // handle processed data request. ReadProcessedDetails readProcessedDetails = details as ReadProcessedDetails; if (readProcessedDetails != null) { // check the list of aggregates. if (readProcessedDetails.AggregateType == null || readProcessedDetails.AggregateType.Count != nodesToRead.Count) { throw new ServiceResultException(StatusCodes.BadAggregateListMismatch); } // check start/end time. if (readProcessedDetails.StartTime == DateTime.MinValue || readProcessedDetails.EndTime == DateTime.MinValue) { throw new ServiceResultException(StatusCodes.BadInvalidTimestampArgument); } HistoryReadProcessed( context, readProcessedDetails, timestampsToReturn, nodesToRead, results, errors, nodesToProcess, cache); return; } // handle raw data at time request. ReadAtTimeDetails readAtTimeDetails = details as ReadAtTimeDetails; if (readAtTimeDetails != null) { HistoryReadAtTime( context, readAtTimeDetails, timestampsToReturn, nodesToRead, results, errors, nodesToProcess, cache); return; } // handle read events request. ReadEventDetails readEventDetails = details as ReadEventDetails; if (readEventDetails != null) { // check start/end time and max values. if (readEventDetails.NumValuesPerNode == 0) { if (readEventDetails.StartTime == DateTime.MinValue || readEventDetails.EndTime == DateTime.MinValue) { throw new ServiceResultException(StatusCodes.BadInvalidTimestampArgument); } } else { if (readEventDetails.StartTime == DateTime.MinValue && readEventDetails.EndTime == DateTime.MinValue) { throw new ServiceResultException(StatusCodes.BadInvalidTimestampArgument); } } // validate the event filter. EventFilter.Result result = readEventDetails.Filter.Validate(new FilterContext(m_server.NamespaceUris, m_server.TypeTree, context)); if (ServiceResult.IsBad(result.Status)) { throw new ServiceResultException(result.Status); } // read the event history. HistoryReadEvents( context, readEventDetails, timestampsToReturn, nodesToRead, results, errors, nodesToProcess, cache); return; } }
/// <summary> /// Reads the history for the specified nodes. /// </summary> public virtual void HistoryRead( OperationContext context, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors) { ServerSystemContext systemContext = m_systemContext.Copy(context); IDictionary<NodeId,NodeState> operationCache = new NodeIdDictionary<NodeState>(); List<NodeHandle> nodesToProcess = new List<NodeHandle>(); lock (Lock) { for (int ii = 0; ii < nodesToRead.Count; ii++) { HistoryReadValueId nodeToRead = nodesToRead[ii]; // skip items that have already been processed. if (nodeToRead.Processed) { continue; } // check for valid handle. NodeHandle handle = GetManagerHandle(systemContext, nodeToRead.NodeId, operationCache); if (handle == null) { continue; } // owned by this node manager. nodeToRead.Processed = true; // create an initial result. HistoryReadResult result = results[ii] = new HistoryReadResult(); result.HistoryData = null; result.ContinuationPoint = null; result.StatusCode = StatusCodes.Good; // check if the node is a area in memory. if (handle.Node == null) { errors[ii] = StatusCodes.BadNodeIdUnknown; // must validate node in a seperate operation handle.Index = ii; nodesToProcess.Add(handle); continue; } errors[ii] = StatusCodes.BadHistoryOperationUnsupported; // check for data history variable. BaseVariableState variable = handle.Node as BaseVariableState; if (variable != null) { if ((variable.AccessLevel & AccessLevels.HistoryRead) != 0) { handle.Index = ii; nodesToProcess.Add(handle); continue; } } // check for event history object. BaseObjectState notifier = handle.Node as BaseObjectState; if (notifier != null) { if ((notifier.EventNotifier & EventNotifiers.HistoryRead) != 0) { handle.Index = ii; nodesToProcess.Add(handle); continue; } } } // check for nothing to do. if (nodesToProcess.Count == 0) { return; } } // validates the nodes (reads values from the underlying data source if required). HistoryRead( systemContext, details, timestampsToReturn, releaseContinuationPoints, nodesToRead, results, errors, nodesToProcess, operationCache); }
/// <see cref="INodeManager.HistoryRead" /> public void HistoryRead( OperationContext context, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors) { if (context == null) throw new ArgumentNullException("context"); if (details == null) throw new ArgumentNullException("details"); if (nodesToRead == null) throw new ArgumentNullException("nodesToRead"); if (results == null) throw new ArgumentNullException("results"); if (errors == null) throw new ArgumentNullException("errors"); ReadRawModifiedDetails readRawModifiedDetails = details as ReadRawModifiedDetails; ReadAtTimeDetails readAtTimeDetails = details as ReadAtTimeDetails; ReadProcessedDetails readProcessedDetails = details as ReadProcessedDetails; ReadEventDetails readEventDetails = details as ReadEventDetails; #if LEGACY_CORENODEMANAGER Dictionary<object,List<RequestHandle>> historians = new Dictionary<object,List<RequestHandle>>(); #endif lock (m_lock) { #if LEGACY_CORENODEMANAGER Type sourceType = typeof(IDataHistoryProducer); if (readEventDetails != null) { sourceType = typeof(IEventHistoryProducer); } #endif for (int ii = 0; ii < nodesToRead.Count; ii++) { HistoryReadValueId nodeToRead = nodesToRead[ii]; // skip items that have already been processed. if (nodeToRead.Processed) { continue; } // look up the node. ILocalNode node = GetLocalNode(nodeToRead.NodeId) as ILocalNode; if (node == null) { continue; } // owned by this node manager. nodeToRead.Processed = true; #if LEGACY_CORENODEMANAGER // find the historian. if (!CheckSourceHandle(node, sourceType, ii, historians)) { errors[ii] = StatusCodes.BadNotReadable; continue; } #else errors[ii] = StatusCodes.BadNotReadable; #endif } #if LEGACY_CORENODEMANAGER // check if nothing to do. if (historians.Count == 0) { return; } #endif } #if LEGACY_CORENODEMANAGER // call the historians. foreach (KeyValuePair<object,List<RequestHandle>> entry in historians) { if (readRawModifiedDetails != null) { ((IDataHistoryProducer)entry.Key).ReadRaw( context, readRawModifiedDetails, timestampsToReturn, releaseContinuationPoints, entry.Value, nodesToRead, results, errors); } else if (readAtTimeDetails != null) { ((IDataHistoryProducer)entry.Key).ReadAtTime( context, readAtTimeDetails, timestampsToReturn, releaseContinuationPoints, entry.Value, nodesToRead, results, errors); } else if (readProcessedDetails != null) { ((IDataHistoryProducer)entry.Key).ReadProcessed( context, readProcessedDetails, timestampsToReturn, releaseContinuationPoints, entry.Value, nodesToRead, results, errors); } else if (readEventDetails != null) { ((IEventHistoryProducer)entry.Key).ReadEvents( context, readEventDetails, timestampsToReturn, releaseContinuationPoints, entry.Value, nodesToRead, results, errors); } } #endif }
/// <summary> /// Reads the history for a single node which has already been validated. /// </summary> protected virtual ServiceResult HistoryRead( ISystemContext context, NodeState source, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, HistoryReadValueId nodesToRead, HistoryReadResult result) { // check for variable. BaseVariableState variable = source as BaseVariableState; if (variable == null) { return StatusCodes.BadHistoryOperationUnsupported; } // check for access. lock (Lock) { if ((variable.AccessLevel & AccessLevels.HistoryRead) == 0) { return StatusCodes.BadNotReadable; } } // handle read raw. ReadRawModifiedDetails readRawDetails = details as ReadRawModifiedDetails; if (readRawDetails != null) { return HistoryReadRaw( context, variable, readRawDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, result); } // handle read processed. ReadProcessedDetails readProcessedDetails = details as ReadProcessedDetails; if (readProcessedDetails != null) { return HistoryReadProcessed( context, variable, readProcessedDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, result); } // handle read processed. ReadAtTimeDetails readAtTimeDetails = details as ReadAtTimeDetails; if (readAtTimeDetails != null) { return HistoryReadAtTime( context, variable, readAtTimeDetails, timestampsToReturn, releaseContinuationPoints, nodesToRead, result); } return StatusCodes.BadHistoryOperationUnsupported; }
/// <summary> /// Reads the history for the specified nodes. /// </summary> public virtual void HistoryRead( OperationContext context, HistoryReadDetails details, TimestampsToReturn timestampsToReturn, bool releaseContinuationPoints, IList<HistoryReadValueId> nodesToRead, IList<HistoryReadResult> results, IList<ServiceResult> errors) { ServerSystemContext systemContext = m_systemContext.Copy(context); IDictionary<NodeId,NodeState> operationCache = new NodeIdDictionary<NodeState>(); List<ReadWriteOperationState> nodesToValidate = new List<ReadWriteOperationState>(); List<ReadWriteOperationState> readsToComplete = new List<ReadWriteOperationState>(); lock (Lock) { for (int ii = 0; ii < nodesToRead.Count; ii++) { HistoryReadValueId nodeToRead = nodesToRead[ii]; // skip items that have already been processed. if (nodeToRead.Processed) { continue; } // check for valid handle. NodeState source = GetManagerHandle(systemContext, nodeToRead.NodeId, operationCache) as NodeState; if (source == null) { continue; } // owned by this node manager. nodeToRead.Processed = true; // only variables supported. BaseVariableState variable = source as BaseVariableState; if (variable == null) { errors[ii] = StatusCodes.BadHistoryOperationUnsupported; continue; } results[ii] = new HistoryReadResult(); ReadWriteOperationState operation = new ReadWriteOperationState(); operation.Source = source; operation.Index = ii; // check if the node is ready for reading. if (source.ValidationRequired) { // must validate node in a seperate operation. errors[ii] = StatusCodes.BadNodeIdUnknown; nodesToValidate.Add(operation); continue; } // read the data. readsToComplete.Add(operation); } // validates the nodes (reads values from the underlying data source if required). for (int ii = 0; ii < nodesToValidate.Count; ii++) { ReadWriteOperationState operation = nodesToValidate[ii]; if (!ValidateNode(systemContext, operation.Source)) { continue; } readsToComplete.Add(operation); } } // reads the data without holding onto the lock. for (int ii = 0; ii < readsToComplete.Count; ii++) { ReadWriteOperationState operation = readsToComplete[ii]; errors[operation.Index] = HistoryRead( systemContext, operation.Source, details, timestampsToReturn, releaseContinuationPoints, nodesToRead[operation.Index], results[operation.Index]); } }