Procházet zdrojové kódy

1. 新增数据类型DataTime、Time、Date
2. 新增倍福客户端
3.版本更新,细节优化

Shun před 2 roky
rodič
revize
dc0d320bb8
31 změnil soubory, kde provedl 1003 přidání a 110 odebrání
  1. 24 0
      src/YSAI.DAQ/YSAI.Beckhoff/YSAI.Beckhoff.csproj
  2. 41 0
      src/YSAI.DAQ/YSAI.Beckhoff/client/BeckhoffClientData.cs
  3. 703 0
      src/YSAI.DAQ/YSAI.Beckhoff/client/BeckhoffClientOperate.cs
  4. 2 2
      src/YSAI.DAQ/YSAI.Can/YSAI.Can.csproj
  5. 1 1
      src/YSAI.DAQ/YSAI.Core/YSAI.Core.csproj
  6. 16 1
      src/YSAI.DAQ/YSAI.Core/enum/Enums.cs
  7. 1 1
      src/YSAI.DAQ/YSAI.Core/subscribe/SubscribeData.cs
  8. 14 0
      src/YSAI.DAQ/YSAI.DAQ.sln
  9. 2 2
      src/YSAI.DAQ/YSAI.DB/YSAI.DB.csproj
  10. 1 1
      src/YSAI.DAQ/YSAI.DaqManage/YSAI.DaqManage.csproj
  11. 1 5
      src/YSAI.DAQ/YSAI.Kafka/KafkaOperate.cs
  12. 2 2
      src/YSAI.DAQ/YSAI.Kafka/YSAI.Kafka.csproj
  13. 7 0
      src/YSAI.DAQ/YSAI.Mitsubishi/Class1.cs
  14. 9 0
      src/YSAI.DAQ/YSAI.Mitsubishi/YSAI.Mitsubishi.csproj
  15. 2 2
      src/YSAI.DAQ/YSAI.Modbus/YSAI.Modbus.csproj
  16. 2 2
      src/YSAI.DAQ/YSAI.Mqtt/YSAI.Mqtt.csproj
  17. 2 2
      src/YSAI.DAQ/YSAI.Netty/YSAI.Netty.csproj
  18. 2 2
      src/YSAI.DAQ/YSAI.Opc/YSAI.Opc.csproj
  19. 1 1
      src/YSAI.DAQ/YSAI.Opc/da/client/OpcDaClientData.cs
  20. 2 0
      src/YSAI.DAQ/YSAI.Opc/da/client/OpcDaClientOperate.cs
  21. 1 1
      src/YSAI.DAQ/YSAI.Opc/ua/client/OpcUaClientData.cs
  22. 2 0
      src/YSAI.DAQ/YSAI.Opc/ua/client/OpcUaClientOperate.cs
  23. 0 3
      src/YSAI.DAQ/YSAI.Pack.Param/Program.cs
  24. 2 2
      src/YSAI.DAQ/YSAI.RabbitMQ/YSAI.RabbitMQ.csproj
  25. 1 1
      src/YSAI.DAQ/YSAI.RelayManage/YSAI.RelayManage.csproj
  26. 2 2
      src/YSAI.DAQ/YSAI.S7/YSAI.S7.csproj
  27. 0 6
      src/YSAI.DAQ/YSAI.S7/client/S7ClientOperate.cs
  28. 69 61
      src/YSAI.DAQ/YSAI.Test.All/Program.cs
  29. 89 9
      src/YSAI.DAQ/YSAI.Test.Console/Program.cs
  30. 1 0
      src/YSAI.DAQ/YSAI.Test.Console/YSAI.Test.Console.csproj
  31. 1 1
      src/YSAI.DAQ/YSAI.Test/YSAI.Test.csproj

+ 24 - 0
src/YSAI.DAQ/YSAI.Beckhoff/YSAI.Beckhoff.csproj

@@ -0,0 +1,24 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+	<ItemGroup>
+		<PackageReference Include="Beckhoff.TwinCAT.Ads" Version="6.1.86" />
+		<PackageReference Include="Beckhoff.TwinCAT.Ads.Reactive" Version="6.1.86" />
+		<PackageReference Include="Beckhoff.TwinCAT.Ads.Server" Version="6.1.86" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.63" />
+	</ItemGroup>
+
+	<ItemGroup>
+	  <Folder Include="service\" />
+	</ItemGroup>
+
+	<!--<ItemGroup>
+    <ProjectReference Include="..\YSAI.Core\YSAI.Core.csproj" />
+  </ItemGroup>-->
+
+</Project>

+ 41 - 0
src/YSAI.DAQ/YSAI.Beckhoff/client/BeckhoffClientData.cs

@@ -0,0 +1,41 @@
+using Newtonsoft.Json.Converters;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Text.Json.Serialization;
+using System.Threading.Tasks;
+using YSAI.Core.subscription;
+using YSAI.Unility;
+
+namespace YSAI.Beckhoff.client
+{
+    /// <summary>
+    /// 倍福基础数据
+    /// </summary>
+    public class BeckhoffClientData
+    {
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        public class Basics : SubscribeData.SCData
+        {
+            /// <summary>
+            /// 唯一标识符
+            /// </summary>
+            [Description("唯一标识符")]
+            public string? SN { get; set; } = Guid.NewGuid().ToNString();
+            /// <summary>
+            /// 设备的网络ID
+            /// </summary>
+            [Description("设备的网络ID")]
+            public string AmsNetID { get; set; } = "192.168.66.130.1.1";
+            /// <summary>
+            /// 端口
+            /// </summary>
+            [Description("端口")]
+            public int Port { get; set; } = 851;
+        }
+    }
+}

+ 703 - 0
src/YSAI.DAQ/YSAI.Beckhoff/client/BeckhoffClientOperate.cs

