浏览代码

OPCUA 新增当订阅的地址点没有在服务器创建订阅,则重新订阅

Shun 2 年之前
父节点
当前提交
9c529e6734

+ 2 - 1
README.md

@@ -506,4 +506,5 @@ while(true)
 
 #### 2023-11-28
 1. 优化数据类型
-2. 优化地址处理函数,严格数据质量
+2. 优化地址处理函数,严格数据质量
+3. OPCUA 新增当订阅的地址点没有在服务器创建订阅,则重新订阅

+ 1 - 1
src/YSAI.Opc/YSAI.Opc.csproj

@@ -3,7 +3,7 @@
     <TargetFrameworks>net6.0;net8.0</TargetFrameworks>
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
-    <Version>23.332.21104</Version>
+    <Version>23.332.21105</Version>
     <PackageOutputPath Condition="'$(Configuration)' == 'Release'">../YSAI.Publish/Release</PackageOutputPath>
     <PackageOutputPath Condition="'$(Configuration)' == 'Debug'">../YSAI.Publish/Debug</PackageOutputPath>
     <Authors>Shun</Authors>

+ 47 - 5
src/YSAI.Opc/ua/client/OpcUaClientOperate.cs

@@ -127,9 +127,14 @@ namespace YSAI.Opc.ua.client
         private SessionReconnectHandler? sessionReconnectHandler { get; set; }
 
         /// <summary>
-        /// 系统所有的节点信息
+        /// 系统所有的订阅节点信息
         /// </summary>
-        private ConcurrentDictionary<string, Subscription> allSubscriptions;
+        private ConcurrentDictionary<string, Subscription> allSubscriptions = new ConcurrentDictionary<string, Subscription>();
+
+        /// <summary>
+        /// 重新订阅的标识
+        /// </summary>
+        private string reSubscribeTag = "re-subscribe";
 
         /// <summary>
         /// token
