Platform_ExtensionHandlerOperation.cs
10.4 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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
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.Application.MessageBus.Commands.PlatformInteraction;
using Rcs.Domain.Repositories;
using Rcs.Executor.PLC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database;
using PLCConvingStatus = HaHRCS.Rcs.Model.Entities.PLCConvingStatus;
namespace Rcs.Infrastructure.MessageBus.Handlers.Commands.PLCInteraction
{
/// <summary>
/// 伸出夹紧站台
/// </summary>
public class Platform_ExtensionHandlerOperation : IConsumer<PLCStationConvingExtend>
{
private readonly EquipmentExecutor _equipmentExecutor;
private readonly ILogger<Platform_ExtensionHandlerOperation> _logger;
private readonly PlatformPickRepository _platformRepository;
public Platform_ExtensionHandlerOperation(
ILogger<Platform_ExtensionHandlerOperation> logger,
PlatformPickRepository platformRepository,
EquipmentExecutor equipmentExecutor)
{
_logger = logger;
_platformRepository = platformRepository;
_equipmentExecutor = equipmentExecutor;
}
/// <summary>
/// 参数校验
/// </summary>
private void ValidateCommand(PLCStationConvingExtend command, ConsumeContext<PLCStationConvingExtend> context)
{
if (string.IsNullOrEmpty(command.EquipmentCode))
{
context.RespondAsync(ApiResponse.ErrorToPlc("请确认设备"));
return;
}
if (command.Operation == 0)
{
context.RespondAsync(ApiResponse.ErrorToPlc("请确认指令发送"));
return;
}
}
public async Task Consume(ConsumeContext<PLCStationConvingExtend> context)
{
var command = context.Message;
try
{
ValidateCommand(command, context);
var equipment = _equipmentExecutor.equipment.First(t => t.Code == command.EquipmentCode);
if (equipment == null || string.IsNullOrEmpty(equipment.Code))
ApiResponse.ErrorToPlc("无效站台设备,请检查设备名称");
await HandlePickupCommand(command, equipment, context);
}
catch (Exception ex)
{
_logger.LogError(ex, $"处理PLC伸出指令异常,设备编码:{command?.EquipmentCode},指令类型:{command?.Operation}");
throw new InvalidOperationException(ex.Message);
}
// throw new NotImplementedException();
}
/// <summary>
/// 处理不同伸出指令
/// </summary>
private async Task HandlePickupCommand(PLCStationConvingExtend command, Equipment equipment, ConsumeContext<PLCStationConvingExtend> context)
{
// 定义超时时间(可根据实际场景调整,比如30秒)
var timeoutSeconds = 10;
var pickupStatus = command.Operation;
switch (pickupStatus)
{
// 伸出请求(单个属性写入+重试)
case var s when s == PLCConvingStatus.Extend.GetIndexInt():
var isExtended1 = equipment[$"{CylinderProps.Retracted}"].Value;
if (isExtended1 == "")
{
await context.RespondAsync(ApiResponse.ErrorToPlc($"请检查设备是否离线,设备不在线"));
break;
}
if (isExtended1 == "True")
{
await context.RespondAsync(ApiResponse.ErrorToPlc($"装置已为伸出状态"));
break;
}
// 1. 下发伸出信号
await WritePlcPropWithRetry(
equipment,
CylinderProps.AirExtended.ToString(),
"True",
"伸出信号下发PLC成功",
"下发伸出信号失败",
context,
retryTimes: 3,
delayMs: 500);
// 2. 等待「伸出到位」为True(带超时+异步等待+实时刷新值)
var extendStartTime = DateTime.Now;
bool extendTimeout = false;
while (true)
{
// 实时刷新PLC属性值(关键:避免读取缓存)
var isExtended = equipment[$"{CylinderProps.Retracted}"].Value;
var isExtendedBool = Convert.ToBoolean(isExtended);
// 条件1:到位信号为True → 跳出循环
if (isExtendedBool)
{
break;
}
// 条件2:超时 → 标记超时并跳出
if ((DateTime.Now - extendStartTime).TotalSeconds >= timeoutSeconds)
{
extendTimeout = true;
break;
}
// 异步等待(替代Thread.Sleep,避免阻塞线程)
await Task.Delay(100);
}
// 3. 根据结果返回响应
if (extendTimeout)
{
await context.RespondAsync(ApiResponse.ErrorToPlc($"等待伸出到位超时({timeoutSeconds}秒)"));
}
else
{
await context.RespondAsync(ApiResponse.SuccessfulToPlc("伸出信号完成"));
}
break;
// 缩回请求(批量属性写入+重试)
case var s when s == PLCConvingStatus.Clamp.GetIndexInt():
var istrue1 = equipment[$"{CylinderProps.Extended}"].Value;
if (istrue1 == "")
{
await context.RespondAsync(ApiResponse.ErrorToPlc($"请检查设备是否离线,设备不在线"));
break;
}
if (istrue1 == "True")
{
await context.RespondAsync(ApiResponse.ErrorToPlc($"装置已为缩回状态"));
break;
}
// 1. 下发缩回信号
await WritePlcPropWithRetry(
equipment,
CylinderProps.AirRetracted.ToString(),
"True",
"伸回信号下发PLC成功",
"下发伸回信号失败",
context,
retryTimes: 3,
delayMs: 500);
// 2. 等待「缩回到位」为True(带超时+异步等待+实时刷新值)
var retractStartTime = DateTime.Now;
bool retractTimeout = false;
while (true)
{
// 实时刷新PLC属性值
var istrue = equipment[$"{CylinderProps.Extended}"].Value;
var isRetractedBool = Convert.ToBoolean(istrue);
// 条件1:到位信号为True → 跳出循环
if (isRetractedBool)
{
break;
}
// 条件2:超时 → 标记超时并跳出
if ((DateTime.Now - retractStartTime).TotalSeconds >= timeoutSeconds)
{
retractTimeout = true;
break;
}
// 异步等待
await Task.Delay(100);
}
// 3. 根据结果返回响应
if (retractTimeout)
{
await context.RespondAsync(ApiResponse.ErrorToPlc($"等待缩回到位超时({timeoutSeconds}秒)"));
break;
}
else
{
await context.RespondAsync(ApiResponse.SuccessfulToPlc("伸回信号完成"));
break;
}
//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<PLCStationConvingExtend> 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}次)");
}
}
}