SharpNodeSettings项目,可配置的数据采集,统一的工业数据网关,OPC UA服务器开发,PLC数据发布到自身内存,redis,opc ua,以及数据可视化开发

本项目隶属于 HslCommunication 项目的SDK套件,如果不清楚HslCommunication组件的话,可以先了解那个项目,源代码地址:https://github.com/dathlin/HslCommunication

本项目源代码地址:https://github.com/dathlin/SharpNodeSettings

本项目的主要实现的功能主要有2个:

  1. 实现单个设备信息的可配置,可存储,采用一个相对标准的Xml存储机制实现,适用的场景是:如果你有20个西门子PLC(种类需要一致),但是PLC的ip地址不一致,或是具体的型号不一致,需要进行可视化的存储
  2. 实现一个数据网关中心,内置了一个自身协议的网络,当然您也可以实现其他的,比如示例项目里的Redis数据网关,OPC UA数据网关。

本项目的所有的核心构建,都是围绕一定格式的Xml文件展开的,以 NodeClass 作为节点的基类,赋予每个节点 Name 值,Description 值,节点下可以跟随子节点,或是跟随设备节点,设备下可以跟随请求节点,多说无益,直接上代码

<?xml version="1.0" encoding="utf-8"?>
<Settings>
  <NodeClass Name="Devices" Description="所有的设备的集合对象">
    <NodeClass Name="分厂一" Description="">
      <NodeClass Name="车间一" Description="" />
      <NodeClass Name="车间二" Description="">
        <DeviceNode Name="ModbusTcp客户端" Description="这是描述" DeviceType="10" ConnectTimeOut="1000" CreateTime="2018/8/9 19:58:49" InstallationDate="2018/8/9 19:58:49" IpAddress="127.0.0.1" Port="502" Station="1" IsAddressStartWithZero="true" IsWordReverse="false" IsStringReverse="false">
          <DeviceRequest Name="数据请求" Description="一次完整的数据请求" Address="0" Length="30" CaptureInterval="1000" PraseRegularCode="ABCD" />
        </DeviceNode>
      </NodeClass>
    </NodeClass>
    <NodeClass Name="分厂二" Description="位于西南方">
      <NodeClass Name="车间三" Description="">
        <DeviceNode Name="测试设备二" Description="这是测试设备二的描述" DeviceType="10" ConnectTimeOut="1000" CreateTime="2018/8/10 23:01:28" InstallationDate="2018/8/10 23:01:28" IpAddress="127.0.0.1" Port="502" Station="1" IsAddressStartWithZero="true" IsWordReverse="false" IsStringReverse="false">
          <DeviceRequest Name="数据请求" Description="一次完整的数据请求" Address="100" Length="10" CaptureInterval="500" PraseRegularCode="B" />
        </DeviceNode>
      </NodeClass>
    </NodeClass>
  </NodeClass>
  <NodeClass Name="Server" Description="所有挂载的服务器">
    <ServerNode Name="异形服务器" Description="这是一个异形服务器" CreateTime="2018/8/8 13:29:30" Port="1234" ServerType="2" Password="" />
  </NodeClass>
  <NodeClass Name="Regular" Description="所有的解析规则的信息">
    <RegularNode Name="ABCD" Description="">
      <RegularItemNode Name="温度" Description="" Index="0" TypeCode="3" TypeLength="1" />
      <RegularItemNode Name="风俗" Description="" Index="2" TypeCode="9" TypeLength="1" />
      <RegularItemNode Name="转速" Description="" Index="14" TypeCode="9" TypeLength="1" />
      <RegularItemNode Name="机器人关节" Description="" Index="18" TypeCode="9" TypeLength="6" />
      <RegularItemNode Name="cvsdf" Description="" Index="42" TypeCode="9" TypeLength="1" />
      <RegularItemNode Name="条码" Description="条码信息" Index="6" TypeCode="11" TypeLength="8" />
      <RegularItemNode Name="开关量" Description="设备的开关量信息" Index="368" TypeCode="1" TypeLength="8" />
    </RegularNode>
    <RegularNode Name="B" Description="">
      <RegularItemNode Name="温度" Description="" Index="0" TypeCode="3" TypeLength="1" />
      <RegularItemNode Name="压力" Description="" Index="2" TypeCode="3" TypeLength="1" />
    </RegularNode>
  </NodeClass>
