Ejemplo n.º 1
0
        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;
        }
Ejemplo n.º 2
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 });
        }
Ejemplo n.º 4
0
        /// <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 });
        }