@@ -0,0 +1,703 @@
+using System.Collections.Concurrent;
+using System.Net;
+using System.Net.Sockets;
+using TwinCAT.Ads;
+using TwinCAT.PlcOpen;
+using YSAI.Core.data;
+using YSAI.Core.@interface;
+using YSAI.Core.virtualAddress;
+using YSAI.Unility;
+using TwinCAT.TypeSystem;
+using System.Net.Http.Headers;
+using Newtonsoft.Json.Linq;
+using System.Reflection.Metadata;
+using TwinCAT.Ads.TypeSystem;
+using TwinCAT;
+
+namespace YSAI.Beckhoff.client
+{
+    /// <summary>
+    /// 倍福PLC
+    /// </summary>
+    public class BeckhoffClientOperate : IBaseAbstract, IDaq
+    {
+        protected override string TAG => "BeckhoffOperate";
+        /// <summary>
+        /// 锁
+        /// </summary>
+        private static readonly object Lock = new object();
+        /// <summary>
+        /// 自身对象集合
+        /// </summary>
+        private static List<BeckhoffClientOperate> ThisObjList = new List<BeckhoffClientOperate>();
+
+        /// <summary>
+        /// 单例模式
+        /// </summary>
+        /// <returns></returns>
+        public static BeckhoffClientOperate Instance(BeckhoffClientData.Basics basics)
+        {
+            if (ThisObjList.Count >= MaxInstanceCount)
+            {
+                throw new Exception(ExceedMaxInstanceCountTips);
+            }
+            BeckhoffClientOperate? exp = ThisObjList.FirstOrDefault(c => c.basics.Comparer(basics).result);
+            if (exp == null)
+            {
+                lock (Lock)
+                {
+                    if (ThisObjList.Count(c => c.basics.Comparer(basics).result) > 0)
+                    {
+                        return ThisObjList.First(c => c.basics.Comparer(basics).result);
+                    }
+                    else
+                    {
+                        BeckhoffClientOperate exp2 = new BeckhoffClientOperate(basics);
+                        ThisObjList.Add(exp2);
+                        return exp2;
+                    }
+                }
+            }
+            return exp;
+        }
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="basics"></param>
+        public BeckhoffClientOperate(BeckhoffClientData.Basics basics)
+        {
+            this.basics = basics;
+        }
+
+        /// <summary>
+        /// 基础数据
+        /// </summary>
+        private BeckhoffClientData.Basics basics { get; set; }
+        /// <summary>
+        /// 虚拟地址
+        /// </summary>
+        private VirtualAddressManage VAM = new VirtualAddressManage();
+
+        /// <summary>
+        /// 全局令牌
+        /// </summary>
+        private CancellationTokenSource Cts = new CancellationTokenSource();
+        /// <summary>
+        /// ads客户端
+        /// </summary>
+        private AdsClient adsClient;
+        /// <summary>
+        /// 通知句柄容器
+        /// </summary>
+        private ConcurrentDictionary<uint, AddressDetails> NotificationHandleIoc = new ConcurrentDictionary<uint, AddressDetails>();
+
+        /// <summary>
+        /// 任务集合
+        /// </summary>
+        private ConcurrentDictionary<CancellationTokenSource, Task> TaskArray;
+        /// <summary>
+        /// 数据队列
+        /// </summary>
+        private ConcurrentQueue<AdsNotificationExEventArgs> DataQueue;
+        /// <summary>
+        /// 任务处理
+        /// </summary>
+        /// <param name="token">任务令牌</param>
+        /// <returns>任务</returns>
+        private Task TaskHandle(CancellationTokenSource token)
+        {
+            //起个新线程处理
+            return Task.Factory.StartNew(() =>
+            {
+                while (!token.IsCancellationRequested)
+                {
+                    //队列数据
+                    AdsNotificationExEventArgs? queueData;
+                    while (DataQueue.TryDequeue(out queueData))
+                    {
+                        if (queueData != null && !token.IsCancellationRequested)
+                        {
+                            try
+                            {
+                                //地址详情
+                                AddressDetails addressDetails = queueData.UserData as AddressDetails;
+                                //得到的数据
+                                string value = queueData.Value.ToString();
+                                //设置参数
+                                ConcurrentDictionary<string, AddressValue> param = new ConcurrentDictionary<string, AddressValue>();
+                                //处理数据
+                                AddressValue addressValue = YSAI.Core.handler.AddressHandler.ExecuteDispose(addressDetails, value);  //数据 
+                                //添加或更新
+                                param.AddOrUpdate(addressDetails.AddressName, addressValue, (k, v) => addressValue);
+
+                                //响应
+                                OnEventHandler(this, new EventResult(true, $"点位数据更新", param, Core.@enum.ResultType.KeyValue));
+                            }
+                            catch (Exception ex)
+                            {
+                                OnEventHandler(this, new EventResult(false, $"异常:{ex.Message}"));
+                            }
+                        }
+                    }
+                    //队列里面的数据处理完休息一下
+                    Thread.Sleep(basics.TaskHandleInterval);
+                }
+            }, token.Token);
+        }
+
+        #region 事件
+        /// <summary>
+        /// 当符号版本发生变化时发生。
+        /// </summary>
+        private void AdsClient_AdsSymbolVersionChanged(object? sender, AdsSymbolVersionChangedEventArgs e)
+        {
+            OnEventHandler(sender, new EventResult(true, "版本更新", e, Core.@enum.ResultType.Object));
+        }
+
+        /// <summary>
+        /// 当从AdsServer收到通知取消注册/无效时发生
+        /// </summary>
+        private void AdsClient_AdsNotificationsInvalidated(object? sender, AdsNotificationsInvalidatedEventArgs e)
+        {
+            OnEventHandler(sender, new EventResult(true, "订阅/取消订阅", e, Core.@enum.ResultType.Object));
+        }
+
+        /// <summary>
+        /// 当ADS设备向客户端发送通知时发生
+        /// </summary>
+        private void AdsClient_AdsNotificationEx(object? sender, AdsNotificationExEventArgs e)
+        {
+            DataQueue.Enqueue(e);
+        }
+
+        /// <summary>
+        /// 数据变更通知
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        //private void Symbol_ValueChanged(object? sender, ValueChangedEventArgs e)
+        //{
+            
+        //}
+
+        /// <summary>
+        /// 在通知管理期间发生异常时发生
+        /// </summary>
+        private void AdsClient_AdsNotificationError(object? sender, AdsNotificationErrorEventArgs e)
+        {
+            OnEventHandler(sender, new EventResult(true, "订阅发生异常", e, Core.@enum.ResultType.Object));
+        }
+
+        /// <summary>
+        /// ADS状态改变时发生
+        /// </summary>
+        private void AdsClient_AdsStateChanged(object? sender, AdsStateChangedEventArgs e)
+        {
+            OnEventHandler(sender, new EventResult(true, "状态已改变", e, Core.@enum.ResultType.Object));
+        }
+        /// <summary>
+        /// 当连接状态已更改时发生
+        /// </summary>
+        private void AdsClient_ConnectionStateChanged(object? sender, TwinCAT.ConnectionStateChangedEventArgs e)
+        {
+            OnEventHandler(sender, new EventResult(true, "连接状态已改变", e, Core.@enum.ResultType.Object));
+        }
+
+        /// <summary>
+        /// 路由器状态改变事件
+        /// </summary>
+        private void AdsClient_RouterStateChanged(object? sender, AmsRouterNotificationEventArgs e)
+        {
+            OnEventHandler(sender, new EventResult(true, "路由器状态改变事件", e, Core.@enum.ResultType.Object));
+        }
+        #endregion
+
+        /// <summary>
+        /// 释放
+        /// </summary>
+        public void Dispose()
+        {
+            Off();
+            GC.Collect();
+            GC.SuppressFinalize(this);
+            ThisObjList.Remove(this);
+        }
+
+        public OperateResult GetStatus()
+        {
+            if (adsClient != null && adsClient.IsConnected)
+            {
+                return Break(Depart("GetStatus"),true,"已连接");
+            }
+            return Break(Depart("GetStatus"), false, "未连接");
+        }
+
+        public Task<OperateResult> GetStatusAsync()
+        {
+            return Task.Run(()=> GetStatus());
+        }
+
+        public OperateResult Off()
+        {
+            string SN = Depart("Off");
+            try
+            {
+                if (adsClient == null || !adsClient.IsConnected)
+                {
+                    return Break(SN, false, "未连接");
+                }
+                if (Cts != null)
+                {
+                    Cts.Cancel();
+                }
+                if (NotificationHandleIoc.Count > 0)
+                {
+                    NotificationHandleIoc.Clear();
+                }
+                //任务清空
+                if (TaskArray != null)
+                {
+                    foreach (var item in TaskArray)
+                    {
+                        item.Key.Cancel();
+                    }
+                    foreach (var item in TaskArray)
+                    {
+                        item.Value.Wait();
+                        item.Value.Dispose();
+                    }
+                    TaskArray.Clear();
+                    TaskArray = null;
+                }
+                //队列数据清空
+                if (DataQueue != null)
+                {
+                    DataQueue.Clear();
+                    DataQueue = null;
+                }
+                adsClient.Close();
+                adsClient.Dispose();
+                adsClient = null;
+                return Break(SN, true);
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+
+        public Task<OperateResult> OffAsync()
+        {
+            return Task.Run(() => Off());
+        }
+
+        public OperateResult On()
+        {
+            string SN = Depart("On");
+            try
+            {
+                if (adsClient != null && adsClient.IsConnected)
+                {
+                    return Break(SN, false, "已连接");
+                }
+
+                //当队列为空,初始化队列
+                if (DataQueue == null)
+                {
+                    DataQueue = new ConcurrentQueue<AdsNotificationExEventArgs>();
+                }
+
+                //任务为空创建任务
+                if (TaskArray == null)
+                {
+                    TaskArray = new ConcurrentDictionary<CancellationTokenSource, Task>();
+                    //创建任务
+                    for (int i = 0; i < basics.TaskNumber; i++)
+                    {
+                        CancellationTokenSource token = new CancellationTokenSource();
+                        TaskArray.TryAdd(token, TaskHandle(token));
+                    }
+                }
+
+                //实例化对象
+                adsClient = new AdsClient();
+                //连接到服务器
+                adsClient.Connect(new AmsNetId(basics.AmsNetID), basics.Port);
+                //事件注册
+                adsClient.AdsNotificationError += AdsClient_AdsNotificationError;
+                adsClient.AdsNotificationEx += AdsClient_AdsNotificationEx;
+                adsClient.AdsNotificationsInvalidated += AdsClient_AdsNotificationsInvalidated;
+                adsClient.AdsStateChanged+= AdsClient_AdsStateChanged;
+                adsClient.AdsSymbolVersionChanged+= AdsClient_AdsSymbolVersionChanged;
+                adsClient.ConnectionStateChanged+= AdsClient_ConnectionStateChanged;
+                adsClient.RouterStateChanged += AdsClient_RouterStateChanged;
+
+                return Break(SN,true);
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+
+        public Task<OperateResult> OnAsync()
+        {
+            return Task.Run(() => On());
+        }
+
+        public OperateResult Read(Address address)
+        {
+            string SN = Depart("Read");
+            try
+            {
+                if (adsClient == null || !adsClient.IsConnected)
+                {
+                    return Break(SN, false, "未连接");
+                }
+                //节点数据
+                ConcurrentDictionary<string, AddressValue> param = new ConcurrentDictionary<string, AddressValue>();
+                //遍历
+                foreach (var item in address.AddressArray)
+                {
+                    //是不是虚拟地址
+                    bool IsVA = false;
+                    //初始化虚拟地址
+                    VAM.InitVirtualAddress(item, out IsVA);
+                    //值
+                    string? Value = string.Empty;
+
+                    if (IsVA)
+                    {
+                        Value = VAM.Read(item);
+                    }
+                    else
+                    {
+                        //先获取句柄
+                        ResultHandle handle = adsClient.CreateVariableHandleAsync(item.AddressName, Cts.Token).Result;
+                        //获取到的值
+                        ResultAnyValue resultAnyValue = null;
+                        //时间格式读取
+                        byte[] readBuffer = new byte[8];
+                        //时间格式返回值
+                        ResultRead resultRead = null;
+                        //判断是否正常
+                        if (handle.Succeeded)
+                        {
+                            //获取到了句柄
+                            switch (item.AddressDataType)
+                            {
+                                case Core.@enum.DataType.Bool:
+                                    resultAnyValue = adsClient.ReadAnyAsync(handle.Handle, typeof(bool), Cts.Token).Result;
+                                    break;
+                                case Core.@enum.DataType.String:
+                                case Core.@enum.DataType.Char:
+                                    resultAnyValue = adsClient.ReadAnyStringAsync(handle.Handle, byte.MaxValue, StringMarshaler.DefaultEncoding, Cts.Token).Result;
+                                    break;
+                                case Core.@enum.DataType.Double:
+                                case Core.@enum.DataType.Float:
+                                    resultAnyValue = adsClient.ReadAnyAsync(handle.Handle, typeof(double), Cts.Token).Result;
+                                    break;
+                                case Core.@enum.DataType.Int:
+                                    resultAnyValue = adsClient.ReadAnyAsync(handle.Handle, typeof(uint), Cts.Token).Result;
+                                    break;
+                                case Core.@enum.DataType.DateTime:
+                                    resultAnyValue = adsClient.ReadAnyAsync(handle.Handle, typeof(DateTime), Cts.Token).Result;
+                                    break;
+                                case Core.@enum.DataType.Time:
+                                    resultRead = adsClient.ReadAsync(handle.Handle, readBuffer.AsMemory(0, TIME.MarshalSize), Cts.Token).Result;
+                                    if (resultRead.Succeeded)
+                                    {
+                                        TIME plcTime = null;
+                                        PrimitiveTypeMarshaler.Default.Unmarshal(readBuffer.AsSpan(0, TIME.MarshalSize), out plcTime);
+                                        if (plcTime != null)
+                                        {
+                                            Value = plcTime.Time.ToString();
+                                        }
+                                    }
+                                    break;
+                                case Core.@enum.DataType.Date:
+                                    resultRead = adsClient.ReadAsync(handle.Handle, readBuffer.AsMemory(0, TIME.MarshalSize), Cts.Token).Result;
+                                    if (resultRead.Succeeded)
+                                    {
+                                        DATE plcDate = null;
+                                        PrimitiveTypeMarshaler.Default.Unmarshal(readBuffer.AsSpan(0, TIME.MarshalSize), out plcDate);
+                                        if (plcDate != null)
+                                        {
+                                            Value = plcDate.ToString();
+                                        }
+                                    }
+                                    break;
+                                default:
+                                    Value = $"不支持{item.AddressDataType}类型读取";
+                                    break;
+                            }
+                        }
+                        else
+                        {
+                            Value = $"未获取到句柄ID";
+                        }
+
+                        if (resultAnyValue != null)
+                        {
+                            if (resultAnyValue.Succeeded)
+                            {
+                                Value = resultAnyValue.Value.ToString();
+                            }
+                        }
+
+                        //数据处理
+                        AddressValue addressValue = Core.handler.AddressHandler.ExecuteDispose(item, Value);
+
+                        //数据添加
+                        param.AddOrUpdate(item.AddressName, addressValue, (k, v) => addressValue);
+                    }
+                }
+
+                if (param.Count > 0)
+                {
+                    //返回读取的数据 
+                    return Break(SN, true, RData: param, RType: Core.@enum.ResultType.KeyValue);
+                }
+                else
+                {
+                    return Break(SN, false, "读取失败");
+                }
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+
+        public Task<OperateResult> ReadAsync(Address address)
+        {
+            return Task.Run(() => Read(address));
+        }
+
+        public OperateResult Subscribe(Address address)
+        {
+            string SN = Depart("Subscribe");
+            try
+            {
+                if (adsClient == null || !adsClient.IsConnected)
+                {
+                    return Break(SN, false, "未连接");
+                }
+                if (address == null || address.AddressArray?.Count <= 0)
+                {
+                    return Break(SN, false, "参数不能为空");
+                }
+                //失败消息
+                List<string> FailMessage = new List<string>();
+                foreach (var item in address.AddressArray)
+                {
+                    //异步通知结果
+                    ResultHandle resultHandle = null;
+                    Type type = null;
+                    switch (item.AddressDataType)
+                    {
+                        case Core.@enum.DataType.Bool:
+                            type = typeof(bool); 
+                            break;
+                        case Core.@enum.DataType.String:
+                        case Core.@enum.DataType.Char:
+                            type = typeof(string);
+                            break;
+                        case Core.@enum.DataType.Double:
+                        case Core.@enum.DataType.Float:
+                            type = typeof(double);
+                            break;
+                        case Core.@enum.DataType.Int:
+                            type = typeof(uint);
+                            break;
+                        case Core.@enum.DataType.DateTime:
+                            type = typeof(DateTime);
+                            break;
+                        case Core.@enum.DataType.Date:
+                            type = typeof(DateTimeOffset);
+                            break;
+                        case Core.@enum.DataType.Time:
+                            type = typeof(TimeSpan);
+                            break;
+                    }
+                    resultHandle = adsClient.AddDeviceNotificationExAsync(item.AddressName, NotificationSettings.ImmediatelyOnChange, item, type, new int[] { byte.MaxValue }, Cts.Token).Result;
+                    if (!resultHandle.Succeeded)
+                    {
+                        FailMessage.Add($"{item.AddressName} 订阅添加失败,{resultHandle.ErrorCode}");
+                    }
+                    else
+                    {
+                        NotificationHandleIoc.AddOrUpdate(resultHandle.Handle, item, (k, v) => item);
+                    }
+                }
+                if (FailMessage.Count > 0)
+                {
+                    return Break(SN, false, FailMessage.ToJson());
+                }
+                return Break(SN, true, "订阅成功");
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+      
+
+        public Task<OperateResult> SubscribeAsync(Address address)
+        {
+            return Task.Run(() => Subscribe(address));
+        }
+
+        public OperateResult UnSubscribe(Address address)
+        {
+            string SN = Depart("UnSubscribe");
+            try
+            {
+                if (adsClient == null || !adsClient.IsConnected)
+                {
+                    return Break(SN, false, "未连接");
+                }
+                if (address == null || address.AddressArray?.Count <= 0)
+                {
+                    return Break(SN, false, "参数不能为空");
+                }
+                //失败消息
+                List<string> FailMessage = new List<string>();
+
+                foreach (var item in address.AddressArray)
+                {
+                    //通知句柄
+                    uint Handle = NotificationHandleIoc.FirstOrDefault(c => c.Value.Comparer(item).result).Key;
+
+                    //判断是否正常
+                    if (!Handle.Equals(0u))
+                    {
+                        //异步通知结果
+                        ResultAds resultAds = adsClient.DeleteDeviceNotificationAsync(Handle, Cts.Token).Result;
+                        if (!resultAds.Succeeded)
+                        {
+                            FailMessage.Add($"{item.AddressName},订阅移除失败,{resultAds.ErrorCode}");
+                        }
+                        else
+                        {
+                            //移除容器中的此此句柄
+                            NotificationHandleIoc.Remove(Handle, out _);
+                        }
+                    }
+                    else
+                    {
+                        FailMessage.Add($"{item.AddressName},未获取到句柄ID");
+                    }
+                }
+                if (FailMessage.Count > 0)
+                {
+                    return Break(SN, false, FailMessage.ToJson());
+                }
+                return Break(SN, true, "移除订阅成功");
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+
+        public Task<OperateResult> UnSubscribeAsync(Address address)
+        {
+            return Task.Run(() => UnSubscribe(address));
+        }
+
+        public OperateResult Write<V>(ConcurrentDictionary<string, V> Values)
+        {
+            string SN = Depart("Write");
+            try
+            {
+                if (adsClient == null || !adsClient.IsConnected)
+                {
+                    return Break(SN, false, "未连接");
+                }
+
+                //失败消息
+                List<string> FailMessage = new List<string>();
+
+                foreach (var item in Values)
+                {
+                    KeyValuePair<string, V> Param = item;
+                    //判断是不是虚拟点
+                    if (VAM.IsVirtualAddress(Param.Key))
+                    {
+                        if (!VAM.Write(Param.Key, Param.Value.ToString()))
+                        {
+                            FailMessage.Add($"{Param.Key},写入失败");
+                        }
+                    }
+                    else
+                    {
+                        //先获取句柄
+                        ResultHandle handle = adsClient.CreateVariableHandleAsync(Param.Key, Cts.Token).Result;
+                        //异步写入结果
+                        ResultWrite resultWrite = null;
+                        //判断是否正常
+                        if (handle.Succeeded)
+                        {
+                            if (typeof(V).Name.Contains("String"))
+                            {
+                                PrimitiveTypeMarshaler converter = new PrimitiveTypeMarshaler(StringMarshaler.DefaultEncoding);
+                                byte[] writeBuffer = new byte[System.Text.Encoding.Default.GetByteCount(Param.Value.ToString()) * 2];
+                                int byteCount = converter.Marshal(Param.Value, writeBuffer);
+                                if (byteCount > 0)
+                                {
+                                    resultWrite = adsClient.WriteAsync(handle.Handle, writeBuffer, Cts.Token).Result;
+                                    if (!resultWrite.Succeeded)
+                                    {
+                                        FailMessage.Add($"{Param.Key},写入失败,{resultWrite.ErrorCode}");
+                                    }
+                                }
+                                else
+                                {
+                                    FailMessage.Add($"{Param.Key},写入失败,字节数小于等于零");
+                                }
+                            }
+                            else if (typeof(V).Name.Contains("TimeSpan") || typeof(V).Name.Contains("DateTimeOffset") || typeof(V).Name.Contains("DateTime")) //时间||日期||时间日期
+                            {
+                                byte[] writeBuffer = new byte[8];
+                                PrimitiveTypeMarshaler.Default.Marshal(Param.Value, writeBuffer.AsSpan());
+                                resultWrite = adsClient.WriteAsync(handle.Handle, writeBuffer.AsMemory(0, TIME.MarshalSize), Cts.Token).Result;
+                                if (!resultWrite.Succeeded)
+                                {
+                                    FailMessage.Add($"{Param.Key},写入失败,{resultWrite.ErrorCode}");
+                                }
+                            }
+                            else
+                            {
+                                resultWrite = adsClient.WriteAnyAsync(handle.Handle, Param.Value, Cts.Token).Result;
+                                if (!resultWrite.Succeeded)
+                                {
+                                    FailMessage.Add($"{Param.Key},写入失败,{resultWrite.ErrorCode}");
+                                }
+                            }
+                        }
+                        else
+                        {
+                            FailMessage.Add($"{Param.Key},写入失败,未获取到句柄ID");
+                        }
+                    }
+                }
+                if (FailMessage.Count > 0)
+                {
+                    return Break(SN, false, FailMessage.ToJson());
+                }
+                return Break(SN, true, "写入成功");
+            }
+            catch (Exception ex)
+            {
+                return Break(SN, false, ex.Message, Exception: ex);
+            }
+        }
+
+        public Task<OperateResult> WriteAsync<V>(ConcurrentDictionary<string, V> Values)
+        {
+            return Task.Run(() => Write(Values));
+        }
+    }
+}

+ 2 - 2
src/YSAI.DAQ/YSAI.Can/YSAI.Can.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
 	  <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-	  <Version>1.0.0.26</Version>
+	  <Version>1.0.0.27</Version>
 	  <Authors>Shun</Authors>
 	  <Company>YSAI</Company>
 	  <Product>SCADA</Product>
@@ -17,7 +17,7 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.63" />
   </ItemGroup>
 
   <ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.Core/YSAI.Core.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
     <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-    <Version>1.0.0.61</Version>
+    <Version>1.0.0.63</Version>
     <Authors>Shun</Authors>
     <Company>YSAI</Company>
     <Product>SCADA</Product>

+ 16 - 1
src/YSAI.DAQ/YSAI.Core/enum/Enums.cs

@@ -76,7 +76,22 @@ namespace YSAI.Core.@enum
         /// 64 位无符号整数类型
         /// </summary>
         [Description("64 位无符号整数类型")]
-        Ushort
+        Ushort,
+        /// <summary>
+        /// 日期时间数据类型
+        /// </summary>
+        [Description("日期时间数据类型")]
+        DateTime,
+        /// <summary>
+        /// 日期数据类型
+        /// </summary>
+        [Description("日期数据类型")]
+        Date,
+        /// <summary>
+        /// 时间数据类型
+        /// </summary>
+        [Description("时间数据类型")]
+        Time
     }
 
     /// <summary>

+ 1 - 1
src/YSAI.DAQ/YSAI.Core/subscribe/SubscribeData.cs

@@ -63,7 +63,7 @@ namespace YSAI.Core.subscription
             /// 任务处理间隔(毫秒)
             /// </summary>
             [Description("任务处理间隔(毫秒)")]
-            public int TaskHandleInterval { get; set; } = 1000;
+            public int TaskHandleInterval { get; set; } = 100;
         }
     }
 }

+ 14 - 0
src/YSAI.DAQ/YSAI.DAQ.sln

@@ -97,6 +97,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Netty", "YSAI.Netty\YS
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "YSAI.Netty.Pack", "YSAI.Netty.Pack\YSAI.Netty.Pack.csproj", "{B2100081-54BC-4500-80D9-2A5B1CBCFD1B}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YSAI.Beckhoff", "YSAI.Beckhoff\YSAI.Beckhoff.csproj", "{B4932E85-54ED-4F1D-8773-184E3A0ADD62}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "YSAI.Mitsubishi", "YSAI.Mitsubishi\YSAI.Mitsubishi.csproj", "{DA9765D1-568D-48CE-A723-D7F10534FA22}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -255,6 +259,14 @@ Global
 		{B2100081-54BC-4500-80D9-2A5B1CBCFD1B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{B2100081-54BC-4500-80D9-2A5B1CBCFD1B}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{B2100081-54BC-4500-80D9-2A5B1CBCFD1B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B4932E85-54ED-4F1D-8773-184E3A0ADD62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B4932E85-54ED-4F1D-8773-184E3A0ADD62}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B4932E85-54ED-4F1D-8773-184E3A0ADD62}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B4932E85-54ED-4F1D-8773-184E3A0ADD62}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DA9765D1-568D-48CE-A723-D7F10534FA22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DA9765D1-568D-48CE-A723-D7F10534FA22}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DA9765D1-568D-48CE-A723-D7F10534FA22}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DA9765D1-568D-48CE-A723-D7F10534FA22}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -302,6 +314,8 @@ Global
 		{36696247-658B-445E-9C05-A815B73F248A} = {1EBA4FD7-DF52-49A0-8AA4-9E61ABC614F5}
 		{D757285D-0B7C-47C4-BC54-744B6E2A7E61} = {9D8EDBBA-7A97-4D84-9B12-7FCC2F834046}
 		{B2100081-54BC-4500-80D9-2A5B1CBCFD1B} = {1EBA4FD7-DF52-49A0-8AA4-9E61ABC614F5}
+		{B4932E85-54ED-4F1D-8773-184E3A0ADD62} = {0A264424-1AD7-49FA-B813-D96498066479}
+		{DA9765D1-568D-48CE-A723-D7F10534FA22} = {0A264424-1AD7-49FA-B813-D96498066479}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {5D5D3927-6714-40C0-84EA-44C5BA4C5E87}

+ 2 - 2
src/YSAI.DAQ/YSAI.DB/YSAI.DB.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
 	  <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-	  <Version>1.0.0.26</Version>
+	  <Version>1.0.0.27</Version>
 	  <Authors>Shun</Authors>
 	  <Company>YSAI</Company>
 	  <Product>SCADA</Product>
@@ -18,7 +18,7 @@
 		<PackageReference Include="System.Data.OracleClient" Version="1.0.8" />
 		<PackageReference Include="System.Data.SqlClient" Version="4.8.5" />
 		<PackageReference Include="System.Data.SQLite" Version="1.0.118" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.63" />
 	</ItemGroup>
 	<!--<ItemGroup>
 		<ProjectReference Include="..\YSAI.Core\YSAI.Core.csproj" />

+ 1 - 1
src/YSAI.DAQ/YSAI.DaqManage/YSAI.DaqManage.csproj

@@ -7,7 +7,7 @@
   </PropertyGroup>
 	<ItemGroup>
 		<FrameworkReference Include="Microsoft.AspNetCore.App" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.63" />
 	</ItemGroup>
 
 	<!--<ItemGroup>

+ 1 - 5
src/YSAI.DAQ/YSAI.Kafka/KafkaOperate.cs

@@ -126,10 +126,6 @@ namespace YSAI.Kafka
                             //消息已处理提交偏移量
                             Consumer?.Commit(result);
                         }
-                        else
-                        {
-                            Thread.Sleep(100);
-                        }
                     }
                 }
                 catch (Exception ex)