</Settings>

以上就是一个示例的XML文件,手动创建这样的一个数据表将会是难以想象的,所以本组件提供了可视化的数据创建中心,

Form nodeSettings = new SharpNodeSettings.View.FormNodeSetting( "settings.xml" )
nodeSettings.ShowDialog();

这样就可以显示一个窗体,显示节点配置信息了。

不仅可以配置左侧的节点,设备信息,还支持配置解析规则和可视化的显示,辅助你找到正确的字节索引。点击保存,即可生成上述示例的一个xml配置表。

我们有了这个配置文件后,如何才能解析出来,并且生成相应的设备呢?

我们可以调用 SharpNodeServer 来创建服务器应用,可以生成相应的节点信息,并且根据配置信息来请求设备,更新对应的数据。创建服务器的代码如下:

SharpNodeServer sharpNodeServer = new SharpNodeServer( );
sharpNodeServer.LoadByXmlFile( "settings.xml" );
sharpNodeServer.ServerStart( 12345 );

  

这样就启动了一个最简单的服务器,主要包含实例化,加载配置,启动服务器,注意:加载配置必须放置到服务器启动之前。

怎样查看服务器的数据呢?内置了一个默认的 SimplifyNet 服务器,想要知道更多的这个服务器的内容,可以参照下面的博客:https://www.cnblogs.com/dathlin/p/7697782.html

基于 NetSimplifyClient 实现了一个通用的数据节点查看器,需要指定服务器的Ip地址和端口号:

SharpNodeSettings.View.FormNodeView form = new SharpNodeSettings.View.FormNodeView( "127.0.0.1",12345 );
form.ShowDialog();

  

如果你想实现访问单个的数据,可以使用 NetSimplifyClient 创建的Demo来访问,需要注意的是,此处请求的数据都是序列化的JSON字符串。 

在实际开发中,可能你不需要上述的配置功能,你就想实现某个PLC的设备信息是可配置的,那么也可以通过本组件实现:

SharpNodeSettings.View.FormSelectDevice selectDevice = new View.FormSelectDevice( );
if (selectDevice.ShowDialog( ) == DialogResult.OK)
{
    XElement xmlDevice = selectDevice.DeviceXml;
    // 设备的配置对象可用于存储,网络传输等等操作

    // 如果想要通过xml信息创建设备
    SharpNodeSettings.Device.DeviceCore deviceCore = SharpNodeSettings.Util.CreateFromXElement( xmlDevice );
    // 演示读取数据,此处有个问题在于如果是相同种类的PLC,应用还是很方便的,如果是不同种类的,地址模型就比较麻烦。
    HslCommunication.OperateResult<short> read = deviceCore.ReadWriteDevice.ReadInt16( "D100" );
}

  

Quick Start

按照如下的步骤走,就可以急速体验本项目所传达的核心功能价值,就可以明白本项目是否符合您的需求。启动测试之前,你需要准备个真实的设备:

  • 西门子PLC
  • 三菱PLC
  • 欧姆龙PLC
  • ModbusTcp设备

如果您没有真实的设备,也可以从网上下载个Modbus服务器软件,这里也提供一个下载地址:ModbusTcpServer.zip

下载完成后启动服务器即可。

配置Xml信息

去本项目的目录下配置设备的信息: \SharpNodeSettings\XmlFile 运行 SharpNodeSettings.Tools.exe 进行配置,已经配置了一部分,如果想要快速开始,忽略本步骤也可以。

SampleServer

本示例直接重新生成 SampleServer 项目,启动程序即可。如果想要看实际的数据信息,启动 SharpNodeSettings.NodeView项目查看 

RedisServer

本示例是在 SampleServer 的基础上添加了Redis服务器,所以需要先安装好Redis服务器,windows版本下载地址:https://github.com/MicrosoftArchive/redis/releases

