public LevelSensor(OpcSimModule parent, OpcName name, OpcContext context, double maxLevel) : base(parent, name, context) { _maxLevelKg = new OpcAnalogItemNode <double>(this, "MaxLevelKg", maxLevel); _maxLevelKg.AccessLevel = OpcAccessLevel.CurrentRead; _levelKg = new OpcAnalogItemNode <double>(this, "LevelKg"); _levelKg.InstrumentRange = new OpcValueRange(MaxLevelKg, 0); _levelKg.EngineeringUnit = new OpcEngineeringUnitInfo(4933453, "Kg", "Kilogramm"); _levelKg.EngineeringUnitRange = new OpcValueRange(MaxLevelKg, 0); _levelKg.Description = "Füllstand in Kilogramm"; _levelKg.BeforeApplyChanges += _levelKg_BeforeApplyChanges; _levelPercent = new OpcDataVariableNode <double>(this, "LevelPercent"); _levelPercent.Description = "Füllstand in Prozent"; _levelPercent.AccessLevel = OpcAccessLevel.CurrentRead; _alarmLevelHeigh = new OpcDataVariableNode <bool>(this, "AlarmFüllstandHoch"); _alarmLevelHeigh.Description = "Füllstand > 95%"; _warningLevelHeigh = new OpcDataVariableNode <bool>(this, "WarnungFüllstandHoch"); _warningLevelHeigh.Description = "Füllstand > 80%"; //Random r = new Random(); //LevelKg = r.NextDouble() * 5000.0; }
public Valve(IOpcNode parent, OpcName name, OpcContext context) : base(parent, name, context) { _maxFlow = new OpcAnalogItemNode <double>(this, "MaxDurchfluss", 600.0); _maxFlow.BeforeApplyChanges += _maxFlow_BeforeApplyChanges; _flow = new OpcAnalogItemNode <double>(this, "Durchfluss"); _flow.InstrumentRange = new OpcValueRange(400.0, 0); _flow.EngineeringUnit = new OpcEngineeringUnitInfo(4666675, "m3/min", "Kubikmeter pro Minute"); _flow.EngineeringUnitRange = new OpcValueRange(400.0, 0); _flow.Description = "Kubikmeter pro Minute"; _open = new OpcDataVariableNode <bool>(this, "Offen"); _open.Description = "True = offen, False = zu"; _movementAlarm = new OpcDataVariableNode <bool>(this, "AlarmPosition"); ManualControl = new ManualControl(this, "Handbetrieb", Context); }
/// <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 }); }