OPCUA client 相关方法

using System;
using System.Threading;
using System.Threading.Tasks;
using Opc.Ua;
using Opc.Ua.Client;
using Opc.Ua.Configuration;

namespace ConsoleApp1
{
//参考至:https://github.com/dathlin/OpcUaHelper
class Program
{
/*
* 当前连接的会话
*/
private static Session m_session;

    static async Task Main1(string[] args)
    {
        /*连接地址*/
        string discoveryUrl = "opc.tcp://desktop-qk37pau:4990/FactoryTalkLinxGateway1";

        m_session = await createSession(discoveryUrl);
        /*
         * 保持活动回调方法  订阅?
         */
        //m_session.KeepAlive += new KeepAliveEventHandler(Session_KeepAlive);

        /**
         * 获取根节点
         * @Param ObjectIds.ObjectsFolder 根节点
         * @Param ReferenceTypes.Organizes 根节点的协议类型
         */
        ReferenceDescriptionCollection rootRDs = getNode(ObjectIds.ObjectsFolder, ReferenceTypes.Organizes,
            m_session);
        /**
          * 根节点数据结构及返回值探究
          */
        testRoot(rootRDs);

        /**
         * Server节点下的信息
         * @Param ReferenceTypes.Aggregates 是Server节点的协议类型
         */
        NodeId serverNode = (NodeId) rootRDs[0].NodeId;
        ReferenceDescriptionCollection serverRDs = getNode(serverNode, ReferenceTypes.Aggregates, m_session);

        /**
         * factoryTalkLinxGateway节点下的信息
         * @Param ReferenceTypes.Organizes 是factoryTalkLinxGateway节点的协议类型
         */
        NodeId ftgNode = (NodeId) rootRDs[1].NodeId;
        ReferenceDescriptionCollection ftgRDs = getNode(ftgNode, ReferenceTypes.Organizes, m_session);

        /**
         * factoryTalkLinxGateway节点下
         * xx 设备节点
         */
        NodeId xxNode = (NodeId) ftgRDs[0].NodeId;
        ReferenceDescriptionCollection xxRDs = getNode(xxNode, ReferenceTypes.Organizes, m_session);

        /**
         * xx 设备节点下
         * online 节点
         */
        NodeId onlineNode = (NodeId) xxRDs[1].NodeId;
        ReferenceDescriptionCollection onlineRDs = getNode(onlineNode, ReferenceTypes.Organizes, m_session);
        /**
         * online 节点
         * i1 节点
         */
        NodeId i1Node = (NodeId) onlineRDs[0].NodeId;
        NodeId i2Node = (NodeId) onlineRDs[1].NodeId;
        ReferenceDescriptionCollection i1RDs = getNode(i1Node, ReferenceTypes.Organizes, m_session);

        /**
         * 修改i1节点参数
         */
        overWriteNode(m_session, i1Node);

        /**
         * 获取节点的某属性
         */
        DataValueCollection DataValues = getAtrrbutes(m_session, i1Node, i2Node);

        /**
         * 获取历史数据
         */
        HistoryReadResultCollection historys = getHistory(m_session, i1Node);
    }

    static async Task Main(string[] args)
    {

// string discoveryUrl = “opc.tcp://118.24.36.220:62547/DataAccessServer”;
string discoveryUrl = “opc.tcp://DESKTOP-QK37PAU:4990/FactoryTalkLinxGateway1”;

        m_session = await createSession(discoveryUrl);
        NodeId node = new NodeId("ns=3;s=[xx]i1");
        //订阅
        subNodes(m_session, node);
        while (true)
        {
            Thread.Sleep(1000);
            Console.WriteLine("程序运行中"+DateTime.Now);
        }

    }