@@ -484,7 +480,7 @@ namespace YSAI.Kafka
 
         public OperateResult GetStatus()
         {
-            return Break(Depart("GetStatus"), true, "已连接");
+            return Break(Depart("GetStatus"), IsOpen, "已连接");
         }
 
         public Task<OperateResult> GetStatusAsync()

+ 2 - 2
src/YSAI.DAQ/YSAI.Kafka/YSAI.Kafka.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
 	  <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-	  <Version>1.0.0.27</Version>
+	  <Version>1.0.0.28</Version>
 	  <Authors>Shun</Authors>
 	  <Company>YSAI</Company>
 	  <Product>SCADA</Product>
@@ -14,7 +14,7 @@
 
   <ItemGroup>
     <PackageReference Include="Confluent.Kafka" Version="2.2.0" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.63" />
   </ItemGroup>
 	
 	<!--<ItemGroup>

+ 7 - 0
src/YSAI.DAQ/YSAI.Mitsubishi/Class1.cs

@@ -0,0 +1,7 @@
+namespace YSAI.Mitsubishi
+{
+    public class Class1
+    {
+
+    }
+}

+ 9 - 0
src/YSAI.DAQ/YSAI.Mitsubishi/YSAI.Mitsubishi.csproj

@@ -0,0 +1,9 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net6.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+
+</Project>

