/// <summary> /// Creates a copy of the context that can be used with the specified operation context. /// </summary> /// <param name="context">The operation context to use.</param> /// <returns> /// A copy of the system context that references the new operation context. /// </returns> public ISystemContext Copy(IOperationContext context) { SystemContext copy = (SystemContext)MemberwiseClone(); if (context != null) { copy.m_operationContext = context; } return(copy); }
/// <summary> /// Creates a new area. /// </summary> private BaseObjectState CreateArea(SystemContext context, BaseObjectState platforms, string areaName) { FolderState area = new FolderState(null); area.NodeId = new NodeId(areaName, NamespaceIndex); area.BrowseName = new QualifiedName(areaName, NamespaceIndex); area.DisplayName = area.BrowseName.Name; area.EventNotifier = EventNotifiers.SubscribeToEvents | EventNotifiers.HistoryRead | EventNotifiers.HistoryWrite; area.TypeDefinitionId = Opc.Ua.ObjectTypeIds.FolderType; platforms.AddNotifier(SystemContext, Opc.Ua.ReferenceTypeIds.HasNotifier, false, area); area.AddNotifier(SystemContext, Opc.Ua.ReferenceTypeIds.HasNotifier, true, platforms); AddPredefinedNode(SystemContext, area); return area; }
/// <summary> /// Creates a new well. /// </summary> private void CreateWell(SystemContext context, BaseObjectState area, string wellId, string wellName) { WellState well = new WellState(null); well.NodeId = new NodeId(wellId, NamespaceIndex); well.BrowseName = new QualifiedName(wellName, NamespaceIndex); well.DisplayName = wellName; well.EventNotifier = EventNotifiers.SubscribeToEvents | EventNotifiers.HistoryRead | EventNotifiers.HistoryWrite; well.TypeDefinitionId = new NodeId(ObjectTypes.WellType, NamespaceIndex); area.AddNotifier(SystemContext, Opc.Ua.ReferenceTypeIds.HasNotifier, false, well); well.AddNotifier(SystemContext, Opc.Ua.ReferenceTypeIds.HasNotifier, true, area); AddPredefinedNode(SystemContext, well); }
/// <summary> /// Creates a modification info record. /// </summary> private ModificationInfo GetModificationInfo(SystemContext context, HistoryUpdateType updateType) { ModificationInfo info = new ModificationInfo(); info.UpdateType = updateType; info.ModificationTime = DateTime.UtcNow; if (context.OperationContext != null && context.OperationContext.UserIdentity != null) { info.UserName = context.OperationContext.UserIdentity.DisplayName; } return info; }
/// <summary> /// Creates a boiler and adds it to the address space. /// </summary> /// <param name="context">The context to use.</param> /// <param name="unitNumber">The unit number for the boiler.</param> private void CreateBoiler(SystemContext context, int unitNumber) { BoilerState boiler = new BoilerState(null); string name = Utils.Format("Boiler #{0}", unitNumber); boiler.Create( context, null, new QualifiedName(name, m_namespaceIndex), null, true); NodeState folder = (NodeState)FindPredefinedNode( ExpandedNodeId.ToNodeId(ObjectIds.Boilers, Server.NamespaceUris), typeof(NodeState)); folder.AddReference(Opc.Ua.ReferenceTypeIds.Organizes, false, boiler.NodeId); boiler.AddReference(Opc.Ua.ReferenceTypeIds.Organizes, true, folder.NodeId); string unitLabel = Utils.Format("{0}0", unitNumber); UpdateDisplayName(boiler.InputPipe, unitLabel); UpdateDisplayName(boiler.Drum, unitLabel); UpdateDisplayName(boiler.OutputPipe, unitLabel); UpdateDisplayName(boiler.LevelController, unitLabel); UpdateDisplayName(boiler.FlowController, unitLabel); UpdateDisplayName(boiler.CustomController, unitLabel); m_boilers.Add(boiler); AddPredefinedNode(context, boiler); }
/// <summary> /// Deletes a property value from the history. /// </summary> public uint DeleteAnnotationHistory(SystemContext context, QualifiedName propertyName, DateTime sourceTimestamp) { bool deleted = false; string filter = String.Format(System.Globalization.CultureInfo.InvariantCulture, "SourceTimestamp = #{0}#", sourceTimestamp); DataView view = new DataView( SelectTable(propertyName), filter, null, DataViewRowState.CurrentRows); for (int ii = 0; ii < view.Count; ii++) { int updateType = (int)view[ii].Row[5]; } if (!deleted) { return StatusCodes.BadNoEntryExists; } return StatusCodes.Good; }
/// <summary> /// Deletes a value from the history. /// </summary> public uint DeleteHistory(SystemContext context, DateTime startTime, DateTime endTime, bool isModified) { // ensure time goes up. if (endTime < startTime) { DateTime temp = startTime; startTime = endTime; endTime = temp; } string filter = String.Format( System.Globalization.CultureInfo.InvariantCulture, "SourceTimestamp >= #{0}# AND SourceTimestamp < #{1}#", startTime, endTime); // select the table. DataTable table = m_archiveItem.DataSet.Tables[0]; if (isModified) { table = m_archiveItem.DataSet.Tables[1]; } // delete the values. DataView view = new DataView( table, filter, null, DataViewRowState.CurrentRows); List<DataRow> rowsToDelete = new List<DataRow>(); for (int ii = 0; ii < view.Count; ii++) { if (!isModified) { DataRow modifiedRow = m_archiveItem.DataSet.Tables[1].NewRow(); modifiedRow[0] = view[ii].Row[0]; modifiedRow[1] = view[ii].Row[1]; modifiedRow[2] = view[ii].Row[2]; modifiedRow[3] = view[ii].Row[3]; modifiedRow[4] = view[ii].Row[4]; modifiedRow[5] = HistoryUpdateType.Delete; modifiedRow[6] = GetModificationInfo(context, HistoryUpdateType.Delete); m_archiveItem.DataSet.Tables[1].Rows.Add(modifiedRow); } rowsToDelete.Add(view[ii].Row); } // delete rows. foreach (DataRow row in rowsToDelete) { row.Delete(); } // commit all changes. m_archiveItem.DataSet.AcceptChanges(); return StatusCodes.Good; }
/// <summary> /// Updates the history. /// </summary> public uint UpdateAnnotations(SystemContext context, Annotation annotation, DataValue value, PerformUpdateType performUpdateType) { bool replaced = false; string filter = String.Format(System.Globalization.CultureInfo.InvariantCulture, "SourceTimestamp = #{0}#", value.SourceTimestamp); DataView view = new DataView( m_archiveItem.DataSet.Tables[2], filter, null, DataViewRowState.CurrentRows); DataRow row = null; for (int ii = 0; ii < view.Count; ii++) { Annotation current = (Annotation)view[ii].Row[5]; replaced = (current.UserName == annotation.UserName); if (performUpdateType == PerformUpdateType.Insert) { if (replaced) { return StatusCodes.BadEntryExists; } } if (replaced) { row = view[ii].Row; break; } } // add record indicating it was inserted. if (!replaced) { if (performUpdateType == PerformUpdateType.Replace || performUpdateType == PerformUpdateType.Remove) { return StatusCodes.BadNoEntryExists; } row = m_archiveItem.DataSet.Tables[2].NewRow(); } // add/update new record. if (performUpdateType != PerformUpdateType.Remove) { row[0] = value.SourceTimestamp; row[1] = value.ServerTimestamp; row[2] = new DataValue(new ExtensionObject(annotation), StatusCodes.Good, value.SourceTimestamp, value.ServerTimestamp); row[3] = BuiltInType.ExtensionObject; row[4] = ValueRanks.Scalar; row[5] = annotation; if (!replaced) { m_archiveItem.DataSet.Tables[2].Rows.Add(row); } } // delete record. else { row.Delete(); } // accept all changes. m_archiveItem.DataSet.AcceptChanges(); return StatusCodes.Good; }
/// <summary> /// Deletes a value from the history. /// </summary> public uint DeleteHistory(SystemContext context, DateTime sourceTimestamp) { bool deleted = false; string filter = String.Format(System.Globalization.CultureInfo.InvariantCulture, "SourceTimestamp = #{0}#", sourceTimestamp); DataView view = new DataView( m_archiveItem.DataSet.Tables[0], filter, null, DataViewRowState.CurrentRows); for (int ii = 0; ii < view.Count; ii++) { int updateType = (int)view[ii].Row[5]; if (updateType == 0) { view[ii].Row[5] = HistoryUpdateType.Delete; view[ii].Row[6] = GetModificationInfo(context, HistoryUpdateType.Delete); deleted = true; } } if (!deleted) { return StatusCodes.BadNoEntryExists; } return StatusCodes.Good; }
/// <summary> /// Updates the history. /// </summary> public uint UpdateHistory(SystemContext context, DataValue value, PerformUpdateType performUpdateType) { bool replaced = false; if (performUpdateType == PerformUpdateType.Remove) { return StatusCodes.BadNotSupported; } if (StatusCode.IsNotBad(value.StatusCode)) { TypeInfo typeInfo = value.WrappedValue.TypeInfo; if (typeInfo == null) { typeInfo = TypeInfo.Construct(value.Value); } if (typeInfo == null || typeInfo.BuiltInType != m_archiveItem.DataType || typeInfo.ValueRank != ValueRanks.Scalar) { return StatusCodes.BadTypeMismatch; } } string filter = String.Format(System.Globalization.CultureInfo.InvariantCulture, "SourceTimestamp = #{0}#", value.SourceTimestamp); DataView view = new DataView( m_archiveItem.DataSet.Tables[0], filter, null, DataViewRowState.CurrentRows); DataRow row = null; for (int ii = 0; ii < view.Count;) { if (performUpdateType == PerformUpdateType.Insert) { return StatusCodes.BadEntryExists; } // add record indicating it was replaced. DataRow modifiedRow = m_archiveItem.DataSet.Tables[1].NewRow(); modifiedRow[0] = view[ii].Row[0]; modifiedRow[1] = view[ii].Row[1]; modifiedRow[2] = view[ii].Row[2]; modifiedRow[3] = view[ii].Row[3]; modifiedRow[4] = view[ii].Row[4]; modifiedRow[5] = HistoryUpdateType.Replace; modifiedRow[6] = GetModificationInfo(context, HistoryUpdateType.Replace); m_archiveItem.DataSet.Tables[1].Rows.Add(modifiedRow); replaced = true; row = view[ii].Row; break; } // add record indicating it was inserted. if (!replaced) { if (performUpdateType == PerformUpdateType.Replace) { return StatusCodes.BadNoEntryExists; } DataRow modifiedRow = m_archiveItem.DataSet.Tables[1].NewRow(); modifiedRow[0] = value.SourceTimestamp; modifiedRow[1] = value.ServerTimestamp; modifiedRow[2] = value; if (value.WrappedValue.TypeInfo != null) { modifiedRow[3] = value.WrappedValue.TypeInfo.BuiltInType; modifiedRow[4] = value.WrappedValue.TypeInfo.ValueRank; } else { modifiedRow[3] = BuiltInType.Variant; modifiedRow[4] = ValueRanks.Scalar; } modifiedRow[5] = HistoryUpdateType.Insert; modifiedRow[6] = GetModificationInfo(context, HistoryUpdateType.Insert); m_archiveItem.DataSet.Tables[1].Rows.Add(modifiedRow); row = m_archiveItem.DataSet.Tables[0].NewRow(); } // add/update new record. row[0] = value.SourceTimestamp; row[1] = value.ServerTimestamp; row[2] = value; if (value.WrappedValue.TypeInfo != null) { row[3] = value.WrappedValue.TypeInfo.BuiltInType; row[4] = value.WrappedValue.TypeInfo.ValueRank; } else { row[3] = BuiltInType.Variant; row[4] = ValueRanks.Scalar; } if (!replaced) { m_archiveItem.DataSet.Tables[0].Rows.Add(row); } // accept all changes. m_archiveItem.DataSet.AcceptChanges(); return StatusCodes.Good; }
/// <summary> /// Creates a new sample. /// </summary> public List<DataValue> NewSamples(SystemContext context) { List<DataValue> newSamples = new List<DataValue>(); while (m_pattern != null && m_nextSampleTime < DateTime.UtcNow) { DataValue value = new DataValue(); value.WrappedValue = m_pattern[m_patternIndex].WrappedValue; value.ServerTimestamp = m_nextSampleTime; value.SourceTimestamp = m_nextSampleTime; value.StatusCode = m_pattern[m_patternIndex].StatusCode; m_nextSampleTime = value.SourceTimestamp.AddMilliseconds(m_archiveItem.SamplingInterval); newSamples.Add(value); DataRow row = m_archiveItem.DataSet.Tables[0].NewRow(); row[0] = value.SourceTimestamp; row[1] = value.ServerTimestamp; row[2] = value; row[3] = value.WrappedValue.TypeInfo.BuiltInType; row[4] = value.WrappedValue.TypeInfo.ValueRank; m_archiveItem.DataSet.Tables[0].Rows.Add(row); m_patternIndex = (m_patternIndex + 1) % m_pattern.Count; } m_archiveItem.DataSet.AcceptChanges(); return newSamples; }
/// <summary> /// Loads the data. /// </summary> public void ReloadFromSource(SystemContext context) { LoadConfiguration(context); if (m_archiveItem.LastLoadTime == DateTime.MinValue || (m_archiveItem.Persistent && m_archiveItem.LastLoadTime.AddSeconds(10) < DateTime.UtcNow)) { DataFileReader reader = new DataFileReader(); reader.LoadHistoryData(context, m_archiveItem); // set the start of the archive. if (m_archiveItem.DataSet.Tables[0].DefaultView.Count > 0) { m_configuration.StartOfArchive.Value = (DateTime)m_archiveItem.DataSet.Tables[0].DefaultView[0].Row[0]; m_configuration.StartOfOnlineArchive.Value = m_configuration.StartOfArchive.Value; } if (m_archiveItem.Archiving) { // save the pattern used to produce new data. m_pattern = new List<DataValue>(); foreach (DataRowView row in m_archiveItem.DataSet.Tables[0].DefaultView) { DataValue value = (DataValue)row.Row[2]; m_pattern.Add(value); m_nextSampleTime = value.SourceTimestamp.AddMilliseconds(m_archiveItem.SamplingInterval); } // fill in data until the present time. m_patternIndex = 0; NewSamples(context); } } }
/// <summary> /// Loads the configuration. /// </summary> public void LoadConfiguration(SystemContext context) { DataFileReader reader = new DataFileReader(); if (reader.LoadConfiguration(context, m_archiveItem)) { this.DataType = (uint)m_archiveItem.DataType; this.ValueRank = m_archiveItem.ValueRank; this.Historizing = m_archiveItem.Archiving; m_configuration.MinTimeInterval.Value = m_archiveItem.SamplingInterval; m_configuration.MaxTimeInterval.Value = m_archiveItem.SamplingInterval; m_configuration.Stepped.Value = m_archiveItem.Stepped; AggregateConfiguration configuration = m_archiveItem.AggregateConfiguration; m_configuration.AggregateConfiguration.PercentDataGood.Value = configuration.PercentDataGood; m_configuration.AggregateConfiguration.PercentDataBad.Value = configuration.PercentDataBad; m_configuration.AggregateConfiguration.UseSlopedExtrapolation.Value = configuration.UseSlopedExtrapolation; m_configuration.AggregateConfiguration.TreatUncertainAsBad.Value = configuration.TreatUncertainAsBad; } }
/// <summary> /// Creates a boiler and adds it to the address space. /// </summary> /// <param name="context">The context to use.</param> /// <param name="unitNumber">The unit number for the boiler.</param> private void CreateBoiler(SystemContext context, int unitNumber) { BoilerState boiler = new BoilerState(null); string name = Utils.Format("Boiler #{0}", unitNumber); boiler.Create( context, null, new QualifiedName(name, m_namespaceIndex), null, true); NodeState folder = (NodeState)FindPredefinedNode( ExpandedNodeId.ToNodeId(ObjectIds.Boilers, Server.NamespaceUris), typeof(NodeState)); folder.AddReference(Opc.Ua.ReferenceTypeIds.Organizes, false, boiler.NodeId); boiler.AddReference(Opc.Ua.ReferenceTypeIds.Organizes, true, folder.NodeId); string unitLabel = Utils.Format("{0}0", unitNumber); UpdateDisplayName(boiler.InputPipe, unitLabel); UpdateDisplayName(boiler.Drum, unitLabel); UpdateDisplayName(boiler.OutputPipe, unitLabel); UpdateDisplayName(boiler.LevelController, unitLabel); UpdateDisplayName(boiler.FlowController, unitLabel); UpdateDisplayName(boiler.CustomController, unitLabel); m_boilers.Add(boiler); AddPredefinedNode(context, boiler); // Autostart boiler simulation state machine MethodState start = boiler.Simulation.Start; IList<Variant> inputArguments = new List<Variant>(); IList<Variant> outputArguments = new List<Variant>(); List<ServiceResult> errors = new List<ServiceResult>(); start.Call(context, boiler.NodeId, inputArguments, errors, outputArguments); }