    /*
     * 创建应用实例 并进行配置
     */
    private static ApplicationInstance initConfig()
    {
        /**
        *不加证书验证配置会报错
        */
        var certificateValidator = new CertificateValidator();
        certificateValidator.CertificateValidation += (sender, eventArgs) =>
        {
            if (ServiceResult.IsGood(eventArgs.Error))
                eventArgs.Accept = true;
            else if (eventArgs.Error.StatusCode.Code == StatusCodes.BadCertificateUntrusted)
                eventArgs.Accept = true;
            else
                throw new Exception(string.Format("Failed to validate certificate with error code {0}: {1}",
                    eventArgs.Error.Code, eventArgs.Error.AdditionalInfo));
        };
        return new ApplicationInstance
        {
            /*
             * 指定应用类型
             */
            ApplicationType = ApplicationType.Client,
            /*
             * 配置名
             */
            ConfigSectionName = "ConnentDemoConfig",
            /*
             * 应用的个配置项
             */
            ApplicationConfiguration = new ApplicationConfiguration
            {
                ApplicationName = "ConnentDemo",
                ApplicationType = ApplicationType.Client,
                /*
                 * 证书验证配置
                 */
                CertificateValidator = certificateValidator,
                /*
                 * 服务端配置
                 */
                ServerConfiguration = new ServerConfiguration
                {
                    MaxSubscriptionCount = 100000,
                    MaxMessageQueueSize = 1000000,
                    MaxNotificationQueueSize = 1000000,
                    MaxPublishRequestCount = 10000000,
                },

                /*
                 * 安全配置
                 */
                SecurityConfiguration = new SecurityConfiguration
                {
                    AutoAcceptUntrustedCertificates = true,
                    RejectSHA1SignedCertificates = false,
                    MinimumCertificateKeySize = 1024,
                },

                TransportQuotas = new TransportQuotas
                {
                    OperationTimeout = 6000000,
                    MaxStringLength = int.MaxValue,
                    MaxByteStringLength = int.MaxValue,
                    MaxArrayLength = 65535,
                    MaxMessageSize = 419430400,
                    MaxBufferSize = 65535,
                    ChannelLifetime = -1,
                    SecurityTokenLifetime = -1
                },
                /*
                 * 客户端配置
                 */
                ClientConfiguration = new ClientConfiguration
                {
                    DefaultSessionTimeout = -1,
                    MinSubscriptionLifetime = -1,
                },

                DisableHiResClock = true
            }
        };
    }

    /*
     * TODO  
     * 事件委托  当会话有变化时会执行下面方法
     */
    private static void Session_KeepAlive(Session session, KeepAliveEventArgs e)
    {
        Console.WriteLine("Session:" + session);
        Console.WriteLine("KeepAliveEventArgs:" + e);
    }

    /**
     * 创建客户端  配置服务端
     * @Param url 服务端地址
     * @Param application 实例配置
     * @return 返回服务端配置信息
     */
    private static ConfiguredEndpoint createClient(String url, ApplicationInstance application)
    {
        Uri serverUrl = new Uri(url);
        /*节点配置   默认*/
        EndpointConfiguration configuration = EndpointConfiguration.Create();
        /*
         * @Param serverUrl 服务器 url
         * @与配置类 生成客户端连接
         */
        EndpointDescription endpointDescription = null;

        using (DiscoveryClient discoveryClient = DiscoveryClient.Create(serverUrl, configuration))
        {
            /*获取所有的节点*/
            EndpointDescriptionCollection endpoints = discoveryClient.GetEndpoints((StringCollection) null);

            /*取出起一个节点*/
            endpointDescription = endpoints[0];
        }

        EndpointConfiguration endpointConfiguration =
            EndpointConfiguration.Create(application.ApplicationConfiguration);
        ConfiguredEndpoint configuredEndpoint =
            new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration);
        return configuredEndpoint;
    }