+ 2 - 2
src/YSAI.DAQ/YSAI.Modbus/YSAI.Modbus.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
 	  <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-	  <Version>1.0.0.26</Version>
+	  <Version>1.0.0.27</Version>
 	  <Authors>Shun</Authors>
 	  <Company>YSAI</Company>
 	  <Product>SCADA</Product>
@@ -15,7 +15,7 @@
 	<ItemGroup>
     <PackageReference Include="NModbus" Version="3.0.80" />
     <PackageReference Include="NModbus.Serial" Version="3.0.80" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.63" />
   </ItemGroup>
 
 	<!--<ItemGroup>

+ 2 - 2
src/YSAI.DAQ/YSAI.Mqtt/YSAI.Mqtt.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
 	  <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-	  <Version>1.0.0.29</Version>
+	  <Version>1.0.0.30</Version>
 	  <Authors>Shun</Authors>
 	  <Company>YSAI</Company>
 	  <Product>SCADA</Product>
@@ -15,7 +15,7 @@
   <ItemGroup>
     <PackageReference Include="MQTTnet" Version="4.3.1.873" />
     <PackageReference Include="MQTTnet.AspNetCore" Version="4.3.1.873" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.63" />
   </ItemGroup>
 
 	<!--<ItemGroup>

+ 2 - 2
src/YSAI.DAQ/YSAI.Netty/YSAI.Netty.csproj

