PLCSystemFaultAnalysis.cs
19.6 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
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
using HHECS.BllModel;
using HHECS.DAQHandle.Dto;
using HHECS.DAQShared.Common.Enums;
using HHECS.DAQShared.Models;
namespace HHECS.DAQHandle.EquipmentHandle
{
/// <summary>
/// PLC系统报警
/// </summary>
/// <remarks>只有报警</remarks>
internal class PLCSystemFaultAnalysis : AnalysisBase
{
public PLCSystemFaultAnalysis(AnalysisParameter parameter) : base(parameter) { }
/// <summary>
/// 无需更新状态
/// </summary>
/// <param name="equipment"></param>
/// <param name="records"></param>
/// <returns></returns>
protected override BllResult UpdateEquipmentStatus(Equipment equipment, IEnumerable<EquipmentDataRecord> records)
{
return BllResultFactory.Success();
}
/// <summary>
/// 无需更新手动状态
/// </summary>
/// <param name="equipment"></param>
/// <param name="records"></param>
/// <returns></returns>
protected override BllResult UpdateEquipmentManualRecord(Equipment equipment, IEnumerable<EquipmentDataRecord> records)
{
return BllResultFactory.Success();
}
protected override BllResult UpdateEquipmentAlarm(Equipment equipment, IEnumerable<EquipmentDataRecord> records)
{
try
{
using var equipmentAlarmRecordRepository = freeSql.GetRepository<EquipmentAlarmRecord>();
using var equipmentAlarmRecordDetailRepository = freeSql.GetRepository<EquipmentAlarmRecordDetail>();
var alarmRecordCacheTempsResult = AssemblyAlarmData(equipment, records);
if (!alarmRecordCacheTempsResult.Success)
{
return BllResultFactory.Error(alarmRecordCacheTempsResult.Msg);
}
//无报警数据
if (alarmRecordCacheTempsResult.Data.Count == 0)
{
//结束当前设备的超时主报警
var needEndAlaremRecords = equipmentAlarmRecordRepository.Where(x => x.EquipmentCode == equipment.Code && !x.IsEnd).OrderBy(x => x.CreateTime).Limit(100)
.ToList(x => new EquipmentAlarmRecord
{
Id = x.Id,
});
foreach (var item in needEndAlaremRecords)
{
equipmentAlarmRecordRepository.Attach(item);
item.IsEnd = true;
}
equipmentAlarmRecordRepository.Update(needEndAlaremRecords);
//结束当前设备的超时报警明细
var mainAlarmIds = needEndAlaremRecords.Select(x => x.Id).ToList();
var needEndAlaremDetailRecords = equipmentAlarmRecordDetailRepository.Where(x => mainAlarmIds.Contains(x.EquipmentAlarmRecordId) && x.EquipmentCode == equipment.Code && !x.IsEnd).OrderBy(x => x.CreateTime).ToList(x => new EquipmentAlarmRecordDetail
{
Id = x.Id,
});
foreach (var item in needEndAlaremDetailRecords)
{
equipmentAlarmRecordDetailRepository.Attach(item);
item.IsEnd = true;
}
equipmentAlarmRecordDetailRepository.Update(needEndAlaremDetailRecords);
//无报警则跳过
return BllResultFactory.Success();
}
var alarmRecordCacheTemps = alarmRecordCacheTempsResult.Data;
var oldAlarmRecord = equipmentAlarmRecordRepository.Where(x => x.EquipmentCode == equipment.Code && x.EquipmentPropCode == EquipmentTotalAlarmCode && !x.IsEnd).OrderByDescending(x => x.CreateTime).First();
var lastCacheTemp = alarmRecordCacheTemps.OrderByDescending(x => x.CreateTime).First();
var addTemps = new List<EquipmentAlarmRecord>();
//数据库无报警记录
if (oldAlarmRecord == null)
{
foreach (var item in alarmRecordCacheTemps)
{
//不是最后一条记录的数据需要结束
if (!item.Equals(lastCacheTemp))
{
item.IsEnd = true;
}
addTemps.Add(item);
}
equipmentAlarmRecordRepository.Insert(addTemps);
var allAlarmDetail = addTemps.SelectMany(x => x.EquipmentAlarmRecordDetails).ToList();
equipmentAlarmRecordDetailRepository.Insert(allAlarmDetail);
return BllResultFactory.Success();
}
//数据库有报警记录,则需要校验
foreach (var item in alarmRecordCacheTemps)
{
//对于之前的数据,这里暂时不做处理
if (oldAlarmRecord.UpdateTime >= item.UpdateTime)
{
continue;
}
//日期为同一天,在设定时间以内,则更新
if (oldAlarmRecord.UpdateTime.Date == item.CreateTime.Date && (item.CreateTime - oldAlarmRecord.UpdateTime).TotalSeconds <= AppConfig.DataTimeOut)
{
equipmentAlarmRecordRepository.Attach(oldAlarmRecord);
//不是最后一条记录,说明已经成为历史报警,需要结束标记
if (!item.Equals(lastCacheTemp))
{
oldAlarmRecord.IsEnd = true;
}
//无具体报警信息,则更新报警文本,这里的文本需要与数据组装方法“AssemblyAlarmData”里面的文本内容一致
if (oldAlarmRecord.AlarmMessage.Contains("无具体报警信息") && oldAlarmRecord.AlarmMessage != item.AlarmMessage)
{
oldAlarmRecord.AlarmMessage = item.AlarmMessage;
}
oldAlarmRecord.ErrorDuration = GetErrorDuration(oldAlarmRecord.CreateTime, item.UpdateTime);
oldAlarmRecord.UpdateTime = item.UpdateTime;
oldAlarmRecord.HandleTime = DateTime.Now;
equipmentAlarmRecordRepository.Update(oldAlarmRecord);
//更新报警明细
var allAlarmDetail = equipmentAlarmRecordDetailRepository.Where(x => !x.IsEnd &&
x.EquipmentAlarmRecordId == oldAlarmRecord.Id).ToList();
var addAlarmDetailTemps = new List<EquipmentAlarmRecordDetail>();
//报警明细
var equipmentAlarmRecordDetails = item.EquipmentAlarmRecordDetails.Select(x => new EquipmentAlarmRecordDetail
{
EquipmentAlarmRecordId = oldAlarmRecord.Id,
EquipmentCode = x.EquipmentCode,
EquipmentName = x.EquipmentName,
EquipmentPropCode = x.EquipmentPropCode,
EquipmentPropName = x.EquipmentPropName,
EquipmentTypeCode = x.EquipmentTypeCode,
ErrorDuration = x.ErrorDuration,
AlarmMessage = x.AlarmMessage,
ProjectCode = x.ProjectCode,
FactoryCode = x.FactoryCode,
IsEnd = oldAlarmRecord.IsEnd,
CreateTime = x.CreateTime,
UpdateTime = x.UpdateTime,
}).ToList();
foreach (var alarmDetailGroup in equipmentAlarmRecordDetails.GroupBy(x => x.EquipmentPropCode))
{
//缓存里面的第一条记录
var firstCacheTemp = alarmDetailGroup.OrderBy(x => x.CreateTime).First();
//数据库里面的最后一条记录
var lastDBTemp = allAlarmDetail.Where(x => x.EquipmentPropCode == alarmDetailGroup.Key).OrderByDescending(x => x.CreateTime).FirstOrDefault();
//存在记录,且在设定时间之内,则需要更新
if (lastDBTemp != null && (firstCacheTemp.CreateTime - lastDBTemp.UpdateTime).TotalSeconds <= AppConfig.DataTimeOut)
{
equipmentAlarmRecordDetailRepository.Attach(lastDBTemp);
lastDBTemp.ErrorDuration = GetErrorDuration(lastDBTemp.CreateTime, firstCacheTemp.UpdateTime);
lastDBTemp.UpdateTime = firstCacheTemp.UpdateTime;
//状态有编号,则更新
if (lastDBTemp.IsEnd != oldAlarmRecord.IsEnd)
{
lastDBTemp.IsEnd = oldAlarmRecord.IsEnd;
}
equipmentAlarmRecordDetailRepository.Update(lastDBTemp);
addAlarmDetailTemps.AddRange(alarmDetailGroup.Where(x => !x.Equals(firstCacheTemp)).ToList());
continue;
}
addAlarmDetailTemps.AddRange(alarmDetailGroup.ToList());
}
equipmentAlarmRecordDetailRepository.Insert(addAlarmDetailTemps);
continue;
}
//其他情况需要新增记录
//不是最后一条记录
if (!item.Equals(lastCacheTemp))
{
item.IsEnd = true;
}
addTemps.Add(item);
}
equipmentAlarmRecordRepository.Insert(addTemps);
equipmentAlarmRecordDetailRepository.Insert(addTemps.SelectMany(x => x.EquipmentAlarmRecordDetails).ToList());
return BllResultFactory.Success();
}
catch (Exception ex)
{
return BllResultFactory.Error(ex.Message);
}
}
protected override BllResult<EquipmentStatus> GetEquipmentStatus(Equipment equipment, EquipmentDataRecord record)
{
try
{
var tagResult = JsonConvertToTagList(record.Tags);
if (!tagResult.Success)
{
//数据格式不正确,忽略报警
return BllResultFactory.Success(EquipmentStatus.Free);
}
var tags = tagResult.Data;
var equipmentProps = equipment.EquipmentProps.Where(x => x.PropType == EquipmentPropType.PLCMonitorAddress && !string.IsNullOrWhiteSpace(x.MonitorCompareValue)).ToList();
foreach (var item in equipmentProps)
{
var tag = tags.Where(x => x.Tag == item.Code).FirstOrDefault();
if (tag == null)
{
continue;
}
if (item.MonitorCompareValue == tag.Value)
{
//故障
return BllResultFactory.Success(EquipmentStatus.Failure);
}
}
return BllResultFactory.Success(EquipmentStatus.Free);
}
catch (Exception ex)
{
return BllResultFactory.Error<EquipmentStatus>(ex.Message);
}
}
protected override BllResult<List<EquipmentAlarmRecord>> AssemblyAlarmData(Equipment equipment, IEnumerable<EquipmentDataRecord> records)
{
try
{
//设备总报警编号
var totalAlarmProp = new EquipmentProp
{
Code = "PLCSystemFault",
Name = "PLC系统报警",
};
//当前设备监控地址属性模板
var monitorPropTemps = equipment.EquipmentProps.Where(x => x.PropType == EquipmentPropType.PLCMonitorAddress
&& !string.IsNullOrEmpty(x.MonitorCompareValue))
.DistinctBy(x => x.Code)
.OrderBy(x => x.Id).ToList();
//数据组装
var temps = new List<EquipmentAlarmRecord>();
foreach (var item in records.OrderBy(x => x.Timestamp))
{
var currentRecordStatusResult = GetEquipmentStatus(equipment, item);
if (!currentRecordStatusResult.Success)
{
continue;
}
if (currentRecordStatusResult.Data != EquipmentStatus.Failure)
{
//状态有变化,则结束最后一条报警记录
var lastTemp = temps.Where(x => !x.IsEnd).OrderByDescending(x => x.CreateTime).FirstOrDefault();
if (lastTemp != null)
{
lastTemp.IsEnd = true;
lastTemp.EquipmentAlarmRecordDetails.ForEach(x => x.IsEnd = true);
}
continue;
}
var time = TimestampConvertToLocalDateTime(item.Timestamp);
var tagResult = JsonConvertToTagList(item.Tags);
//数据异常,则直接弃用这条记录
if (!tagResult.Success)
{
continue;
}
var tagItems = tagResult.Data;
var (mainAlarm, detailAlarms) = GenerateAlarmMessage(equipment, totalAlarmProp, monitorPropTemps, tagItems);
var cacheTemp = temps.Where(x => x.EquipmentPropCode == totalAlarmProp.Code && !x.IsEnd)
.OrderByDescending(x => x.CreateTime).FirstOrDefault();
//间隔在设定时间内,认为是同一个主报警
if (cacheTemp != null && cacheTemp.UpdateTime.Date == time.Date &&
(time - cacheTemp.UpdateTime).TotalSeconds <= AppConfig.DataTimeOut)
{
cacheTemp.UpdateTime = time;
cacheTemp.ErrorDuration = GetErrorDuration(cacheTemp.CreateTime, time);
//结束其他报警明细
var alarmCodes = detailAlarms.Select(x => x.Key).ToList();
foreach (var oldAlarm in cacheTemp.EquipmentAlarmRecordDetails)
{
if (oldAlarm.IsEnd)
{
continue;
}
if (!alarmCodes.Contains(oldAlarm.EquipmentPropCode))
{
//本次无报警的记录,需要结束
oldAlarm.IsEnd = true;
}
}
//更新报警明细
foreach (var newAlarm in detailAlarms)
{
var lastItem = cacheTemp.EquipmentAlarmRecordDetails.Where(x => x.EquipmentPropCode == newAlarm.Key && !x.IsEnd).FirstOrDefault();
if (lastItem == null)
{
var newItem = new EquipmentAlarmRecordDetail
{
EquipmentAlarmRecordId = cacheTemp.Id,
EquipmentCode = equipment.Code,
EquipmentName = equipment.Name,
EquipmentPropCode = newAlarm.Key,
EquipmentPropName = monitorPropTemps.Where(p => p.Code == newAlarm.Key).Select(p => p.Remark).FirstOrDefault(),
EquipmentTypeCode = CurrentEquipmentType.Code,
ProjectCode = equipment.ProjectCode,
FactoryCode = equipment.FactoryCode,
AlarmMessage = newAlarm.Value,
IsEnd = false,
ErrorDuration = 1,
CreateTime = time,
UpdateTime = time,
};
cacheTemp.EquipmentAlarmRecordDetails.Add(newItem);
continue;
}
//记录不为空,更新时间
lastItem.UpdateTime = time;
lastItem.ErrorDuration = GetErrorDuration(lastItem.CreateTime, time);
}
continue;
}
//获取设备故障坐标
var alarmMessage = string.Join(";", detailAlarms.Select(x => x.Value));
if (string.IsNullOrWhiteSpace(alarmMessage))
{
alarmMessage = $"{mainAlarm},无具体报警信息";
}
var mainAlarmRecord = new EquipmentAlarmRecord
{
Id = Guid.NewGuid(),
EquipmentCode = equipment.Code,
EquipmentName = equipment.Name,
EquipmentPropCode = totalAlarmProp.Code,
EquipmentPropName = totalAlarmProp.Name,
EquipmentTypeCode = CurrentEquipmentType.Code,
ErrorDuration = 1,
IsEnd = false,
AlarmMessage = alarmMessage,
FactoryCode = equipment.FactoryCode,
ProjectCode = equipment.ProjectCode,
HandleTime = DateTime.Now,
CreateTime = time,
UpdateTime = time,
};
mainAlarmRecord.EquipmentAlarmRecordDetails = detailAlarms.Select(x => new EquipmentAlarmRecordDetail
{
EquipmentAlarmRecordId = mainAlarmRecord.Id,
EquipmentCode = equipment.Code,
EquipmentName = equipment.Name,
EquipmentPropCode = x.Key,
EquipmentPropName = monitorPropTemps.Where(p => p.Code == x.Key).Select(p => p.Remark).FirstOrDefault(),
EquipmentTypeCode = CurrentEquipmentType.Code,
ProjectCode = equipment.ProjectCode,
FactoryCode = equipment.FactoryCode,
AlarmMessage = x.Value,
IsEnd = false,
ErrorDuration = 1,
CreateTime = time,
UpdateTime = time,
}).ToList();
//其他情况,新增
temps.Add(mainAlarmRecord);
}
return BllResultFactory.Success(temps);
}
catch (Exception ex)
{
return BllResultFactory.Error<List<EquipmentAlarmRecord>>(ex.Message);
}
}
}
}