当然,最好再下载安装一个redis服务器的可视化工具,此处推荐 RedisDesktopManagerhttps://github.com/uglide/RedisDesktopManager/releases

然后基于本项目,重新生成 SharpNodeSettings.RedisServer 项目,启动服务器

上述的 SharpNodeSettings.NodeView 项目依然可以查看,然后下图演示Redis

OpcUaServer

本示例是演示从PLC采集数据并且写入到OPC UA服务器中的示例,重新生成 SharpNodeSettings.OpcUaServer 项目,启动它,如果显示是否增加信任证书时,选择是即可。

首先创建OPC UA服务器项目的时候,需要根据xml文件创建对应的OPC UA节点,这部分还是比较麻烦的

        #region INodeManager Members
        /// <summary>
        /// Does any initialization required before the address space can be used.
        /// </summary>
        /// <remarks>
        /// The externalReferences is an out parameter that allows the node manager to link to nodes
        /// in other node managers. For example, the ‘Objects‘ node is managed by the CoreNodeManager and
        /// should have a reference to the root folder node(s) exposed by this node manager.
        /// </remarks>
        public override void CreateAddressSpace( IDictionary<NodeId, IList<IReference>> externalReferences )
        {
            lock (Lock)
            {
                LoadPredefinedNodes( SystemContext, externalReferences );

                IList<IReference> references = null;

                if (!externalReferences.TryGetValue( ObjectIds.ObjectsFolder, out references ))
                {
                    externalReferences[ObjectIds.ObjectsFolder] = references = new List<IReference>( );
                }

                dict_BaseDataVariableState = new Dictionary<string, BaseDataVariableState>( );
                try
                {
                    // =========================================================================================
                    //
                    // 此处需要加载本地文件,并且创建对应的节点信息,
                    //
                    // =========================================================================================
                    sharpNodeServer = new SharpNodeServer( );
                    sharpNodeServer.WriteCustomerData = ( Device.DeviceCore deviceCore, string name ) =>
                    {
                        string opcNode = "ns=2;s=" + string.Join( "/", deviceCore.DeviceNodes ) + "/" + name;
                        lock (Lock)
                        {
                            if (dict_BaseDataVariableState.ContainsKey( opcNode ))
                            {
                                dict_BaseDataVariableState[opcNode].Value = deviceCore.GetDynamicValueByName( name );
                                dict_BaseDataVariableState[opcNode].ClearChangeMasks( SystemContext, false );
                            }
                        }
                    };

                    XElement element = XElement.Load( "settings.xml" );
                    dicRegularItemNode = SharpNodeSettings.Util.ParesRegular( element );

                    AddNodeClass( null, element, references );

                    // 加载配置文件之前设置写入方法

                    sharpNodeServer.LoadByXmlFile( "settings.xml" );
                    // 最后再启动服务器信息
                    sharpNodeServer.ServerStart( 12345 );
                }
                catch (Exception e)
                {
                    Utils.Trace( e, "Error creating the address space." );
                }
            }
        }

        private void AddNodeClass( NodeState parent, XElement nodeClass, IList<IReference> references )
        {
            foreach (var xmlNode in nodeClass.Elements( ))
            {
                if (xmlNode.Name == "NodeClass")
                {
                    SharpNodeSettings.Node.NodeBase.NodeClass nClass = new SharpNodeSettings.Node.NodeBase.NodeClass( );
                    nClass.LoadByXmlElement( xmlNode );

                    FolderState son;
                    if (parent == null)
                    {
                        son = CreateFolder( null, nClass.Name );
                        son.Description = nClass.Description;
                        son.AddReference( ReferenceTypes.Organizes, true, ObjectIds.ObjectsFolder );
                        references.Add( new NodeStateReference( ReferenceTypes.Organizes, false, son.NodeId ) );
                        son.EventNotifier = EventNotifiers.SubscribeToEvents;
                        AddRootNotifier( son );

                        AddNodeClass( son, xmlNode, references );
                        AddPredefinedNode( SystemContext, son );
                    }
                    else
                    {
                        son = CreateFolder( parent, nClass.Name, nClass.Description );
                        AddNodeClass( son, xmlNode, references );
                    }
                }
                else if (xmlNode.Name == "DeviceNode")
                {
                    AddDeviceCore( parent, xmlNode );
                }
                else if (xmlNode.Name == "Server")
                {
                    AddServer( parent, xmlNode, references );
                }
            }
        }

        private void AddDeviceCore( NodeState parent, XElement device )
        {
            if (device.Name == "DeviceNode")
            {
                // 提取名称和描述信息
                string name = device.Attribute( "Name" ).Value;
                string description = device.Attribute( "Description" ).Value;

                // 创建OPC节点
                FolderState deviceFolder = CreateFolder( parent, device.Attribute( "Name" ).Value, device.Attribute( "Description" ).Value );
                // 添加Request
                foreach (var requestXml in device.Elements( "DeviceRequest" ))
                {
                    DeviceRequest deviceRequest = new DeviceRequest( );
                    deviceRequest.LoadByXmlElement( requestXml );

                    AddDeviceRequest( deviceFolder, deviceRequest );
                }
            }
        }

        private void AddServer( NodeState parent, XElement xmlNode, IList<IReference> references )
        {
            int serverType = int.Parse( xmlNode.Attribute( "ServerType" ).Value );
            if (serverType == ServerNode.ModbusServer)
            {
                NodeModbusServer serverNode = new NodeModbusServer( );
                serverNode.LoadByXmlElement( xmlNode );

                FolderState son = CreateFolder( parent, serverNode.Name, serverNode.Description );
                AddNodeClass( son, xmlNode, references );
            }
            else if (serverType == ServerNode.AlienServer)
            {
                AlienServerNode alienNode = new AlienServerNode( );
                alienNode.LoadByXmlElement( xmlNode );

                FolderState son = CreateFolder( parent, alienNode.Name, alienNode.Description );
                AddNodeClass( son, xmlNode, references );
            }
        }
        private void AddDeviceRequest( NodeState parent, DeviceRequest deviceRequest )
        {
            // 提炼真正的数据节点
            if (!dicRegularItemNode.ContainsKey( deviceRequest.PraseRegularCode )) return;
            List<RegularItemNode> regularNodes = dicRegularItemNode[deviceRequest.PraseRegularCode];

            foreach (var regularNode in regularNodes)
            {
                if (regularNode.RegularCode == RegularNodeTypeItem.Bool.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Boolean, ValueRanks.Scalar, default( bool ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Boolean, ValueRanks.OneDimension, new bool[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.Byte.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Byte, ValueRanks.Scalar, default( byte ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Byte, ValueRanks.OneDimension, new byte[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.Int16.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Int16, ValueRanks.Scalar, default( short ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Int16, ValueRanks.OneDimension, new short[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.UInt16.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.UInt16, ValueRanks.Scalar, default( ushort ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.UInt16, ValueRanks.OneDimension, new ushort[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.Int32.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Int32, ValueRanks.Scalar, default( int ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Int32, ValueRanks.OneDimension, new int[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.UInt32.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.UInt32, ValueRanks.Scalar, default( uint ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.UInt32, ValueRanks.OneDimension, new uint[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.Float.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Float, ValueRanks.Scalar, default( float ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Float, ValueRanks.OneDimension, new float[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.Int64.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Int64, ValueRanks.Scalar, default( long ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Int64, ValueRanks.OneDimension, new long[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.UInt64.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.UInt64, ValueRanks.Scalar, default( ulong ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.UInt64, ValueRanks.OneDimension, new ulong[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.Double.Code)
                {
                    if (regularNode.TypeLength == 1)
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Double, ValueRanks.Scalar, default( double ) );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                    else
                    {
                        var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.Double, ValueRanks.OneDimension, new double[regularNode.TypeLength] );
                        dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                    }
                }
                else if (regularNode.RegularCode == RegularNodeTypeItem.StringAscii.Code ||
                    regularNode.RegularCode == RegularNodeTypeItem.StringUnicode.Code ||
                    regularNode.RegularCode == RegularNodeTypeItem.StringUtf8.Code)
                {

                    var dataVariableState = CreateBaseVariable( parent, regularNode.Name, regularNode.Description, DataTypeIds.String, ValueRanks.OneDimension, string.Empty );
                    dict_BaseDataVariableState.Add( dataVariableState.NodeId.ToString( ), dataVariableState );
                }
            }

        }

        /// <summary>
        /// 创建一个新的节点,节点名称为字符串
        /// </summary>
        protected FolderState CreateFolder( NodeState parent, string name )
        {
            return CreateFolder( parent, name, string.Empty );
        }

        /// <summary>
        /// 创建一个新的节点,节点名称为字符串
        /// </summary>
        protected FolderState CreateFolder( NodeState parent, string name, string description )
        {
            FolderState folder = new FolderState( parent );

            folder.SymbolicName = name;
            folder.ReferenceTypeId = ReferenceTypes.Organizes;
            folder.TypeDefinitionId = ObjectTypeIds.FolderType;
            folder.Description = description;
            if (parent == null)
            {
                folder.NodeId = new NodeId( name, NamespaceIndex );
            }
            else
            {
                folder.NodeId = new NodeId( parent.NodeId.ToString( ) + "/" + name );
            }
            folder.BrowseName = new QualifiedName( name, NamespaceIndex );
            folder.DisplayName = new LocalizedText( name );
            folder.WriteMask = AttributeWriteMask.None;
            folder.UserWriteMask = AttributeWriteMask.None;
            folder.EventNotifier = EventNotifiers.None;

            if (parent != null)
            {
                parent.AddChild( folder );
            }

            return folder;
        }

        /// <summary>
        /// 创建一个值节点,类型需要在创建的时候指定
        /// </summary>
        protected BaseDataVariableState CreateBaseVariable( NodeState parent, string name, string description, NodeId dataType, int valueRank, object defaultValue )
        {
            BaseDataVariableState variable = new BaseDataVariableState( parent );

            variable.SymbolicName = name;
            variable.ReferenceTypeId = ReferenceTypes.Organizes;
            variable.TypeDefinitionId = VariableTypeIds.BaseDataVariableType;
            if (parent == null)
            {
                variable.NodeId = new NodeId( name, NamespaceIndex );
            }
            else
            {
                variable.NodeId = new NodeId( parent.NodeId.ToString( ) + "/" + name );
            }
            variable.Description = description;
            variable.BrowseName = new QualifiedName( name, NamespaceIndex );
            variable.DisplayName = new LocalizedText( name );
            variable.WriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
            variable.UserWriteMask = AttributeWriteMask.DisplayName | AttributeWriteMask.Description;
            variable.DataType = dataType;
            variable.ValueRank = valueRank;
            variable.AccessLevel = AccessLevels.CurrentReadOrWrite;
            variable.UserAccessLevel = AccessLevels.CurrentReadOrWrite;
            variable.Historizing = false;
            variable.Value = defaultValue;
            variable.StatusCode = StatusCodes.Good;
            variable.Timestamp = DateTime.Now;

            if (parent != null)
            {
                parent.AddChild( variable );
            }

            return variable;
        }

  

然后再启动一个 OPC UA Client的示例项目

原文地址:https://www.cnblogs.com/dathlin/p/9459633.html

时间: 2024-11-06 09:47:50

SharpNodeSettings项目,可配置的数据采集,统一的工业数据网关,OPC UA服务器开发,PLC数据发布到自身内存,redis,opc ua,以及数据可视化开发的相关文章

(C#)一个项目的配置和增删改查

一.windows窗体项目环境配置步骤 1.文件—>新建—>项目—>windows—>修改文件名/路径—>确定 2.右键添加sqlhelper.cs,再添加引用(.net):System.Configuration 3.右键添加—>新建项—>App.config(修改文件中数据库名.文件名) 4.在代码中添加using System.Data.SqlClient 二.添加DataGridView时,需要加bindingsource(绑定源) //从数据库中读取数据

VS项目属性配置实验过程

一.实验背景 cocos2d-x已经发展的相对完善了,从项目的创建.编译.运行到最后的打包都有相应的便捷工具,开发者只需要关注自己的游戏逻辑代码即可,这一点很赞,可是傻瓜式的编程,让我至今还只停留在使用vs建个空项目做个小demo的阶段,我根本不知道cocos2d-x项目究竟是如何组织的,那些项目与项目之间的关系,那些库文件的引用,那些属性的配置,那些路径设置,那些宏定义究竟是在哪里,为什么会出现两个窗口,一大片属性究竟是什么意思,,所以很有必要研究一下.现在把实验过程同大家交流一下,有什么说的

Android项目:proguard混淆之常见开源项目混淆配置

1.Gson混淆 ## ---------------------------------- ##   ########## Gson混淆    ########## ## ---------------------------------- -keepattributes Signature  -keep class sun.misc.Unsafe { *; }  -keep class com.google.gson.examples.android.model.** { *; } 2.gr

ckeditor编辑器在java项目中配置

一.基本使用: 1.所需文件架包 A. Ckeditor基本文件包,比如:ckeditor_3.6.2.zip 下载地址:http://ckeditor.com/download 2.配置使用 A.将下载下来的CKEditor压缩解压,将解压后的文件夹("ckeditor")拷贝进项目里面,比如我是放在"WebContent"的"commons"文件夹下: B.在需要使用CKEditor的页面引入CKEditor的支持javascript <

Spring Boot项目属性配置

接着上面的入门教程,我们来学习下Spring Boot的项目属性配置. 1.配置项目内置属性 属性配置主要是在application.properties文件里配置的(编写时有自动提示)这里我们将server的端口变为8888,路径加上HelloWorld: 在DeomApplication.java的页面时点击运行按钮,打开浏览器输入:http://localhost:8888/HelloWorld/hello 此时,控制台的输出信息也可以看到端口变成8888了: 之前的url已无效: 更改后

gitlab+jenkins+maven+docker持续集成(五)——Maven 项目构建配置

首先,安装插件Maven Integration plugin 接下来我们配置Global Tool Configuration 前提先在系统里安装好jdk, maven, 创建maven项目 其它配置大同小异,主要说明下这步 pom.xml 我这里的是在项目中,如果是其它路径这里直接配置好路径就可以 pom.xml配置这里略过 配置后,我们构建

maven 项目pom配置

一.什么是pom? pom作为项目对象模型.通过xml表示maven项目,使用pom.xml来实现.主要描述了项目:包括配置文件:开发者需要遵循的规则,缺陷管理系统,组织和licenses,项目的url,项目的依赖性,以及其他所有的项目相关因素.  二.基本内容: POM包括了所有的项目信息. maven 相关: pom定义了最小的maven2元素,允许groupId,artifactId,version.所有需要的元素 groupId:项目或者组织的唯一标志,并且配置时生成的路径也是由此生成,

Hibernate项目里配置环境时,jar包配置不当会对测试结果产生影响。

问题情况: 如下图所示,该图中,显示了一堆错误的jar包.这是导致了Junit4测试通过了,数据库却没反应的原因. 原因: 之所以出现这种情况,eclipse其实已经告诉了我们原因.如下图所示,这些jar包的入口消失了.换句话说就是项目无法使用这些jar包. 解决方法:把这些JAR包全部删掉,因为项目里已经有了所有的jar包.上面这些纯属多余,而且由于它们的存在,导致真正有用的JAR包不能本使用. 结果:新的数据录入了数据库. http://www.bycoder.cn/t/hibernate/

pycharm3.4 下svn 项目checkout&amp;配置

pycharm 社区版: 3.4 1. checkout 项目 注意,之前配置好:设置里面的一些配置:(以下勾勾不要勾上) 2. checkout 项目之后,做以下操作: vcs ->enable subversion version control (这步很关键,否则无法在pycharm里面checkin代码.) pycharm3.4 下svn 项目checkout&配置,布布扣,bubuko.com