@@ -5,7 +5,7 @@
 		<ImplicitUsings>enable</ImplicitUsings>
 		<Nullable>enable</Nullable>
 		<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-		<Version>1.0.0.1</Version>
+		<Version>1.0.0.2</Version>
 		<Authors>Shun</Authors>
 		<Company>YSAI</Company>
 		<Product>SCADA</Product>
@@ -14,6 +14,6 @@
 	<ItemGroup>
 		<PackageReference Include="DotNetty.Handlers" Version="0.7.5" />
 		<PackageReference Include="DotNetty.Transport" Version="0.7.5" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.63" />
 	</ItemGroup>
 </Project>

+ 2 - 2
src/YSAI.DAQ/YSAI.Opc/YSAI.Opc.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
 	  <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-	  <Version>1.0.0.36</Version>
+	  <Version>1.0.0.37</Version>
 	  <Authors>Shun</Authors>
 	  <Company>YSAI</Company>
 	  <Product>SCADA</Product>
@@ -13,7 +13,7 @@
   </PropertyGroup>
   <ItemGroup>
     <PackageReference Include="OPCFoundation.NetStandard.Opc.Ua" Version="1.4.372.56" />
-	<PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+	<PackageReference Include="YSAI.Core" Version="1.0.0.63" />
   </ItemGroup>
 
 