    /**
     * 创建Session
     */
    private static async Task<Session> createSession(String Url)
    {
        /*获取应用实例  并对其进行参数配置*/
        ApplicationInstance application = initConfig();
        /*
         * 登录策略  默认匿名
         * TODO 用户名密码策略与证书登录策略未实验
         */
        IUserIdentity iUserIdentity = new UserIdentity();
        /**
          * 获取连接配置
          */
        ConfiguredEndpoint configuredEndpoint = createClient(Url, application);
        /*
         * 创建会话连接
         */
        Session session = await Session.Create(
            application.ApplicationConfiguration,
            configuredEndpoint,
            false,
            false,
            application.ApplicationConfiguration.ApplicationName,
            60000,
            iUserIdentity,
            new string[] { });
        return session;
    }

    /**
     * 设置要查找的节点
     */
    private static BrowseDescriptionCollection nodeConfig(NodeId nodeId, NodeId referenceTypeId)
    {
        /**
        * @see Opc.Ua.ObjectIds 要查找节点的定义
        * 要浏览的节点描述
        * 当页面初始化时使用 ObjectIds.ObjectsFolder 获取节点
        */
        BrowseDescription nodeToBrowse = new BrowseDescription();
        nodeToBrowse.NodeId = nodeId;
        nodeToBrowse.BrowseDirection = BrowseDirection.Forward;

        /**
         * 要查找的节点要与其协议类型匹配 不然查找不到节点信息
         * @see Opc.Ua.ReferenceTypeIds
         * Organizes 组织
         * Aggregates 合计  根节点下的server子节点使用此类型
         */
        nodeToBrowse.ReferenceTypeId = referenceTypeId;
        nodeToBrowse.IncludeSubtypes = true;
        /**
         * 查找节点的类型
         * Unspecified 不指定  则显示所有类型
         * Variable 变量 
         */
        nodeToBrowse.NodeClassMask = (uint) NodeClass.Unspecified;
        /**
         * 设置BrowseResult的返回信息
         * BrowseResultMask.All显示全部
         */
        nodeToBrowse.ResultMask = (uint) BrowseResultMask.All;

        BrowseDescriptionCollection BDCollection = new BrowseDescriptionCollection();
        BDCollection.Add(nodeToBrowse);

        return BDCollection;
    }

    /**
     * 获取根节点
     * @Param nodeId 要查找的节点
     * @Param referenceTypeId 要查找的节点的协议类型
     * @Param nodeId session 与opcServer连接的session
     * @Param nodeId results 返回值
     * @Param nodeId diagnosticInfos TODO 
     */
    private static ReferenceDescriptionCollection getNode(NodeId nodeId, NodeId referenceTypeId, Session session)
    {
        BrowseDescriptionCollection BDCollection = nodeConfig(nodeId, referenceTypeId);

// 发送请求 获取节点
session.Browse(
null,
null,
0,
BDCollection,
out BrowseResultCollection results,
out DiagnosticInfoCollection diagnosticInfos
);
return results[0].References;
}

    /**
     *  根节点
     */
    private static void testRoot(ReferenceDescriptionCollection referenceDescriptions)
    {
        foreach (var references in referenceDescriptions)
        {
            NodeId nodeId = (NodeId) references.NodeId;
            /**
             * Server节点类型为Numeric 它没有节点名和命名空间
             */
            if (nodeId.IdType == IdType.Numeric)
                continue;
            //节点名
            String name = (String) nodeId.Identifier;
            //命名空间
            int namespaceIndex = nodeId.NamespaceIndex;
        }
    }

    /**
     * 修改节点值
     */
    private static void overWriteNode(Session session, params NodeId[] nodeId)
    {
        /**
         * 修改节点数据
         * @see Opc.Ua.BuiltInType UA内置参数类型 可用于参数校验
         */
        WriteValue valueToWrite = new WriteValue();

// 要修改的节点 测试取第一个
valueToWrite.NodeId = nodeId[0];
// 要修改什么属性
valueToWrite.AttributeId = Attributes.Value;
// 修改值
valueToWrite.Value.Value = 9;
// 可省略
// valueToWrite.Value.StatusCode = StatusCodes.Good;
// valueToWrite.Value.ServerTimestamp = DateTime.MinValue;
// valueToWrite.Value.SourceTimestamp = DateTime.MinValue;

        WriteValueCollection valuesToWrite = new WriteValueCollection(1);
        valuesToWrite.Add(valueToWrite);

// 发送修改请求 TODO 为什么成功返回的状态值有一个bad
session.Write(
null,
valuesToWrite,
out StatusCodeCollection statusCodeResults,
out DiagnosticInfoCollection diagnosticInfos);
}

