using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using NPOI.Util; using Newtonsoft.Json; using System.Threading.Tasks; using MainForm.ClassFile.XiaomiAPI; using MainForm.ClassFile.XiaomiAPI_MES; using static MainForm.ClassFile.XiaomiAPI.XiaomiMqttClient_Extend; using static MainForm.ClassFile.XiaomiAPI_MES.XiaomiMESHttp_StationInbound; using static MainForm.ClassFile.XiaomiAPI_MES.XiaomiMESHttp_StationOutbound; using System.IO; using MainForm.ClassFile.FALibraryClass; using NPOI.SS.Formula.Functions; namespace MainForm { /// /// Form_Home类 - 保存数据 /// 简单拆分Form_Home类 /// public partial class Form_Home { #region 保存数据 #region 进站数据 /// /// 调用进站接口并保存进站数据 /// /// 工站信息 /// 工单号 /// 型号(物料号) /// 产品SN /// 进站数据 /// 1成功;5MES报警;6上位机报警 public int SaveStationInData(string stationNameStr, string workorder_code, string mtltmrk, string sn, List items,out string msg) { int result = 0; msg = ""; XmMES_StationInRequest_Body inRequest_Body = new XmMES_StationInRequest_Body(); switch (stationNameStr) { case "[S1]Tray盘上料装备": inRequest_Body.machineId = GlobalContext.S1_MachineId; // 装备ID(可配置) inRequest_Body.stationId = GlobalContext.S1_StationId; // ⼯位ID(可配置) break; case "[S2]FCT": inRequest_Body.machineId = GlobalContext.S2_MachineId; // 装备ID(可配置) inRequest_Body.stationId = GlobalContext.S2_StationId; // ⼯位ID(可配置) break; case "[S3]值板机": inRequest_Body.machineId = GlobalContext.S3_MachineId; // 装备ID(可配置) inRequest_Body.stationId = GlobalContext.S3_StationId; // ⼯位ID(可配置) break; case "[S4_1]载具下线装备": inRequest_Body.machineId = GlobalContext.S4_MachineId; // 装备ID(可配置) inRequest_Body.stationId = GlobalContext.S4_StationId; // ⼯位ID(可配置) break; case "[S4_3]提升机1": //inRequest_Body.machineId = GlobalContext.S5_1_MachineId; // 装备ID(可配置) //inRequest_Body.stationId = GlobalContext.S5_1_StationId; // ⼯位ID(可配置) break; case "[S4_4]提升机2": //inRequest_Body.machineId = GlobalContext.S5_2_MachineId; // 装备ID(可配置) //inRequest_Body.stationId = GlobalContext.S5_2_StationId; // ⼯位ID(可配置) break; case "[S4_5]载具上线装备": inRequest_Body.machineId = GlobalContext.S6_MachineId; // 装备ID(可配置) inRequest_Body.stationId = GlobalContext.S6_StationId; // ⼯位ID(可配置) break; case "[S5]Tray盘下料装备": inRequest_Body.machineId = GlobalContext.S7_MachineId; // 装备ID(可配置) inRequest_Body.stationId = GlobalContext.S7_StationId; // ⼯位ID(可配置) break; default: break; } inRequest_Body.clientMac = GlobalContext.MacStr; // 客⼾端本机MAC地址,格式:XX-XX-XX-XX-XX-XX inRequest_Body.clientTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); // 客⼾端请求时间,格式yyyy-MM-dd HH:mm:ss.fff inRequest_Body.unitSn = sn; // 产品SN inRequest_Body.userId = GlobalContext.MESUserId; // 用户ID;非必填 inRequest_Body.factoryId = GlobalContext.Factory_Code; // 工厂ID;非必填 string json_Body = JsonConvert.SerializeObject(inRequest_Body); StationIn stationIn = new StationIn() { Workorder_code = workorder_code, // 车间订单号 Mtltmrk = mtltmrk, // 产品型号(物料号) Sn = sn, // SN StationIn_body = json_Body, // 进站接口Json数据 - Body Parameter_values = items, // 进站数据 Write_user = inRequest_Body.userId, // 员工Id Test_time = inRequest_Body.clientTime // 进站时间 }; // 本地数据 string sql = stationIn.ToStringInsert(0); string ret = SQLHelper_New.ExecuteNonQuery(sql, null); result = ret == "成功" ? 1 : 6; msg = ret; AddMessage_Station(stationNameStr, LogType.Info, string.Concat(stationNameStr, "_保存本地进站数据---" + ret)); //await Task.Delay(200); // 上传MES if (result == 1 && GlobalContext.IsSendStationIn) { try { XmMES_StationInResponse response = new XmMES_StationInResponse(); string mesRet = string.Empty; int i = 0; while (i < 2) // 1009会多次尝试上传 { response = XiaomiMESHttp_StationInbound.StationIn(inRequest_Body); if (response != null && response.header.code == "200") break; else if (response != null && response.header.code != "503") // 503是服务器报错 i++; i++; mesRet = $"[{response?.header?.code}]{response?.header?.desc}"; // 记录失败原因 OnMessage(LogType.Error, "上传出站数据到MES服务器---失败!正在重新上传!接口报错信息:" + mesRet + "参数:" + json_Body); } AddMessage_Station(stationNameStr, LogType.Info, stationNameStr + "_上传进站数据到MES服务器---" + mesRet); if (response?.header?.code == "200") { string sql_Upd = stationIn.ToStringUpdateStatusByID(1); string ret_Upd = SQLHelper_New.ExecuteNonQuery(sql_Upd, null); result = ret_Upd == "成功" ? result : 6; msg = ret_Upd == "成功" ? msg : "更新【进站数据 id {stationIn.GUID}】上传状态---失败"; AddMessage_Station(stationNameStr, LogType.Info, $"更新【进站数据 id {stationIn.GUID}】上传状态---" + ret_Upd); } else { result = 5; msg = "上传进站数据到MES服务器---失败!接口报错信息:" + mesRet + "参数:" + json_Body; OnMessage(LogType.Error, "上传进站数据到MES服务器---失败!接口报错信息:" + mesRet + "参数:" + json_Body); } } catch (Exception ex) { result = 6; string str = ex.StackTrace; msg = $"PLC上传进站数据MES报错!错误信息:" + ex.Message.ToString() + ";异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1); AddMessage_Station(stationNameStr, LogType.Error, $"PLC上传进站数据MES报错!错误信息:" + ex.Message.ToString() + ";异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1)); } } return result; } #endregion 进站数据 #region 出站数据 /// /// 选择如何记录出站数据 /// /// 工站信息 /// 出站数据 /// 设备编号 /// 测试项目 /// 车间订单号 /// 型号 /// 产品序列号的 /// 产品结果 /// 载具SN /// 载具穴号 /// 上位机发送1代表OK;2代表上传客户MES失败;3代表上位机保存数据失败;4代表上位机报警; private int SwitctProcessData_old(string stationNameStr, List items, string equipmentCode, string processItem, string workorder_code, string mtltmrk, string sn, bool pass, string vehicleSn, string vehicleSlot) { //if (DataSwitch == 1) //{ return SaveProcessDataByDB(stationNameStr, items, equipmentCode, processItem, workorder_code, mtltmrk, sn, pass, vehicleSn, vehicleSlot); //} //else // 旧代码,废弃 //{ // return SaveProcessData(items, equipmentCode, processItem, sn_Number); //} } /// /// 添加出站数据(提交到MES+本地保存到数据库) /// /// 工站信息 /// 出站数据 /// 设备编号 /// 测试项目 /// 车间订单号 /// 型号 /// 产品序列号 /// 产品结果 /// 载具SN /// 载具穴号 /// 上位机发送1代表OK;2代表上传客户MES失败;3代表上位机保存数据失败;4代表上位机报警; public int SaveProcessDataByDB(string stationNameStr, List items, string equipmentCode, string processItem, string workorder_code, string mtltmrk, string sn, bool pass, string vehicleSn, string vehicleSlot) { int mesUpload = 0; // 0未上传或上传失败;1上传成功;2忽略 int iotUpload = 0; // 0未上传或上传失败;1上传成功;2忽略 ProcessData processData = new ProcessData() { Equipment_code = equipmentCode, Testitem = processItem, Workorder_code = workorder_code, //Batch_number = batch_num, Sn = sn, // SN Parameter_values = items, Write_user = GlobalContext.CurrentUser, Test_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") }; // 本地数据 string sql = processData.ToStringInsert(mesUpload, iotUpload); string ret = SQLHelper_New.ExecuteNonQuery(sql, null); AddMessage_Station(stationNameStr, LogType.Info, string.Concat("[[", equipmentCode, "]", stationNameStr, "]保存本地出站数据---" + ret)); if (ret != "成功") return 3; // 3代表上位机保存数据失败 //await Task.Delay(200); // 上传MES string mesJson = string.Empty; if (GlobalContext.IsSendProcessData) { try { string id = processData.ID; XmMES_StationOutRequest_Body outRequest_Body = new XmMES_StationOutRequest_Body(); switch (stationNameStr) { case "[S1]Tray盘上料装备": outRequest_Body.machineId = GlobalContext.S1_MachineId; // 装备ID(可配置) outRequest_Body.stationId = GlobalContext.S1_StationId; // ⼯位ID(可配置) break; case "[S2]FCT": outRequest_Body.machineId = GlobalContext.S2_MachineId; // 装备ID(可配置) outRequest_Body.stationId = GlobalContext.S2_StationId; // ⼯位ID(可配置) break; case "[S3]值板机": outRequest_Body.machineId = GlobalContext.S3_MachineId; // 装备ID(可配置) outRequest_Body.stationId = GlobalContext.S3_StationId; // ⼯位ID(可配置) break; case "[S4_1]载具下线装备": outRequest_Body.machineId = GlobalContext.S4_MachineId; // 装备ID(可配置) outRequest_Body.stationId = GlobalContext.S4_StationId; // ⼯位ID(可配置) break; case "[S4_3]提升机1": //outRequest_Body.machineId = GlobalContext.S5_1_MachineId; // 装备ID(可配置) //outRequest_Body.stationId = GlobalContext.S5_1_StationId; // ⼯位ID(可配置) break; case "[S4_4]提升机2": //outRequest_Body.machineId = GlobalContext.S5_2_MachineId; // 装备ID(可配置) //outRequest_Body.stationId = GlobalContext.S5_2_StationId; // ⼯位ID(可配置) break; case "[S4_5]载具上线装备": outRequest_Body.machineId = GlobalContext.S6_MachineId; // 装备ID(可配置) outRequest_Body.stationId = GlobalContext.S6_StationId; // ⼯位ID(可配置) break; case "[S5]Tray盘下料装备": outRequest_Body.machineId = GlobalContext.S7_MachineId; // 装备ID(可配置) outRequest_Body.stationId = GlobalContext.S7_StationId; // ⼯位ID(可配置) break; default: break; } outRequest_Body.clientMac = GlobalContext.MacStr; // 客⼾端本机MAC地址,格式:XX-XX-XX-XX-XX-XX outRequest_Body.clientTime = processData.Test_time; // 客⼾端请求时间,格式yyyy-MM-dd HH:mm:ss.fff outRequest_Body.unitSn = sn; // 产品SN outRequest_Body.state = pass ? "PASS" : "FAIL"; // 出站条件 PASS或FAIL outRequest_Body.userId = GlobalContext.MESUserId; // ⽤⼾ID;非必填 outRequest_Body.factoryId = GlobalContext.Factory_Code; // ⼯⼚id;非必填 //outRequest_Body.unitData.vehicleData.Add( // new XmMES_StationOutRequest_Body.XmStationOut_VehicleData() // { // vehicleSn = vehicleSn, // vehicleType = string.Empty, // slot = vehicleSlot // }); // 设备数据 - 载具信息 mesJson = JsonConvert.SerializeObject(outRequest_Body); XmMES_StationOutResponse response = new XmMES_StationOutResponse(); string mesRet = string.Empty; int i = 0; while (i < 2) // 404等会多次尝试上传 { response = XiaomiMESHttp_StationOutbound.StationOut(outRequest_Body); if (response != null && response.header.code == "200") break; else if (response != null && response.header.code != "503") // 503是服务器报错 i++; i++; mesRet = $"[{response?.header?.code}]{response?.header?.desc}"; // 记录失败原因 OnMessage(LogType.Error, "上传出站数据到MES服务器---失败!正在重新上传!接口报错信息:" + mesRet + "参数:" + mesJson); } AddMessage_Station(stationNameStr, LogType.Info, "[" + processItem + "]上传出站数据到MES服务器---" + mesRet); if (response != null && response.header.code == "200") mesUpload = 1; else mesUpload = 0; } catch (Exception ex) { mesUpload = 0; string str = ex.StackTrace; AddMessage_Station(stationNameStr, LogType.Error, $"PLC上传出站数据MES报错!错误信息:" + ex.Message.ToString() + ";异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1)); } } else mesUpload = 2; // 上传IOT string iotJson = string.Empty; if (GlobalContext.IsMqttSendProcessData) { try { string id = processData.ID; string guid = Guid.NewGuid().ToString(); // 过站结果 0 PassStationResultRequest passStaResultRequ = new PassStationResultRequest(); passStaResultRequ.pass_station_id = guid; // 过站唯⼀标识(36位) passStaResultRequ.project_code = GlobalContext.Project_Code; // 项⽬编码 passStaResultRequ.factory_code = GlobalContext.Factory_Code; // ⼯⼚Id passStaResultRequ.process_section_code = GlobalContext.Process_Section_Code; // ⼯段编码 passStaResultRequ.line_code = GlobalContext.LineCode; // 线体编码 switch (stationNameStr) { // [S1] Tray盘上料装备 // [S2] FCT // [S3] 值板机 // [S4_1] 载具下线装备 [S4_5] 载具上线装备 // [S5] Tray盘下料装备 case "[S1]Tray盘上料装备": passStaResultRequ.work_station = GlobalContext.S1_work_station; // ⼯站 passStaResultRequ.device_code = GlobalContext.S1_device_code; // 装备编码 passStaResultRequ.station = GlobalContext.S1_station; // ⼯位Id break; case "[S2]FCT": passStaResultRequ.work_station = GlobalContext.S2_work_station; // ⼯站 passStaResultRequ.device_code = GlobalContext.S2_device_code; // 装备编码 passStaResultRequ.station = GlobalContext.S2_station; // ⼯位Id break; //case "[S3]值板机": // passStaResultRequ.work_station = GlobalContext.S3_work_station; // ⼯站 // passStaResultRequ.device_code = GlobalContext.S3_device_code; // 装备编码 // passStaResultRequ.station = GlobalContext.S3_station; // ⼯位Id // break; //case "[S4_1]载具下线装备": // passStaResultRequ.work_station = GlobalContext.S4_1_work_station; // ⼯站 // passStaResultRequ.device_code = GlobalContext.S4_1_device_code; // 装备编码 // passStaResultRequ.station = GlobalContext.S4_1_station; // ⼯位Id // break; //case "[S4_3]提升机1": // passStaResultRequ.work_station = GlobalContext.S4_3_work_station; // ⼯站 // passStaResultRequ.device_code = GlobalContext.S4_3_device_code; // 装备编码 // passStaResultRequ.station = GlobalContext.S4_3_station; // ⼯位Id // break; //case "[S4_4]提升机2": // passStaResultRequ.work_station = GlobalContext.S4_4_work_station; // ⼯站 // passStaResultRequ.device_code = GlobalContext.S4_4_device_code; // 装备编码 // passStaResultRequ.station = GlobalContext.S4_4_station; // ⼯位Id // break; //case "[S4_5]载具上线装备": // passStaResultRequ.work_station = GlobalContext.S4_5_work_station; // ⼯站 // passStaResultRequ.device_code = GlobalContext.S4_5_device_code; // 装备编码 // passStaResultRequ.station = GlobalContext.S4_5_station; // ⼯位Id // break; //case "[S5]Tray盘下料装备": // passStaResultRequ.work_station = GlobalContext.S5_work_station; // ⼯站 // passStaResultRequ.device_code = GlobalContext.S5_device_code; // 装备编码 // passStaResultRequ.station = GlobalContext.S5_station; // ⼯位Id // break; //default: break; } passStaResultRequ.process_time = processData.Test_time; // 过站时间 passStaResultRequ.slot = "1"; // 槽位编码 passStaResultRequ.sn = processData.Sn; // 产品SN passStaResultRequ.result = pass ? "PASS" : "FAIL"; // 过站结果 passStaResultRequ.work_type = "OUT_STATION"; // 作业类型 iotJson = JsonConvert.SerializeObject(passStaResultRequ); //int result_Result = XiaomiMqttClient_Extend.Write_PassStationResult(passStaResultRequ); int result_Result = 0; string result_ResultStr = string.Empty; var try1 = Enum.TryParse(result_Result.ToString(), out XiaomiMqttResponse_ErrCode errCode); if (try1) result_ResultStr = errCode.ToString(); AddMessage_Station(stationNameStr, LogType.Info, "[" + processItem + $"]上传【过站结果 id {id}】到IOT服务器---[" + result_Result + "]" + result_ResultStr); iotUpload = result_Result == 0 ? 1 : 0; //// 过站数据 0 int result_Log = 0; { //List passStaLogRequs = new List(); //PassStationLogRequest passStaLogRequ = new PassStationLogRequest(); //passStaLogRequ.pass_station_id = guid; //passStaLogRequ.sn = processData.Sn; // 产品SN //passStaLogRequ.slot ="1"; // 槽位 //passStaLogRequ.test_item_num ="1"; // 测试项序号 1,2,递增 //passStaLogRequ.function_name = "Machine_"+stationNameStr; // 功能名称 //passStaLogRequ.test_item =""; // 测试项 //passStaLogRequ.result_val =""; // 测试值/输出值 //passStaLogRequ.hi_limit =""; // 上限值 //passStaLogRequ.low_limit =""; // 下限值 //passStaLogRequ.status =""; // 测试状态 //passStaLogRequ.test_time =""; // 单项测试时间 //passStaLogRequ.error_code =""; // 错误码 //passStaLogRequ.project_code =""; // 描述 //passStaLogRequs.Add(passStaLogRequ); //int result_Log = XiaomiMqttClient_Extend.Write_PassStationLog(passStaLogRequs); //if (result_Log == 0) //{ // string sql_Upd = ProcessData.ToStringUpdateStatusByID(1, processData.ID); // string ret_Upd = string.Empty; // //ret_Upd = SQLHelper_New.ExecuteNonQuery(sql_Upd, null); // AddMessage_Station(stationNameStr, LogType.Info, $"更新【过站明细 id {processData.ID}】上传状态---" + ret_Upd); //} //else //{ // OnMessage(LogType.Error, $"上传过站明细到MES服务器---失败!id {processData.ID}"); //} } AddMessage_Station(stationNameStr, LogType.Info, "[" + processItem + $"]上传[{processData.Sn}]过站数据到IOT服务器---" + result_Result + "," + result_Log); } catch (Exception ex) { iotUpload = 0; string str = ex.StackTrace; AddMessage_Station(stationNameStr, LogType.Error, $"PLC上传过站数据IOT报错!错误信息:" + ex.Message.ToString() + ";异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1)); } } else iotUpload = 2; // 更新上传状态 int mesUpload1 = mesUpload; if (mesUpload1 == 2) mesUpload1 = 0; int iotUpload1 = iotUpload; if (iotUpload1 == 2) iotUpload1 = 0; string sql_Upd = ProcessData.ToStringUpdateStatusByID(mesJson, mesUpload1, iotJson, iotUpload1, processData.ID); string ret_Upd = SQLHelper_New.ExecuteNonQuery(sql_Upd, null); AddMessage_Station(stationNameStr, LogType.Info, $"更新【出站数据 id {processData.ID}】上传状态---" + ret_Upd); if (mesUpload == 2) mesUpload = 1; if (iotUpload == 2) iotUpload = 1; int result = (mesUpload == 1 && iotUpload == 1) ? 1 : 2; return result; } #endregion 出站数据 #region 点检数据 /// /// 选择如何记录点检数据 /// /// /// /// /// /// private int SwitctOneCheckData(OneCheckData oneCheckData, string equipmentCode, string stationNameStr) { //if (DataSwitch == 1) //{ return SaveOneCheckDataByDB(oneCheckData, equipmentCode, stationNameStr); //} //else // 废弃 //{ // SaveOneCheckData(names, contents, results, equipmentCode, stationNameStr); //} } /// /// 添加点检数据ByDB(本地保存;不提交到MES) /// /// 点检数据 /// 设备编号 /// 工站名称 public int SaveOneCheckDataByDB(OneCheckData oneCheckData, string equipmentCode, string stationNameStr) { int upload = 0; //本地数据保存 string sql = oneCheckData.ToStringInsert(upload); string ret = SQLHelper_New.ExecuteNonQuery(sql, null); AddMessage_Station(stationNameStr, LogType.Info, string.Concat("[[", equipmentCode, "]", stationNameStr, "]保存本地点检数据---", ret)); //Task.Run(() => // 上传mes-异步 //{ // //上传mes // string jsonstr = JsonConvert.SerializeObject(oneCheckData); // if (GlobalContext.IsSendCheckOneData) // { // string url = @"HTTP://" + GlobalContext.ServerHost + ":" + GlobalContext.ServerPort + @"/api/ProductionLine/OneCheckData"; // string mesRet = HttpUitls.SubmitDataToMES(url, jsonstr); // AddMessage_Station(stationNameStr, LogType.Info, string.Concat("[[", equipmentCode, "]", stationNameStr, "]上传点检数据到MES---", mesRet)); // if (mesRet == "成功") // { // // 更新上传状态 // string sql_Upd = OneCheckData.ToStringUpdateStatusByID(1, oneCheckData.ID); // string ret_Upd = SQLHelper_New.ExecuteNonQuery(sql_Upd, null); // AddMessage_Station(stationNameStr, LogType.Info, $"更新【点检数据 id {oneCheckData.ID}】上传状态---" + ret_Upd); // } // } //}); return ret == "成功" ? 1 : 0; } /// /// 提交点检数据到MES /// /// 工序编号 = 设备编号 /// 车间订单号 /// public int SubmitToMESByDB(string procedure_code, string stationNameStr, string plcOrder) { // 获取今天的点检数据 string querySQL_Today = new OneCheckData().ToQuerySQL_Today(procedure_code, plcOrder); DataSet ds = SQLHelper_New.Query(querySQL_Today, null); if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0) { // 拼接所有点检数据 OneCheckData oneCheckDatas_MES = new OneCheckData() { ID = ds.Tables[0].Rows[0][0].ToString(), Line_code = ds.Tables[0].Rows[0][1].ToString(), Line_name = ds.Tables[0].Rows[0][2].ToString(), Equipment_code = ds.Tables[0].Rows[0][3].ToString(), Equipment_name = ds.Tables[0].Rows[0][4].ToString(), Workorder_code = ds.Tables[0].Rows[0][5].ToString(), Procedure_code = ds.Tables[0].Rows[0][6].ToString(), Procedure_name = ds.Tables[0].Rows[0][7].ToString(), Onecheck_empcode = ds.Tables[0].Rows[0][8].ToString(), Onecheck_empname = ds.Tables[0].Rows[0][9].ToString(), Onecheck_time = ds.Tables[0].Rows[0][10].ToString() }; List upd_Ids = new List(); foreach (DataRow row in ds.Tables[0].Rows) { var obj1 = row["Oneckeck_values"]; if (obj1 != null) { upd_Ids.Add(row["ID"].ToString()); List item = JsonConvert.DeserializeObject>(obj1.ToString()); oneCheckDatas_MES.Oneckeck_values.AddRange(item); } } //上传mes string jsonstr = JsonConvert.SerializeObject(oneCheckDatas_MES); if (GlobalContext.IsSendCheckOneData) { string url = @"HTTP://" + GlobalContext.ServerHost + ":" + @"/api/ProductionLine/OneCheckData"; string mesRet = HttpUitls.SubmitDataToMES(url, jsonstr); AddMessage_Station(stationNameStr, LogType.Info, string.Concat("[", stationNameStr, "]PLC通知上传点检数据到MES到---", mesRet)); if (mesRet == "成功") { // 更新上传状态 string sql_Upd = OneCheckData.ToStringUpdateStatusByIDs(1, upd_Ids); string ret_Upd = SQLHelper_New.ExecuteNonQuery(sql_Upd, null); AddMessage_Station(stationNameStr, LogType.Info, $"更新【点检数据 id [{string.Join("','", upd_Ids)}]】上传状态---" + ret_Upd); // 保存最新一条点检数据 到文件中 StandardLibrary.IniFile.INIWriteValue(GlobalContext.CheckOneDataPath, "S" + procedure_code, "WorkOrderCode", GlobalContext.WorkOrderCode); StandardLibrary.IniFile.INIWriteValue(GlobalContext.CheckOneDataPath, "S" + procedure_code, "Oneckeck_values", JsonConvert.SerializeObject(oneCheckDatas_MES.Oneckeck_values)); return ret_Upd == "成功" ? 1 : 0; } } } //else //{ // AddMessage_Station(stationNameStr, LogType.Info, string.Concat("[", stationNameStr, "]PLC通知上传点检数据到MES---失败!今天还未点检。")); //} return 0; } /// /// 添加点检数据ByDB(本地保存 + 提交到MES) /// /// 点检数据 /// 设备编号 /// 工站名称 /// public int SaveOneCheckDataByDBAndSubmit(OneCheckData oneCheckData, string equipmentCode, string stationNameStr) { int upload = 0; //本地数据保存 string sql = oneCheckData.ToStringInsert(upload); string ret = SQLHelper_New.ExecuteNonQuery(sql, null); AddMessage_Station(stationNameStr, LogType.Info, string.Concat("[[", equipmentCode, "]", stationNameStr, "]保存本地点检数据---", ret)); Task.Run(() => // 上传mes-异步 { //上传mes string jsonstr = JsonConvert.SerializeObject(oneCheckData); string jsonItems = JsonConvert.SerializeObject(oneCheckData.Oneckeck_values); if (GlobalContext.IsSendCheckOneData) { string url = @"HTTP://" + GlobalContext.ServerHost + ":" + @"/api/ProductionLine/OneCheckData"; string mesRet = HttpUitls.SubmitDataToMES(url, jsonstr); AddMessage_Station(stationNameStr, LogType.Info, string.Concat("[[", equipmentCode, "]", stationNameStr, "]上传点检数据到MES---", mesRet)); if (mesRet == "成功") { // 更新上传状态 string sql_Upd = OneCheckData.ToStringUpdateStatusByID(1, oneCheckData.ID); string ret_Upd = SQLHelper_New.ExecuteNonQuery(sql_Upd, null); AddMessage_Station(stationNameStr, LogType.Info, $"更新【点检数据 id {oneCheckData.ID}】上传状态---" + ret_Upd); // 保存最新一条点检数据 到文件中 StandardLibrary.IniFile.INIWriteValue(GlobalContext.CheckOneDataPath, equipmentCode, "WorkOrderCode", GlobalContext.WorkOrderCode); StandardLibrary.IniFile.INIWriteValue(GlobalContext.CheckOneDataPath, equipmentCode, "Oneckeck_values", jsonItems); } } }); return ret == "成功" ? 1 : 0; } /// /// 清空 点检数据 By 工序号、订单号 /// /// 工序号 /// 工站号 /// 订单号 /// /// private int ClearOneCheckDataByDB(string procedure_code, string stationNameStr, string plcOrder) { // 清空 string sql_Det = OneCheckData.ToDeteleByProcedurecodeAndPlcOrder(procedure_code, plcOrder); string ret_Upd = SQLHelper_New.ExecuteNonQuery(sql_Det, null); AddMessage_Station(stationNameStr, LogType.Info, $"清空【工位编号{procedure_code}】【车间订单{plcOrder}】的点检项缓存 ---" + ret_Upd); return ret_Upd == "成功" ? 1 : 2; } /// /// 生产过程中,自动判断 是否 使用上次的点检数据 /// 在工单加工第一个产品时触发该方法 /// 如果工单是上次的点检工单则直接返回成功,工单不是上次的点检工单则使用上个工单的点检数据,上传点检信息 /// /// /// 设备编号 /// 工序编号 /// 点检数据 /// private int SwitctOneCheckData_First(string stationNameStr, string equipmentCode, string accno, string processItem) { string WorkOrderCode = StandardLibrary.IniFile.INIGetStringValue(GlobalContext.CheckOneDataPath, equipmentCode, "WorkOrderCode", string.Empty); //如果当前工单和记录中的工单是一致,表示这个工单是需要点检的,跳过 //如果当前工单和记录中的工单是不一致,表示这个工单和上个工单是同型号的,可以使用上个工单的点检数据 if (GlobalContext.WorkOrderCode == WorkOrderCode) { return 1; } //点检数据 string Oneckeck_values = StandardLibrary.IniFile.INIGetStringValue(GlobalContext.CheckOneDataPath, equipmentCode, "Oneckeck_values", string.Empty); List items = new List(); try { items = JsonConvert.DeserializeObject>(Oneckeck_values); } catch (Exception ex) { return 0; } // 拼接所有点检数据 OneCheckData oneCheckDatas_MES = new OneCheckData() { ID = Guid.NewGuid().ToString(), Line_code = GlobalContext.LineCode, Line_name = GlobalContext.LineName, Equipment_code = equipmentCode, Equipment_name = equipmentCode, Workorder_code = GlobalContext.WorkOrderCode, Procedure_code = accno, Procedure_name = processItem, Onecheck_empcode = "", Onecheck_empname = "", Onecheck_time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), Oneckeck_values = items }; // 本地保存 + 提交到MES return SaveOneCheckDataByDBAndSubmit(oneCheckDatas_MES, equipmentCode, stationNameStr); } #endregion 点检数据 #region 设备状态数据 /// /// 记录上次保存 设备状态数据CSV 的时间 /// private DateTime dtSaveDeviceStateCSV_Old = DateTime.Now.AddMinutes(-5); /// /// 上传设备状态数据 /// 上传IOT + 5分钟记录一次数据到txt中 /// /// 工站信息 /// 设备状态 /// 左右工位标识 /// 故障编码 /// 故障发⽣时间 /// 上位机发送1代表OK;2代表上传客户MES失败;3代表上位机保存数据失败;4代表上位机报警; public (int, string) SaveDeviceStateData(string stationNameStr, XiaomiDeviceState deviceState,string flag, string fault_code = "A40000", string fault_tm = "") { int result = 0; string msg = ""; DateTime dtNow = DateTime.Now; try { // 上传到IOT if (GlobalContext.IsUseIot && GlobalContext.IsMqttDeviceState) { DeviceStateDataRequest request = new DeviceStateDataRequest(); if (GlobalContext.IsUsePLC1) request.station = GlobalContext.S1_station; // 工位ID(可配置) if (GlobalContext.IsUsePLC2) request.station = GlobalContext.S2_station; // 工位ID(可配置) if (GlobalContext.IsUsePLC3) { if (flag == "left") request.station = GlobalContext.s3_1_station; // 工位ID(可配置) else request.station = GlobalContext.s3_2_station; // ⼯位ID(可配置) } if (GlobalContext.IsUsePLC4) request.station = GlobalContext.s4_station; // 工位ID(可配置) if (GlobalContext.IsUsePLC5) request.station = GlobalContext.s5_station; // 工位ID(可配置) if (GlobalContext.IsUsePLC6) request.station = GlobalContext.s6_station; // 工位ID(可配置) if (GlobalContext.IsUsePLC7) { if (flag == "left") request.station = GlobalContext.s7_1_station; // ⼯位ID(可配置) else request.station = GlobalContext.s7_2_station; // ⼯位ID(可配置) } if (GlobalContext.IsUsePLC8) request.station = GlobalContext.s8_station; // ⼯位ID(可配置) if (GlobalContext.IsUsePLC9) request.station = GlobalContext.s9_station; // ⼯位ID(可配置) request.state = deviceState.ToString(); // 设备状态 request.time = dtNow.ToString("yyyy-MM-dd HH:mm:ss.fff"); // 状态切换时的时间 2022-06-01 14:27:57.283 if (deviceState == XiaomiDeviceState.Fault || deviceState == XiaomiDeviceState.Alarm) { request.fault_code = fault_code; // 对应的故障编码 request.fault_tm = fault_tm; // 故障发⽣时间(需要实际的发生时间) } // 上传 (int, string) iotResult = XiaomiMqttClient_Extend.Write_DeviceStateData(request); result = iotResult.Item1 == 0 ? 1 : 2; msg = $"[{iotResult.Item1}]{iotResult.Item2}"; SaveDeviceStateDataLog(iotResult, request, dtNow); } else return (1, "OK;未启用上传Iot"); } catch (Exception ex) { result = 4; string str = ex.StackTrace; msg = $"错误信息:" + ex.Message.ToString() + ";异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1); OnMessage(LogType.Error, "【设备状态】"+stationNameStr + $"_PLC上传Iot设备状态数据报错!错误信息:" + ex.Message.ToString() + ";异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1)); } return (result, msg); } /// /// 5分钟记录一次数据到txt中 /// /// /// private void SaveDeviceStateDataLog((int, string) iotResult, DeviceStateDataRequest request,DateTime dtNow) { if (dtSaveDeviceStateCSV_Old < dtNow) { string fileDir = GlobalContext.MqttDeviceStateDir + dtNow.ToString("yyyy_MM"); // 文件夹路径 if (!Directory.Exists(fileDir)) Directory.CreateDirectory(fileDir); string filePath = fileDir + dtNow.ToString("yyyy_MM_dd"); // 文件路径 StringBuilder sbData = new StringBuilder(); if (!File.Exists(filePath)) sbData.AppendLine("工位ID,设备状态,状态切换时的时间,故障编码,故障发生时间,上传结果"); string iotResultMsg = $"[{iotResult.Item1}]{iotResult.Item2}"; sbData.AppendLine($"{request.station},{request.state},{request.time},{request.fault_code},{request.fault_tm},{iotResultMsg}"); // 文件内容 // 保存到CSV文件中 string newLineData = sbData.ToString(); // 文件内容 CSVHelper.CSVFile_AddLog(filePath, newLineData); } } #endregion 设备状态数据 #region 报警数据 /// /// 添加报警数据ByDB(提交到MES+本地保存) /// /// 数据 /// 更新而不是新增 public void SaveAlarmDataByDB(string stationNameStr, AlarmData alarmData, bool isUpd) { try { if (isUpd) { string sql = alarmData.ToStringUpdate(); SQLHelper_New.ExecuteSQL(sql, null); //OnMessage(LogType.Info, "【报警日志】消除报警[" + alarmData.LineName + "-" + alarmData.AlarmDesc + "]完毕!"); } else { string sql = alarmData.ToStringInsert(); SQLHelper_New.ExecuteSQL(sql, null); //OnMessage(LogType.Info, "【报警日志】发生了报警[" + alarmData.LineName + "-" + alarmData.AlarmDesc + "]!"); FaultLogRequest request = new FaultLogRequest(); request.station = alarmData.LineName; // ⼯位 request.fault_name = alarmData.AlarmDesc; // 故障名称(同数据字典中的事件名称) request.fault_code = alarmData.AlarmType; // 故障编码(A,B,C,D,E) request.fault_cmpnt = alarmData.Type4; // 故障部件 request.fault_desc = alarmData.AlarmDesc; // 故障描述 request.fault_tm = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); // 故障发⽣时间 2022-06-01 14:27:57.283 // 上传 (int, string) iotResult = XiaomiMqttClient_Extend.Write_FaultLog(request); if (iotResult.Item1 == 0) AddMessage_Station(stationNameStr, LogType.Info, "【报警日志】[" + alarmData.LineName + "-" + alarmData.AlarmDesc + "]上传IOT成功!"); else AddMessage_Station(stationNameStr, LogType.Info, "【报警日志】[" + alarmData.LineName + "-" + alarmData.AlarmDesc + "]上传IOT失败,错误原因:"+ iotResult.Item2 + "!"); } } catch (Exception e) { throw e; } } #endregion 报警数据 #region 节拍数据 /// /// 上传节拍数据 /// /// /// /// /// /// /// /// /// /// /// 上位机发送1代表OK;2代表上传客户MES失败;3代表上位机保存数据失败;4代表上位机报警; public (short, string) SaveOEEData(int plcNo, string stationNameStr, XiaomiDeviceOEE deviceOEE, string oEEPartNo, string oEEVSN, string extra = "" , string class_level_1 = "beat_log", string class_level_2 = "business", string class_level_3 = "OEE") { // 上传OEE if (GlobalContext.IsMqttStationInputBegin) { Task.Run(() => { try { StationInputBeginRequest oee = new StationInputBeginRequest(); oee.action = deviceOEE.ToString(); // 节拍动作(XiaomiDeviceOEE) oee.beat_tm = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"); // 节拍发⽣时间 oee.action_subject = oEEPartNo; // 该动作操作的⽬标对象(SN) oee.action_subject_parent = oEEVSN; // ⼤板SN/载具SN switch (stationNameStr) { case "[OP10]壳体清洁上料": oee.action_location = GlobalContext.S1_station; break; case "[OP20]上盖板上料装备": oee.action_location = GlobalContext.S2_station; break; case "[OP30]点散热胶装备_Left": oee.action_location = GlobalContext.s3_1_station; break; case "[OP30]点散热胶装备_Right": oee.action_location = GlobalContext.s3_2_station; break; case "[OP40]胶线检测": oee.action_location = GlobalContext.s4_station; break; case "[OP50]ADD板上料组装装备": oee.action_location = GlobalContext.s5_station; break; case "[OP60]组上盖板": oee.action_location = GlobalContext.s6_station; break; case "[OP70]上盖板锁螺丝_Left": oee.action_location = GlobalContext.s7_1_station; break; case "[OP70]上盖板锁螺丝_Right": oee.action_location = GlobalContext.s7_2_station; break; case "[OP80]NG下料": oee.action_location = GlobalContext.s8_station; break; case "[OP90]半成品下料": oee.action_location = GlobalContext.s8_station; break; } oee.action_material = oee.action_location + "_1"; // 该动作的物料信息 oee.extra = extra; // 额外信息 oee.class_level_1 = class_level_1; // 分类层级1 oee.class_level_2 = class_level_2; // 分类层级2 oee.class_level_3 = class_level_3; // 分类层级3 var iotResult = XiaomiMqttClient_Extend.Write_StationInputBegin(oee); int result = iotResult.Item1; string msg = $"[{iotResult.Item1}]{iotResult.Item2}"; if (result == 0) OnMessage(LogType.Info, stationNameStr + $"_异步上传Iot节拍数据[SN:{oEEPartNo}]成功!iot接口返回结果:{msg}"); else AddMessage(LogType.Info, stationNameStr + $"_异步上传Iot节拍数据[SN:{oEEPartNo}]失败!iot接口返回结果:{msg}"); } catch (Exception ex) { string str = ex.StackTrace; AddMessage(LogType.Error, $"PLC{plcNo}_{stationNameStr}_[{oEEPartNo}]异步上传Iot节拍数据失败!报错信息:" + ex.Message + "异常位置:" + str.Substring(str.LastIndexOf("\\") + 1, str.Length - str.LastIndexOf("\\") - 1)); } }); return ((short)1, "异步上传中!"); } else return ((short)1, "未启用上传!"); } #endregion 节拍数据 #endregion 保存数据 } }