+ 1 - 1
src/YSAI.DAQ/YSAI.Opc/da/client/OpcDaClientData.cs

@@ -45,7 +45,7 @@ namespace YSAI.Opc.da.client
             /// 任务处理间隔(毫秒)
             /// </summary>
             [Description("任务处理间隔(毫秒)")]
-            public int TaskHandleInterval { get; set; } = 1000;
+            public int TaskHandleInterval { get; set; } = 100;
         }
 
         /// <summary>

+ 2 - 0
src/YSAI.DAQ/YSAI.Opc/da/client/OpcDaClientOperate.cs

@@ -758,6 +758,8 @@ namespace YSAI.Opc.da.client
                             item.Value.Wait();
                             item.Value.Dispose();
                         }
+                        TaskArray.Clear();
+                        TaskArray = null;
                     }
                     //队列数据清空
                     if (DataQueue != null)

+ 1 - 1
src/YSAI.DAQ/YSAI.Opc/ua/client/OpcUaClientData.cs

@@ -80,7 +80,7 @@ namespace YSAI.Opc.ua.client
             /// 任务处理间隔(毫秒)
             /// </summary>
             [Description("任务处理间隔(毫秒)")]
-            public int TaskHandleInterval { get; set; } = 1000;
+            public int TaskHandleInterval { get; set; } = 100;
         }
         /// <summary>
         /// 步骤枚举

