Platform_InteractionHandlerPick.cs
9.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
using Grpc.Core;
using HaHRCS.Rcs.Dal.Repository;
using HaHRCS.Rcs.Executor.Enums;
using HaHRCS.Rcs.Executor.PLC;
using HaHRCS.Rcs.Model.Entities;
using MassTransit;
using Microsoft.Extensions.Logging;
using Rcs.Application.Common;
using Rcs.Application.MessageBus.Commands;
using Rcs.Domain.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ConvingStatus = HaHRCS.Rcs.Model.Entities.ConvingStatus;
namespace Rcs.Infrastructure.MessageBus.Handlers.Commands.PLCInteraction
{
/// <summary>
/// 站台交互处理器
/// </summary>
public class Platform_InteractionHandlerPick : IConsumer<PLCStationInteraction>
{
private readonly EquipmentExecutor _equipmentExecutor;
private readonly ILogger<Platform_InteractionHandlerPick> _logger;
private readonly PlatformPickRepository _platformRepository;
public Platform_InteractionHandlerPick(
ILogger<Platform_InteractionHandlerPick> logger,
PlatformPickRepository platformRepository,
EquipmentExecutor equipmentExecutor)
{
_logger = logger;
_platformRepository = platformRepository;
_equipmentExecutor = equipmentExecutor;
}
/// <summary>
/// 取货
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task Consume(ConsumeContext<PLCStationInteraction> context)
{
var command = context.Message;
try
{
// 1. 集中参数校验
ValidateCommand(command,context);
// 2. 获取并校验设备
var equipment = _equipmentExecutor.equipment.First(t => t.Code == command.EquipmentCode);
if (equipment == null || string.IsNullOrEmpty(equipment.Code))
await context.RespondAsync(ApiResponse.ErrorToPlc("无效站台设备,请检查设备名称"));
// 3. 检查设备就绪状态
var pickConveyorReady = equipment[$"{StationProps.PickConveyorReady}"].Value;
if (pickConveyorReady == "")
{
await context.RespondAsync(ApiResponse.ErrorToPlc("请检查设备是否离线,设备不在线"));
return;
}
if (pickConveyorReady == "False")
{
await context.RespondAsync(ApiResponse.ErrorToPlc("取货设备暂未准备就绪"));
return;
}
// 4. 处理取货指令(带重试逻辑)
await HandlePickupCommand(command, equipment, context);
}
catch (Exception ex)
{
_logger.LogError(ex, $"处理PLC取货指令异常,设备编码:{command?.EquipmentCode},指令类型:{command?.Pickup}");
throw new InvalidOperationException(ex.Message);
}
}
#region 核心辅助方法(带重试)
/// <summary>
/// 参数校验
/// </summary>
private void ValidateCommand(PLCStationInteraction command, ConsumeContext<PLCStationInteraction> context)
{
if (string.IsNullOrEmpty(command.EquipmentCode))
{
context.RespondAsync(ApiResponse.ErrorToPlc("请确认哪条输送线设备"));
return;
}
if (command.Pickup == 0)
{
context.RespondAsync(ApiResponse.ErrorToPlc("请确认指令发送"));
return;
}
if (string.IsNullOrEmpty(command.Barcode))
{
context.RespondAsync(ApiResponse.ErrorToPlc("无效托盘码,托盘码为空"));
return;
}
}
/// <summary>
/// 处理不同取货指令
/// </summary>
private async Task HandlePickupCommand(PLCStationInteraction command, Equipment equipment, ConsumeContext<PLCStationInteraction> context)
{
var pickupStatus = command.Pickup;
var allowPick = equipment[$"{StationProps.AllowPick}"].Value;
switch (pickupStatus)
{
// 取货请求(单个属性写入+重试)
case var s when s == ConvingStatus.PickRequest.GetIndexInt():
await WritePlcPropWithRetry(equipment, StationProps.PickRequest.ToString(), "True", "取货信号下发PLC成功", "下发取货信号失败", context, retryTimes: 3, delayMs: 500);
if (allowPick != "True")
{
await context.RespondAsync(ApiResponse.ErrorToPlc("PLC未给允许取货信号"));
return;
}
await WritePlcPropWithRetry(equipment, StationProps.PickRuning.ToString(), "True", "取货准备好信号下发成功", "取货准备好信号下发失败", context, retryTimes: 3, delayMs: 500);
break;
// 取货运行中(单个属性写入+重试)
//case var s when s == ConvingStatus.PickRuning.GetIndexInt():
// if (allowPick != "True")
// {
// await context.RespondAsync(ApiResponse.ErrorToPlc("PLC未给允许取货信号"));
// return;
// }
// await WritePlcPropWithRetry(equipment, StationProps.PickRuning.ToString(), "True", "取货准备好信号下发成功", "取货准备好信号下发失败", context, retryTimes: 3, delayMs: 500);
// break;
// 取货完成(批量属性写入+重试)
case var s when s == ConvingStatus.PickDone.GetIndexInt():
await WritePlcPropsBatchWithRetry(equipment, context, retryTimes: 3, delayMs: 500);
break;
default:
await context.RespondAsync(ApiResponse.ErrorToPlc("指令错误"));
break;
}
}
/// <summary>
/// 单个PLC属性写入(带重试机制)
/// </summary>
/// <param name="retryTimes">重试次数</param>
/// <param name="delayMs">每次重试间隔(毫秒)</param>
private async Task WritePlcPropWithRetry(Equipment equipment, string propKey, string value,
string successMsg, string failMsg, ConsumeContext<PLCStationInteraction> context,
int retryTimes = 3, int delayMs = 500)
{
int attempt = 0;
while (attempt < retryTimes)
{
lock (_equipmentExecutor.WriteFlag)
{
var prop = equipment[$"{propKey}"];
prop.Value = value;
try
{
var result = _equipmentExecutor.EquipmentCommunicationHub.Write(prop);
if (result.Success)
{
context.RespondAsync(ApiResponse.SuccessfulToPlc(successMsg));
return; // 成功则退出
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"第{attempt + 1}次写入PLC属性【{propKey}】失败,将重试");
}
}
attempt++;
if (attempt < retryTimes)
await Task.Delay(delayMs); // 重试前等待
}
// 重试逻辑
// 所有重试都失败,抛出异常
throw new InvalidOperationException($"{failMsg}(已重试{retryTimes}次)");
}
/// <summary>
/// 批量PLC属性写入(带重试机制)
/// </summary>
private async Task WritePlcPropsBatchWithRetry(Equipment equipment, ConsumeContext<PLCStationInteraction> context,
int retryTimes = 3, int delayMs = 500)
{
int attempt = 0;
//var props = new List<EquipmentProp> { prop1, prop2, prop3 };
// 重试逻辑
while (attempt < retryTimes)
{
lock (_equipmentExecutor.WriteFlag)
{
// 准备要写入的属性
var prop1 = equipment[$"{StationProps.PickRequest}"]; prop1.Value = "False";
var prop2 = equipment[$"{StationProps.PickRuning}"]; prop2.Value = "Fasle";
var prop3 = equipment[$"{StationProps.PickDone}"]; prop3.Value = "True";
try
{
var result = _equipmentExecutor.EquipmentCommunicationHub.Writes(prop1, prop2, prop3);
if (result.Success)
{
context.RespondAsync(ApiResponse.SuccessfulToPlc("取货完成信号告知PLC成功"));
return; // 成功则退出
}
}
catch (Exception ex)
{
_logger.LogWarning(ex, $"第{attempt + 1}次批量写入PLC属性失败,将重试");
}
}
attempt++;
if (attempt < retryTimes)
await Task.Delay(delayMs);
}
// 所有重试都失败
throw new InvalidOperationException($"取货完成信号告知PLC失败(已重试{retryTimes}次)");
}
#endregion
}
}