上次文章是采集数据,这篇是处理数据
完整代码放在文章最后,大家感兴趣可以看看!
处理流程
数据分析
设计软件页面
整理采集思路
编辑代码
调试运行
数据处理效果预览
导线单压被判断为异常,后续已更新判断逻辑
效率计算逻辑已更改,图片效率为单个订单效率,后面更改为平均效率
补充更改后的效果
KOMAX的Alpha 550数据分析
界面设计
这是设计的界面,有点麻烦,我就没做,不好意思!设计思路也是,改了又改,有点乱了,我又没整理就不发了!
数据结构定义
public class HmiData : INotifyPropertyChanged
{
private string machinNumber;
// 机台号
public string MachinNumber
{
get { return machinNumber; }
set
{
if (value != machinNumber)
{
machinNumber = value;
OnPropertyChanged(nameof(MachinNumber));
}
}
}
private string orderName;
// 订单名称
public string OrderName
{
get { return orderName; }
set
{
if (value != orderName)
{
orderName = value;
OnPropertyChanged(nameof(OrderName));
}
}
}
private string orderStartTime;
// 订单开始时间
public string OrderStartTime
{
get { return orderStartTime; }
set
{
if (value != orderStartTime)
{
orderStartTime = value;
OnPropertyChanged(nameof(OrderStartTime));
}
}
}
private string orderEndTime;
// 订单结束时间
public string OrderEndTime
{
get { return orderEndTime; }
set
{
if (value != orderEndTime)
{
orderEndTime = value;
OnPropertyChanged(nameof(OrderEndTime));
}
}
}
private string wireNumber;
// 导线号
public string WireNumber
{
get { return wireNumber; }
set
{
if (value != wireNumber)
{
wireNumber = value;
OnPropertyChanged(nameof(WireNumber));
}
}
}
private string wireFIFO;
// 导线FIFO
public string WireFIFO
{
get { return wireFIFO; }
set
{
if (value != wireFIFO)
{
wireFIFO = value;
OnPropertyChanged(nameof(WireFIFO));
}
}
}
private string terminalNumber1;
// 端子号1
public string TerminalNumber1
{
get { return terminalNumber1; }
set
{
if (value != terminalNumber1)
{
terminalNumber1 = value;
OnPropertyChanged(nameof(TerminalNumber1));
}
}
}
private string terminalFIFO1;
// 端子1FIFO
public string TerminalFIFO1
{
get { return terminalFIFO1; }
set
{
if (value != terminalFIFO1)
{
terminalFIFO1 = value;
OnPropertyChanged(nameof(TerminalFIFO1));
}
}
}
private string toolNumber1;
// 模具号1
public string ToolNumber1
{
get { return toolNumber1; }
set
{
if (value != toolNumber1)
{
toolNumber1 = value;
OnPropertyChanged(nameof(ToolNumber1));
}
}
}
private string terminalNumber2;
// 端子号2
public string TerminalNumber2
{
get { return terminalNumber2; }
set
{
if (value != terminalNumber2)
{
terminalNumber2 = value;
OnPropertyChanged(nameof(TerminalNumber2));
}
}
}
private string terminalFIFO2;
// 端子2FIFO
public string TerminalFIFO2
{
get { return terminalFIFO2; }
set
{
if (value != terminalFIFO2)
{
terminalFIFO2 = value;
OnPropertyChanged(nameof(TerminalFIFO2));
}
}
}
private string toolNumber2;
// 模具号2
public string ToolNumber2
{
get { return toolNumber2; }
set
{
if (value != toolNumber2)
{
toolNumber2 = value;
OnPropertyChanged(nameof(ToolNumber2));
}
}
}
private string orderQuantity;
// 订单数量
public string OrderQuantity
{
get { return orderQuantity; }
set
{
if (value != orderQuantity)
{
orderQuantity = value;
OnPropertyChanged(nameof(OrderQuantity));
}
}
}
private string orderCompletedQuantity;
// 订单已完成数量
public string OrderCompletedQuantity
{
get { return orderCompletedQuantity; }
set
{
if (value != orderCompletedQuantity)
{
orderCompletedQuantity = value;
OnPropertyChanged(nameof(OrderCompletedQuantity));
}
}
}
private string batchQuantity;
// 批次数量
public string BatchQuantity
{
get { return batchQuantity; }
set
{
if (value != batchQuantity)
{
batchQuantity = value;
OnPropertyChanged(nameof(BatchQuantity));
}
}
}
private string orderStatus;
// 订单状态
public string OrderStatus
{
get { return orderStatus; }
set
{
if (value != orderStatus)
{
orderStatus = value;
OnPropertyChanged(nameof(OrderStatus));
}
}
}
private string productionEfficiency;
// 生产效率
public string ProductionEfficiency
{
get { return productionEfficiency; }
set
{
if (value != productionEfficiency)
{
productionEfficiency = value;
OnPropertyChanged(nameof(ProductionEfficiency));
}
}
}
private string jobNotes;
// 生产效率
public string JobNotes
{
get { return jobNotes; }
set
{
if (value != jobNotes)
{
productionEfficiency = value;
OnPropertyChanged(nameof(JobNotes));
}
}
}
//数据改变事件
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
数据绑定
//初始化DataTable
private void IintDataTable()
{
// Create a new DataTable
dataTable = new DataTable();
// Add columns to the DataTable
dataTable.Columns.Add("机台号", typeof(string));
dataTable.Columns.Add("订单号", typeof(string));
dataTable.Columns.Add("开始时间", typeof(string));
dataTable.Columns.Add("结束时间", typeof(string));
dataTable.Columns.Add("导线号", typeof(string));
dataTable.Columns.Add("导线FIFO", typeof(string));
dataTable.Columns.Add("端子1", typeof(string));
dataTable.Columns.Add("端子1FIFO", typeof(string));
dataTable.Columns.Add("模具1", typeof(string));
dataTable.Columns.Add("端子2", typeof(string));
dataTable.Columns.Add("端子2FIFO", typeof(string));
dataTable.Columns.Add("模具2", typeof(string));
dataTable.Columns.Add("订单数量", typeof(string));
dataTable.Columns.Add("完成数量", typeof(string));
dataTable.Columns.Add("批次数量", typeof(string));
dataTable.Columns.Add("订单状态", typeof(string));
dataTable.Columns.Add("效率(PCS/H)", typeof(string));
dataTable.Columns.Add("备注", typeof(string));
AddnewRow();
// Bind the HmiDataCollection to the DataGrid
MyDataGrid.ItemsSource = dataTable.DefaultView;
}
private void AddnewRow()
{
// Create a new instance of the HmiData class
HmiData newData = new HmiData
{
MachinNumber = strmachinenumber,
OrderName = "",
OrderStartTime = "",
OrderEndTime = "",
WireNumber = "",
WireFIFO = "",
TerminalNumber1 = "",
TerminalFIFO1 = "",
ToolNumber1 = "",
TerminalNumber2 = "",
TerminalFIFO2 = "",
ToolNumber2 = "",
OrderQuantity = "",
OrderCompletedQuantity = "",
BatchQuantity = "",
OrderStatus = "",
ProductionEfficiency = "",
JobNotes = ""
};
// Add a new row to the DataTable
DataRow newRow = dataTable.NewRow();
Set the values of the columns in the new row
newRow.ItemArray = new object[] {
newData.OrderName,
newData.OrderStartTime,
newData.OrderEndTime,
newData.WireNumber,
newData.WireFIFO,
newData.TerminalNumber1,
newData.TerminalFIFO1,
newData.ToolNumber1,
newData.TerminalNumber2,
newData.TerminalFIFO2,
newData.ToolNumber2,
newData.OrderQuantity,
newData.OrderCompletedQuantity,
newData.BatchQuantity,
newData.OrderStatus,
newData.ProductionEfficiency,
newData.JobNotes
};
// Add the new row to the DataTable
dataTable.Rows.Add(newRow);
//更新列表行数
datarows = dataTable.Rows.Count - 1;
rownow = dataTable.Rows[datarows];
rownow["机台号"] = strmachinenumber;
}
采集主线程
private void Work()
{
try
{
while (true)
{
System.Threading.Thread.Sleep(1000); //毫秒
//对比数据,如果相等就跳出本次循环
if (tempstr != myMqtt.hmidatat)
{
tempstr = myMqtt.hmidatat;
}
else
{
System.Threading.Thread.Sleep(1000); //毫秒
continue;
}
//更新列表行数
datarows = dataTable.Rows.Count - 1;
rownow = dataTable.Rows[datarows];
//rownow = dataTable.Rows[0];
string topic = myMqtt.hmitopic;
if (topic.Contains("/application/production/job/state"))
{
MyJobStateData = myMqtt.hmidatat;
var tt2 = new Task(() => JobState());
tt2.Start();
//MyJobStateData = myMqtt.hmidatat;
//JobState();
topic = "";
logger.LogInfo("/job/state");
continue;
}
else
{
//判断订阅的话题,然后赋值
if (topic.Contains("/application/production/job/update/progress"))
{
MyJobProgressData = myMqtt.hmidatat;
var tt1 = new Task(() => JobProgress());
tt1.Start();
topic = "";
continue;
}
if (topic.Contains("/status/scan/material"))
{
var tt3 = new Task(() => MaterialScanGood());
tt3.Start();
MyMaterialScanGoodData = myMqtt.hmidatat;
topic = "";
logger.LogInfo("/status/scan/material");
continue;
}
if (topic.Contains("/application/production/job/report/counter"))
{
var tt3 = new Task(() => MaterialScan());
tt3.Start();
MyMaterialScanData = myMqtt.hmidatat;
topic = "";
logger.LogInfo("/job/report/counter");
continue;
}
System.Threading.Thread.Sleep(1000); //毫秒
}
}
}
catch (Exception ex)
{
// write the error message and stack trace to the log file
logger.LogError(ex.Message);
logger.LogError(ex.StackTrace);
}
}
订单状态监控
//当前行
DataRow rownow;
//string StartTime = "";
//string CompleteTime = "";
//string OrderName = "";
//订单状态变化
private void JobState()
{
try
{
string xm1 = MyJobStateData;
// 解析XML字符串
XDocument Doc1 = XDocument.Parse(xm1);
// 提取订单状态
string OrderState = Doc1.Root.Element("State").Value;
// 提取订单号
string href = Doc1.Root.Element("Job").Attribute("href").Value;
//string strorder = href.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last();
string strorder = GetValueFromHref(href);
logger.LogInfo(strorder);
// 提取时间
string OrderdateTime = Doc1.Root.Attribute("dateTime").Value;
//UTC时间转换成本地时间
DateTime date = DateTime.Parse(OrderdateTime).ToLocalTime();
//判断订单结束
if(OrderState == "Done")
{
//比较订单号
if (rownow["订单号"].ToString() == strorder)
{
rownow["结束时间"] = date.ToString();
logger.LogInfo("Done");
//增加一个空行
AddOrder();
return;
}
}
//判断订单开始
if (OrderState == "InWork")
{
//比较订单号
if (rownow["订单号"].ToString() == "")
{
logger.LogInfo("InWork");
rownow["开始时间"] = date.ToString();
rownow["订单号"] = strorder;
//增加一个空行
//AddOrder();
return;
}
}
}
catch (Exception ex)
{
// write the error message and stack trace to the log file
logger.LogError(ex.Message);
logger.LogError(ex.StackTrace);
}
}
产量监控
//订单数量变化
private void JobProgress()
{
try
{
string xm2 = MyJobProgressData;
XDocument doc2 = XDocument.Parse(xm2);
//取出订单号
string href = doc2.Root.Element("Job").Attribute("href").Value;
//string strorder = href.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last();
string strorder = GetValueFromHref(href);
//判断订单号是否为空
if (rownow["订单号"].ToString() == "")
{
rownow["订单号"] = strorder;
}
else
{
//否则订单号不一致,判断为订单改变
if (strorder != rownow["订单号"].ToString())
{
//增加订单
AddOrder();
logger.LogInfo("JobProgress 订单不一致");
rownow["订单号"] = strorder;
}
}
//Mydata.OrderStatus = doc.Root.Element("JobType").Value;
rownow["订单状态"] = doc2.Root.Element("JobType").Value;
rownow["完成数量"] = doc2.Root.Element("CompletedHarnesses").Value;
//string completedAdditionals = doc.Root.Element("CompletedAdditionals").Value;
rownow["订单数量"] = doc2.Root.Element("TargetHarnesses").Value;
//string targetAdditionals = doc.Root.Element("TargetAdditionals").Value;
rownow["批次数量"] = doc2.Root.Element("TargetBatchSize").Value;
}
catch (Exception ex)
{
// write the error message and stack trace to the log file
logger.LogError(ex.Message);
logger.LogError(ex.StackTrace);
}
}
物料监控
//物料状态变化
private void MaterialScanGood()
{
try
{
string xm3 = MyMaterialScanGoodData;
XmlDocument doc3 = new XmlDocument();
doc3.LoadXml(xm3);
XmlNode root3 = doc3.DocumentElement;
XmlNode wireLineNode = root3.SelectSingleNode("ProcessModule/WireLine");
bool isGood = bool.Parse(root3.SelectSingleNode("IsGood").InnerText);
//判断扫描的是导线
if (wireLineNode != null && isGood)
{
rownow["导线号"] = root3.SelectSingleNode("MaterialKey").InnerText;
rownow["导线FIFO"] = root3.SelectSingleNode("MaterialHandlingUnit").InnerText;
return;
}
XmlNode crimpModuleNode = root3.SelectSingleNode("ProcessModule/CrimpModule");
//判断工作站1
if (crimpModuleNode != null && crimpModuleNode.Attributes["href"].Value.Contains("%255DC1MCI721-0011") && isGood)
{
rownow["模具1"] = root3.SelectSingleNode("ToolKey").InnerText;
rownow["端子1"] = root3.SelectSingleNode("MaterialKey").InnerText;
rownow["端子1FIFO"] = root3.SelectSingleNode("MaterialHandlingUnit").InnerText;
return;
}
//判断工作站2
if (crimpModuleNode != null && crimpModuleNode.Attributes["href"].Value.Contains("%255DC1MCI721-0012") && isGood)
{
rownow["模具2"] = root3.SelectSingleNode("ToolKey").InnerText;
rownow["端子2"] = root3.SelectSingleNode("MaterialKey").InnerText;
rownow["端子2FIFO"] = root3.SelectSingleNode("MaterialHandlingUnit").InnerText;
return;
}
}
catch (Exception ex)
{
// write the error message and stack trace to the log file
logger.LogError(ex.Message);
logger.LogError(ex.StackTrace);
}
//App.Current.Dispatcher.Invoke(() =>
//{
// mytext.Text = "/status/scan/material";
// MyLabel.Content = myMqtt.hmidatat;
//});
}
//物料状态变化
private void MaterialScan()
{
try
{
string xm4 = MyMaterialScanData;
XmlDocument doc4 = new XmlDocument();
doc4.LoadXml(xm4);
XmlNode root4 = doc4.DocumentElement;
XmlNode wireLineNode = root4.SelectSingleNode("//Wire");
//判断是导线
if (wireLineNode != null)
{
string wireHref = GetValueFromHref(wireLineNode.Attributes["href"].Value);
rownow["导线号"] = wireHref;
XmlNode handlingUnitNode = doc4.SelectSingleNode("//SlotConsumption/HandlingUnit");
if (handlingUnitNode != null && handlingUnitNode.Attributes["material"] != null)
{
rownow["导线FIFO"] = handlingUnitNode.Attributes["material"].Value;
}
}
//取端子信息
XmlNodeList terminalNodes = doc4.SelectNodes("//Terminal");
XmlNodeList crimpModuleNodes = doc4.SelectNodes("//CrimpModule");
XmlNodeList HandlingUnitNodes = doc4.SelectNodes("//CrimpModuleConsumption/HandlingUnit");
for (int i = 0; i < terminalNodes.Count; i++)
{
string crimpModuleHref = crimpModuleNodes[i].Attributes["href"].Value;
if (crimpModuleHref.Contains("%255DC1MCI721-0011"))
{
string terminalHref = terminalNodes[i].Attributes["href"].Value;
rownow["端子1"] = GetValueFromHref(terminalHref);
if (HandlingUnitNodes[i].Attributes["material"] != null)
{
rownow["端子1FIFO"] = HandlingUnitNodes[i].Attributes["material"].Value;
}
if (HandlingUnitNodes[i].Attributes["tool"] != null)
{
rownow["模具1"] = HandlingUnitNodes[i].Attributes["tool"].Value;
}
continue;
}
if (crimpModuleHref.Contains("%255DC1MCI721-0012"))
{
string terminalHref = terminalNodes[i].Attributes["href"].Value;
rownow["端子2"] = GetValueFromHref(terminalHref);
if (HandlingUnitNodes[i].Attributes["material"] != null)
{
rownow["端子2FIFO"] = HandlingUnitNodes[i].Attributes["material"].Value;
}
if (HandlingUnitNodes[i].Attributes["tool"] != null)
{
rownow["模具2"] = HandlingUnitNodes[i].Attributes["tool"].Value;
}
continue;
}
}
}
catch (Exception ex)
{
// write the error message and stack trace to the log file
logger.LogError(ex.Message);
logger.LogError(ex.StackTrace);
}
}
static string GetValueFromHref(string href)
{
href = href.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries).Last();
return href;
}
日志模块
public interface ILogger
{
void LogError(string message);
void LogWarning(string message);
void LogInfo(string message);
}
//错误日志
public class FileLogger : ILogger
{
private readonly Mutex _mutex;
private readonly string _logFilePath;
public FileLogger(string logFilePath)
{
_logFilePath = logFilePath;
_mutex = new Mutex();
}
public void LogError(string message)
{
_mutex.WaitOne();
try
{
WriteLog("ERROR", message);
}
finally
{
_mutex.ReleaseMutex();
}
}
public void LogWarning(string message)
{
_mutex.WaitOne();
try
{
WriteLog("WARNING", message);
}
finally
{
_mutex.ReleaseMutex();
}
}
public void LogInfo(string message)
{
_mutex.WaitOne();
try
{
WriteLog("INFO", message);
}
finally
{
_mutex.ReleaseMutex();
}
}
private void WriteLog(string level, string message)
{
string logMessage = string.Format("[{0}] {1}: {2}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), level, message);
File.AppendAllText(_logFilePath, logMessage + Environment.NewLine);
}
}
效率计算和备注信息模块
private void AddOrder()
{
try
{
//计算效率
if (rownow["开始时间"].ToString() != "" && rownow["结束时间"].ToString() != "" && rownow["完成数量"].ToString() != "")
{
efficiencynumber = efficiencynumber + 1;
// calculate efficiency using completed quantity, start time, and end time
double completedQuantity = Convert.ToDouble(rownow["完成数量"]);
DateTime startTime = Convert.ToDateTime(rownow["开始时间"]);
DateTime endTime = Convert.ToDateTime(rownow["结束时间"]);
efficiency = (efficiency + completedQuantity / (endTime - startTime).TotalHours)/ efficiencynumber;
// update the efficiency column in the current row
if(efficiency.ToString().Length > 6)
{
rownow["效率(PCS/H)"] = efficiency.ToString().Substring(0, 6);
}
else
{
rownow["效率(PCS/H)"] = efficiency.ToString();
}
}
//添加备注
if (rownow["订单数量"].ToString() == "")
{
rownow["备注"] = "订单数量异常;";
}
if (rownow["开始时间"].ToString() == "")
{
rownow["备注"] = rownow["备注"] + "订单状态异常;";
}
if (rownow["导线号"].ToString() == "" ||( rownow["端子1"].ToString() == "" && rownow["端子2"].ToString() == ""))
{
rownow["备注"] = rownow["备注"] + "物料状态异常;";
}
//更新订单状态
rownow["订单状态"] = "Finish";
//此处一定要有委托,否则报错
// Add the new row to the DataTable
App.Current.Dispatcher.Invoke(() =>
{
//设备备注的字体颜色
DataGridColumn column = MyDataGrid.Columns[17]; // 获取第2列
DataGridTextColumn textColumn = column as DataGridTextColumn;
if (textColumn != null)
{
Style cellStyle = new Style(typeof(DataGridCell));
cellStyle.Setters.Add(new Setter(Control.ForegroundProperty, Brushes.Red));
textColumn.CellStyle = cellStyle;
}
//添加一行空数据
AddnewRow();
});
}
catch(Exception ex)
{
// write the error message and stack trace to the log file
logger.LogError(ex.Message);
logger.LogError(ex.StackTrace);
}
}
运行日志
分享使人快乐!我为人人,人人为我!努力学习,努力工作!
完整代码包下载链接
链接:https://pan.baidu.com/s/1tyDBPAZmoecOs_bGrRC_jw
提取码:eton