@@ -460,6 +465,8 @@ namespace YSAI.Opc.ua.client
         {
             //休眠时间
             int sleep = 60000;
+            //订阅失败的地址
+            List<AddressDetails> details = new List<AddressDetails>();
             return Task.Run(() =>
             {
                 while (true)
@@ -478,9 +485,41 @@ namespace YSAI.Opc.ua.client
                         {
                             if (!monitoredItem.Status.Created)
                             {
-                                LogHelper.Error($"{monitoredItem.DisplayName} 地址未能在服务器上创建订阅,请检查地址是否正常", $"{TAG}/SubscribeCheckStatus.log", consoleShow: false);
+                                AddressDetails? addressDetails = monitoredItem.Handle as AddressDetails;
+                                if (addressDetails != null)
+                                {
+                                    details.Add(addressDetails);
+                                }
+                            }
+                        }
+                    }
+
+                    if (details.Count > 0)
+                    {
+                        LogHelper.Error($"存在 {details.Count} 个地址未能在服务器上创建订阅,正在执行重新订阅", $"{TAG}/SubscribeCheckStatus.log", consoleShow: false);
+                        //移除这些点位成功后,在来进行订阅
+                        OperateResult operateResult = RemoveSubscribe(new Address { AddressArray = details });
+                        if (operateResult.State)
+                        {
+                            operateResult = AddSubscribe(new ConcurrentDictionary<string, Address>
+                            {
+                                [reSubscribeTag] = new Address { AddressArray = details }
+                            });
+                            if (operateResult.State)
+                            {
+                                LogHelper.Info($"重新订阅成功", $"{TAG}/SubscribeCheckStatus.log", consoleShow: false);
+                            }
+                            else
+                            {
+                                LogHelper.Error($"重新订阅失败,{operateResult.Message}", $"{TAG}/SubscribeCheckStatus.log", consoleShow: false);
                             }
                         }
+                        else
+                        {
+                            LogHelper.Error($"重新订阅失败,{operateResult.Message}", $"{TAG}/SubscribeCheckStatus.log", consoleShow: false);
+                        }
+                        //清空
+                        details.Clear();
                     }
 
                     Thread.Sleep(sleep);
@@ -1061,6 +1100,7 @@ namespace YSAI.Opc.ua.client
                     return Break("AddSubscribe", false, $"地址不能为空");
                 }
 
+                //移除虚拟点
                 List<AddressDetails> Nodes = p.Value.RemoveVirtualAddress();
 
                 try
@@ -1072,6 +1112,8 @@ namespace YSAI.Opc.ua.client
                         //判断是否存在此节点订阅
                         for (int i = 0; i < Nodes.Count; i++)
                         {
+                            if (!Nodes[i].IsEnable) continue;
+
                             foreach (var alls in allSubscriptions)
                             {
                                 //节点与键对应
@@ -1111,6 +1153,7 @@ namespace YSAI.Opc.ua.client
                             if (!item.IsEnable) continue;
 
                             MonitoredItem monitoredItem = new MonitoredItem(allSubscriptions[Tag].DefaultItem);
+                            monitoredItem.Handle = item; //分配给被监视项的本地句柄
                             monitoredItem.StartNodeId = new NodeId(item.AddressName);  //标识要监视的节点的浏览路径的开始节点
                             monitoredItem.AttributeId = Attributes.Value;  //要监视的属性
                             monitoredItem.SamplingInterval = basics.SamplingInterval;  //多少秒采集一次数据
@@ -1162,6 +1205,7 @@ namespace YSAI.Opc.ua.client
                             if (!item.IsEnable) continue;
 
                             MonitoredItem monitoredItem = new MonitoredItem(subscription.DefaultItem);
+                            monitoredItem.Handle = item; //分配给被监视项的本地句柄
                             monitoredItem.StartNodeId = new NodeId(item.AddressName);  //标识要监视的节点的浏览路径的开始节点
                             monitoredItem.AttributeId = Attributes.Value;  //要监视的属性
                             monitoredItem.SamplingInterval = basics.SamplingInterval;  //多少秒采集一次数据
@@ -1543,8 +1587,6 @@ namespace YSAI.Opc.ua.client
                 {
                     return Break("On", false, "已连接");
                 }
-                //实例化对象
-                allSubscriptions = new ConcurrentDictionary<string, Subscription>();
                 //OPCUA证书验证
                 CertificateValidator certificateValidator = new CertificateValidator();
                 //当发生证书验证错误时引发

+ 16 - 0
src/YSAI.Rest/RestData.cs

@@ -0,0 +1,16 @@
+namespace YSAI.Rest
+{
+    public class RestData
+    {
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        public class Basics
+        {
+            /// <summary>
+            /// 地址
+            /// </summary>
+            public string Uri { get; set; }
+        }
+    }
+}

+ 6 - 0
src/YSAI.Rest/RestOperate.cs

@@ -0,0 +1,6 @@
+namespace YSAI.Rest
+{
+    public class RestOperate
+    {
+    }
+}

+ 0 - 12
src/YSAI.Rest/client/Class1.cs

@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace YSAI.Rest.client
-{
-    internal class Class1
-    {
-    }
-}

+ 0 - 12
src/YSAI.Rest/service/Class1.cs

@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace YSAI.Rest.service
-{
-    internal class Class1
-    {
-    }
-}

+ 35 - 29
src/YSAI.Test.All/Program.cs

@@ -4,6 +4,7 @@ using YSAI.Core.script;
 using YSAI.Log;
 using YSAI.Model.data;
 using YSAI.Model.@enum;
+using YSAI.Mqtt.service;
 using YSAI.Opc.ua.client;
 using YSAI.Unility;
 
@@ -26,23 +27,23 @@ List<string> ReadCsv(string path, bool hasTitle)
     return lines;
 }
 
-////启动两个服务端
+//启动两个服务端
 
-//Console.WriteLine(MqttServiceOperate.Instance(new MqttServiceData.Basics
-//{
-//    MaxNumber = 1000,
-//    Password = "ysai",
-//    UserName = "ysai",
-//    Port = 8881
-//}).On().ToJson().JsonFormatting());
+Console.WriteLine(MqttServiceOperate.Instance(new MqttServiceData.Basics
+{
+    MaxNumber = 1000,
+    Password = "ysai",
+    UserName = "ysai",
+    Port = 8881
+}).On().ToJson().JsonFormatting());
 
-//Console.WriteLine(MqttServiceOperate.Instance(new MqttServiceData.Basics
-//{
-//    MaxNumber = 1000,
-//    Password = "ysai",
-//    UserName = "ysai",
-//    Port = 8882
-//}).On().ToJson().JsonFormatting());
+Console.WriteLine(MqttServiceOperate.Instance(new MqttServiceData.Basics
+{
+    MaxNumber = 1000,
+    Password = "ysai",
+    UserName = "ysai",
+    Port = 8882
+}).On().ToJson().JsonFormatting());
 
 
 
@@ -184,20 +185,25 @@ while (true)
     OperateResult operateResult = opcUaClientOperate.Subscribe(address);
     Console.WriteLine(operateResult.ToJson().JsonFormatting());
     Console.ReadLine();
-    operateResult = opcUaClientOperate.UnSubscribe(address);
-    Console.WriteLine(operateResult.ToJson().JsonFormatting());
-    Console.ReadLine();
-    address = new Address();
-    address.SN = Guid.NewGuid().ToString();
-    address.CreationTime = DateTime.Now;
-    address.AddressArray = new List<AddressDetails>();
-    address.AddressArray.Add(new AddressDetails()
-    {
-        AddressName = $"6666",
-        SN = Guid.NewGuid().ToString()
-    });
-    operateResult = opcUaClientOperate.Subscribe(address);
-    Console.WriteLine(operateResult.ToJson().JsonFormatting());
+
+    //OperateResult operateResult = opcUaClientOperate.Subscribe(address);
+    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
+    //Console.ReadLine();
+
+    //operateResult = opcUaClientOperate.UnSubscribe(address);
+    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
+    //Console.ReadLine();
+    //address = new Address();
+    //address.SN = Guid.NewGuid().ToString();
+    //address.CreationTime = DateTime.Now;
+    //address.AddressArray = new List<AddressDetails>();
+    //address.AddressArray.Add(new AddressDetails()
+    //{
+    //    AddressName = $"6666",
+    //    SN = Guid.NewGuid().ToString()
+    //});
+    //operateResult = opcUaClientOperate.Subscribe(address);
+    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
 
 }
 

+ 1 - 1
src/YSAI.Test.All/YSAI.Test.All.csproj

@@ -9,7 +9,7 @@
   </PropertyGroup>
 
   <ItemGroup>
-    <!--<ProjectReference Include="..\YSAI.Mqtt\YSAI.Mqtt.csproj" />-->
+    <ProjectReference Include="..\YSAI.Mqtt\YSAI.Mqtt.csproj" />
     <ProjectReference Include="..\YSAI.Opc\YSAI.Opc.csproj" />
   </ItemGroup>