using Admin.NET.Core.Service;
|
using DocumentFormat.OpenXml.Bibliography;
|
using DocumentFormat.OpenXml.Drawing;
|
using DocumentFormat.OpenXml.Drawing.Charts;
|
using Elastic.Clients.Elasticsearch.Snapshot;
|
using Furion.Logging;
|
using Microsoft.AspNetCore.SignalR;
|
using NewLife.Serialization;
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical;
|
using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
|
using OnceMi.AspNetCore.OSS;
|
using Qiniu.Storage;
|
using System;
|
using System.Drawing.Drawing2D;
|
using System.Net.NetworkInformation;
|
using WCS.Application.Entity;
|
using WCS.Application.Util;
|
using static SKIT.FlurlHttpClient.Wechat.Api.Models.CgibinExpressIntracityUpdateStoreRequest.Types;
|
//using WCS.Application.Util;
|
|
namespace WCS.Application;
|
public static class PLCTaskAction
|
{
|
//服务运行状态
|
public static bool boRunningState = false;
|
//脱机模式
|
public static bool boOffline = false;
|
//自刷新
|
public static bool boRefresh = false;
|
//演示模式
|
public static bool boDemo = false;
|
//滚筒反转
|
public static bool boDrumReversal = false;
|
//出库锁定
|
public static bool boOutLock = false;
|
//入库锁定
|
public static bool boEnterLock = false;
|
|
public static List<PlcPositionInfo> listPositionInfo = new List<PlcPositionInfo>();
|
|
private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId);
|
private static readonly SysCacheService sysCacheService = App.GetRequiredService<SysCacheService>();
|
private static readonly SysConfigService _sysConfigService = App.GetService<SysConfigService>();
|
private static readonly WcsTaskService _taskService = App.GetService<WcsTaskService>();
|
|
private static List<WcsPlc> listPlc = new List<WcsPlc>();
|
private static List<WcsDevice> listPlcDevice = new List<WcsDevice>();
|
private static List<WcsPosition> listPlcPosition = new List<WcsPosition>();
|
private static List<WcsAlarmInfo> listAlarmInfo = new List<WcsAlarmInfo>();
|
|
private static List<PLCUtil> listPlcUtil = new List<PLCUtil>();
|
private static CancellationTokenSource cts = new CancellationTokenSource();//取消线程标识
|
|
private static List<ModbusUtil> listModbusUtil = new List<ModbusUtil>();
|
|
public static List<ModbusUtil> modbusUtilConn
|
{
|
get { return listModbusUtil; }
|
}
|
//对外公布连接状态
|
public static List<PLCUtil> listPlcConn
|
{
|
get { return listPlcUtil; }
|
}
|
// 交互点集合
|
public static List<WcsDevice> plcDevices
|
{
|
get { return listPlcDevice; }
|
}
|
public static List<WcsPosition> plcPositions
|
{
|
get { return listPlcPosition; }
|
}
|
public static List<WcsPlc> plcs
|
{
|
get { return listPlc; }
|
}
|
public static event EventHandler DeviceValueChangeEvent;
|
static PLCTaskAction()
|
{
|
//订阅事件
|
DeviceValueChangeEvent += PLCService.OnChangeEvent;
|
boRunningState = _sysConfigService.GetConfigValue<bool>("sys_RunningState").Result;
|
boOffline = _sysConfigService.GetConfigValue<bool>("sys_Offline").Result;
|
boRefresh = _sysConfigService.GetConfigValue<bool>("sys_Refresh").Result;
|
boDemo = _sysConfigService.GetConfigValue<bool>("sys_demo").Result;
|
boDrumReversal = _sysConfigService.GetConfigValue<bool>("sys_DrumReversal").Result;
|
boOutLock = _sysConfigService.GetConfigValue<bool>("sys_BoOutLock").Result;
|
boEnterLock = _sysConfigService.GetConfigValue<bool>("sys_BoEnterLock").Result;
|
}
|
/// <summary>
|
/// 初始化PLC连接
|
/// </summary>
|
public static void Init()
|
{
|
cts.Cancel();
|
listPlc = _db.Queryable<WcsPlc>()
|
//.Where(s => s.Type == PLCTypeEnum.ShuttleCar || s.Type == PLCTypeEnum.ConveyorLine || s.Type == PLCTypeEnum.AGV)
|
.Where(s => s.Enable == YesNoEnum.Y)
|
.ToList();
|
listPlcDevice = _db.Queryable<WcsDevice>().ToList();
|
listPlcPosition = _db.Queryable<WcsPosition>().ToList();
|
listAlarmInfo = _db.Queryable<WcsAlarmInfo>().ToList();
|
//等待几秒钟,把已有线程取消掉再连接
|
//Thread.Sleep(5000);
|
foreach (var modPlcUtil in listPlcUtil)
|
{
|
modPlcUtil.Close();
|
}
|
listPlcUtil.Clear();
|
foreach (var modPlc in listPlc)
|
{
|
switch (modPlc.PLCType)
|
{
|
case PLCEnum.None:
|
break;
|
case PLCEnum.S7_200:
|
case PLCEnum.S7_200Smart:
|
case PLCEnum.S7_300:
|
case PLCEnum.S7_400:
|
case PLCEnum.S7_1200:
|
case PLCEnum.S7_1500:
|
var plc = new PLCUtil(modPlc);
|
listPlcUtil.Add(plc);
|
break;
|
case PLCEnum.ModBusTcp:
|
var modbus = new ModbusUtil(modPlc);
|
listModbusUtil.Add(modbus);
|
break;
|
default:
|
break;
|
}
|
|
}
|
HubUtil.UpdateService(new PLCServiceModel()
|
{
|
BoRunningState = boRunningState,
|
BoOffline = boOffline,
|
BoRefresh = boRefresh
|
});
|
if (boRunningState)
|
{
|
cts = new CancellationTokenSource();
|
StartRead();
|
ConnectionStatus();
|
StartWatchAlarm();
|
AssignTasks();
|
//StartWatchPosition();
|
}
|
}
|
/// <summary>
|
/// 开启读取plc线程
|
/// </summary>
|
public static void StartRead()
|
{
|
Console.WriteLine("开启读取plc线程");
|
foreach (var modPlc in listPlc)
|
{
|
Task.Run(() =>
|
{
|
var _modplc = modPlc;
|
while (true)
|
{
|
//取消线程 关闭PLC连接
|
if (cts.Token.IsCancellationRequested)
|
{
|
foreach (var modPlcUtil in listPlcUtil)
|
{
|
if (modPlcUtil != null && modPlcUtil.Connected)
|
modPlcUtil.Close();
|
}
|
break;
|
//throw new OperationCanceledException();
|
}
|
try
|
{
|
switch (_modplc.PLCType)
|
{
|
case PLCEnum.None:
|
break;
|
case PLCEnum.S7_200:
|
case PLCEnum.S7_200Smart:
|
case PLCEnum.S7_300:
|
case PLCEnum.S7_400:
|
case PLCEnum.S7_1200:
|
case PLCEnum.S7_1500:
|
{
|
var modPlcUtil = listPlcUtil.FirstOrDefault(s => s != null && s.PlcId == modPlc.Id);
|
if (modPlcUtil == null)
|
{
|
Console.WriteLine($"连接plc{modPlc.IP}");
|
modPlcUtil = new PLCUtil(modPlc);
|
listPlcUtil.Add(modPlcUtil);
|
if (modPlcUtil.Connected)
|
Console.WriteLine($"连接plc{modPlc.IP}成功");
|
}
|
if (!modPlcUtil.Connected)
|
{
|
Thread.Sleep(100);
|
modPlcUtil.Open();
|
continue;
|
}
|
var listDevice = listPlcDevice
|
.Where(s => s.PlcId == _modplc.Id && s.DeviceType == DeviceTypeEnum.Business)
|
.WhereIF(modPlc.Type == PLCTypeEnum.ConveyorLine, s => s.Level == DeviceLevelEnum.DB)
|
.ToList();
|
//循环读设备
|
foreach (var modDevice in listDevice)
|
{
|
var (result, value) = modPlcUtil.GetPlcDBValue(modDevice.PosType, modDevice.DbNumber, modDevice.PlcPos);
|
if (result.IsSucceed)
|
{
|
////如果是穿梭车,这里发送心跳
|
//if (modPlc.Type == PLCTypeEnum.ShuttleCar)
|
//{
|
// var modHeart = listPlcPosition.Where(s => s.DeviceId == modDevice.Id && s.Text == "心跳").FirstOrDefault();
|
// if (modHeart != null)
|
// {
|
// modPlcUtil.SetPlcDBValue(modHeart.PosType, modHeart.PlcPos, "1");
|
// }
|
//}
|
//无流程跳出
|
if (Convert.ToInt32(value) == 0)
|
continue;
|
var dto = modDevice.Adapt<WcsDeviceDto>();
|
dto.Value = value;
|
dto.Type = _modplc.Type;
|
dto.PLCUtil = modPlcUtil;
|
dto.listStation = listPlcPosition.Where(s => s.DeviceId == modDevice.Id).ToList();
|
dto.listDevice = listDevice.Where(s => s.StationNum == modDevice.StationNum && s.Level == DeviceLevelEnum.Station).ToList();
|
//这里触发值变更事件
|
DeviceValueChangeEvent?.Invoke(dto, EventArgs.Empty);
|
}
|
else if (!modPlcUtil.Connected)
|
{
|
//重新打开连接
|
modPlcUtil.Open();
|
}
|
}
|
}
|
break;
|
case PLCEnum.ModBusTcp:
|
{
|
var modbusUtil = listModbusUtil.FirstOrDefault(s => s != null && s.PlcId == _modplc.Id);
|
if (modbusUtil == null)
|
{
|
Console.WriteLine($"连接ModBus{modPlc.IP}");
|
modbusUtil = new ModbusUtil(modPlc);
|
listModbusUtil.Add(modbusUtil);
|
if (modbusUtil.Connected)
|
Console.WriteLine($"连接ModBus{modPlc.IP}成功");
|
}
|
if (!modbusUtil.Connected)
|
{
|
Thread.Sleep(100);
|
modbusUtil.Open();
|
continue;
|
}
|
var listDevice = listPlcDevice
|
.Where(s => s.PlcId == _modplc.Id && s.DeviceType == DeviceTypeEnum.Business)
|
.WhereIF(modPlc.Type == PLCTypeEnum.ConveyorLine, s => s.Level == DeviceLevelEnum.DB)
|
.ToList();
|
//循环读设备
|
foreach (var modDevice in listDevice)
|
{
|
var (result, value) = modbusUtil.GetDBValue(modDevice.PosType, modDevice.PlcPos);
|
if (result.IsSucceed)
|
{
|
//如果是穿梭车,这里发送心跳
|
if (modPlc.Type == PLCTypeEnum.ShuttleCar)
|
{
|
var modHeart = listPlcPosition.Where(s => s.DeviceId == modDevice.Id && s.Text == "心跳").FirstOrDefault();
|
if (modHeart != null)
|
{
|
modbusUtil.SetDBValue(modHeart.PosType, modHeart.PlcPos, "1");
|
}
|
}
|
|
//无流程跳出
|
if (value == 0)
|
continue;
|
var dto = modDevice.Adapt<WcsDeviceDto>();
|
dto.Value = value;
|
dto.PlcIdIP = modPlc.IP;
|
dto.Type = _modplc.Type;
|
dto.modbusUtil = modbusUtil;
|
dto.listStation = listPlcPosition.Where(s => s.DeviceId == modDevice.Id).ToList();
|
dto.listDevice = listDevice.Where(s => s.StationNum == modDevice.StationNum && s.Level == DeviceLevelEnum.Station).ToList();
|
//这里触发值变更事件
|
DeviceValueChangeEvent?.Invoke(dto, EventArgs.Empty);
|
}
|
else if (!modbusUtil.Connected)
|
{
|
//重新打开连接
|
modbusUtil.Open();
|
}
|
}
|
}
|
|
break;
|
case PLCEnum.HTTP:
|
{
|
Ping pingSender = new Ping();
|
try
|
{
|
// 发送Ping请求,并等待回复
|
PingReply reply = pingSender.Send(_modplc.IP);
|
|
if (reply.Status == IPStatus.Success)
|
{
|
var listDevice = listPlcDevice
|
.Where(s => s.PlcId == _modplc.Id && s.DeviceType == DeviceTypeEnum.Business)
|
.ToList();
|
foreach (var modDevice in listDevice)
|
{
|
var dto = modDevice.Adapt<WcsDeviceDto>();
|
dto.modPlc = _modplc;
|
dto.Type = _modplc.Type;
|
dto.listStation = listPlcPosition.Where(s => s.DeviceId == modDevice.Id).ToList();
|
dto.listDevice = listDevice.Where(s => s.StationNum == modDevice.StationNum && s.Level == DeviceLevelEnum.Station).ToList();
|
//这里触发值变更事件
|
DeviceValueChangeEvent?.Invoke(dto, EventArgs.Empty);
|
}
|
}
|
else
|
{
|
Console.WriteLine($"连接不到主机: {_modplc.IP} {reply.Status}");
|
}
|
}
|
catch (Exception ex)
|
{
|
Console.WriteLine(ex.Message);
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
|
|
|
Thread.Sleep(3000);
|
}
|
catch (OperationCanceledException)
|
{
|
Console.WriteLine("中止线程");
|
}
|
catch (Exception ex)
|
{
|
Log.Error("读取PLC线程发生异常", ex);
|
}
|
}
|
}, cts.Token);
|
}
|
}
|
|
/// <summary>
|
/// 四向车任务分配
|
/// </summary>
|
private static void AssignTasks()
|
{
|
|
Task.Run(() =>
|
{
|
while (true)
|
{
|
Console.WriteLine("开启四向车任务自分配");
|
//取消线程 关闭PLC连接
|
if (cts.Token.IsCancellationRequested)
|
{
|
foreach (var modModBusUtil in listModbusUtil)
|
{
|
if (modModBusUtil != null && modModBusUtil.Connected)
|
modModBusUtil.Close();
|
}
|
break;
|
}
|
try
|
{
|
// 获取密集库未执行任务 根据创建时间排序
|
var waitTask = _db.Queryable<WcsTask>().Where(s => s.IsDelete == false && s.Status == TaskStatusEnum.Wait && s.Type == PLCTypeEnum.ShuttleCar).OrderBy(s => new {s.Levels, s.CreateTime}).First();
|
if (waitTask == null)
|
{
|
continue;
|
}
|
//01010101: 01排 01列 01层 01深度-此项目不做判断
|
var taskpai = int.Parse(waitTask.StartLocate.Substring(0, 2));
|
var tasklie = int.Parse(waitTask.StartLocate.Substring(2, 2));
|
var taskceng = int.Parse(waitTask.StartLocate.Substring(4, 2));
|
|
#region 获取当前任务所在层所有空闲小车
|
|
// 获取有任务的小车编号
|
var taskCarList = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && m.Status == TaskStatusEnum.Wait).Select(m => m.CarNo).Distinct().ToList();
|
|
// 获取当前任务所在层所有空闲小车(根据小车任务表是否有任务和小车状态共同判断小车是否空闲)
|
var kXCarList = new List<CarInfo>();
|
var carErr = false;//小车是否有失联的
|
foreach (var modbusUtil in listModbusUtil)
|
{
|
//如果小车有未执行的任务,跳出
|
if (taskCarList.Contains(modbusUtil.PlcIP))
|
{
|
continue;
|
}
|
//获取小车的WcsDevice信息
|
var listDevice = listPlcDevice.Where(s => s.PlcId == modbusUtil.PlcId && s.DeviceType == DeviceTypeEnum.Business).ToList();
|
//循环读设备
|
foreach (var modDevice in listDevice)
|
{
|
var (result, value) = modbusUtil.GetDBValue(modDevice.PosType, modDevice.PlcPos);
|
if (result.IsSucceed)
|
{
|
//获取工位WCSPLCPosition信息
|
var plcPosition = listPlcPosition.Where(s => s.DeviceId == modDevice.Id).ToList();
|
if (value == 3)
|
{
|
var modCarDl = plcPosition.FirstOrDefault(s => s.Text == "电池电量");
|
var (resultDl, valueDl) = modbusUtil.GetDBValue(modCarDl.PosType, modCarDl.PlcPos);
|
if (resultDl.IsSucceed && valueDl> (int)FourWayCarDLEnum.Dl3)
|
{
|
//写入结束充电命令
|
var modCdEnd = plcPosition.FirstOrDefault(s => s.Text == "充电命令");
|
var resultDl22 = modbusUtil.SetDBValue(modCdEnd.PosType, modCdEnd.PlcPos.ToString(), "3") ;
|
carErr = true;
|
break; //暂缓分配,防止同层小车关机或失联导致阻挡路径
|
}
|
}
|
//小车空闲加入集合
|
if (value == 1)
|
{
|
var modStationX = plcPosition.FirstOrDefault(s => s.Text == "四向车位置(X)");
|
var (resultx, valuex) = modbusUtil.GetDBValue(modStationX.PosType, modStationX.PlcPos);
|
var modStationY = plcPosition.FirstOrDefault(s => s.Text == "四向车位置(Y)");
|
var (resulty, valuey) = modbusUtil.GetDBValue(modStationY.PosType, modStationY.PlcPos);
|
var modStationZ = plcPosition.FirstOrDefault(s => s.Text == "四向车位置(Z)");
|
var (resultz, valuez) = modbusUtil.GetDBValue(modStationZ.PosType, modStationZ.PlcPos);
|
//小车当前层
|
var carZ = (int)valuez;
|
//任务层与小车层相同
|
if (taskceng == carZ)
|
{
|
if (!kXCarList.Any(m => m.CarPlcIp == modbusUtil.PlcIP))
|
{
|
var carVal = ((int)valuex).ToString().PadLeft(2, '0') + ((int)valuey).ToString().PadLeft(2, '0') + ((int)valuez).ToString().PadLeft(2, '0');
|
//小车到取货储位路径
|
var d = FourWayCarUtil.GetCarPath(carVal, waitTask.StartLocate);
|
kXCarList.Add(new CarInfo()
|
{
|
CarPlcIp = modbusUtil.PlcIP,
|
X = (int)valuex,
|
Y = (int)valuey,
|
Z = (int)valuez,
|
Level = d.Count,
|
});
|
}
|
}
|
}
|
}
|
else
|
{
|
Console.WriteLine($"读取四向车{modbusUtil.PlcIP}状态失败");
|
carErr = true;
|
break;//有一个小车读取失败跳出方法,暂缓分配,防止同层小车关机或失联导致阻挡路径
|
}
|
}
|
//有小车失联,不分配任务
|
if (carErr)
|
{
|
kXCarList.Clear();//清楚空车记录
|
break;
|
}
|
}
|
|
#endregion
|
|
|
// 获取适合执行当前任务的小车 生成路径(需考虑小车阻阻挡)
|
var assignCar = kXCarList.OrderBy(m => m.Level).FirstOrDefault();
|
if (assignCar == null)
|
{
|
continue;//没有空闲小车
|
}
|
|
if (assignCar.Level != 1)
|
{
|
//判断小车位置是否与任务的起始储位相同,不相同:获取小车到取货储位路径
|
var carLocate = assignCar.X.ToString().PadLeft(2, '0')+assignCar.Y.ToString().PadLeft(2, '0')+ assignCar.Z.ToString().PadLeft(2, '0');
|
//获取小车去取货储位任务路径
|
var data1 = FourWayCarUtil.GetCarPath(carLocate, waitTask.StartLocate);
|
var datas1 = FourWayCarUtil.GetCarPathUp(data1, 0);
|
if (datas1 == null)
|
{
|
continue;
|
}
|
else
|
{
|
var bl = FourWayCarUtil.AddCarTask(datas1, kXCarList, assignCar, waitTask,0);
|
//分配错误,删除分配信息
|
if (!bl)
|
{
|
var carTask = _db.Queryable<WcsCarTasks>().Where(m => m.IsDelete == false && m.TaskNo == waitTask.TaskNo).ToList();
|
_db.Deleteable(carTask).ExecuteCommand();
|
}
|
}
|
}
|
var typeStr = "1";
|
var typeStr2 = 1;
|
if (waitTask.Levels == 888 )
|
{
|
typeStr = "0";//小车任务是充电任务
|
typeStr2 = 0;
|
}
|
//获取小车去放货储位任务路径
|
var data2 = FourWayCarUtil.GetCarPath(waitTask.StartLocate, waitTask.EndLocate, typeStr);
|
var datas2 = FourWayCarUtil.GetCarPathUp(data2, typeStr2);
|
|
if (datas2 == null)
|
{
|
continue;
|
}
|
else
|
{
|
var bl = FourWayCarUtil.AddCarTask(datas2,kXCarList,assignCar,waitTask,1);
|
//分配错误,删除分配信息
|
if (!bl)
|
{
|
waitTask.Status = TaskStatusEnum.Wait;
|
_db.Updateable(waitTask).ExecuteCommand();
|
var carTask = _db.Queryable<WcsCarTasks>().Where(m=>m.IsDelete == false && m.TaskNo == waitTask.TaskNo).ToList();
|
_db.Deleteable(carTask).ExecuteCommand();
|
}
|
}
|
|
|
|
Thread.Sleep(3000);
|
}
|
catch (Exception ex)
|
{
|
Log.Error("任务分配发生异常", ex);
|
}
|
}
|
},cts.Token);
|
}
|
|
|
/// <summary>
|
/// 连接状态线程
|
/// </summary>
|
public static void ConnectionStatus()
|
{
|
Task.Run(() =>
|
{
|
try
|
{
|
Console.WriteLine("连接状态线程");
|
while (true)
|
{
|
//取消线程 关闭PLC连接
|
if (cts.Token.IsCancellationRequested)
|
{
|
foreach (var modPlcUtil in listPlcUtil)
|
{
|
if (modPlcUtil != null && modPlcUtil.Connected)
|
modPlcUtil.Close();
|
}
|
break;
|
//throw new OperationCanceledException();
|
}
|
//获取每个PLC连接状态
|
foreach (var modPlc in listPlc)
|
{
|
switch (modPlc.PLCType)
|
{
|
case PLCEnum.None:
|
break;
|
case PLCEnum.S7_200:
|
case PLCEnum.S7_200Smart:
|
case PLCEnum.S7_300:
|
case PLCEnum.S7_400:
|
case PLCEnum.S7_1200:
|
case PLCEnum.S7_1500:
|
{
|
var modPlcUtil = listPlcUtil.FirstOrDefault(s => s.PlcId == modPlc.Id);
|
if (modPlcUtil == null)
|
modPlc.IsConn = false;
|
else
|
modPlc.IsConn = modPlcUtil.Connected;
|
if (sysCacheService.ExistKey("PLCCONN:" + modPlc.Id))
|
{
|
var cachePlc = sysCacheService.Get<WcsPlc>("PLCCONN:" + modPlc.Id);
|
if (cachePlc.IsConn != modPlc.IsConn)
|
{
|
//连接状态变更 通知前端
|
Console.WriteLine($"通知前端变更{modPlc.Text} {modPlc.IsConn}");
|
HubUtil.PublicPlcConn(modPlc);
|
}
|
sysCacheService.Set("PLCCONN:" + modPlc.Id, modPlc);
|
}
|
else
|
{
|
sysCacheService.Set("PLCCONN:" + modPlc.Id, modPlc);
|
HubUtil.PublicPlcConn(modPlc);
|
}
|
}
|
break;
|
case PLCEnum.ModBusTcp:
|
{
|
var modbudUtil = listModbusUtil.FirstOrDefault(s => s.PlcId == modPlc.Id);
|
if (modbudUtil == null)
|
modPlc.IsConn = false;
|
else
|
modPlc.IsConn = modbudUtil.Connected;
|
if (sysCacheService.ExistKey("PLCCONN:" + modPlc.Id))
|
{
|
var cachePlc = sysCacheService.Get<WcsPlc>("PLCCONN:" + modPlc.Id);
|
if (cachePlc.IsConn != modPlc.IsConn)
|
{
|
//连接状态变更 通知前端
|
Console.WriteLine($"通知前端变更{modPlc.Text} {modPlc.IsConn}");
|
HubUtil.PublicPlcConn(modPlc);
|
}
|
sysCacheService.Set("PLCCONN:" + modPlc.Id, modPlc);
|
}
|
else
|
{
|
sysCacheService.Set("PLCCONN:" + modPlc.Id, modPlc);
|
HubUtil.PublicPlcConn(modPlc);
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
|
}
|
Thread.Sleep(10000);
|
}
|
}
|
catch (OperationCanceledException)
|
{
|
sysCacheService.RemoveByPrefixKey("PLCCONN");
|
Console.WriteLine("中止线程");
|
}
|
catch (Exception ex)
|
{
|
Log.Error("连接状态线程发生异常", ex);
|
}
|
|
}, cts.Token);
|
|
}
|
|
/// <summary>
|
/// 开启报警监控
|
/// </summary>
|
public static void StartWatchAlarm()
|
{
|
Task.Run(() =>
|
{
|
var listPlc = listAlarmInfo.GroupBy(s => new { s.PlcIP, s.PlcPort, s.Type }).Select(s => s.Key).ToList();
|
List<PLCUtil> listPlcUtil = new List<PLCUtil>();
|
List<ModbusUtil> listModbusUtil = new List<ModbusUtil>();
|
int i = 0;
|
foreach (var modPlc in listPlc.Where(s => s.Type != PLCTypeEnum.ShuttleCar))
|
{
|
listPlcUtil.Add(new PLCUtil(new WcsPlc() { Id = i++, IP = modPlc.PlcIP, Port = modPlc.PlcPort, PLCType = PLCEnum.S7_1500 }));
|
}
|
foreach (var modPlc in listPlc.Where(s => s.Type == PLCTypeEnum.ShuttleCar))
|
{
|
listModbusUtil.Add(new ModbusUtil(new WcsPlc() { Id = i++, IP = modPlc.PlcIP, Port = modPlc.PlcPort, PLCType = PLCEnum.ModBusTcp }));
|
}
|
while (true)
|
{
|
//取消线程 关闭PLC连接
|
if (cts.Token.IsCancellationRequested)
|
{
|
foreach (var modPlcUtil in listPlcUtil)
|
{
|
if (modPlcUtil != null && modPlcUtil.Connected)
|
modPlcUtil.Close();
|
}
|
foreach (var modModbusUtil in listModbusUtil)
|
{
|
if (modModbusUtil != null && modModbusUtil.Connected)
|
modModbusUtil.Close();
|
}
|
break;
|
//throw new OperationCanceledException();
|
}
|
try
|
{
|
var listPulish = new List<WcsAlarmInfo>();
|
foreach (var modUtil in listPlcUtil)
|
{
|
//报警点位
|
var listAlarm = listAlarmInfo.Where(s => s.PlcIP == modUtil.PlcIP.ToString()).ToList();
|
var listaddress = new Dictionary<string, PLCDataTypeEnum>();
|
foreach (var modAlarm in listAlarm)
|
{
|
listaddress.Add(modAlarm.AlarmCode, PLCDataTypeEnum.Bit);
|
}
|
var result = modUtil.GetPlcBatchDBValue(listaddress);
|
foreach (var item in result.Value)
|
{
|
var value = Convert.ToBoolean(item.Value);
|
var modAlarm = listAlarm.FirstOrDefault(s => s.AlarmCode == item.Key);
|
var stationNum = modAlarm.StationNum;
|
if (value && modAlarm.Status == YesNoEnum.N)
|
{
|
//修改报警状态同时记录报警日志
|
modAlarm.AlarmTime = DateTime.Now;
|
modAlarm.Status = YesNoEnum.Y;
|
listPulish.Add(modAlarm);
|
}
|
//取消报警
|
else if (value && modAlarm.Status == YesNoEnum.Y)
|
{
|
modAlarm.AlarmTime = null;
|
modAlarm.Status = YesNoEnum.N;
|
listPulish.Add(modAlarm);
|
}
|
}
|
if (listPulish.Count > 0)
|
{
|
_db.Updateable(listPulish).ExecuteCommand();
|
var listLog = new List<WcsAlarmLog>();
|
foreach (var mod in listPulish.Where(s => s.Status == YesNoEnum.Y))
|
{
|
WcsAlarmLog modLog = mod.Adapt<WcsAlarmLog>();
|
modLog.Id = 0;
|
listLog.Add(modLog);
|
}
|
_db.Insertable(listLog).ExecuteCommand();
|
HubUtil.PublicAlarm(listPulish);
|
}
|
}
|
//穿梭车报警
|
var listCacheAlarm = sysCacheService.GetHashMap<int>("AlarmInfo_Car");
|
listPulish = new List<WcsAlarmInfo>();
|
foreach (var modCacheAlarm in listCacheAlarm)
|
{
|
if (modCacheAlarm.Value == -1)
|
{
|
//取消报警
|
var modAlarm = listAlarmInfo.FirstOrDefault(s => s.PlcIP == modCacheAlarm.Key && s.Status == YesNoEnum.Y);
|
if (modAlarm != null)
|
{
|
modAlarm.Status = YesNoEnum.N;
|
modAlarm.AlarmTime = null;
|
_db.Updateable(modAlarm).ExecuteCommand();
|
listPulish.Add(modAlarm);
|
}
|
}
|
else
|
{
|
var modAlarm = listAlarmInfo.FirstOrDefault(s => s.PlcIP == modCacheAlarm.Key && s.AlarmCode == modCacheAlarm.Value.ToString());
|
if (modAlarm != null && modAlarm.Status != YesNoEnum.Y)
|
{
|
modAlarm.Status = YesNoEnum.Y;
|
modAlarm.AlarmTime = DateTime.Now;
|
_db.Updateable(modAlarm).ExecuteCommand();
|
WcsAlarmLog modLog = new WcsAlarmLog()
|
{
|
PlcIP = modAlarm.PlcIP,
|
AlarmCode = modAlarm.AlarmCode,
|
AlarmName = modAlarm.AlarmName,
|
AlarmTime = modAlarm.AlarmTime,
|
};
|
_db.Insertable(modLog).ExecuteCommand();
|
listPulish.Add(modAlarm);
|
}
|
}
|
}
|
if (listPulish.Count > 0)
|
{
|
HubUtil.PublicAlarm(listPulish);
|
}
|
}
|
catch (Exception ex)
|
{
|
Log.Error("报警监控发生异常", ex);
|
}
|
Thread.Sleep(10000);
|
}
|
}, cts.Token);
|
}
|
/// <summary>
|
/// 开启位置监控
|
/// </summary>
|
public static void StartWatchPosition()
|
{
|
Console.WriteLine("开启位置监控");
|
Task.Run(() =>
|
{
|
while (true)
|
{
|
//取消线程 关闭PLC连接
|
if (cts.Token.IsCancellationRequested)
|
{
|
foreach (var modPlcUtil in listPlcUtil)
|
{
|
if (modPlcUtil != null && modPlcUtil.Connected)
|
modPlcUtil.Close();
|
}
|
break;
|
//throw new OperationCanceledException();
|
}
|
try
|
{
|
foreach (var modPlcUtil in listPlcUtil)
|
{
|
if (modPlcUtil == null)
|
continue;
|
var plcIp = modPlcUtil.PlcIP;
|
var listDevice = listPlcDevice.Where(s => s.PlcId == modPlcUtil.PlcId && s.DeviceType == DeviceTypeEnum.Show).ToList();
|
var modPlc = listPlc.FirstOrDefault(s => s.Id == modPlcUtil.PlcId);
|
var listaddress = new Dictionary<string, PLCDataTypeEnum>();
|
foreach (var modDevice in listDevice)
|
{
|
listaddress.Add(modDevice.DbNumber + "." + modDevice.PlcPos, modDevice.PosType);
|
}
|
//批量读
|
var result = modPlcUtil.GetPlcBatchDBValue(listaddress);
|
//测试用
|
//foreach (var modDevice in listDevice)
|
//{
|
// if (modPlc.Type == PLCTypeEnum.StackingMachine)
|
// result.Value.Add(modDevice.DbNumber + "." + modDevice.PlcPos, new Random().Next(790000));
|
// else if (modPlc.Type == PLCTypeEnum.ConveyorLine)
|
// result.Value.Add(modDevice.DbNumber + "." + modDevice.PlcPos, new Random().Next(2) == 0);
|
//}
|
foreach (var item in result.Value)
|
{
|
var modDevice = listDevice.FirstOrDefault(s => item.Key == (s.DbNumber + "." + s.PlcPos));
|
if (modDevice == null)
|
continue;
|
switch (modPlc.Type)
|
{
|
case PLCTypeEnum.StackingMachine:
|
{
|
var value = Convert.ToInt32(item.Value);
|
var height = Math.Round(value / 790000d * 200).ToInt();
|
var modPosition = listPlcPosition.FirstOrDefault(s => s.DeviceId == modDevice.Id && s.Text == "目的工位");
|
string EndLocat = "";
|
if (modPosition != null)
|
{
|
var (result2, value2) = modPlcUtil.GetPlcDBValue(modPosition.PosType, modDevice.DbNumber, modPosition.PlcPos);
|
if (result2.IsSucceed)
|
EndLocat = Convert.ToString(value2);
|
}
|
if (modDevice.BoxHeight != height || modDevice.EndLocat != EndLocat)
|
{
|
modDevice.EndLocat = EndLocat;
|
modDevice.BoxHeight = Math.Round(value / 790000d * 200).ToInt();
|
var modInfo = new PlcPositionInfo()
|
{
|
Type = modPlc.Type,
|
StationNum = modDevice.StationNum,
|
BoxHeight = modDevice.BoxHeight,
|
EndLocat = EndLocat,
|
};
|
HubUtil.PublicPosition(modInfo);
|
UpdatePosition(modInfo);
|
}
|
}
|
break;
|
case PLCTypeEnum.ConveyorLine:
|
{
|
var bl = false;
|
int value = Convert.ToInt32(item.Value);
|
if (value <= 30)
|
{
|
bl = false;
|
}
|
else
|
{
|
bl = true;
|
}
|
|
if (bl != modDevice.BoHaveItem)
|
{
|
modDevice.BoHaveItem = bl;
|
var modInfo = new PlcPositionInfo() { Type = modPlc.Type, StationNum = modDevice.StationNum.PadLeft(3, '0'), BoHaveItem = bl };
|
HubUtil.PublicPosition(modInfo);
|
UpdatePosition(modInfo);
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
}
|
Thread.Sleep(3000);
|
}
|
catch (Exception ex)
|
{
|
Log.Error("位置监控发生异常", ex);
|
}
|
}
|
});
|
}
|
/// <summary>
|
/// 修改位置信息
|
/// </summary>
|
/// <param name="modInfo"></param>
|
private static void UpdatePosition(PlcPositionInfo modInfo)
|
{
|
var modTemp = listPositionInfo.FirstOrDefault(s => s.StationNum == modInfo.StationNum && modInfo.Type == s.Type);
|
if (modTemp == null)
|
{
|
listPositionInfo.Add(modInfo);
|
}
|
else
|
{
|
modTemp.BoHaveItem = modInfo.BoHaveItem;
|
}
|
}
|
/// <summary>
|
/// 停止服务
|
/// </summary>
|
public static void Stop()
|
{
|
cts.Cancel();
|
boRunningState = false;
|
}
|
}
|