|
using Furion.Logging;
|
using IoTClient;
|
using Microsoft.AspNetCore.SignalR;
|
using System.Data;
|
|
namespace WCS.Application;
|
public static class PLCService
|
{
|
private static readonly ISqlSugarClient _db = SqlSugarSetup.ITenant.GetConnectionScope(SqlSugarConst.MainConfigId);
|
private static readonly IHubContext<TaskLogHub, ITaskLogHub> _taskLogHubContext;
|
|
static PLCService()
|
{
|
_taskLogHubContext = App.GetService<IHubContext<TaskLogHub, ITaskLogHub>>();
|
}
|
|
public static void OnChangeEvent(object sender, EventArgs e)
|
{
|
try
|
{
|
var mod = sender as WcsDeviceDto;
|
Console.WriteLine("PLC值为" + mod.Value);
|
switch (mod.Type)
|
{
|
case PLCTypeEnum.StackingMachine:
|
StackingMachine(mod);
|
break;
|
case PLCTypeEnum.ConveyorLine:
|
ConveyorLine(mod);
|
break;
|
case PLCTypeEnum.AGV:
|
AGV(mod);
|
break;
|
case PLCTypeEnum.PalletMachine:
|
PalletMachine(mod);
|
break;
|
default:
|
break;
|
}
|
}
|
catch (Exception ex)
|
{
|
Log.Error(ex.Message, ex);
|
}
|
}
|
/// <summary>
|
/// 跺机业务处理
|
/// </summary>
|
/// <param name="modDevice"></param>
|
private static void StackingMachine(WcsDeviceDto modDevice)
|
{
|
var plcConn = modDevice.PLCUtil;
|
switch (modDevice.ToString())
|
{
|
case "820":
|
{
|
var modTask = _db.Queryable<WcsTask>().First(s => s.Status == TaskStatusEnum.Wait && s.TaskType == TaskTypeEnum.Out && s.StartRoadway == modDevice.StationNum);
|
if (modTask == null)
|
{
|
break;
|
}
|
var modTaskMonitor = new WcsTaskMonitor()
|
{
|
TaskNo = modTask.TaskNo,
|
StartLocat = modTask.StartLocate,
|
EndLocat = modTask.EndLocate,
|
PalletNo = modTask.PalletNo,
|
};
|
// 根据跺机号确认放货工位
|
string outStationNum = "0";
|
string endRow = "", endColumn = "", endStorey = "";
|
switch (modDevice.StationNum)
|
{
|
case "R01":
|
outStationNum = "11";
|
endRow = "1";
|
endColumn = "100";
|
endStorey = "1";
|
break;
|
case "R02":
|
outStationNum = "7";
|
endRow = "1";
|
endColumn = "100";
|
endStorey = "1";
|
break;
|
default: break;
|
}
|
var modD = modDevice.listDevice.FirstOrDefault();
|
if (modD == null)
|
{
|
Log.Error($"IP{modDevice.PlcId}.设备id:{modDevice.Id}缺少工位级别设备信息");
|
break;
|
}
|
var (result, value) = plcConn.GetPlcDBValue(modD.PosType, modD.DbNumber, modD.PlcPos);
|
if (result.IsSucceed)
|
{
|
if (value == 120)// 放货工位空闲 可放货
|
{
|
if (int.Parse(outStationNum) > 0)
|
{
|
var row = int.Parse(modTaskMonitor.StartLocat.Substring(0, 2)).ToString();
|
var column = int.Parse(modTaskMonitor.StartLocat.Substring(2, 2)).ToString();
|
var layer = int.Parse(modTaskMonitor.StartLocat.Substring(4, 2)).ToString();
|
var deep = int.Parse(modTaskMonitor.StartLocat.Substring(6, 2)).ToString();
|
if (int.Parse(row) > 2) //大于4
|
{
|
row = (int.Parse(row) - 2).ToString();
|
}
|
else
|
{
|
// 起始储位地址为空,跳过 写入任务明细表
|
modTaskMonitor.StartLocat = "";
|
modTaskMonitor.InteractiveMsg = "起始储位为空!";
|
|
_db.Insertable(modTaskMonitor).ExecuteCommand();
|
//下发任务日志
|
_taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
|
break;
|
}
|
//给PLC写入任务数据
|
var listResult = new List<Result>();
|
//任务号
|
var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
|
listResult.Add(plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, modTaskMonitor.TaskNo));
|
//托盘号
|
var modPosPalletNo = modDevice.listStation.FirstOrDefault(s => s.Text == "PalletNo");
|
listResult.Add(plcConn.SetPlcDBValue(modPosPalletNo.PosType, modDevice.DbNumber, modPosPalletNo.PlcPos, modTaskMonitor.PalletNo));
|
//起始排
|
var modPosRow = modDevice.listStation.FirstOrDefault(s => s.Text == "StartRow");
|
listResult.Add(plcConn.SetPlcDBValue(modPosRow.PosType, modDevice.DbNumber, modPosRow.PlcPos, row));
|
// 起始列
|
var modPosColumn = modDevice.listStation.FirstOrDefault(s => s.Text == "StartColumn");
|
listResult.Add(plcConn.SetPlcDBValue(modPosColumn.PosType, modDevice.DbNumber, modPosColumn.PlcPos, column));
|
// 起始层
|
var modPosStorey = modDevice.listStation.FirstOrDefault(s => s.Text == "StartLayer");
|
listResult.Add(plcConn.SetPlcDBValue(modPosStorey.PosType, modDevice.DbNumber, modPosStorey.PlcPos, layer));
|
|
// 目标放货工位
|
var modPosEndRow = modDevice.listStation.FirstOrDefault(s => s.Text == "EndRow");
|
listResult.Add(plcConn.SetPlcDBValue(modPosEndRow.PosType, modDevice.DbNumber, modPosEndRow.PlcPos, endRow));
|
var modPosEndColumn = modDevice.listStation.FirstOrDefault(s => s.Text == "EndColumn");
|
listResult.Add(plcConn.SetPlcDBValue(modPosEndColumn.PosType, modDevice.DbNumber, modPosEndColumn.PlcPos, endColumn));
|
var modPosEndStorey = modDevice.listStation.FirstOrDefault(s => s.Text == "EndLayer");
|
listResult.Add(plcConn.SetPlcDBValue(modPosEndStorey.PosType, modDevice.DbNumber, modPosEndStorey.PlcPos, endColumn));
|
//全部写入成功
|
if (listResult.All(s => s.IsSucceed))
|
{
|
// 写入跺机任务下发完成
|
plcConn.SetPlcDBValue(modDevice.PosType.Value, modDevice.DbNumber, modDevice.WcsPos, "10");
|
|
// 将出库任务待执行改为正在执行
|
_db.Updateable<WcsTask>()
|
.SetColumns(s => s.FinishDate == DateTime.Now)
|
.SetColumns(s => s.Status == TaskStatusEnum.Doing)
|
.SetColumns(s => s.Levels == 2)
|
.Where(s => s.Id == modTask.Id)
|
.ExecuteCommand();
|
var modInsertTaskMonitor = new WcsTaskMonitor()
|
{
|
TaskNo = modTask.TaskNo,
|
PlcId = modDevice.Id,
|
PlcName = modDevice.Text,
|
InteractiveMsg = $"写入指令:{modTask.StartLocate}储位====》{outStationNum}工位",
|
PalletNo = modTask.PalletNo,
|
Status = TaskStatusEnum.Complete,
|
StartLocat = modTask.StartLocate,
|
EndLocat = outStationNum,
|
};
|
_db.Insertable(modInsertTaskMonitor).ExecuteCommand();
|
//下发任务日志
|
_taskLogHubContext.Clients.All.PublicTaskMonitor(modInsertTaskMonitor.Adapt<WcsTaskMonitorOutput>());
|
//修改led屏信息
|
//LedDisplay(modDevice.LedIP, "工位:" + modTask.EndLocate, "出库中 " + $"储位地址:{modTask.StartLocate}", "托盘号:" + modTask.PalletNo);
|
}
|
}
|
}
|
}
|
else
|
{
|
Log.Error(string.Join(',', result.ErrList));
|
}
|
}
|
break;
|
case "20":
|
{
|
var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo");
|
var modPosTask = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
|
var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos);
|
if (!result.IsSucceed)
|
break;
|
string taskNo = Convert.ToString(TaskNo);
|
var modTask = _db.Queryable<WcsTask>().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing);
|
if (modTask == null)
|
{
|
Log.Error("【跺机】当前托盘号不存在对应的任务");
|
break;
|
}
|
if (modTask.TaskType.Value == TaskTypeEnum.In)
|
{
|
//入库任务
|
var res = plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, taskNo);
|
if (!res.IsSucceed)
|
break;
|
// 根据跺机号确认取货工位
|
string outStationNum = "0";
|
switch (modDevice.StationNum)
|
{
|
case "R01":
|
outStationNum = "10";
|
break;
|
case "R02":
|
outStationNum = "6";
|
break;
|
default: break;
|
}
|
var modDevice2 = modDevice.listDevice.Where(s => s.StationNum == outStationNum).FirstOrDefault();
|
var modStation = _db.Queryable<WcsPosition>().First(s => s.DeviceId == modDevice2.Id && s.Text == "TaskNo");
|
// 向取货工位写入任务号
|
res = plcConn.SetPlcDBValue(modStation.PosType, modDevice2.DbNumber, modStation.PlcPos, taskNo);
|
if (!res.IsSucceed)
|
break;
|
// 向取货工位写入流程控制字
|
res = plcConn.SetPlcDBValue(modDevice2.PosType, modDevice2.DbNumber, modDevice2.WcsPos, "100");
|
if (!res.IsSucceed)
|
break;
|
var modTaskMonitor = new WcsTaskMonitor()
|
{
|
TaskNo = modTask.TaskNo,
|
PlcId = modDevice2.PlcId,
|
PlcName = modDevice2.Text,
|
InteractiveMsg = "跺机取货完成",
|
StartLocat = outStationNum,
|
EndLocat = modTask.EndLocate,
|
PalletNo = modTask.PalletNo,
|
Status = TaskStatusEnum.Complete
|
};
|
_db.Insertable(modTaskMonitor).ExecuteCommand();
|
//下发任务日志
|
_taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
|
|
}
|
else if (modTask.TaskType.Value == TaskTypeEnum.Out)
|
{
|
//入库任务
|
var res = plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, taskNo);
|
if (!res.IsSucceed)
|
break;
|
res = plcConn.SetPlcDBValue(modDevice.PosType.Value, modDevice.DbNumber, modDevice.WcsPos, "20");
|
if (!res.IsSucceed)
|
break;
|
// 根据跺机号确认取货工位
|
string outStationNum = "0";
|
switch (modDevice.StationNum)
|
{
|
case "R01":
|
outStationNum = "11";
|
break;
|
case "R02":
|
outStationNum = "7";
|
break;
|
default: break;
|
}
|
var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
|
var modTaskMonitor = new WcsTaskMonitor()
|
{
|
TaskNo = modTask.TaskNo,
|
PlcId = modDevice.PlcId,
|
PlcName = modDevice.Text,
|
InteractiveMsg = "跺机取货完成",
|
StartLocat = outStationNum,
|
EndLocat = modTask.EndLocate,
|
PalletNo = modTask.PalletNo,
|
Status = TaskStatusEnum.Complete
|
};
|
_db.Insertable(modTaskMonitor).ExecuteCommand();
|
//下发任务日志
|
_taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
|
}
|
}
|
break;
|
case "30":
|
{
|
//操作完成(放货完成)
|
var modPosPlcTask = modDevice.listStation.FirstOrDefault(s => s.Text == "PlcTaskNo");
|
var (result, TaskNo) = plcConn.GetPlcDBValue(modPosPlcTask.PosType, modDevice.DbNumber, modPosPlcTask.PlcPos);
|
if (!result.IsSucceed)
|
break;
|
string taskNo = Convert.ToString(TaskNo);
|
var modTask = _db.Queryable<WcsTask>().First(s => s.TaskNo == taskNo && s.Status == TaskStatusEnum.Doing);
|
if (modTask == null)
|
{
|
Log.Error("【跺机】当前托盘号不存在对应的任务");
|
break;
|
}
|
switch (modTask.TaskType)
|
{
|
case TaskTypeEnum.In:
|
case TaskTypeEnum.PLC:
|
{
|
//入库任务
|
var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
|
// 写入plc任务号
|
var res = plcConn.SetPlcDBValue(modStation.PosType, modDevice.DbNumber, modStation.PlcPos, taskNo);
|
if (!res.IsSucceed)
|
break;
|
res = plcConn.SetPlcDBValue(modDevice.PosType.Value, modDevice.DbNumber, modDevice.WcsPos, "30");
|
if (!res.IsSucceed)
|
break;
|
//修改任务状态
|
modTask.Status = TaskStatusEnum.Complete;
|
_db.Updateable<WcsTask>()
|
.SetColumns(s => s.Status == TaskStatusEnum.Complete)
|
.Where(s => s.Id == modTask.Id)
|
.ExecuteCommand();
|
//反馈给WMS
|
var modTaskRequest = modTask.Adapt<TaskRequest>();
|
HttpService httpService = new HttpService();
|
var modResponseTask = httpService.RequestTask(modTaskRequest).Result;
|
if (modResponseTask.StatusCode == "0")
|
{
|
//请求成功
|
modTask.IsSuccess = TaskSuccessEnum.Success;
|
_db.Updateable(modTask).UpdateColumns(s => s.IsSuccess).ExecuteCommand();
|
//todo:修改储位信息 任务类型 执行状态 起始位置 目标位置
|
//
|
|
//记录任务明细
|
var modTaskMonitor = new WcsTaskMonitor()
|
{
|
TaskNo = modTask.TaskNo,
|
PlcId = modDevice.PlcId,
|
PlcName = modDevice.Text,
|
InteractiveMsg = "任务完成,返回给WMS任务完成",
|
StartLocat = modTask.StartLocate,
|
EndLocat = modTask.EndLocate,
|
PalletNo = modTask.PalletNo,
|
Status = TaskStatusEnum.Complete
|
};
|
_db.Insertable(modTaskMonitor).ExecuteCommand();
|
//下发任务日志
|
_taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
|
}
|
else
|
{
|
//请求失败
|
modTask.IsSuccess = TaskSuccessEnum.Fail;
|
modTask.Information = modResponseTask.Message;
|
_db.Updateable(modTask).UpdateColumns(s => new { s.IsSuccess, s.Information }).ExecuteCommand();
|
}
|
//todo:垛机入库不空跑
|
|
//todo:LED
|
}
|
break;
|
case TaskTypeEnum.Out://出库
|
// 从出库任务获取巷道号
|
string num = ""; // 放货工位号
|
if (modTask.StartRoadway == "R01")
|
{
|
num = "11"; //交互工位
|
}
|
else if (modTask.StartRoadway == "R02")
|
{
|
num = "7"; //交互工位
|
}
|
var modDevice2 = modDevice.listDevice.FirstOrDefault(s => s.StationNum == num);
|
if (modDevice2 == null)
|
{
|
Log.Error($"【跺机】找不到工位{num}设备信息");
|
break;
|
}
|
// 根据目标口获取目标工位
|
string outCode = modTask.EndLocate.IsNullOrEmpty() ? "-1" : modTask.EndLocate;
|
|
var listStation = _db.Queryable<WcsPosition>().Where(s => s.DeviceId == modDevice2.Id).ToList();
|
//给PLC写入任务数据
|
var listResult = new List<Result>();
|
//任务号
|
var modPosTask = listStation.FirstOrDefault(s => s.Text == "TaskNo");
|
listResult.Add(plcConn.SetPlcDBValue(modPosTask.PosType, modDevice.DbNumber, modPosTask.PlcPos, modTask.TaskNo));
|
//托盘号
|
var modPosPalletNo = listStation.FirstOrDefault(s => s.Text == "PalletNo");
|
listResult.Add(plcConn.SetPlcDBValue(modPosPalletNo.PosType, modDevice.DbNumber, modPosPalletNo.PlcPos, modTask.PalletNo));
|
//起始工位
|
var modPosLocatNo = listStation.FirstOrDefault(s => s.Text == "StartLocatNo");
|
listResult.Add(plcConn.SetPlcDBValue(modPosLocatNo.PosType, modDevice.DbNumber, modPosLocatNo.PlcPos, num));
|
// 目标工位
|
var modPosEndLocatNo = listStation.FirstOrDefault(s => s.Text == "EndLocatNo");
|
listResult.Add(plcConn.SetPlcDBValue(modPosEndLocatNo.PosType, modDevice.DbNumber, modPosEndLocatNo.PlcPos, outCode));
|
//全部写入成功
|
if (listResult.All(s => s.IsSucceed))
|
{
|
// 写入工位wcs控制字
|
var res = plcConn.SetPlcDBValue(modDevice2.PosType, modDevice2.DbNumber, modDevice2.WcsPos, "120");
|
if (!res.IsSucceed)
|
break;
|
//写入plc任务号
|
var modStation = modDevice.listStation.FirstOrDefault(s => s.Text == "TaskNo");
|
res = plcConn.SetPlcDBValue(modStation.PosType, modDevice.DbNumber, modStation.PlcPos, modTask.TaskNo);
|
if (!res.IsSucceed)
|
break;
|
//写入跺机wcs控制字流程30 返回垛机执行完成
|
res = plcConn.SetPlcDBValue(modDevice.PosType.Value, modDevice.DbNumber, modDevice.WcsPos, "30");
|
if (!res.IsSucceed)
|
break;
|
//记录任务明细
|
var modTaskMonitor = new WcsTaskMonitor()
|
{
|
TaskNo = modTask.TaskNo,
|
PlcId = modDevice2.PlcId,
|
PlcName = modDevice2.Text,
|
InteractiveMsg = $"写入指令:收到跺机放货完成;放货{num}工位===》{outCode}出库口",
|
PalletNo = modTask.PalletNo,
|
Status = TaskStatusEnum.Complete,
|
StartLocat = num, //起始位置
|
EndLocat = outCode, //目标工位
|
};
|
_db.Insertable(modTaskMonitor).ExecuteCommand();
|
|
//下发任务日志
|
_taskLogHubContext.Clients.All.PublicTaskMonitor(modTaskMonitor.Adapt<WcsTaskMonitorOutput>());
|
//todo:垛机出库不空跑
|
}
|
|
break;
|
case TaskTypeEnum.Move:
|
|
break;
|
default:
|
break;
|
}
|
}
|
break;
|
default:
|
break;
|
}
|
}
|
/// <summary>
|
/// 输送线业务处理
|
/// </summary>
|
/// <param name="modDevice"></param>
|
private static void ConveyorLine(WcsDeviceDto modDevice)
|
{
|
|
}
|
/// <summary>
|
/// AGV业务处理
|
/// </summary>
|
/// <param name="modDevice"></param>
|
private static void AGV(WcsDeviceDto modDevice)
|
{
|
|
}
|
/// <summary>
|
/// 叠托机业务处理
|
/// </summary>
|
/// <param name="modDevice"></param>
|
private static void PalletMachine(WcsDeviceDto modDevice)
|
{
|
|
}
|
|
private static void Test(WcsDeviceDto modDevice)
|
{
|
//写死测试读string
|
var (res, val) = modDevice.PLCUtil.GetPlcDBValue(PLCDataTypeEnum.String, "DB100", "64");
|
Console.WriteLine("DB100.64----" + val);
|
//测试批量读取
|
Dictionary<string, PLCDataTypeEnum> listaddress = new Dictionary<string, PLCDataTypeEnum>();
|
foreach (var modStation in modDevice.listStation)
|
{
|
listaddress.Add(modStation.PlcPos, modStation.PosType);
|
}
|
var result = modDevice.PLCUtil.GetPlcBatchDBValue(listaddress);
|
if (result.Value.Count > 0)
|
{
|
foreach (var value in result.Value)
|
{
|
Console.WriteLine("地址" + value.Key + "----值" + value, value);
|
}
|
}
|
if (!result.IsSucceed)
|
{
|
foreach (var err in result.ErrList)
|
{
|
Console.WriteLine(err);
|
}
|
if (result.Value.Count > 0)//有错误的也有成功的
|
{
|
|
}
|
}
|
if (modDevice.Value == 820)
|
{
|
//测试写入830
|
//var result = mod.PLCUtil.SetPlcDBValue(mod.PosType.Value, mod.DbNumber, mod.PlcPos, "830");
|
////写入是否成功
|
//if (result.IsSucceed)
|
//{
|
|
//}
|
}
|
else if (modDevice.Value == 840)
|
{
|
|
}
|
else if (modDevice.Value == 860)
|
{
|
|
}
|
}
|
|
}
|