diff --git a/Sln.Wcs.HoistAdapter/Domain/Dto/HoistControl/HoistControlDto.cs b/Sln.Wcs.HoistAdapter/Domain/Dto/HoistControl/HoistControlDto.cs index e189a67..1b74790 100644 --- a/Sln.Wcs.HoistAdapter/Domain/Dto/HoistControl/HoistControlDto.cs +++ b/Sln.Wcs.HoistAdapter/Domain/Dto/HoistControl/HoistControlDto.cs @@ -34,6 +34,11 @@ public class HoistControlDto /// public string hoistCode { get; set; } + /// + /// 设备序号 + /// + public int deviceSerialNo{get;set;} + /// /// 动作 /// diff --git a/Sln.Wcs.HoistAdapter/Domain/Dto/HoistTaskExecutor/HoistTaskExeDto.cs b/Sln.Wcs.HoistAdapter/Domain/Dto/HoistTaskExecutor/HoistTaskExeDto.cs index aa3e217..a6cc66d 100644 --- a/Sln.Wcs.HoistAdapter/Domain/Dto/HoistTaskExecutor/HoistTaskExeDto.cs +++ b/Sln.Wcs.HoistAdapter/Domain/Dto/HoistTaskExecutor/HoistTaskExeDto.cs @@ -37,6 +37,11 @@ public class HoistTaskExeDto /// public string taskCode { get; set; } + /// + /// 设备序号 + /// + public int deviceSerialNo{get;set;} + /// /// 起点 /// diff --git a/Sln.Wcs.HoistAdapter/Service/Impl/HoistService.cs b/Sln.Wcs.HoistAdapter/Service/Impl/HoistService.cs index cc2a5c5..0ea50b0 100644 --- a/Sln.Wcs.HoistAdapter/Service/Impl/HoistService.cs +++ b/Sln.Wcs.HoistAdapter/Service/Impl/HoistService.cs @@ -114,6 +114,7 @@ public class HoistService:IHoistService { hoistCode = hoistTaskExeDto.hoistCode, taskCode = hoistTaskExeDto.taskCode, + deviceSerialNo = hoistTaskExeDto.deviceSerialNo, startPoint = hoistTaskExeDto.startPoint, endPoint = hoistTaskExeDto.endPoint, diff --git a/Sln.Wcs.HoistDispatcher/HoistDispatchHub.cs b/Sln.Wcs.HoistDispatcher/HoistDispatchHub.cs new file mode 100644 index 0000000..54334a1 --- /dev/null +++ b/Sln.Wcs.HoistDispatcher/HoistDispatchHub.cs @@ -0,0 +1,192 @@ +#region << 版 本 注 释 >> + +/*-------------------------------------------------------------------- +* 版权所有 (c) 2026 WenJY 保留所有权利。 +* CLR版本:4.0.30319.42000 +* 机器名称:Mr.Wen's MacBook Pro +* 命名空间:Sln.Wcs.HoistDispatchHub +* 唯一标识:764B880E-8084-48A5-B773-95E8EA044319 +* +* 创建者:WenJY +* 电子邮箱: +* 创建时间:2026-06-01 13:24:25 +* 版本:V1.0.0 +* 描述: +* +*-------------------------------------------------------------------- +* 修改人: +* 时间: +* 修改说明: +* +* 版本:V1.0.0 +*--------------------------------------------------------------------*/ + +#endregion << 版 本 注 释 >> + +using Newtonsoft.Json; +using Sln.Wcs.HoistAdapter.Domain.Dto.GetHoistStatus; +using Sln.Wcs.HoistAdapter.Domain.Dto.HoistControl; +using Sln.Wcs.HoistAdapter.Domain.Dto.HoistTaskExecutor; +using Sln.Wcs.HoistAdapter.Domain.Enum; +using Sln.Wcs.HoistAdapter.Service; +using Sln.Wcs.Model.Domain; +using Sln.Wcs.Serilog; + +namespace Sln.Wcs.HoistDispatcher; + +public class HoistDispatchHub +{ + private readonly SerilogHelper _logger; + private readonly IHoistService _hoistAdapter; + public HoistDispatchHub(IHoistService hoistAdapter, SerilogHelper logger) + { + _hoistAdapter = hoistAdapter; + _logger = logger; + } + + /// + /// 提升机启动:放置完成下发 + /// + /// + public void TaskRun(BaseDeviceInfo deviceInfo) + { + try + { + HoistControlResultDto res = _hoistAdapter.HoistControl(new HoistControlDto() + { + hoistCode = deviceInfo.hostCode, + deviceSerialNo = deviceInfo.deviceSerialNo, + action = ControlAction.Start + }); + + if (res.code == HoistStatusEnum.成功) + { + _logger.Info($"提升机启动指令(放置完成)下发成功"); + } + else + { + _logger.Info($"提升机启动指令(放置完成)下发失败:{res.msg},SDK返回信息:{res.data.message}"); + } + } + catch (Exception e) + { + _logger.Info($"提升机启动指令(放置完成)下发异常:{e.Message}"); + } + } + + /// + /// 提升机任务下发执行:可根据现场节拍进行提前下发(AGV 确定接驳位后即可下发) + /// + /// + /// + public void TaskDispatch(BaseDeviceInfo deviceInfo,LiveTaskDetail liveTaskDetail) + { + try + { + //解析起始点,组合 PLC 所需的起始点 + TryParsePointCode(liveTaskDetail.startPoint, out string startBuilding, out string startFloor, + out string startLocation); + TryParsePointCode(liveTaskDetail.endPoint, out string endBuilding, out string endFloor, + out string endLocation); + int endPoint = Convert.ToInt32(deviceInfo.deviceSerialNo + startFloor + endFloor); + + //调用适配层下发 提升机调度任务 + HoistTaskExeResultDto res = _hoistAdapter.HoistTaskExecutor(new HoistTaskExeDto() + { + hoistCode = deviceInfo.hostCode, + taskCode = liveTaskDetail.taskCode, + deviceSerialNo = deviceInfo.deviceSerialNo, + endPoint = endPoint, + }); + + if (res.code == HoistStatusEnum.成功) + { + _logger.Info($"提升机任务{liveTaskDetail.taskCode}下发成功:目标位置-{endPoint}"); + } + else + { + _logger.Info($"提升机任务{liveTaskDetail.taskCode}下发失败:{res.msg},SDK返回信息:{res.data.message}"); + } + } + catch (Exception e) + { + _logger.Info($"提升机任务下发异常:{e.Message}"); + } + } + + /// + /// 获取空闲提升机 + /// + /// + /// + public async Task GetFreeHoistAsync(string hostCode) + { + while (true) + { + RefreshDeviceParams(hostCode, out List deviceInfos); + + var freeHoist = deviceInfos?.FirstOrDefault(info => + info.deviceParams.Any(item => + item.paramName.Contains("提升机反馈任务状态") && item.paramValue == 0 + ) + ); + + if (freeHoist != null) + return freeHoist; + + await Task.Delay(1000); + } + } + + /// + /// 刷新设备参数:根据设备参数地址通过 PLC 获取参数值 + /// hostCode为空时获取配置的所有参数值 + /// + /// + /// + private void RefreshDeviceParams(string hostCode,out List deviceParams) + { + deviceParams = null; + + GetHoistStatusResultDto getRes = _hoistAdapter.GetHoistStatus(new GetHoistStatusDto(){hoistCode = hostCode}); + + if (getRes.code == HoistStatusEnum.成功) + { + deviceParams = JsonConvert.DeserializeObject>(getRes.data.deviceParamStr); + } + else + { + _logger.Info($"设备参数获取失败:{getRes.msg}"); + } + } + + /// + /// 解析起始点内容 + /// 14#_L2_02 => 14栋、2层、02货位 + /// + /// + /// + /// + /// + /// + private bool TryParsePointCode(string taskCode, out string building, out string floor, out string location) + { + building = null; + floor = null; + location = null; + + if (string.IsNullOrWhiteSpace(taskCode)) + return false; + + // 使用正则表达式匹配格式:数字+#+_+L+数字+_+数字(至少一位) + // 示例:14#_L2_03 + var match = System.Text.RegularExpressions.Regex.Match(taskCode, @"^(\d+)#_L(\d+)_(\d+)$"); + if (!match.Success) + return false; + + building = match.Groups[1].Value; + floor = match.Groups[2].Value; + location = match.Groups[3].Value; + return true; + } +} \ No newline at end of file diff --git a/Sln.Wcs.HoistDispatcher/HoistDispatcher.cs b/Sln.Wcs.HoistDispatcher/HoistDispatcher.cs deleted file mode 100644 index e16993b..0000000 --- a/Sln.Wcs.HoistDispatcher/HoistDispatcher.cs +++ /dev/null @@ -1,112 +0,0 @@ -#region << 版 本 注 释 >> - -/*-------------------------------------------------------------------- -* 版权所有 (c) 2026 WenJY 保留所有权利。 -* CLR版本:4.0.30319.42000 -* 机器名称:Mr.Wen's MacBook Pro -* 命名空间:Sln.Wcs.HoistDispatcher -* 唯一标识:764B880E-8084-48A5-B773-95E8EA044319 -* -* 创建者:WenJY -* 电子邮箱: -* 创建时间:2026-06-01 13:24:25 -* 版本:V1.0.0 -* 描述: -* -*-------------------------------------------------------------------- -* 修改人: -* 时间: -* 修改说明: -* -* 版本:V1.0.0 -*--------------------------------------------------------------------*/ - -#endregion << 版 本 注 释 >> - -using Newtonsoft.Json; -using Sln.Wcs.HoistAdapter.Domain.Dto.GetHoistStatus; -using Sln.Wcs.HoistAdapter.Domain.Enum; -using Sln.Wcs.HoistAdapter.Service; -using Sln.Wcs.Model.Domain; -using Sln.Wcs.Plc.Service; -using Sln.Wcs.Repository.service; -using Sln.Wcs.Serilog; - -namespace Sln.Wcs.HoistDispatcher; - -public class HoistDispatcher -{ - private readonly SerilogHelper _logger; - private readonly IHoistService _hoistAdapter; - public HoistDispatcher(IHoistService hoistAdapter, SerilogHelper logger) - { - _hoistAdapter = hoistAdapter; - _logger = logger; - } - - public void Run() - { - _logger.Info("提升机调度就绪,输入 start 启动,stop 停止,quit 退出"); - - while (true) - { - var input = Console.ReadLine()?.Trim().ToLower(); - - switch (input) - { - case "start": - Start(); - break; - case "stop": - Stop(); - break; - case "quit": - Stop(); - return; - default: - _logger.Info("未知指令,可用: start | stop | quit"); - break; - } - } - } - - private void Start() - { - - } - - private void Stop() - { - - } - - - - public void Run(string hostCode,string tagCode,int startPoint,int endPoint) - { - //收到提升机调度任务 - - // 1、读取 RFID 条码 - // 2、下发提升机任务:起点、终点 - // 3、等待提升机完成任务 - RefreshDeviceParams(hostCode,out List deviceInfos); - - } - - - public void RefreshDeviceParams(string hostCode,out List deviceParams) - { - deviceParams = null; - - GetHoistStatusResultDto getRes = _hoistAdapter.GetHoistStatus(new GetHoistStatusDto(){hoistCode = hostCode}); - - if (getRes.code == HoistStatusEnum.成功) - { - deviceParams = JsonConvert.DeserializeObject>(getRes.data.deviceParamStr); - } - else - { - _logger.Info($"设备参数获取失败:{getRes.msg}"); - } - } -} \ No newline at end of file diff --git a/Sln.Wcs.HoistSdk/Dto/HoistControl/HoistControlDto.cs b/Sln.Wcs.HoistSdk/Dto/HoistControl/HoistControlDto.cs index 87714f4..0ff97ff 100644 --- a/Sln.Wcs.HoistSdk/Dto/HoistControl/HoistControlDto.cs +++ b/Sln.Wcs.HoistSdk/Dto/HoistControl/HoistControlDto.cs @@ -34,6 +34,11 @@ public class HoistControlDto /// public string hoistCode { get; set; } + /// + /// 设备序号 + /// + public int deviceSerialNo{get;set;} + /// /// 动作 /// diff --git a/Sln.Wcs.HoistSdk/Dto/HoistTaskExecutor/HoistTaskExeDto.cs b/Sln.Wcs.HoistSdk/Dto/HoistTaskExecutor/HoistTaskExeDto.cs index 4d7d457..8e12def 100644 --- a/Sln.Wcs.HoistSdk/Dto/HoistTaskExecutor/HoistTaskExeDto.cs +++ b/Sln.Wcs.HoistSdk/Dto/HoistTaskExecutor/HoistTaskExeDto.cs @@ -37,6 +37,11 @@ public class HoistTaskExeDto /// public string taskCode { get; set; } + /// + /// 设备序号 + /// + public int deviceSerialNo{get;set;} + /// /// 起点 /// diff --git a/Sln.Wcs.HoistSdk/HoistSdk.cs b/Sln.Wcs.HoistSdk/HoistSdk.cs index 08e8bce..ec3b48a 100644 --- a/Sln.Wcs.HoistSdk/HoistSdk.cs +++ b/Sln.Wcs.HoistSdk/HoistSdk.cs @@ -24,6 +24,7 @@ #endregion << 版 本 注 释 >> using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Sln.Wcs.HoistSdk.Config; using Sln.Wcs.HoistSdk.Dto.GetHoistStatus; using Sln.Wcs.HoistSdk.Dto.HoistControl; @@ -50,8 +51,9 @@ public class HoistSdk:IHoistSdk HoistControlResultDto result = new HoistControlResultDto(); try { + string paramAddress = GetPlcParam(hoistControlDto.hoistCode,hoistControlDto.deviceSerialNo,"放置完成"); var plc = _plcs.Where(x => x.ConfigKey.Equals(hoistControlDto.hoistCode)).ToList().First(); - var res = plc.writeInt16ByAddress(_hoistConfig.hoist_control_addr, (int)hoistControlDto.action); + var res = plc.writeInt16ByAddress(paramAddress, (int)hoistControlDto.action); if (res) { result.code = "0"; @@ -73,7 +75,29 @@ public class HoistSdk:IHoistSdk public HoistTaskExeResultDto HoistTaskExecutor(HoistTaskExeDto hoistTaskExeDto) { - throw new NotImplementedException(); + HoistTaskExeResultDto result = new HoistTaskExeResultDto(); + try + { + string paramAddress = GetPlcParam(hoistTaskExeDto.hoistCode,hoistTaskExeDto.deviceSerialNo,"任务执行指令"); + var plc = _plcs.Where(x => x.ConfigKey.Equals(hoistTaskExeDto.hoistCode)).ToList().First(); + var res = plc.writeInt16ByAddress(paramAddress, hoistTaskExeDto.endPoint); + if (res) + { + result.code = "0"; + result.message = "写入成功"; + } + else + { + result.code = "99"; + result.message = "写入失败"; + } + } + catch (Exception e) + { + result.code = "99"; + result.message = e.Message; + } + return result; } public GetHoistStatusResultDto GetHoistStatus(GetHoistStatusDto hoistStatusDto) @@ -97,18 +121,18 @@ public class HoistSdk:IHoistSdk if (item.hostCode == hoistStatusDto.hoistCode) { - // var plc = _plcs.Where(x => x.ConfigKey.Equals(item.hostCode)).FirstOrDefault(); - // if (plc == null) - // { - // result.code = "99"; - // result.message = $"未找到PLC: {item.hostCode}"; - // result.hoistCode = hoistStatusDto.hoistCode; - // return result; - // } - // + var plc = _plcs.Where(x => x.ConfigKey.Equals(item.hostCode)).FirstOrDefault(); + if (plc == null) + { + result.code = "99"; + result.message = $"未找到PLC: {item.hostCode}"; + result.hoistCode = hoistStatusDto.hoistCode; + return result; + } + foreach (var param in item.deviceParams) { - //int value = plc.readInt16ByAddress(param.paramAddress); + int value = plc.readInt16ByAddress(param.paramAddress); param.paramValue = param.objId; @@ -138,5 +162,20 @@ public class HoistSdk:IHoistSdk } return result; } + + private string GetPlcParam(string hostCode,int deviceSerialNo,string paramName) + { + List paramStr = JsonConvert.DeserializeObject>(_hoistConfig.hoist_plc_param); + + dynamic deviceInfo = paramStr.Where(x => x.hostCode == hostCode && x.deviceSerialNo == deviceSerialNo) + .FirstOrDefault(); + + List deviceParams = (deviceInfo.deviceParams as JArray)?.ToObject>(); + + dynamic deviceParam = deviceParams + .Where(x => ((string)x.paramName).Contains(paramName) && (int)x.operationType == 2).FirstOrDefault(); + + return deviceParam.paramAddress; + } } \ No newline at end of file diff --git a/Sln.Wcs.Model/Domain/BaseDeviceInfo.cs b/Sln.Wcs.Model/Domain/BaseDeviceInfo.cs index c786aca..f6b50a2 100644 --- a/Sln.Wcs.Model/Domain/BaseDeviceInfo.cs +++ b/Sln.Wcs.Model/Domain/BaseDeviceInfo.cs @@ -60,12 +60,16 @@ namespace Sln.Wcs.Model.Domain public string deviceName { get; set; } /// - /// Desc:主机编号 - /// Default: - /// Nullable:False + /// 设备别名 /// - [SugarColumn(ColumnName = "host_code")] - public string hostCode { get; set; } + [SugarColumn(ColumnName = "device_alias")] + public string deviceAlias { get; set; } + + /// + /// 设备序号 + /// + [SugarColumn(ColumnName = "device_serialNo")] + public int deviceSerialNo { get; set; } /// /// Desc:设备类型:0-输送线;1-AGV;2-提升机 @@ -82,6 +86,14 @@ namespace Sln.Wcs.Model.Domain /// [SugarColumn(ColumnName = "device_status")] public int? deviceStatus { get; set; } + + /// + /// Desc:主机编号 + /// Default: + /// Nullable:False + /// + [SugarColumn(ColumnName = "host_code")] + public string hostCode { get; set; } /// /// Desc:是否标识:1-是;0-否 diff --git a/Sln.Wcs.Repository/service/Impl/BaseDeviceInfoServiceImpl.cs b/Sln.Wcs.Repository/service/Impl/BaseDeviceInfoServiceImpl.cs index 60b1343..f1062ed 100644 --- a/Sln.Wcs.Repository/service/Impl/BaseDeviceInfoServiceImpl.cs +++ b/Sln.Wcs.Repository/service/Impl/BaseDeviceInfoServiceImpl.cs @@ -52,6 +52,8 @@ namespace Sln.Wcs.Repository.service.Impl deviceName = device.deviceName, deviceType = device.deviceType, deviceStatus = device.deviceStatus, + deviceSerialNo = device.deviceSerialNo, + deviceAlias = device.deviceAlias, hostCode = device.hostCode, isFlag = device.isFlag, remark = device.remark, diff --git a/Sln.Wcs/Program.cs b/Sln.Wcs/Program.cs index a400623..20e9500 100644 --- a/Sln.Wcs/Program.cs +++ b/Sln.Wcs/Program.cs @@ -13,8 +13,11 @@ using Sln.Wcs.HikRoBotAdapter.Domain.Dto.GenAgvSchedulingTask; using Sln.Wcs.HikRoBotAdapter.Service; using Sln.Wcs.HikRoBotAdapter.Service.Impl; using Sln.Wcs.HoistAdapter.Service; +using Sln.Wcs.HoistDispatcher; using Sln.Wcs.HoistSdk; using Sln.Wcs.HoistSdk.Dto.GetHoistStatus; +using Sln.Wcs.HoistSdk.Dto.HoistControl; +using Sln.Wcs.HoistSdk.Enum; using Sln.Wcs.Model.Domain; using Sln.Wcs.Repository; using Sln.Wcs.Repository.service; @@ -70,9 +73,6 @@ namespace Sln.Wcs // } // }); - var service = serviceProvider.GetService(); - service.Run(string.Empty,"tagCode",1,2); - Task.Delay(-1).Wait(); } @@ -89,11 +89,11 @@ namespace Sln.Wcs Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HikRoBotAdapter.dll")), Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HikRoBotSdk.dll")), Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HoistAdapter.dll")), + Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HoistDispatcher.dll")), Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HoistSdk.dll")), Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Plc.dll")), Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Business.dll")), Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.Strategy.dll")), - Assembly.LoadFrom(Path.Combine(basePath, "Sln.Wcs.HoistDispatcher.dll")), }; services.Scan(scan => scan.FromAssemblies(assemblies)