+ 2 - 0
src/YSAI.DAQ/YSAI.Opc/ua/client/OpcUaClientOperate.cs

@@ -1449,6 +1449,8 @@ namespace YSAI.Opc.ua.client
                         item.Value.Wait();
                         item.Value.Dispose();
                     }
+                    TaskArray.Clear();
+                    TaskArray = null;
                 }
                 //队列数据清空
                 if (DataQueue != null)

+ 0 - 3
src/YSAI.DAQ/YSAI.Pack.Param/Program.cs

@@ -86,9 +86,6 @@ namespace YSAI.Pack.Param
                         libInstanceParams = ReflexTool.GetClassAllPropertyData<NettyClientData.Basics>();
                         break;
                 }
-
-
-
                 if (message.Equals("Modbus"))
                 {
                     string[] strings = new string[] { "Modbus-Tcp", "Modbus-Udp", "Modbus-Rtu", "Modbus-Ascii" };

+ 2 - 2
src/YSAI.DAQ/YSAI.RabbitMQ/YSAI.RabbitMQ.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
 	  <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-	  <Version>1.0.0.28</Version>
+	  <Version>1.0.0.29</Version>
 	  <Authors>Shun</Authors>
 	  <Company>YSAI</Company>
 	  <Product>SCADA</Product>
@@ -14,7 +14,7 @@
 
   <ItemGroup>
     <PackageReference Include="RabbitMQ.Client" Version="6.6.0" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.63" />
   </ItemGroup>
 
   <ItemGroup>

+ 1 - 1
src/YSAI.DAQ/YSAI.RelayManage/YSAI.RelayManage.csproj

@@ -9,7 +9,7 @@
 	<ItemGroup>
 		<PackageReference Include="RabbitMQ.Client" Version="6.6.0" />
 		<PackageReference Include="Confluent.Kafka" Version="2.2.0" />
-		<PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+		<PackageReference Include="YSAI.Core" Version="1.0.0.63" />
 		<FrameworkReference Include="Microsoft.AspNetCore.App" />
 	</ItemGroup>
 

+ 2 - 2
src/YSAI.DAQ/YSAI.S7/YSAI.S7.csproj

@@ -5,7 +5,7 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
 	  <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
-	  <Version>1.0.0.25</Version>
+	  <Version>1.0.0.26</Version>
 	  <Authors>Shun</Authors>
 	  <Company>YSAI</Company>
 	  <Product>SCADA</Product>
@@ -14,7 +14,7 @@
 
 	<ItemGroup>
     <PackageReference Include="S7netplus" Version="0.20.0" />
-    <PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+    <PackageReference Include="YSAI.Core" Version="1.0.0.63" />
   </ItemGroup>
 
 	<!--<ItemGroup>

+ 0 - 6
src/YSAI.DAQ/YSAI.S7/client/S7ClientOperate.cs

@@ -265,12 +265,6 @@ namespace YSAI.S7.client
                                     Value = $"不支持{item.AddressDataType}类型读取";
                                     break;
                             }
-
-
-                            if (string.IsNullOrEmpty(Value))
-                            {
-                                Value = "null";
-                            }
                             //switch (item.AddressDataType)
                             //{
                             //    case Core.@enum.DataType.Bool:

+ 69 - 61
src/YSAI.DAQ/YSAI.Test.All/Program.cs

@@ -1,71 +1,79 @@
-using System.Net;
-using YSAI.Core.data;
-using YSAI.Log;
-using YSAI.Netty.client;
-using YSAI.Netty.service;
-using YSAI.Unility;
-
-NettyServiceOperate nettyServiceOperate = NettyServiceOperate.Instance(new NettyServiceData.Basics
-{
-    Port = 8007,
-    SN = "1"
-});
-
-Console.WriteLine(nettyServiceOperate.On().ToJson());
-nettyServiceOperate.OnEvent += delegate (object? sender, EventResult e)
-{
-    LogHelper.Info(e.ToJson().JsonFormatting());
-};
-
-
-//转发协议
-NettyClientOperate operate1 = NettyClientOperate.Instance(new NettyClientData.Basics
-{
-    Host = "127.0.0.1",
-    Port = 8007,
-    SN = "1"
-});
-
-//NettyClientOperate operate2 = NettyClientOperate.Instance(new NettyClientData.Basics
+
+
+
+
+
+
+
+
+//using System.Net;
+//using YSAI.Core.data;
+//using YSAI.Log;
+//using YSAI.Netty.client;
+//using YSAI.Netty.service;
+//using YSAI.Unility;
+
+//NettyServiceOperate nettyServiceOperate = NettyServiceOperate.Instance(new NettyServiceData.Basics
+//{
+//    Port = 8007,
+//    SN = "1"
+//});
+
+//Console.WriteLine(nettyServiceOperate.On().ToJson());
+//nettyServiceOperate.OnEvent += delegate (object? sender, EventResult e)
+//{
+//    LogHelper.Info(e.ToJson().JsonFormatting());
+//};
+
+
+////转发协议
+//NettyClientOperate operate1 = NettyClientOperate.Instance(new NettyClientData.Basics
 //{
 //    Host = "127.0.0.1",
 //    Port = 8007,
-//    SN = "2"
+//    SN = "1"
 //});
 
-//打开
-OperateResult result = operate1.On();
-LogHelper.Info(result.ToJson().JsonFormatting());
-//result = operate2.On();
+////NettyClientOperate operate2 = NettyClientOperate.Instance(new NettyClientData.Basics
+////{
+////    Host = "127.0.0.1",
+////    Port = 8007,
+////    SN = "2"
+////});
+
+////打开
+//OperateResult result = operate1.On();
 //LogHelper.Info(result.ToJson().JsonFormatting());
+////result = operate2.On();
+////LogHelper.Info(result.ToJson().JsonFormatting());
 
