using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; namespace WindowsService1 { public class MqttDataService { public static string BU_id; public static string District_id; public static string Factory_id; public static string Production_line_id; public static string Device_name; public static string Topic; public static string Work_Center_id; public class OperationData { public int Item_Value { get; set; } public string Start_Time { get; set; } public string End_Time { get; set; } } public class MqttMessage { public string bu_id { get; set; } public string district_id { get; set; } public string factory_id { get; set; } public string production_line_id { get; set; } public string production_processes_id { get; set; } public string work_center_id { get; set; } public string station_id { get; set; } public string device_name { get; set; } public List taglist { get; set; } } public class TagList { public string device_time { get; set; } public Dictionary collection_items { get; set; } } /// /// /// /// /// /// /// /// /// public static MqttMessage CreateMqttMessage(string source, AcquisitionType type, List processedValues, Dictionary> _plcAddresses, Dictionary _collectionGroups) { try { Logger.WriteInfo($"开始创建 MQTT 消息, 类型: {type}, 数据点数量: {processedValues?.Count ?? 0}"); if (processedValues == null || processedValues.Count == 0) { Logger.WriteInfo("没有需要处理的数据,返回 null"); return null; } var addresses = _plcAddresses[type]; var config = _collectionGroups[type]; var collectionItems = new Dictionary(); // 获取当前时间作为设备时间 var currentTime = DateTime.Now; var deviceTimeStr = currentTime.ToString("yyyy-MM-dd HH:mm:ss.fff"); Logger.WriteInfo($"处理数据类型: {type}, 当前时间: {deviceTimeStr}"); switch (type) { case AcquisitionType.PPM: ProcessPPMData(processedValues, addresses, config, collectionItems); break; case AcquisitionType.Axis: case AcquisitionType.Cylinder: ProcessFloatData(processedValues, addresses, config, currentTime, collectionItems); break; default: Logger.WriteError($"未知的数据类型: {type}"); return null; } if (collectionItems.Count == 0) { Logger.WriteInfo("没有有效的采集项,返回 null"); return null; } var message = new MqttMessage { bu_id = BU_id, district_id = District_id, factory_id = Factory_id, production_line_id = Production_line_id, production_processes_id = string.Empty, work_center_id = Work_Center_id, station_id = "1", device_name = Device_name, taglist = new List { new TagList { device_time = deviceTimeStr, collection_items = collectionItems } } }; // 记录创建的消息内容 Logger.WriteInfo($"MQTT 消息创建完成: {JsonConvert.SerializeObject(message, Formatting.None)}"); return message; } catch (Exception ex) { Logger.WriteError($"创建 MQTT 消息时发生错误: {ex.Message}"); return null; } } /// /// PPM点位数据 /// /// /// /// /// /// // 添加静态字段来存储上次发送的数据 private static Dictionary _lastSentData = new Dictionary(); public static void ProcessPPMData(List processedValues, Dictionary addresses, CollectionGroupConfig config, Dictionary collectionItems) { try { Logger.WriteInfo($"开始处理 PPM 数据,数据点数量: {processedValues.Count}"); // 创建临时字典存储当前所有数据点 var tempItems = new Dictionary(); foreach (var value in processedValues) { var addressPair = addresses.FirstOrDefault(x => x.Key == value.Name); if (!string.IsNullOrEmpty(addressPair.Key)) { int itemValue = Convert.ToInt32(ConvertToIntegerWithThreeDecimals(value.MainValue)); // 计算开始时间 (结束时间 - 时长) var startTime = value.Timestamp.AddMilliseconds(-itemValue); var operationData = new OperationData { Item_Value = itemValue, Start_Time = startTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), End_Time = value.Timestamp.ToString("yyyy-MM-dd HH:mm:ss.fff") }; // 检查数据是否发生变化 bool shouldAdd = true; // 检查是否与上次发送的数据重复 if (_lastSentData.TryGetValue(addressPair.Key, out var lastData)) { var currentEndTime = operationData.End_Time.ToString(); var lastEndTime = lastData.End_Time.ToString(); if (string.Equals(lastEndTime, currentEndTime, StringComparison.OrdinalIgnoreCase)) { shouldAdd = false; Logger.WriteInfo($"跳过重复数据点: {addressPair.Key}"); continue; } } if (shouldAdd) { tempItems[addressPair.Key] = operationData; Logger.WriteInfo($"处理数据点: {addressPair.Key}, 值: {itemValue}, " + $"开始时间: {startTime:yyyy-MM-dd HH:mm:ss.fff}, " + $"结束时间: {operationData.End_Time}"); } //if (shouldAdd) //{ // // 检查是否与当前批次的其他数据有重复的结束时间 // var duplicateEndTimeItem = tempItems.FirstOrDefault(x => // string.Equals(x.Value.End_Time.ToString(), operationData.End_Time.ToString(), StringComparison.OrdinalIgnoreCase)); // if (duplicateEndTimeItem.Key != null) // { // Logger.WriteError($"检测到结束时间重复: {operationData.End_Time} 对应地址: {addressPair.Key}, " + // $"与地址 {duplicateEndTimeItem.Key} 的数据重复"); // // 根据地址的字母顺序决定哪个需要调整时间,确保调整的一致性 // if (string.Compare(addressPair.Key, duplicateEndTimeItem.Key) > 0) // { // operationData.End_Time = value.Timestamp.AddMilliseconds(1).ToString("yyyy-MM-dd HH:mm:ss.fff"); // Logger.WriteInfo($"调整后的结束时间: {operationData.End_Time}"); // } // } // tempItems[addressPair.Key] = operationData; // Logger.WriteInfo($"处理数据点: {addressPair.Key}, 值: {itemValue}, " + // $"开始时间: {startTime:yyyy-MM-dd HH:mm:ss.fff}, " + // $"结束时间: {operationData.End_Time}"); //} } else { Logger.WriteError($"未找到数据点 {value.Name} 对应的地址配置"); } } // 将处理后的数据添加到最终结果并更新上次发送的数据 foreach (var item in tempItems) { collectionItems[item.Key] = item.Value; _lastSentData[item.Key] = item.Value; // 更新上次发送的数据 } Logger.WriteInfo($"PPM 数据处理完成,处理后的数据点数量: {collectionItems.Count}"); } catch (Exception ex) { Logger.WriteError($"处理 PPM 数据时出错: {ex.Message}"); throw; } } private static bool IsDataEqual(OperationData data1, OperationData data2, string addressKey) { if (data1 == null || data2 == null) return false; bool isEqual = data1.Item_Value == data2.Item_Value && data1.Start_Time == data2.Start_Time && data1.End_Time == data2.End_Time; if (isEqual) { Logger.WriteInfo($"检测到重复数据 - 地址: {addressKey}, " + $"值: {data1.Item_Value}, " + $"开始时间: {data1.Start_Time}, " + $"结束时间: {data1.End_Time}"); } return isEqual; } /// /// 预测性点位 /// /// /// /// /// /// public static void ProcessFloatData(List processedValues, Dictionary addresses, CollectionGroupConfig config, DateTime endTime, Dictionary collectionItems) { for (int i = 0; i < processedValues.Count && i < config.Length; i++) { string address = $"D{int.Parse(config.StartAddress.Substring(1)) + i * 2}"; if (addresses.ContainsValue(address)) { var key = addresses.FirstOrDefault(x => x.Value == address).Key; int itemValue = Convert.ToInt32(ConvertToIntegerWithThreeDecimals(processedValues[i].MainValue)); // 计算开始时间 (结束时间 - 时长) //var startTime = endTime.AddMilliseconds(-itemValue); collectionItems[key] = new OperationData { Item_Value = (int)itemValue, Start_Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), End_Time = endTime.ToString("yyyy-MM-dd HH:mm:ss.fff") }; } } } /// /// 机械臂数据 /// /// /// /// /// /// /// public static LRobot LRobotMessage(string source, AcquisitionType type, List processedValues, Dictionary> _plcAddresses, Dictionary _collectionGroups) { if (processedValues == null || processedValues.Count == 0) { return null; } var addresses = _plcAddresses[type]; var config = _collectionGroups[type]; return new LRobot() { bu_id = BU_id, district_id = District_id, factory_id = Factory_id, production_line_id = Production_line_id, production_processes_id = "", work_center_id = "", station_id = "", device_name = "601PWM01", robot_name = "LUR01", taglist = new List { new Taglist//上料动子1 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[0].MainValue.ToString(), y_value="0", z_value=processedValues[1].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//上料动子2 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[2].MainValue.ToString(), y_value="0", z_value=processedValues[3].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//上料动子3 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[4].MainValue.ToString(), y_value="0", z_value=processedValues[5].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//上料动子4 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[6].MainValue.ToString(), y_value="0", z_value=processedValues[7].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//上料动子5 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[8].MainValue.ToString(), y_value="0", z_value=processedValues[9].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//上料动子6 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[10].MainValue.ToString(), y_value="0", z_value=processedValues[11].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//上料动子7 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[13].MainValue.ToString(), y_value="0", z_value=processedValues[14].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//上料动子8 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[16].MainValue.ToString(), y_value="0", z_value=processedValues[17].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//上料动子9 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[18].MainValue.ToString(), y_value="0", z_value=processedValues[19].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机1 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[20].MainValue.ToString(), y_value=processedValues[21].MainValue.ToString(), z_value=processedValues[22].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机2 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[23].MainValue.ToString(), y_value=processedValues[24].MainValue.ToString(), z_value=processedValues[25].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机3 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[26].MainValue.ToString(), y_value=processedValues[27].MainValue.ToString(), z_value=processedValues[28].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机4 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[29].MainValue.ToString(), y_value=processedValues[30].MainValue.ToString(), z_value=processedValues[31].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机5 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[32].MainValue.ToString(), y_value=processedValues[33].MainValue.ToString(), z_value=processedValues[34].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机6 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[35].MainValue.ToString(), y_value=processedValues[36].MainValue.ToString(), z_value=processedValues[37].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机7 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[38].MainValue.ToString(), y_value=processedValues[39].MainValue.ToString(), z_value=processedValues[40].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机8 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[41].MainValue.ToString(), y_value=processedValues[42].MainValue.ToString(), z_value=processedValues[43].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机9 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[44].MainValue.ToString(), y_value=processedValues[45].MainValue.ToString(), z_value=processedValues[46].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机10 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[47].MainValue.ToString(), y_value=processedValues[48].MainValue.ToString(), z_value=processedValues[49].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机11 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[50].MainValue.ToString(), y_value=processedValues[51].MainValue.ToString(), z_value=processedValues[52].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//焊机12 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[53].MainValue.ToString(), y_value=processedValues[54].MainValue.ToString(), z_value=processedValues[55].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//下料动子1 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[56].MainValue.ToString(), y_value="0", z_value=processedValues[57].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//下料动子2 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[58].MainValue.ToString(), y_value="0", z_value=processedValues[59].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//下料动子3 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[61].MainValue.ToString(), y_value="0", z_value=processedValues[62].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//下料动子4 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[63].MainValue.ToString(), y_value="0", z_value=processedValues[64].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//下料动子5 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[65].MainValue.ToString(), y_value="0", z_value=processedValues[66].MainValue.ToString(), time_span="2.5", hand_status="1", } }, new Taglist//下料动子6 { device_time=DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), collections_items=new Collection() { robot_status = "1", x_value=processedValues[67].MainValue.ToString(), y_value="0", z_value=processedValues[68].MainValue.ToString(), time_span="2.5", hand_status="1", } } } }; } // 辅助方法 private static List ConvertToShortList(object[] data) { return data.Select(x => Convert.ToInt16(x)).ToList(); } private static List ConvertToFloatList(object[] data) { return data.Select(x => Convert.ToSingle(x)).ToList(); } private static object ConvertToIntegerWithThreeDecimals(object value) { try { if (value == null) return 0; if (value is float floatValue) { return (int)Math.Round(floatValue * 1000); } else if (value is double doubleValue) { return (int)Math.Round(doubleValue * 1000); } else if (value is decimal decimalValue) { return (int)Math.Round(decimalValue * 1000); } else { // 尝试转换其他类型 float converted = Convert.ToSingle(value); return (int)Math.Round(converted * 1000); } } catch (Exception ex) { Logger.WriteError($"转换值到整数时出错: {ex.Message}, 值: {value}"); return 0; } } } }