    /**
     * 节点属性
     */
    private static DataValueCollection getAtrrbutes(Session session, params NodeId[] nodeIds)
    {
        /**
         * 要读取的点
         */
        ReadValueIdCollection nodesToRead = new ReadValueIdCollection();
        foreach (var nodeId in nodeIds)
        {
            ReadValueId readValueId = new ReadValueId();
            readValueId.NodeId = nodeId;
            readValueId.AttributeId = Attributes.BrowseName;
            nodesToRead.Add(readValueId);
        }

        m_session.Read(
            null,
            0,
            TimestampsToReturn.Neither,
            nodesToRead,
            out DataValueCollection results,
            out DiagnosticInfoCollection diagnosticInfos);

        return results;
    }

    /**
     * 获取节点的历史数据 TODO 读取不了
     */
    private static HistoryReadResultCollection getHistory(Session session, params NodeId[] nodeIds)
    {
        HistoryReadValueIdCollection nodesToRead = new HistoryReadValueIdCollection();
        /**
         * 要查找的点
         */
        foreach (var nodeId in nodeIds)
        {
            HistoryReadValueId node = new HistoryReadValueId()
            {
                NodeId = nodeId
            };
            nodesToRead.Add(node);
        }

        /**
         * 要获取节点的信息
         */
        ReadRawModifiedDetails m_details = new ReadRawModifiedDetails
        {

// 开始时间
StartTime = new DateTime(2018, 12, 1),
// 结束时间
EndTime = new DateTime(2019, 12, 10),

            NumValuesPerNode = 1,
            IsReadModified = false,
            ReturnBounds = false
        };

        m_session.HistoryRead(
            null,
            new ExtensionObject(m_details),
            TimestampsToReturn.Both,
            false,
            nodesToRead,
            out HistoryReadResultCollection results,
            out DiagnosticInfoCollection diagnosticInfos);
        return results;
    }

    /**
     * 订阅
     */
    private static void subNodes(Session session, params NodeId[] nodeIds)
    {
        /**
         * 订阅的相关配置
         */
        Subscription subConfig = new Subscription(session.DefaultSubscription);

        subConfig.PublishingEnabled = true;
        subConfig.PublishingInterval = 0;
        subConfig.KeepAliveCount = uint.MaxValue;
        subConfig.LifetimeCount = uint.MaxValue;
        subConfig.MaxNotificationsPerPublish = uint.MaxValue;
        subConfig.Priority = 100;
        //订阅的主题key
        subConfig.DisplayName = "test";

        //要监听的点
        foreach (var node in nodeIds)
        {
            var item = new MonitoredItem
            {
                StartNodeId = node,
                AttributeId = Attributes.Value,
                DisplayName = node.ToString(),
                SamplingInterval = 100,
            };
            /**
             * 当监听点发生改变时调用的函数
             */
            item.Notification += (MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args) =>
            {
                subCallback("test", monitoredItem, args);
            };
            /**
             * 将点添加到订阅配置中
             */
            subConfig.AddItem(item);
        }

        /**
         * AddSubscription 添加订阅  
         * RemoveSubscription 删除订阅
         * 执行删除方法前要将 Subscription中的Delete方法传入true
         * 例:subConfig.Delete(true);
         */
        session.AddSubscription(subConfig);

        /**
         * TODO??
         */
        subConfig.Create();
    }
    /**
     * 当监听点发生改变时调用的函数
     */
    private static void subCallback(string key, MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args )
    {
        MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification;
        ExpandedNodeId e=notification.TypeId;
        DataValue d=notification.Value;
        NotificationMessage n=notification.Message;
    }
}

}

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值