-//消费
-operate1.OnEvent += delegate (object? sender, EventResult e)
-{
-    LogHelper.Info(e.ToJson().JsonFormatting());
-};
-result = operate1.Subscribe("测试");
-LogHelper.Info(result.ToJson().JsonFormatting());
-
-while (true)
-{
-    Console.WriteLine("请输入端口:");
-   string port= Console.ReadLine();
-    for (int i = 0; i < 2; i++)
-    {
-        if (i == 0)
-        {
-            //生产
-            //operate1.Produce("测试", new Random().NextDouble().ToString());
-        }
-        else
-        {
-            IPEndPoint endPoint=new IPEndPoint(IPAddress.Parse("127.0.0.1"), int.Parse(port));
-            //生产
-            Console.WriteLine(nettyServiceOperate.Send("测试", "啊啊啊啊", endPoint.ToString()).ToJson().JsonFormatting());
-        }
-    }
-}
+////消费
+//operate1.OnEvent += delegate (object? sender, EventResult e)
+//{
+//    LogHelper.Info(e.ToJson().JsonFormatting());
+//};
+//result = operate1.Subscribe("测试");
+//LogHelper.Info(result.ToJson().JsonFormatting());
+
+//while (true)
+//{
+//    Console.WriteLine("请输入端口:");
+//   string port= Console.ReadLine();
+//    for (int i = 0; i < 2; i++)
+//    {
+//        if (i == 0)
+//        {
+//            //生产
+//            //operate1.Produce("测试", new Random().NextDouble().ToString());
+//        }
+//        else
+//        {
+//            IPEndPoint endPoint=new IPEndPoint(IPAddress.Parse("127.0.0.1"), int.Parse(port));
+//            //生产
+//            Console.WriteLine(nettyServiceOperate.Send("测试", "啊啊啊啊", endPoint.ToString()).ToJson().JsonFormatting());
+//        }
+//    }
+//}
 
 
 //using YSAI.Core.subscribe.core;

+ 89 - 9
src/YSAI.DAQ/YSAI.Test.Console/Program.cs

@@ -1,4 +1,77 @@
-Console.WriteLine(  );
+
+
+
+using System.Collections.Concurrent;
+using YSAI.Beckhoff.client;
+using YSAI.Core.data;
+using YSAI.Unility;
+
+BeckhoffClientOperate beckhoffClientOperate = BeckhoffClientOperate.Instance(new BeckhoffClientData.Basics
+{
+    AmsNetID = "192.168.66.130.1.1",
+    Port = 1233
+});
+OperateResult operateResult = beckhoffClientOperate.On();
+Console.WriteLine(operateResult.ToJson().JsonFormatting());
+
+//点位地址
+Address address = new Address();
+address.SN = Guid.NewGuid().ToString();
+address.CreationTime = DateTime.Now.ToLocalTime();
+address.AddressArray = new List<AddressDetails> {
+    new AddressDetails()
+    {
+        AddressName = "Constants.bFPUSupport",
+        AddressDataType = YSAI.Core.@enum.DataType.Bool
+    }
+};
+
+
+operateResult = beckhoffClientOperate.Read(address);
+Console.WriteLine(operateResult.ToJson().JsonFormatting());
+
+
+beckhoffClientOperate.OnEvent += BeckhoffClientOperate_OnEvent;
+operateResult = beckhoffClientOperate.Subscribe(address);
+Console.WriteLine(operateResult.ToJson().JsonFormatting());
+
+
+
+
+void BeckhoffClientOperate_OnEvent(object? sender, EventResult e)
+{
+    Console.WriteLine(e.ToJson().JsonFormatting());
+}
+
+int index = 0;
+
+while (true)
+{
+    Console.ReadLine();
+    ConcurrentDictionary<string, bool> keyValuePairs = new ConcurrentDictionary<string, bool>();
+    if (index % 2 == 0)
+    {
+        keyValuePairs.TryAdd("Constants.bFPUSupport", true);
+    }
+    else
+    {
+        keyValuePairs.TryAdd("Constants.bFPUSupport", false);
+    }
+    
+
+    operateResult = beckhoffClientOperate.Write(keyValuePairs);
+    Console.WriteLine(operateResult.ToJson().JsonFormatting());
+
+    //if (index == 20)
+    //{
+    //    operateResult = beckhoffClientOperate.UnSubscribe(address);
+    //    Console.WriteLine(operateResult.ToJson().JsonFormatting());
+    //}
+
+    index++;
+}
+
+//Console.WriteLine(  );
 
 //using YSAI.Opc.ua.client;
 
@@ -649,23 +722,30 @@
 
 //Console.WriteLine();
 
-//KafkaOperate kafkaOperate = KafkaOperate.Instance(new KafkaData.Basics() 
+
+
+//using YSAI.Core.data;
+//using YSAI.Kafka;
+//using YSAI.Unility;
+
+//KafkaOperate kafkaOperate = KafkaOperate.Instance(new KafkaData.Basics()
 //{
-//    BootstrapServers= "192.168.2.140:9092",
+//    BootstrapServers = "192.168.2.221:9092",
 //});
 
-//OperateResult operateResult= kafkaOperate.On();
-////Console.WriteLine(operateResult.ToJson().JsonFormatting());
+//OperateResult operateResult = kafkaOperate.On();
+//Console.WriteLine(operateResult.ToJson().JsonFormatting());
 
 //kafkaOperate.OnEvent += KafkaOperate_OnEvent;
 
-//operateResult = kafkaOperate.Subscribe("VariableTopic");
-////Console.WriteLine(operateResult.ToJson().JsonFormatting());
+//operateResult = kafkaOperate.Subscribe("test");
+//Console.WriteLine(operateResult.ToJson().JsonFormatting());
 
 //while (true)
 //{
-//    operateResult = kafkaOperate.Produce("VariableTopic", new Random().NextDouble().ToString());
-//    //Console.WriteLine(operateResult.ToJson().JsonFormatting());
+//    Console.ReadLine();
+//    operateResult = kafkaOperate.Produce("test", new Random().NextDouble().ToString());
+//    Console.WriteLine(operateResult.ToJson().JsonFormatting());
 //}
 //void KafkaOperate_OnEvent(object? sender, EventResult e)
 //{

+ 1 - 0
src/YSAI.DAQ/YSAI.Test.Console/YSAI.Test.Console.csproj

@@ -8,6 +8,7 @@
   </PropertyGroup>
 
 	<ItemGroup>
+		<ProjectReference Include="..\YSAI.Beckhoff\YSAI.Beckhoff.csproj" />
 		<ProjectReference Include="..\YSAI.DB\YSAI.DB.csproj" />
 		<ProjectReference Include="..\YSAI.Kafka\YSAI.Kafka.csproj" />
 		<ProjectReference Include="..\YSAI.Modbus\YSAI.Modbus.csproj" />

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

@@ -17,7 +17,7 @@
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
-	<PackageReference Include="YSAI.Core" Version="1.0.0.61" />
+	<PackageReference Include="YSAI.Core" Version="1.0.0.63" />
   </ItemGroup>
 
   <ItemGroup>