diff --git a/DOAN.Admin.WebApi/appsettings.Development.json b/DOAN.Admin.WebApi/appsettings.Development.json index 1ae1546..61ba6d4 100644 --- a/DOAN.Admin.WebApi/appsettings.Development.json +++ b/DOAN.Admin.WebApi/appsettings.Development.json @@ -10,7 +10,7 @@ "dbConfigs": [ { - "Conn": "Data Source=192.168.0.58;User ID=root;Password=123456;Initial Catalog=pbl_huaxiang;Port=3306", + "Conn": "Data Source=139.224.232.211;User ID=root;Password=doantech123;Initial Catalog=pbl_huaxiang;Port=3308", //"Conn": "Data Source=10.72.80.161;User ID=root;Password=doantech123;Initial Catalog=pbl_huaxiang_v2;Port=3306", "DbType": 0, //数据库类型 MySql = 0, SqlServer = 1, Oracle = 3,PgSql = 4 "ConfigId": "0", //多租户唯一标识 diff --git a/DOAN.Admin.WebApi/appsettings.json b/DOAN.Admin.WebApi/appsettings.json index 9e26dfe..240bc29 100644 --- a/DOAN.Admin.WebApi/appsettings.json +++ b/DOAN.Admin.WebApi/appsettings.json @@ -1 +1,5 @@ -{} \ No newline at end of file +{ + "PLCConfig": { + "Address": "10.72.82.242" + } +} \ No newline at end of file diff --git a/DOAN.ServiceCore/DoanBackgroundService.cs b/DOAN.ServiceCore/DoanBackgroundService.cs index 3d91b76..75521e6 100644 --- a/DOAN.ServiceCore/DoanBackgroundService.cs +++ b/DOAN.ServiceCore/DoanBackgroundService.cs @@ -21,10 +21,11 @@ namespace DOAN.ServiceCore /// 永驻线程 /// 功能:检测传感器信号,判断箱子数 /// - public class DoanBackgroundService : IHostedService, IDisposable + public class DoanBackgroundService : BaseService, IHostedService, IDisposable { private readonly IHubContext notificationHubContext; - private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); + private readonly CancellationTokenSource _cancellationTokenSource = + new CancellationTokenSource(); private Task _executingTask; private PLCTool pLCTool; private List storagelocationList = new List(); @@ -39,13 +40,13 @@ namespace DOAN.ServiceCore public Task StartAsync(CancellationToken cancellationToken) { - Console.WriteLine($"PCL定时任务开启!"); pLCTool = new PLCTool(); pLCTool.ConnectPLC(); - - // 初始化料架层和点位表数据 - RefreshData(null); + // sql标准 + Context.Queryable(); + // 初始化料架层和点位表数据 + RefreshData(null); // 启动后台任务 _executingTask = ExecuteAsync(_cancellationTokenSource.Token); @@ -72,7 +73,10 @@ namespace DOAN.ServiceCore { if (position < 0 || position > 7) { - throw new ArgumentOutOfRangeException(nameof(position), "Position must be between 0 and 7" + position); + throw new ArgumentOutOfRangeException( + nameof(position), + "Position must be between 0 and 7" + position + ); } byte mask = (byte)(1 << position); @@ -111,24 +115,34 @@ namespace DOAN.ServiceCore // 读取按钮PLC I/O状态 foreach (PlcButton button in buttonPositionList) { - int row = button.Address - 100; int col = button.Index; - if (plcSensorValues != null && row >= 0 && row < plcSensorValues.Length && !GetInvertedBit(plcSensorValues[row], col)) + if ( + plcSensorValues != null + && row >= 0 + && row < plcSensorValues.Length + && !GetInvertedBit(plcSensorValues[row], col) + ) { // 按钮按下灭灯 if (button.Code == "灭灯按钮") { - - Storagelocation offLightstoragelocation = storagelocationList.Where(it => it.Id == button.StoragelocationId).First(); - bool isSuccess = pLCTool.WriteBit(offLightstoragelocation.PlcAddress, false); + Storagelocation offLightstoragelocation = storagelocationList + .Where(it => it.Id == button.StoragelocationId) + .First(); + bool isSuccess = pLCTool.WriteBit( + offLightstoragelocation.PlcAddress, + false + ); if (isSuccess) { offLightstoragelocation.IsLight = 0; using (var scope = DbScoped.SugarScope.CopyNew()) { - await scope.Updateable(offLightstoragelocation).ExecuteCommandAsync(); + await scope + .Updateable(offLightstoragelocation) + .ExecuteCommandAsync(); //灭灯日志 Light_Log light_Log = new Light_Log { @@ -143,7 +157,10 @@ namespace DOAN.ServiceCore await scope.Insertable(light_Log).ExecuteCommandAsync(); } } - await notificationHubContext.Clients.All.SendAsync("PBL_storagelocation_change", "手动灭灯"); + await notificationHubContext.Clients.All.SendAsync( + "PBL_storagelocation_change", + "手动灭灯" + ); } // 镜体补料按钮 if (button.Code == "镜体补料按钮") @@ -172,10 +189,16 @@ namespace DOAN.ServiceCore LayerNum = 1, CurrentPackageCount = 0, AlarmThreshold = 1, - ActionTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss").ToString(), + ActionTime = DateTime + .Now.ToString("yyyy-MM-dd HH:mm:ss") + .ToString(), }; - string alarmMessage = System.Text.Json.JsonSerializer.Serialize(alarmData); - await notificationHubContext.Clients.All.SendAsync("PBL_lack_alarm", alarmMessage); + string alarmMessage = + System.Text.Json.JsonSerializer.Serialize(alarmData); + await notificationHubContext.Clients.All.SendAsync( + "PBL_lack_alarm", + alarmMessage + ); } } else @@ -187,14 +210,15 @@ namespace DOAN.ServiceCore } } - var updateStoragelocationList = new List(); var inventoryLogs = new List(); foreach (var layerItem in storagelocationList) { // 获取这个料架层的点位表 - var layerPoints = pointPositionList.Where(it => it.FkStorageId == layerItem.Id).ToList(); + var layerPoints = pointPositionList + .Where(it => it.FkStorageId == layerItem.Id) + .ToList(); if (layerPoints.Any()) { @@ -205,9 +229,15 @@ namespace DOAN.ServiceCore int row = point.ByteNum - 100; int col = point.BitNum - 1; - if (plcSensorValues != null && row >= 0 && row < plcSensorValues.Length) + if ( + plcSensorValues != null + && row >= 0 + && row < plcSensorValues.Length + ) { - currentPackageCount += GetInvertedBit(plcSensorValues[row], col) ? 1 : 0; + currentPackageCount += GetInvertedBit(plcSensorValues[row], col) + ? 1 + : 0; } } @@ -215,22 +245,38 @@ namespace DOAN.ServiceCore int previousPackageCount = layerItem.PackageNum.GetValueOrDefault(); if (currentPackageCount > previousPackageCount) { - UpdateAndLog(layerItem, currentPackageCount, 2, "出库", inventoryLogs); + UpdateAndLog( + layerItem, + currentPackageCount, + 2, + "出库", + inventoryLogs + ); updateStoragelocationList.Add(layerItem); } else if (currentPackageCount < previousPackageCount) { - UpdateAndLog(layerItem, currentPackageCount, 1, "入库", inventoryLogs); + UpdateAndLog( + layerItem, + currentPackageCount, + 1, + "入库", + inventoryLogs + ); updateStoragelocationList.Add(layerItem); } // 补料报警触发 - if (layerItem.IsLackAlarm == 1 && currentPackageCount < layerItem.AlarmNum) + if ( + layerItem.IsLackAlarm == 1 + && currentPackageCount < layerItem.AlarmNum + ) { using (var scope = DbScoped.SugarScope.CopyNew()) { // 是否已经报警过,并且 - bool hasLastAlarm = await scope.Queryable() + bool hasLastAlarm = await scope + .Queryable() .Where(it => it.StoragelocationId == layerItem.Id) .Where(it => it.Type == 1) .Where(it => it.Status == 1) @@ -243,7 +289,8 @@ namespace DOAN.ServiceCore AlarmLog alarmLog = new AlarmLog { Id = SnowFlakeSingle.Instance.NextId().ToString(), - Name = $"镜壳需补料:{layerItem.RackCode} {layerName} 阈值{layerItem.AlarmNum}", + Name = + $"镜壳需补料:{layerItem.RackCode} {layerName} 阈值{layerItem.AlarmNum}", Code = "镜壳补料", StoragelocationId = layerItem.Id, Type = 1, @@ -259,10 +306,16 @@ namespace DOAN.ServiceCore LayerNum = layerItem.LayerNum, CurrentPackageCount = currentPackageCount, AlarmThreshold = layerItem.AlarmNum, - ActionTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss").ToString(), + ActionTime = DateTime + .Now.ToString("yyyy-MM-dd HH:mm:ss") + .ToString(), }; - string alarmMessage = System.Text.Json.JsonSerializer.Serialize(alarmData); - await notificationHubContext.Clients.All.SendAsync("PBL_lack_alarm", alarmMessage); + string alarmMessage = + System.Text.Json.JsonSerializer.Serialize(alarmData); + await notificationHubContext.Clients.All.SendAsync( + "PBL_lack_alarm", + alarmMessage + ); } } } @@ -274,19 +327,32 @@ namespace DOAN.ServiceCore { using (var scope = DbScoped.SugarScope.CopyNew()) { - await scope.Updateable(updateStoragelocationList) - .IgnoreColumns(it => new { it.IsLight, it.IsLackAlarm, it.AlarmNum, it.MaxCapacity }) + await scope + .Updateable(updateStoragelocationList) + .IgnoreColumns(it => new + { + it.IsLight, + it.IsLackAlarm, + it.AlarmNum, + it.MaxCapacity + }) .ExecuteCommandAsync(); } // 发送库存变更Socket通知 string changeMessage = "库存变动"; - await notificationHubContext.Clients.All.SendAsync("PBL_storagelocation_change", changeMessage); + await notificationHubContext.Clients.All.SendAsync( + "PBL_storagelocation_change", + changeMessage + ); } // 插入库存变更日志 if (inventoryLogs.Any()) { - await DbScoped.SugarScope.CopyNew().Insertable(inventoryLogs).ExecuteCommandAsync(); + await DbScoped + .SugarScope.CopyNew() + .Insertable(inventoryLogs) + .ExecuteCommandAsync(); } // 添加延迟以避免频繁查询(暂定3秒防误触) await Task.Delay(2000, stoppingToken); @@ -298,7 +364,9 @@ namespace DOAN.ServiceCore } catch (Exception ex) { - Console.WriteLine($"DoanBackGround线程ExecuteAsync异常: {ex.Message}\n堆栈跟踪: {ex.StackTrace}"); + Console.WriteLine( + $"DoanBackGround线程ExecuteAsync异常: {ex.Message}\n堆栈跟踪: {ex.StackTrace}" + ); } } @@ -338,7 +406,8 @@ namespace DOAN.ServiceCore int newPackageCount, int operation, string operatorName, - List inventoryLogs) + List inventoryLogs + ) { storageLocation.PackageNum = newPackageCount; storageLocation.UpdatedBy = operatorName; @@ -350,7 +419,9 @@ namespace DOAN.ServiceCore RackCode = storageLocation.RackCode, Partnumber = storageLocation.Partnumber, Operation = operation, - PackageNum = Math.Abs(newPackageCount - storageLocation.PackageNum.GetValueOrDefault()), + PackageNum = Math.Abs( + newPackageCount - storageLocation.PackageNum.GetValueOrDefault() + ), CreatedBy = operatorName, CreatedTime = DateTime.Now.ToLocalTime() }; @@ -376,6 +447,3 @@ namespace DOAN.ServiceCore } } } - - - diff --git a/DOAN.ServiceCore/DoanBackgroundService2.cs b/DOAN.ServiceCore/DoanBackgroundService2.cs new file mode 100644 index 0000000..e2b3d72 --- /dev/null +++ b/DOAN.ServiceCore/DoanBackgroundService2.cs @@ -0,0 +1,420 @@ +using DOAN.Infrastructure.PLC; +using DOAN.Model.PBL; +using DOAN.ServiceCore.Signalr; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.Hosting; + +namespace DOAN.ServiceCore +{ + /// + /// 永驻线程 + /// 功能:检测传感器信号,判断箱子数 + /// + public class DoanBackgroundService2 : BaseService, IHostedService, IDisposable + { + private readonly IHubContext notificationHubContext; + private readonly CancellationTokenSource _cancellationTokenSource = + new CancellationTokenSource(); + private Task _executingTask; + private PLCTool pLCTool; + private List storagelocationList = new List(); + private List pointPositionList = new List(); + private List buttonPositionList = new List(); + private Timer refreshTimer; + + public DoanBackgroundService2(IHubContext hubContext) + { + notificationHubContext = hubContext; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + Console.WriteLine($"PCL定时任务开启!"); + pLCTool = new PLCTool(); + pLCTool.ConnectPLC(); + // 初始化料架层和点位表数据 + RefreshData(null); + // 启动后台任务 + _executingTask = ExecuteAsync(_cancellationTokenSource.Token); + + // 设置定时器每10分钟刷新一次料架层和点位表 .FromMinutes(1) + refreshTimer = new Timer(RefreshData, null, TimeSpan.Zero, TimeSpan.FromMinutes(10)); + + return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask; + } + + public async Task StopAsync(CancellationToken cancellationToken) + { + // 请求取消后台任务 + _cancellationTokenSource.Cancel(); + + // 停止定时器 + refreshTimer?.Change(Timeout.Infinite, Timeout.Infinite); + refreshTimer?.Dispose(); + + // 等待后台任务完成 + await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite, cancellationToken)); + } + + private static bool GetInvertedBit(byte b, int position) + { + if (position < 0 || position > 7) + { + throw new ArgumentOutOfRangeException( + nameof(position), + "Position must be between 0 and 7" + position + ); + } + + byte mask = (byte)(1 << position); + bool isSet = (b & mask) != 0; + return !isSet; // 返回取反后的值 + } + + /// + /// 功能:检测传感器信号,判断箱子数并更新库存及日志 + /// + /// 取消令牌 + /// + private async Task ExecuteAsync(CancellationToken stoppingToken) + { + Console.WriteLine($"PCL定时任务ExecuteAsync!"); + try + { + while (!stoppingToken.IsCancellationRequested) + { + // 读取PLC I/O状态(12个字节) + byte[] plcSensorValues; + try + { + // 读取1开头100,101。。。等全部地址数据 + plcSensorValues = pLCTool.ReadAllValue("VB100", 13); + } + catch (Exception ex) + { + Console.WriteLine($"读取PLC数据异常: {ex.Message}\n堆栈跟踪: {ex.StackTrace}"); + continue; + } + + // 读取按钮PLC I/O状态 + foreach (PlcButton button in buttonPositionList) + { + int row = button.Address - 100; + int col = button.Index; + + if ( + plcSensorValues != null + && row >= 0 + && row < plcSensorValues.Length + && !GetInvertedBit(plcSensorValues[row], col) + ) + { + // 按钮按下灭灯 + if (button.Code == "灭灯按钮") + { + var offLightstoragelocation = await Context + .Queryable() + .Where(it => it.Id == button.StoragelocationId) + .FirstAsync(); + + bool isSuccess = pLCTool.WriteBit( + offLightstoragelocation.PlcAddress, + false + ); + if (isSuccess) + { + offLightstoragelocation.IsLight = 0; + await Context + .Updateable(offLightstoragelocation) + .ExecuteCommandAsync(); + //灭灯日志 + Light_Log light_Log = new Light_Log + { + Id = SnowFlakeSingle.Instance.NextId().ToString(), + LightOperation = 2, + LayerNum = offLightstoragelocation.LayerNum, + ShelfCode = offLightstoragelocation.RackCode, + IsSuccess = isSuccess, + Operationer = "按钮手动灭灯", + CreatedTime = DateTime.Now + }; + await Context.Insertable(light_Log).ExecuteCommandAsync(); + } + await notificationHubContext.Clients.All.SendAsync( + "PBL_storagelocation_change", + "手动灭灯" + ); + } + // 镜体补料按钮 + if (button.Code == "镜体补料按钮") + { + bool lightStatus = pLCTool.ReadBit("V208.4"); + // 原本灭灯,亮灯补料 + if (!lightStatus) + { + AlarmLog alarmLog = new AlarmLog + { + Id = SnowFlakeSingle.Instance.NextId().ToString(), + Name = "镜体需要补料", + Code = "镜体补料", + StoragelocationId = 0, + Type = 2, + Status = 1, + ActionTime = DateTime.Now, + EndTime = DateTime.Now + }; + await Context.Insertable(alarmLog).ExecuteCommandAsync(); + var alarmData = new + { + RackCode = "镜体需要补料", + LayerNum = 1, + CurrentPackageCount = 0, + AlarmThreshold = 1, + ActionTime = DateTime + .Now.ToString("yyyy-MM-dd HH:mm:ss") + .ToString(), + }; + string alarmMessage = System.Text.Json.JsonSerializer.Serialize( + alarmData + ); + await notificationHubContext.Clients.All.SendAsync( + "PBL_lack_alarm", + alarmMessage + ); + } + else + { + // 原本亮灯,按一下灭灯 + pLCTool.WriteBit("V208.4", false); + } + } + } + } + + var updateStoragelocationList = new List(); + var inventoryLogs = new List(); + + foreach (var layerItem in storagelocationList) + { + // 获取这个料架层的点位表 + var layerPoints = await Context + .Queryable() + .Where(it => it.FkStorageId == layerItem.Id) + .ToListAsync(); + + if (layerPoints.Any()) + { + int currentPackageCount = 0; // 默认最小值为0 + + foreach (var point in layerPoints) + { + int row = point.ByteNum - 100; + int col = point.BitNum - 1; + + if ( + plcSensorValues != null + && row >= 0 + && row < plcSensorValues.Length + ) + { + currentPackageCount += GetInvertedBit(plcSensorValues[row], col) + ? 1 + : 0; + } + } + + // 检查箱子数量变化并记录日志 + int previousPackageCount = layerItem.PackageNum.GetValueOrDefault(); + if (currentPackageCount > previousPackageCount) + { + UpdateAndLog( + layerItem, + currentPackageCount, + 2, + "出库", + inventoryLogs + ); + updateStoragelocationList.Add(layerItem); + } + else if (currentPackageCount < previousPackageCount) + { + UpdateAndLog( + layerItem, + currentPackageCount, + 1, + "入库", + inventoryLogs + ); + updateStoragelocationList.Add(layerItem); + } + + // 补料报警触发 + if ( + layerItem.IsLackAlarm == 1 + && currentPackageCount < layerItem.AlarmNum + ) + { + // 是否已经报警过,并且 + bool hasLastAlarm = await Context + .Queryable() + .Where(it => it.StoragelocationId == layerItem.Id) + .Where(it => it.Type == 1) + .Where(it => it.Status == 1) + .Where(it => DateTime.Now <= it.EndTime) + .OrderBy(it => it.ActionTime, OrderByType.Desc) + .AnyAsync(); + if (!hasLastAlarm) + { + string layerName = layerItem.LayerNum == 1 ? "上层" : "中层"; + AlarmLog alarmLog = new AlarmLog + { + Id = SnowFlakeSingle.Instance.NextId().ToString(), + Name = + $"镜壳需补料:{layerItem.RackCode} {layerName} 阈值{layerItem.AlarmNum}", + Code = "镜壳补料", + StoragelocationId = layerItem.Id, + Type = 1, + Status = 1, + ActionTime = DateTime.Now, + // 过X分钟超时jishi + EndTime = DateTime.Now.AddMinutes(2) + }; + await Context.Insertable(alarmLog).ExecuteCommandAsync(); + var alarmData = new + { + RackCode = layerItem.RackCode, + LayerNum = layerItem.LayerNum, + CurrentPackageCount = currentPackageCount, + AlarmThreshold = layerItem.AlarmNum, + ActionTime = DateTime + .Now.ToString("yyyy-MM-dd HH:mm:ss") + .ToString(), + }; + string alarmMessage = System.Text.Json.JsonSerializer.Serialize( + alarmData + ); + await notificationHubContext.Clients.All.SendAsync( + "PBL_lack_alarm", + alarmMessage + ); + } + } + } + } + + // 更新库存 + if (updateStoragelocationList.Any()) + { + await Context + .Updateable(updateStoragelocationList) + .IgnoreColumns(it => new + { + it.IsLight, + it.IsLackAlarm, + it.AlarmNum, + it.MaxCapacity + }) + .ExecuteCommandAsync(); + // 发送库存变更Socket通知 + string changeMessage = "库存变动"; + await notificationHubContext.Clients.All.SendAsync( + "PBL_storagelocation_change", + changeMessage + ); + } + + // 插入库存变更日志 + if (inventoryLogs.Any()) + { + await Context.Insertable(inventoryLogs).ExecuteCommandAsync(); + } + // 添加延迟以避免频繁查询(暂定3秒防误触) + await Task.Delay(2000, stoppingToken); + } + } + catch (OperationCanceledException) + { + Console.WriteLine("任务已取消"); + } + catch (Exception ex) + { + Console.WriteLine( + $"DoanBackGround线程ExecuteAsync异常: {ex.Message}\n堆栈跟踪: {ex.StackTrace}" + ); + } + } + + /// + /// 刷新料架层和点位表数据 + /// + /// + private async void RefreshData(object state) + { + try + { + Console.WriteLine($"刷新料架点位和按钮"); + storagelocationList = await Context.Queryable().ToListAsync(); + pointPositionList = await Context.Queryable().ToListAsync(); + buttonPositionList = await Context.Queryable().ToListAsync(); + } + catch (Exception ex) + { + Console.WriteLine($"刷新数据异常: {ex.Message}\n堆栈跟踪: {ex.StackTrace}"); + // 如果刷新失败,保持现有数据不变 + } + } + + /// + /// 更新料架位置的箱子数量并记录库存日志 + /// + /// 料架位置对象 + /// 新的箱子数量 + /// 操作类型 (1-出库, 2-入库) + /// 操作员名称 + /// 库存日志列表 + private void UpdateAndLog( + Storagelocation storageLocation, + int newPackageCount, + int operation, + string operatorName, + List inventoryLogs + ) + { + storageLocation.PackageNum = newPackageCount; + storageLocation.UpdatedBy = operatorName; + storageLocation.UpdatedTime = DateTime.Now; + + var inventoryLog = new Inventorylog + { + Id = SnowFlakeSingle.Instance.NextId().ToString(), + RackCode = storageLocation.RackCode, + Partnumber = storageLocation.Partnumber, + Operation = operation, + PackageNum = Math.Abs( + newPackageCount - storageLocation.PackageNum.GetValueOrDefault() + ), + CreatedBy = operatorName, + CreatedTime = DateTime.Now.ToLocalTime() + }; + + inventoryLogs.Add(inventoryLog); + } + + public void Dispose() + { + try + { + _cancellationTokenSource.Cancel(); + _executingTask?.GetAwaiter().GetResult(); // 确保任务完成 + _cancellationTokenSource.Dispose(); + refreshTimer?.Change(Timeout.Infinite, Timeout.Infinite); + refreshTimer?.Dispose(); + pLCTool.ConnectClose(); + } + catch (Exception ex) + { + Console.WriteLine("DoanBackGround线程Dispose异常:" + ex.Message); + } + } + } +} diff --git a/Infrastructure/PLC/PLCTool.cs b/Infrastructure/PLC/PLCTool.cs index 865fb70..0e82fe7 100644 --- a/Infrastructure/PLC/PLCTool.cs +++ b/Infrastructure/PLC/PLCTool.cs @@ -1,8 +1,6 @@ -using HslCommunication; -using HslCommunication.Profinet.Inovance; -using HslCommunication.Profinet.Siemens; +using HslCommunication.Profinet.Siemens; using Infrastructure; -using JinianNet.JNTemplate; +using MiniExcelLibs; using System; using System.Collections.Generic; using System.Linq; @@ -13,145 +11,93 @@ namespace DOAN.Infrastructure.PLC { public class PLCTool { - - - // private NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); - - public SiemensS7Net siemensTcpNet = null; + // 私有连接对象 + private SiemensS7Net siemensTcpNet = null; + private readonly string plcAddress; public PLCTool() { - - this.siemensTcpNet = new SiemensS7Net(SiemensPLCS.S200Smart, "10.72.82.242") + plcAddress = AppSettings.GetConfig("PLCConfig:Address"); + this.siemensTcpNet = new SiemensS7Net(SiemensPLCS.S200Smart, plcAddress) { ConnectTimeOut = 5000 - }; + }; } - public bool ConnectPLC() + /// + /// 尝试连接到PLC + /// + /// 连接成功返回true,失败返回false + public bool ConnectPLC() { try { - OperateResult connect = siemensTcpNet.ConnectServer(); + var connect = siemensTcpNet.ConnectServer(); if (connect.IsSuccess) { - // 连接成功 - Console.WriteLine("PLC连接成功"); + Console.WriteLine($"PLC连接成功,地址{plcAddress}"); return true; } else { - // 连接失败,输出原因 - Console.WriteLine("PLC连接失败:" + connect.Message); - throw new CustomException("connect failed:" + connect.Message); + Console.WriteLine($"PLC连接失败,地址{plcAddress}: {connect.Message}"); + return false; } } catch (Exception e) { - Console.WriteLine("PLC连接失败:" + e.Message); + Console.WriteLine($"PLC连接失败,地址{plcAddress}: {e.Message}"); return false; } - - - - } - /// - /// 写入bit - /// - /// - /// - /// - public bool WriteBit(string addr, bool value) - { - OperateResult write = siemensTcpNet.Write(addr, value); + /// + /// 向PLC写入单个bit值 + /// + /// PLC地址 + /// 要写入的bool值 + /// 写入成功返回true,失败返回false + public bool WriteBit(string addr, bool value) + { + var write = siemensTcpNet.Write(addr, value); return write.IsSuccess; - } + /// - /// 读取bit + /// 从PLC读取单个bit值 /// - /// - /// - public bool ReadBit(string addr) + /// PLC地址 + /// 读取到的bool值 + public bool ReadBit(string addr) { - - bool M100_7 = siemensTcpNet.ReadBool(addr).Content; - return M100_7; + return siemensTcpNet.ReadBool(addr).Content; } /// - /// 读多个连续的二进制数据 转为字节数组 + /// 从PLC读取多个连续的二进制数据并转为字节数组 /// - /// - /// - /// - //public byte[,] ReadAllValue(string addr = "VB100", ushort length = 11) - //{ - // byte[,] data = new byte[length, 8]; - // //需要自行解析,length为地址个数 - // siemensTcpNet.ReadByte(addr); - // OperateResult result = siemensTcpNet.Read(addr, length); - // if (result.IsSuccess) - // { - - // if (result.Content.Length > 0) - // { - - // for (int i = 0; i < result.Content.Length; i++) - // { - - // int row = i / 8; - // int col = i % 8; - // data[row, col] = result.Content[i]; - - // } - // return data; - - - // } - - // } - // else - // { - // Console.WriteLine($"PLC IO 取值失败,地址为{addr},地址个数为{length}"); - // return null; - // } - //} - - /// - /// 读多个连续的二进制数据 转为字节数组 - /// - /// - /// - /// + /// 起始PLC地址,默认为"VB100" + /// 要读取的字节数,默认为12 + /// 读取到的字节数组,如果失败返回null public byte[] ReadAllValue(string addr = "VB100", ushort length = 12) { - - //需要自行解析,length为地址个数 - siemensTcpNet.ReadByte(addr); - OperateResult result = siemensTcpNet.Read(addr, length); + var result = siemensTcpNet.Read(addr, length); if (result.IsSuccess) { - - return result.Content; - + return result.Content; } else { - Console.WriteLine($"PLC IO 取值失败,地址为{addr},地址个数为{length}"); + Console.WriteLine($"PLC IO 取值失败,PLC地址{plcAddress},访问地址为{addr},地址个数为{length}"); return null; } } - - - - public void ConnectClose() + /// + /// 关闭与PLC的连接 + /// + public void ConnectClose() { siemensTcpNet.ConnectClose(); - } - } -} +} \ No newline at end of file