internal IOpcNode AddNode(IOpcNode parentNode, params string[] path) { var context = this.SystemContext; foreach (var name in path) { var childNode = (OpcInstanceNode)parentNode.Child(context, name); if (childNode == null) { if (name[0] == '.') { childNode = new OpcDataVariableNode <int>(parentNode, name, DateTime.Now.Millisecond); } else { childNode = new OpcFolderNode(parentNode, name); } this.AddNode(context, childNode); if (childNode is OpcVariableNode) { return(childNode); } } parentNode = childNode; } return(parentNode); }
private OpcDataVariableNode <T[]> CreateArrayNode <T>( OpcFolderNode nodes, T defaultValue, Func <T, int, T> randomizer = null) { var value = Enumerable.Repeat(defaultValue, 5).ToArray(); if (randomizer == null) { return(this.CreateNode(nodes, value, randomizer: null)); } return(this.CreateNode(nodes, value, (oldValue, random) => { var index = this.indexRandom.Next(0, oldValue.Length - 1); ////var newValue = oldValue; // Array values need to be copied, otherwise there is no // Value-Changed-Bit set by the node. var newValue = new T[oldValue.Length]; Array.Copy(oldValue, newValue, oldValue.Length); newValue[index] = randomizer(oldValue[index], random); return newValue; })); }
private OpcDataVariableNode <T> CreateNode <T>( OpcFolderNode nodes, T defaultValue, Func <T, int, T> randomizer = null) { var name = typeof(T).Name; name = char.ToUpper(name[0]) + name.Substring(1); if (typeof(T).IsArray) { name = typeof(T).GetElementType().Name + "Array"; } var node = new OpcDataVariableNode <T>(nodes, name, defaultValue); node.ReadVariableValueCallback = this.HandleReadVariableValue; node.WriteVariableValueCallback = this.HandleWriteVariableValue; if (randomizer != null) { this.tasks.Add(() => { node.Value = randomizer(node.Value, this.valueRandom.Next(0, 183)); node.ApplyChanges(this.SystemContext); }); } return(node); }
protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { var machineNode = new OpcObjectNode(this.DefaultNamespace.GetName("Machine")); this.jobsNode = new OpcFolderNode(machineNode, "Jobs"); references.Add(machineNode, OpcObjectTypes.ObjectsFolder); // Add some predefined jobs. new OpcDataVariableNode <int>(this.jobsNode, "JOB01", value: 0); new OpcDataVariableNode <int>(this.jobsNode, "JOB02", value: 0); new OpcDataVariableNode <int>(this.jobsNode, "JOB03", value: 0); // Define a generic event to notify about job-scheduled. this.jobScheduldedEventNode = new OpcEventNode(this.jobsNode, "JobSchedulded"); this.jobScheduldedEventNode.Severity = OpcEventSeverity.Medium; this.jobScheduldedEventNode.Message = "The job has been schedulded."; this.jobsNode.AddNotifier(this.SystemContext, this.jobScheduldedEventNode); // Define a generic event to notify about job-completed. this.jobCompletedEventNode = new OpcEventNode(this.jobsNode, "JobCompleted"); this.jobCompletedEventNode.Severity = OpcEventSeverity.Medium; this.jobCompletedEventNode.Message = "The job has been completed."; this.jobsNode.AddNotifier(this.SystemContext, this.jobCompletedEventNode); return(new IOpcNode[] { machineNode }); }
/// <summary> /// Creates the nodes provided and associated with the node manager. /// </summary> /// <param name="references">A dictionary used to determine the logical references between /// existing nodes (e.g. OPC default nodes) and the nodes provided by the node /// manager.</param> /// <returns>An enumerable containing the root nodes of the node manager.</returns> /// <remarks>This method will be only called once by the server on start up.</remarks> protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { // It is necessary to assign to all root nodes one of the namespaces used to // identify one of the associated namespaces (see the ctor of the class). This // namespace does identify the node as member of the namespace of the node // manager. Optionally it is possible to assign namespace to the child nodes // too. But by default their missing namespace will be auto-completed through the // namespace of their parent node. var machineOne = new OpcFolderNode(this.DefaultNamespace.GetName("Machine_1")); // Add new reference to make the node visible beneath the ObjectsFolder // (the top most root node within every OPC UA server). references.Add(machineOne, OpcObjectTypes.ObjectsFolder); new OpcDataVariableNode <string>(machineOne, "Name", "Machine 1"); new OpcDataVariableNode <byte>(machineOne, "Status", 1); this.positionHistorian = new OpcNodeHistorian( this, new OpcDataVariableNode <int>(machineOne, "Position", -1)); SampleNodeManager.CreateHistoryEntries(this.positionHistorian); new OpcDataVariableNode <bool>(machineOne, "IsActive", true); new OpcDataVariableNode <double>(machineOne, "Temperature", 18.3); return(new IOpcNode[] { machineOne }); }
/// <summary> /// Creates the nodes provided and associated with the node manager. /// </summary> /// <param name="references">A dictionary used to determine the logical references between /// existing nodes (e.g. OPC default nodes) and the nodes provided by the node /// manager.</param> /// <returns>An enumerable containing the root nodes of the node manager.</returns> /// <remarks>This method will be only called once by the server on start up.</remarks> protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { // It is necessary to assign to all root nodes one of the namespaces used to // identify one of the associated namespaces (see the ctor of the class). This // namespace does identify the node as member of the namespace of the node // manager. Optionally it is possible to assign namespace to the child nodes // too. But by default their missing namespace will be auto-completed through the // namespace of their parent node. var machineOne = new OpcFolderNode(this.DefaultNamespace.GetName("Machine_1")); // Add new reference to make the node visible beneath the ObjectsFolder // (the top most root node within every OPC UA server). references.Add(machineOne, OpcObjectTypes.ObjectsFolder); new OpcDataVariableNode <string>(machineOne, "Name", "Machine 1"); // Using an enumeration type which defines the necessary OpcDataType-Attribute and // that is defined as a custom data type node does not need more node setup to use // the custom data type like follows: new OpcDataVariableNode <MachineStatus>(machineOne, "Status", MachineStatus.Started); new OpcDataVariableNode <bool>(machineOne, "IsActive", true); // Ensure that the used enumeration type is defined as a data type node. return(new IOpcNode[] { machineOne, new OpcDataTypeNode <MachineStatus>() }); }
public static void Main(string[] args) { var node = new OpcFolderNode("MyFolder"); node.DisplayName = new OpcText("MyFolder", "en-US", "MyFolder.DisplayName"); node.Description = new OpcText("MyFolder Description", "en-US", "MyFolder.Description"); using (var server = new OpcServer("opc.tcp://localhost:4840", node)) { server.Globalization.AddResources( "en-US", new KeyValuePair <string, string>("MyFolder.DisplayName", "MyFolder (en)"), new KeyValuePair <string, string>("MyFolder.Description", "MyFolder Description (en)")); server.Globalization.AddResources( "de-DE", new KeyValuePair <string, string>("MyFolder.DisplayName", "Mein Ordner (de)"), new KeyValuePair <string, string>("MyFolder.Description", "Meine Ordner Beschreibung (de)")); server.Globalization.AddResources( "fr-FR", new KeyValuePair <string, string>("MyFolder.DisplayName", "Mon dossier (fr)"), new KeyValuePair <string, string>("MyFolder.Description", "Description de mon dossier (fr)")); server.Start(); Console.WriteLine("Server started - press any key to exit."); Console.ReadKey(true); } }
private void CreateMethodNodes(OpcFolderNode nodes) { var methodNodes = new OpcFolderNode(nodes, "Methods"); new OpcMethodNode(methodNodes, "Add", new Func <int, int, int>(this.Add)); new OpcMethodNode(methodNodes, "Divide", new Func <int, int, int>(this.Divide)); new OpcMethodNode(methodNodes, "Multiply", new Func <int, int, int>(this.Multiply)); new OpcMethodNode(methodNodes, "Power", new Func <int, int, int>(this.Power)); new OpcMethodNode(methodNodes, "Subtract", new Func <int, int, int>(this.Substract)); }
protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { var zementTech = new OpcFolderNode(new OpcName("ZementTech", this.DefaultNamespaceIndex)); references.Add(zementTech, OpcObjectTypes.ObjectsFolder); var zementTechConfig = new OpcFolderNode(new OpcName("SimKonfiguration", this.DefaultNamespaceIndex)); references.Add(zementTechConfig, OpcObjectTypes.ObjectsFolder); Context = this.SystemContext; AddConfig(zementTechConfig); RohMaterialGewinnung rohmaterialgewinnung = new RohMaterialGewinnung(zementTech, "Gewinnung", this.SystemContext); MotorDelayLane brecher = new MotorDelayLane(zementTech, "Brecher", this.SystemContext, 2); MotorDelayLane transport = new MotorDelayLane(zementTech, "Transport", this.SystemContext, 4); Silo mischbett = new Silo(zementTech, "Mischbett", this.SystemContext, 45000.0); MotorDelayLane walzmühle = new MotorDelayLane(zementTech, "Mühle", this.SystemContext, 1); Silo rohmehlsilo = new Silo(zementTech, "RohmehlSilo", this.SystemContext, 30000.0); Brennstoffzufuhr bsz = new Brennstoffzufuhr(zementTech, "Brennstoffzufuhr", this.SystemContext); Drehrohrofen drehrohrofen = new Drehrohrofen(zementTech, "Drehrohrofen", this.SystemContext, bsz); Zyklon zyklon = new Zyklon(zementTech, "Zyklon", this.SystemContext, drehrohrofen); Kuehler kuehler = new Kuehler(zementTech, "Kühler", this.SystemContext); Silo klinkerSilo = new Silo(zementTech, "KlinkerSilo", this.SystemContext, 20000.0); MotorDelayLane zementMühle = new MotorDelayLane(zementTech, "Zementmühle", this.SystemContext, 1); Silo zementSilo = new Silo(zementTech, "ZementSilo", this.SystemContext, 35000.0); Absackung absackung = new Absackung(zementTech, "Absackung", this.SystemContext); rohmaterialgewinnung.Receiver = brecher; brecher.Receiver = transport; transport.Receiver = mischbett; mischbett.Receiver = walzmühle; walzmühle.Receiver = rohmehlsilo; rohmehlsilo.Receiver = zyklon; zyklon.Receiver = drehrohrofen; drehrohrofen.Receiver = kuehler; kuehler.Receiver = klinkerSilo; klinkerSilo.Receiver = zementMühle; zementMühle.Receiver = zementSilo; zementSilo.Receiver = absackung; return(new IOpcNode[] { zementTech, zementTechConfig, new OpcDataTypeNode <OperationState>(), new OpcDataTypeNode <OperationMode>(), new OpcDataTypeNode <TimeMultiplier>() }); }
private static OpcFolderNode CreateDataNode() { var dataNode = new OpcFolderNode("Data"); for (int index = 0; index < NumberOfNodes; index++) { dataNodes.Add(new OpcDataVariableNode <int>(dataNode, $"Var{index:00000}", value: index)); } timestampNode = new OpcDataVariableNode <DateTime>(dataNode, "Timestamp"); return(dataNode); }
protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { // Define custom root node. var FDANode = new OpcFolderNode(new OpcName("FDA", this.DefaultNamespaceIndex)); // Add custom root node to the Objects-Folder (the root of all server nodes): references.Add(FDANode, OpcObjectTypes.ObjectsFolder); // Add custom sub node beneath of the custom root node: //var isMachineRunningNode = new OpcDataVariableNode<bool>(FDANode, "IsRunning"); // Return each custom root node using yield return. yield return(FDANode); }
internal IOpcNode AddRootNode(params string[] path) { var newNode = new OpcFolderNode(path[0].TrimStart('$')); var reference = OpcNodeReference.To(OpcObjectTypes.ObjectsFolder); this.AddNode(this.SystemContext, newNode, reference); if (path.Length > 1) { return(this.AddNode(newNode, path.Skip(1).ToArray())); } return(newNode); }
protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { var nodes = new OpcFolderNode(this.DefaultNamespace.GetName("Nodes")); references.Add(nodes, OpcObjectTypes.ObjectsFolder); yield return(nodes); this.CreateStaticNodes(nodes); this.CreateDynamicNodes(nodes); this.CreateMethodNodes(nodes); yield return(new OpcDataTypeNode <MyEnum>()); yield return(new OpcDataTypeNode <MyEnumFlags>()); }
private static OpcFolderNode CreateDataNode() { var dataNode = new OpcFolderNode("Data"); dataAvailableNode = new OpcDataVariableNode <bool>(dataNode, "DataAvailable"); dataProcessedNode = new OpcDataVariableNode <bool>(dataNode, "DataProcessed"); dataProcessedNode.WriteVariableValueCallback = WriteDataProcessed; for (int index = 0; index < NumberOfNodes; index++) { dataNodes.Add(new OpcDataVariableNode <int>(dataNode, $"Var{index:00000}", value: index)); } timestampNode = new OpcDataVariableNode <DateTime>(dataNode, "Timestamp"); return(dataNode); }
private void CreateStaticNodes(OpcFolderNode nodes) { var staticNodes = new OpcFolderNode(nodes, "Static"); this.CreateNode <byte>(staticNodes, 1); this.CreateArrayNode <byte>(staticNodes, 1); this.CreateNode <sbyte>(staticNodes, 2); this.CreateArrayNode <sbyte>(staticNodes, 2); this.CreateNode <short>(staticNodes, 3); this.CreateArrayNode <short>(staticNodes, 3); this.CreateNode <ushort>(staticNodes, 4); this.CreateArrayNode <ushort>(staticNodes, 4); this.CreateNode <int>(staticNodes, 5); this.CreateArrayNode <int>(staticNodes, 5); this.CreateNode <uint>(staticNodes, 6u); this.CreateArrayNode <uint>(staticNodes, 6u); this.CreateNode <long>(staticNodes, 7L); this.CreateArrayNode <long>(staticNodes, 7L); this.CreateNode <ulong>(staticNodes, 8u); this.CreateArrayNode <ulong>(staticNodes, 8u); this.CreateNode <float>(staticNodes, 9.10f); this.CreateArrayNode <float>(staticNodes, 9.10f); this.CreateNode <double>(staticNodes, 11.12); this.CreateArrayNode <double>(staticNodes, 11.12); var stringValue = this.RandomString(); this.CreateNode <string>(staticNodes, stringValue); this.CreateArrayNode <string>(staticNodes, stringValue); this.CreateNode <MyEnum>(staticNodes, MyEnum.Maintenance); //this.CreateArrayNode<MyEnum>(staticNodes, MyEnum.Starting); this.CreateNode <MyEnumFlags>(staticNodes, MyEnumFlags.CanCut | MyEnumFlags.CanFold); //this.CreateArrayNode<MyEnumFlags>(staticNodes, MyEnumFlags.CanPrint | MyEnumFlags.CanCorrugate); }
private void CreateDynamicNodes(OpcFolderNode nodes) { var dynamicNodes = new OpcFolderNode(nodes, "Dynamic"); this.CreateNode <byte>(dynamicNodes, 1, (old, random) => unchecked ((byte)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <byte>(dynamicNodes, 1, (old, random) => unchecked ((byte)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <sbyte>(dynamicNodes, 2, (old, random) => unchecked ((sbyte)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <sbyte>(dynamicNodes, 2, (old, random) => unchecked ((sbyte)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <short>(dynamicNodes, 3, (old, random) => unchecked ((short)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <short>(dynamicNodes, 3, (old, random) => unchecked ((short)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <ushort>(dynamicNodes, 4, (old, random) => unchecked ((ushort)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <ushort>(dynamicNodes, 4, (old, random) => unchecked ((ushort)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <int>(dynamicNodes, 5, (old, random) => unchecked ((int)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <int>(dynamicNodes, 5, (old, random) => unchecked ((int)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <uint>(dynamicNodes, 6u, (old, random) => unchecked ((uint)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <uint>(dynamicNodes, 6u, (old, random) => unchecked ((uint)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <long>(dynamicNodes, 7L, (old, random) => unchecked ((long)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <long>(dynamicNodes, 7L, (old, random) => unchecked ((long)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <ulong>(dynamicNodes, 8u, (old, random) => unchecked ((ulong)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <ulong>(dynamicNodes, 8u, (old, random) => unchecked ((ulong)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <float>(dynamicNodes, 9.10f, (old, random) => unchecked ((float)(DateTime.Now.Second * random) / (int)Math.Max((int)old, 1))); this.CreateArrayNode <float>(dynamicNodes, 9.10f, (old, random) => unchecked ((float)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateNode <double>(dynamicNodes, 11.12, (old, random) => unchecked ((double)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); this.CreateArrayNode <double>(dynamicNodes, 11.12, (old, random) => unchecked ((double)(DateTime.Now.Second * random / (int)Math.Max((int)old, 1)))); var stringValue = this.RandomString(); this.CreateNode <string>(dynamicNodes, stringValue, this.RandomString); this.CreateArrayNode <string>(dynamicNodes, stringValue, this.RandomString); this.CreateNode <MyEnum>(dynamicNodes, MyEnum.Starting, this.RandomEnum); //this.CreateArrayNode<MyEnum>(dynamicNodes, MyEnum.Maintenance, this.RandomEnum); this.CreateNode <MyEnumFlags>(dynamicNodes, MyEnumFlags.CanCut | MyEnumFlags.CanLaminate, this.RandomEnum); //this.CreateArrayNode<MyEnumFlags>(dynamicNodes, MyEnumFlags.CanFold | MyEnumFlags.CanPrint, this.RandomEnum); }
protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { _matlabFolder = new OpcFolderNode( new OpcName(MatlabFolderName, this.DefaultNamespaceIndex)); references.Add(_matlabFolder, OpcObjectTypes.ObjectsFolder); MyDeleagate del = UpdateVariables; new OpcMethodNode(_matlabFolder, GetVariablesMethod, del); var v = new OpcDataVariableNode <int>(_matlabFolder, new OpcName("GetVariablesVariable"), 0);//new OpcVariableNode(_matlabFolder,new OpcName("GetVariablesVariable"), 0); v.WriteVariableValueCallback = WriteVariableValueCallback; v.AccessLevel = OpcAccessLevel.CurrentReadOrWrite; Console.WriteLine(); UpdateVariables(); return(new IOpcNode[] { _matlabFolder }); }
public static void Main(string[] args) { producerControl = new CancellationTokenSource(); dataNodes = new List <OpcDataVariableNode <int> >(); dataNode = CreateDataNode(); var producer = new Thread(ProduceDataChanges); using (var server = new OpcServer("opc.tcp://localhost:4840/", dataNode)) { server.Start(); producer.Start(server); Console.WriteLine("Server started - press any key to exit."); Console.ReadKey(true); producerControl.Cancel(); producer.Join(); } }
public static void Main(string[] args) { OpcNodeId.Factory = new SimaticNodeIdFactory(); var db1 = new OpcFolderNode( "DataBlock1", new OpcDataVariableNode <byte>("MaxByte", value: byte.MaxValue), new OpcDataVariableNode <short>("MaxInt", value: short.MaxValue), new OpcDataVariableNode <int>("MaxDInt", value: int.MaxValue)); var db2 = new OpcFolderNode( "DataBlock2", new OpcObjectNode("MyStruct", new OpcDataVariableNode <int>("FieldA", value: 10), new OpcDataVariableNode <int>("FieldB", value: 20))); using (var server = new OpcServer("opc.tcp://localhost:4840/", db1, db2)) { server.Start(); Console.WriteLine("Server started - press any key to exit."); Console.ReadKey(true); } }
/// <summary> /// Creates the nodes provided and associated with the node manager. /// </summary> /// <param name="references">A dictionary used to determine the logical references between /// existing nodes (e.g. OPC default nodes) and the nodes provided by the node /// manager.</param> /// <returns>An enumerable containing the root nodes of the node manager.</returns> /// <remarks>This method will be only called once by the server on start up.</remarks> protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { // It is necessary to assign to all root nodes one of the namespaces used to // identify one of the associated namespaces (see the ctor of the class). This // namespace does identify the node as member of the namespace of the node // manager. Optionally it is possible to assign namespace to the child nodes // too. But by default their missing namespace will be auto-completed through the // namespace of their parent node. var machineOne = new OpcFolderNode(this.DefaultNamespace.GetName("Machine_1")); // Add new reference to make the node visible beneath the ObjectsFolder // (the top most root node within every OPC UA server). references.Add(machineOne, OpcObjectTypes.ObjectsFolder); new OpcDataVariableNode <string>(machineOne, "Name", "Machine 1"); new OpcDataVariableNode <byte>(machineOne, "Status", 1); new OpcDataVariableNode <bool>(machineOne, "IsActive", true); // The mapping of the UNECE codes to OPC UA (OpcEngineeringUnitInfo.UnitId) is available here: // http://www.opcfoundation.org/UA/EngineeringUnits/UNECE/UNECE_to_OPCUA.csv var pressureNode = new OpcAnalogItemNode <double>(machineOne, "Pressure", 2.116); pressureNode.InstrumentRange = new OpcValueRange(230.11315); pressureNode.EngineeringUnit = new OpcEngineeringUnitInfo(4732211, "kg/bar", "kilogram per bar"); pressureNode.EngineeringUnitRange = new OpcValueRange(120.0); var temperatureNode = new OpcAnalogItemNode <double>(machineOne, "Temperature", 18.3); temperatureNode.InstrumentRange = new OpcValueRange(80.0, -40.0); temperatureNode.EngineeringUnit = new OpcEngineeringUnitInfo(4408652, "°C", "degree Celsius"); temperatureNode.EngineeringUnitRange = new OpcValueRange(70.8, 5.0); return(new IOpcNode[] { machineOne }); }
/// <summary> /// Creates the nodes provided and associated with the node manager. /// </summary> /// <param name="references">A dictionary used to determine the logical references between /// existing nodes (e.g. OPC default nodes) and the nodes provided by the node /// manager.</param> /// <returns>An enumerable containing the root nodes of the node manager.</returns> /// <remarks>This method will be only called once by the server on start up.</remarks> protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { // It is necessary to assign to all root nodes one of the namespaces used to // identify one of the associated namespaces (see the ctor of the class). This // namespace does identify the node as member of the namespace of the node // manager. Optionally it is possible to assign namespace to the child nodes // too. But by default their missing namespace will be auto-completed through the // namespace of their parent node. var machineOne = new OpcFolderNode(this.DefaultNamespace.GetName("Machine_1")); // In case a client requests a condition referesh it queries the current event // information which is gathered using the CreateEvent method from each active // and retained alarm nodes. machineOne.QueryEventsCallback = (context, events) => { // Ensure that an re-entrance upon notifier cross-references will not add // events to the collection which are already stored in. if (events.Count != 0) { return; } if (this.statusChangeNode.IsRetained) { events.Add(this.statusChangeNode.CreateEvent(context)); } if (this.positionLimitNode.IsRetained) { events.Add(this.positionLimitNode.CreateEvent(context)); } if (this.temperatureCriticalNode.IsRetained) { events.Add(this.temperatureCriticalNode.CreateEvent(context)); } }; // Add new reference to make the node visible beneath the ObjectsFolder // (the top most root node within every OPC UA server). references.Add(machineOne, OpcObjectTypes.ObjectsFolder); new OpcDataVariableNode <string>(machineOne, "Name", "Machine 1"); this.isActiveNode = new OpcDataVariableNode <bool>(machineOne, "IsActive", true); //// An alarm node have to be a notifier for another node or for the whole server. //// Is a alarm a notifier of another node: //// -> this node (the notified one) needs to be subscribed by the client to receive //// the alarm data. //// Is a alarm a notifier of the whole server: //// -> the OpcObjectTypes.Server needs to be subscribed by the client to receive //// the alarm data. // Machine 1, Status nodes setup { this.statusNode = new OpcDataVariableNode <byte>(machineOne, "Status", 1); // Define an alarm used to request a dialog which requires a dedicated response // action by a client. This kind of node can be used for service / operator tasks. this.statusChangeNode = new OpcDialogConditionNode(machineOne, "StatusChange"); this.statusChangeNode.AutoReportChanges = true; this.statusChangeNode.Message = "Operator requested"; this.statusChangeNode.Prompt = "The job has been finished, continue with the next one?"; this.statusChangeNode.ResponseOptions = new OpcText[] { "Yes", "No" }; this.statusChangeNode.DefaultResponse = 0; this.statusChangeNode.CancelResponse = 1; this.statusChangeNode.OkResponse = 0; // Handle any client response on an active dialog through applying the response // using RespondDialog and configuring the dialog as inactive. this.statusChangeNode.RespondCallback = (context, response) => { this.isActiveNode.Value = (response == this.statusChangeNode.OkResponse); this.isActiveNode.ApplyChanges(context); this.statusChangeNode.RespondDialog(context, response); this.statusChangeNode.Message = "No operator required"; this.statusChangeNode.IsRetained = false; return(OpcStatusCode.Good); }; // Define the alarm as the notifier of the machineOne node. machineOne.AddNotifier(this.SystemContext, this.statusChangeNode); } // Machine 1, Position nodes setup { this.positionNode = new OpcAnalogItemNode <int>(machineOne, "Position", -1); this.positionNode.InstrumentRange = new OpcValueRange(low: 120, high: 1); this.positionNode.EngineeringUnit = new OpcEngineeringUnitInfo(4732211, "mm", "millimetre"); this.positionNode.EngineeringUnitRange = new OpcValueRange(byte.MaxValue); // Define an alarm used to indicate the reaching of one or more limits during // a progress. Such limits may be predefined or progress dependent. this.positionLimitNode = new OpcExclusiveLimitAlarmNode( machineOne, "PositionLimit", OpcLimitAlarmStates.All); this.positionLimitNode.HighHighLimit = 120; // e.g. mm this.positionLimitNode.HighLimit = 100; // e.g. mm this.positionLimitNode.LowLimit = 5; // e.g. mm this.positionLimitNode.LowLowLimit = 1; // e.g. mm this.positionLimitNode.Message = "No range problems"; this.positionLimitNode.ReceiveTime = DateTime.UtcNow; this.positionLimitNode.AcknowledgeCallback = (context, eventId, comment) => { this.positionLimitNode.Message = "Acknowledged with " + comment; return(OpcStatusCode.Good); }; // Define the alarm as the notifier of the machineOne node. machineOne.AddNotifier(this.SystemContext, this.positionLimitNode); } // Machine 1, Temperature nodes setup { this.temperatureNode = new OpcAnalogItemNode <double>(machineOne, "Temperature", 18.3); this.temperatureNode.InstrumentRange = new OpcValueRange(80.0, -40.0); this.temperatureNode.EngineeringUnit = new OpcEngineeringUnitInfo(4408652, "°C", "degree Celsius"); this.temperatureNode.EngineeringUnitRange = new OpcValueRange(70.8, 5.0); // Define an alarm which just indicates the fulfillment of an alarm associated // condition. Such simple alarms only notify about the fulfillment without to // define additional prerequisites defined by the alarm itself. Much more // specialized alarms are subclasses of this type of alarm node. this.temperatureCriticalNode = new OpcAlarmConditionNode(machineOne, "TemperatureCritical"); // Define the alarm as the notifier of the machineOne node. machineOne.AddNotifier(this.SystemContext, this.temperatureCriticalNode); // Define the alarm as the notifier of the whole Server node. this.AddNotifierNode(this.temperatureCriticalNode); } return(new IOpcNode[] { machineOne }); }
/// <summary> /// Creates the nodes provided and associated with the node manager. /// </summary> /// <param name="references">A dictionary used to determine the logical references between /// existing nodes (e.g. OPC default nodes) and the nodes provided by the node /// manager.</param> /// <returns>An enumerable containing the root nodes of the node manager.</returns> /// <remarks>This method will be only called once by the server on start up.</remarks> protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { yield return(new OpcDataTypeNode <MachineStatus>()); yield return(new OpcDataTypeNode <MachineSetup>()); yield return(new OpcDataTypeNode <MachineJob>()); yield return(new OpcDataTypeNode <ManufacturingOrder>()); var machines = new OpcFolderNode("Machines"); // Add new reference to make the node visible beneath the ObjectsFolder // (the top most root node within every OPC UA server). references.Add(machines, OpcObjectTypes.ObjectsFolder); var machineOne = new OpcFolderNode(machines, "Machine_1"); new OpcDataVariableNode <string>(machineOne, "Name", "Machine 1"); new OpcDataVariableNode <MachineStatus>(machineOne, "Status", MachineStatus.Stopped); new OpcDataVariableNode <bool>(machineOne, "IsActive", false); new OpcDataVariableNode <double>(machineOne, "Temperature", 18.3); new OpcMethodNode(machineOne, "StartJob", new Action <MachineJob>(job => Console.WriteLine(job.Number))); new OpcDataVariableNode <MachineJob>(machineOne, "Job", new MachineJob() { Number = "JOB001", EstimatedDuration = 12500, InProcess = false, CuttingPositions = new int[] { 1000, 1500, 1570, 2020 }, RequiredSetup = MachineSetup.Packager, ScheduleTime = DateTime.UtcNow.AddMinutes(10) }); var machineTwo = new OpcFolderNode(machines, "Machine_2"); new OpcDataVariableNode <string>(machineTwo, "Name", "Machine 2"); new OpcDataVariableNode <MachineStatus>(machineTwo, "Status", MachineStatus.Suspended); new OpcDataVariableNode <bool>(machineTwo, "IsActive", true); new OpcDataVariableNode <double>(machineTwo, "Temperature", 20.7); new OpcMethodNode(machineOne, "StartJob", new Action <MachineJob>(job => Console.WriteLine(job.Number))); new OpcDataVariableNode <ManufacturingOrder>(machineTwo, "Order", new ManufacturingOrder() { Order = "2020.10.10001", Article = "ART10025", Jobs = new [] { new MachineJob { Number = "JOB1001", Duration = 900, EstimatedDuration = 1000, InProcess = false, CuttingPositions = new int[4], RequiredSetup = MachineSetup.Corrugator, ScheduleTime = DateTime.UtcNow }, new MachineJob { Number = "JOB1002", Duration = 510, EstimatedDuration = 500, InProcess = true, CuttingPositions = new int[] { 100, 1300, 1700, 2520 }, RequiredSetup = MachineSetup.Cutter, ScheduleTime = DateTime.UtcNow.AddSeconds(1) }, new MachineJob { Number = "JOB1003", Duration = 1030, EstimatedDuration = 2200, InProcess = true, CuttingPositions = new int[4], RequiredSetup = MachineSetup.Printer1, ScheduleTime = DateTime.UtcNow.AddSeconds(2) } } }); yield return(machines); }
/// <summary> /// Creates the nodes provided and associated with the node manager. /// </summary> /// <param name="references">A dictionary used to determine the logical references between /// existing nodes (e.g. OPC default nodes) and the nodes provided by the node /// manager.</param> /// <returns>An enumerable containing the root nodes of the node manager.</returns> /// <remarks>This method will be only called once by the server on start up.</remarks> protected override IEnumerable <IOpcNode> CreateNodes(OpcNodeReferenceCollection references) { // It is necessary to assign to all root nodes one of the namespaces used to // identify one of the associated namespaces (see the ctor of the class). This // namespace does identify the node as member of the namespace of the node // manager. Optionally it is possible to assign namespace to the child nodes // too. But by default their missing namespace will be auto-completed through the // namespace of their parent node. var methods = new OpcFolderNode("Methods"); // Add new reference to make the node visible beneath the ObjectsFolder // (the top most root node within every OPC UA server). references.Add(methods, OpcObjectTypes.ObjectsFolder); { var methodsByDelegate = new OpcFolderNode(methods, "Delegates"); // Define a method node using an existing generic delegate type receiving information // about the context within the method is being called by a client. new OpcMethodNode( methodsByDelegate, "Add", new Func <OpcMethodContext, int, int, int>(AddByDelegate)); // Define a method node using a custom / specific delegate type receiving information // about the context within the method is being called by a client. new OpcMethodNode( methodsByDelegate, "Add2", new AddDelegate(AddByDelegate)); // Define a method node using an existing generic delegate type without receiving // information about the context within the method is being called by a client. new OpcMethodNode( methodsByDelegate, "Multiply", new Func <int, int, int>(MultiplyByDelegate)); // Define a method node using a custom / specific delegate type without receiving // information about the context within the method is being called by a client. new OpcMethodNode( methodsByDelegate, "Multiply2", new MultiplyDelegate(MultiplyByDelegate)); { var moreMethods = new OpcFolderNode(methodsByDelegate, "More"); new OpcMethodNode( moreMethods, "ProcessInputs", new Action <int, string>(ProcessInputs)); new OpcMethodNode( moreMethods, "ProcessInputsWithMetadata", new Action <int, string>(ProcessInputsWithMetadata)); new OpcMethodNode( moreMethods, "ProcessOutputs", new ProcessOutputsDelegate(ProcessOutputs)); new OpcMethodNode( moreMethods, "ProcessOutputsWithMetadata", new ProcessOutputsDelegate(ProcessOutputsWithMetadata)); new OpcMethodNode( moreMethods, "ProcessMultipleOutputs", new ProcessMultipleOutputsDelegate(ProcessMultipleOutputs)); new OpcMethodNode( moreMethods, "ProcessMultipleOutputsWithMetadata", new ProcessMultipleOutputsDelegate(ProcessMultipleOutputsWithMetadata)); new OpcMethodNode( moreMethods, "ProcessInOutputs", new ProcessInOutputsDelegate(ProcessInOutputs)); new OpcMethodNode( moreMethods, "ProcessInOutputsWithMetadata", new ProcessInOutputsDelegate(ProcessInOutputsWithMetadata)); new OpcMethodNode( moreMethods, "ProcessMultipleInOutputs", new ProcessMultipleInOutputsDelegate(ProcessMultipleInOutputs)); new OpcMethodNode( moreMethods, "ProcessMultipleInOutputsWithMetadata", new ProcessMultipleInOutputsDelegate(ProcessMultipleInOutputsWithMetadata)); new OpcMethodNode( moreMethods, "ProcessWithContext", new Action <OpcMethodContext>(ProcessWithContext)); new OpcMethodNode( moreMethods, "ProcessWithoutContext", new Action(ProcessWithoutContext)); } } { var methodsByCommand = new OpcFolderNode(methods, "Commands"); // Define a method node using a method to that the call is to be delegated while // receiving information about the context of the call. new OpcMethodNode( methodsByCommand, "Add", new OpcMethodDelegateCommand(AddByCommand), inputArguments: new[] { new OpcArgument("a", OpcDataType.Int32), new OpcArgument("b", OpcDataType.Int32) }, outputArguments: new[] { new OpcArgument("result", OpcDataType.Int32) }); // Define a method node using a custom command instance to that the call is to be // delegated while receiving information about the context of the call. new OpcMethodNode( methodsByCommand, "Add2", new AddCommand(), inputArguments: new[] { new OpcArgument("a", OpcDataType.Int32), new OpcArgument("b", OpcDataType.Int32) }, outputArguments: new[] { new OpcArgument("result", OpcDataType.Int32) }); // Define a method node using a method to that the call is to be delegated while // receiving information about the context of the call. new OpcMethodNode( methodsByCommand, "Multiply", new OpcMethodDelegateCommand(MultiplyByCommand), inputArguments: new[] { new OpcArgument("a", OpcDataType.Int32), new OpcArgument("b", OpcDataType.Int32) }, outputArguments: new[] { new OpcArgument("result", OpcDataType.Int32) }); // Define a method node using a custom command instance to that the call is to be // delegated while receiving information about the context of the call. new OpcMethodNode( methodsByCommand, "Multiply2", new MultiplyCommand(), inputArguments: new[] { new OpcArgument("a", OpcDataType.Int32), new OpcArgument("b", OpcDataType.Int32) }, outputArguments: new[] { new OpcArgument("result", OpcDataType.Int32) }); } return(new IOpcNode[] { methods }); }
public NodeManager(string name) : base($"http://sampleserver/{name.ToLower()}") { this.Name = name; this.rootNode = new OpcFolderNode(this.DefaultNamespace.GetName(name)); }
public NodeManager() : base("http://sampleserver/dynamicnodes") { this.rootNode = new OpcFolderNode(this.DefaultNamespace.GetName("Root")); }