Platform_InteractionHandlerRelease.cs
9.68 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
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_InteractionHandlerRelease : IConsumer<PLCStationReleaseInteraction>
{
private readonly EquipmentExecutor _equipmentExecutor;
private readonly ILogger<Platform_InteractionHandlerRelease> _logger;
private readonly PlatformPickRepository _platformRepository;
public Platform_InteractionHandlerRelease(
ILogger<Platform_InteractionHandlerRelease> 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<PLCStationReleaseInteraction> 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.PutConveyorReady}"].Value;
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?.Release}");
throw new InvalidOperationException(ex.Message);
}
}
#region 核心辅助方法(带重试)
/// <summary>
/// 参数校验
/// </summary>
private void ValidateCommand(PLCStationReleaseInteraction command, ConsumeContext<PLCStationReleaseInteraction> context)
{
if (string.IsNullOrEmpty(command.EquipmentCode))
{
context.RespondAsync(ApiResponse.ErrorToPlc("请确认哪条输送线设备"));
return;
}
if (command.Release == 0)
{
context.RespondAsync(ApiResponse.ErrorToPlc("请确认指令发送"));
return;
}
if (string.IsNullOrEmpty(command.Barcode))
{
context.RespondAsync(ApiResponse.ErrorToPlc("无效托盘码,托盘码为空"));
return;
}
}
/// <summary>
/// 处理不同取货指令
/// </summary>
private async Task HandlePickupCommand(PLCStationReleaseInteraction command, Equipment equipment, ConsumeContext<PLCStationReleaseInteraction> context)
{
var pickupStatus = command.Release;
var allowPick = equipment[$"{StationProps.AllowPick}"].Value;
switch (pickupStatus)
{
// 取货请求(单个属性写入+重试)
case var s when s == ConvingStatus.PutRequest.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;
//await WritePlcPropWithRetry(equipment, StationProps.PickRuning.ToString(), "True", "取货准备好信号下发成功", "取货准备好信号下发失败", context, retryTimes: 3, delayMs: 500);
//break;
// 取货运行中(单个属性写入+重试)
//case var s when s == ConvingStatus.PutRuning.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.PutDone.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<PLCStationReleaseInteraction> 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<PLCStationReleaseInteraction> context,
int retryTimes = 3, int delayMs = 500)
{
// 准备要写入的属性
//var props = new List<EquipmentProp> { prop1, prop2, prop3 };
// 重试逻辑
int attempt = 0;
while (attempt < retryTimes)
{
lock (_equipmentExecutor.WriteFlag)
{
var prop1 = equipment[$"{StationProps.PutRequest}"]; prop1.Value = "0";
var prop2 = equipment[$"{StationProps.PutRuning}"]; prop2.Value = "0";
var prop3 = equipment[$"{StationProps.PutDone}"]; prop3.Value = "1";
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
}
}