alielie
2026-03-02 12e606635c42ea20f4b7c2bdda5204237a4b4c96
Plugin.TestResult/SingleCell.xaml.cs
@@ -1,10 +1,19 @@
using Plugin.TestResult_WPF.Constant;
using CSVHelper;
using HMI.Core.Entity;
using HMI.Core.Manager;
using HMI.Core.Setting;
using HMI.Core.Util;
using HMI.Util;
using PLCHelper;
using Plugin.TestResult.Util;
using Plugin.TestResult_WPF.Constant;
using Plugin.TestResult_WPF.Model;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
@@ -33,32 +42,105 @@
        }
        #endregion
        private static readonly HashSet<string> IgnoreTestItem = new HashSet<string> {
            "产品条码","checkin","预检电流","precheckresult","checkout",
        };
        private InfoWindow window;
        private int maxSize;
        public SingleCell()
        {
            DataContext = this;
            InitializeComponent();
        }
        private DataTable table;
        public SingleCell(string parentName, int index, int maxSize)
        public SingleCell(DataTable table, string title, int index, int maxSize, string iniFile)
        {
            this.parentName = parentName;
            this.table = table;
            this.title = title;
            this.index = index;
            this.maxSize = maxSize;
            this.countIniPath = iniFile;
            DataContext = this;
            InitializeComponent();
            RefreshProbe();
        }
        private string _parentName;
        public string parentName
        public void RefreshProbe()
        {
            get { return _parentName; }
            try
            {
                string key = string.Empty;
                ParameterData value;
                if (ParamSetting.ProbeByModel)
                {
                    string model = table.CbProduct?.SelectedItem?.ToString();
                    key = $"{title}_{model}";
                    value = ProductManager.GetParameterByProductAndName(model, "ProbeWarn");
                    if (value == null)
                    {
                        value = ParameterManager.GetCommonParameterByName("ProbeWarn");
                    }
                    ProbeWarn = value != null ? int.Parse(value.Value) : 1000;
                }
                else
                {
                    key = $"{title}";
                    value = ParameterManager.GetCommonParameterByName("ProbeWarn");
                    ProbeWarn = value != null ? int.Parse(value.Value) : 1000;
                }
                string temp = IniFileHelper.ReadIniData(key, "ProbeCount", "0", countIniPath);
                int count = Convert.ToInt32(temp);
                ProbeCount = count;
            }
            catch
            {
                ProbeWarn = 1000;
            }
            if (window != null) window.UpdateProbeCount(ProbeCount, ProbeWarn);
        }
        public void RefreshCharts()
        {
            charts = new LiveChart[3];
            try
            {
                ParameterData value;
                string model = table.CbProduct?.SelectedItem?.ToString();
                for (int i = 0; i < charts.Length; i++)
                {
                    value = ProductManager.GetParameterByProductAndName(model, $"ChartConfig_{i}");
                    if (value == null)
                    {
                        value = ParameterManager.GetCommonParameterByName($"ChartConfig_{i}");
                    }
                    var config = value != null ? value.Value : null;
                    if (string.IsNullOrEmpty(config))
                    {
                        charts[i] = null;
                    }
                    else
                    {
                        charts[i] = new LiveChart(config) //new string[] { "温度(℃)", "流量(L/m)" }
                        {
                            MinHeight = 120
                        };
                    }
                }
            }
            catch
            {
                charts = new LiveChart[0];
            }
        }
        private string _sn;
        public string sn
        {
            get { return _sn; }
            set
            {
                RaiseAndSetIfchanged(ref _parentName, value);
                RaisePropertyChanged("title");
                RaiseAndSetIfchanged(ref _sn, value);
                RaisePropertyChanged("sn");
            }
        }
@@ -74,7 +156,36 @@
            }
        }
        public string title => $"{parentName}{index + 1}";
        private bool cellIsDisabled;
        public bool CellIsDisabled
        {
            get { return cellIsDisabled; }
            set
            {
                RaiseAndSetIfchanged(ref cellIsDisabled, value);
            }
        }
        private string _title;
        public string title
        {
            get => _title;
            set
            {
                RaiseAndSetIfchanged(ref _title, value);
            }
        }
        private int _probeWarn;
        public int ProbeWarn
        {
            get => _probeWarn;
            set
            {
                RaiseAndSetIfchanged(ref _probeWarn, value);
            }
        }
        private string _status = CommonStatus.WAITING;
@@ -102,7 +213,9 @@
        private ConcurrentQueue<Info> queue = new ConcurrentQueue<Info>();
        private ObservableCollection<Info> _infos;
        private List<Info> allInfos = new List<Info>();
        private ObservableCollection<Info> _infos = new ObservableCollection<Info>();
        public ObservableCollection<Info> infos
        {
@@ -114,12 +227,51 @@
            }
        }
        private string countIniPath;
        /// <summary>
        /// 探针寿命
        /// </summary>
        private int probeCount;
        public int ProbeCount
        {
            get => probeCount;
            set
            {
                RaiseAndSetIfchanged(ref probeCount, value);
                probeAlarm = value >= ProbeWarn;
            }
        }
        private bool _probeAlarm;
        public bool probeAlarm
        {
            get => _probeAlarm;
            set
            {
                RaiseAndSetIfchanged(ref _probeAlarm, value);
            }
        }
        private void UpdateProbeCount(int count)
        {
            ProbeCount = count;
            string key = $"{title}";
            if (ParamSetting.ProbeByModel)
            {
                string model = table?.CbProduct?.SelectedItem?.ToString();
                key = $"{title}_{model}";
            }
            IniFileHelper.WriteIniData(key, "ProbeCount", ProbeCount.ToString(), countIniPath);
            if (window != null) window.UpdateProbeCount(ProbeCount, ProbeWarn);
        }
        private void UserControl_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (window == null)
            {
                window = new InfoWindow(title, infos);
                window = new InfoWindow(title, infos, charts, ProbeCount, ProbeWarn);
                window.Closed += Window_Closed;
                window.ClearProbeCountEvent += Window_ClearProbeCountEvent;
                window.Owner = Window.GetWindow(this);
                window.Show();
            }
@@ -129,59 +281,609 @@
            }
        }
        private void Window_ClearProbeCountEvent(object sender, EventArgs e)
        {
            UpdateProbeCount(0);
        }
        private void Window_Closed(object sender, EventArgs e)
        {
            this.window = null;
        }
        private string visualTestId;
        private Sqlite3Helper helper;
        public void SetStatus(string status)
        {
            var oldStatus = this.status;
            this.status = status;
            if (oldStatus != "testing" && status == "testing")
            {
                UpdateProbeCount(ProbeCount + 1);
                var now = DateTime.Now;
                string dateStr = now.ToString("yyyyMMdd");
                visualTestId = $"{title}_{now.ToString("yyyyMMddHHmmssfff")}";
                helper = CheckSqlHelper(dateStr);
            }
            if (oldStatus != "ok" && status == "ok")
            {
                SaveInfoToDB();
            }
            if (oldStatus != "ng" && status == "ng")
            {
                SaveInfoToDB();
            }
        }
        public void SetInfos(List<Info> infos)
        public void WriteCSV(Info info)
        {
            this.infos = new ObservableCollection<Info>(infos);
            if (window != null) window.UpdateSource(this.infos);
            try
            {
                if (ParamSetting.CustomerCode != "LIXUN")
                {
                    return;
                }
                string fileName = this.sn?.Replace("/", "#")?.Replace("\\", "#") + ".csv";
                string dir = Path.Combine(ParamSetting.DataLogFolder, "csv", this.title);
                string title = $"{this.lang("Test.Name")},{this.lang("Test.Value")},{this.lang("Test.LimitDown")},{this.lang("Test.LimitUp")},{this.lang("Test.Unit")},{this.lang("Test.Result")},{this.lang("Test.TestTime")}";
                string line = $"{info.step},{info.value},{info.limitDown},{info.limitUp},{info.unit},{info.result},{info.updateTime}";
                CSVPrinter.Print(dir, fileName, title, line);
                // ReverseCSV(Path.Combine(dir, fileName));
            }
            catch (Exception ex)
            {
            }
        }
        public void SendToChart(Info info)
        {
            try
            {
                foreach (var chart in charts)
                {
                    if (chart?.CanHandle(info.step) == true)
                    {
                        chart.AddData(info.step, DateTime.Parse(info.updateTime), double.Parse(info.value));
                    }
                }
                //if (electricChart.CanHandle(info.step))
                //{
                //    electricChart.AddData(info.step, DateTime.Parse(info.updateTime), double.Parse(info.value));
                //}
                //if (vChart.CanHandle(info.step))
                //{
                //    vChart.AddData(info.step, DateTime.Parse(info.updateTime), double.Parse(info.value));
                //}
                //if (waterChart?.CanHandle(info.step) == true)
                //{
                //    waterChart?.AddData(info.step, DateTime.Parse(info.updateTime), double.Parse(info.value));
                //}
            }
            catch (Exception ex)
            {
            }
        }
        public void SetInfos(Info info)
        {
            if (queue.Count >= maxSize)
            string sql = string.Empty;
            try
            {
                queue.TryDequeue(out var first);
                queue.Enqueue(info);
                this.infos = new ObservableCollection<Info>(queue);
                if (window != null) window.UpdateSource(this.infos);
            }
            else
            {
                queue.Enqueue(info);
                if (window != null)
                allInfos.Add(info);
                SendToChart(info);
                WriteCSV(info);
                if (queue.Count >= maxSize)
                {
                    window.Dispatcher.Invoke(() =>
                    {
                        this.infos.Add(info);
                    });
                    queue.TryDequeue(out var first);
                    queue.Enqueue(info);
                    this.infos = new ObservableCollection<Info>(queue);
                    if (window != null) window.UpdateSource(this.infos);
                }
                else
                {
                    Dispatcher.Invoke(() =>
                    queue.Enqueue(info);
                    if (window != null)
                    {
                        this.infos.Add(info);
                    });
                        window.Dispatcher.Invoke(() =>
                        {
                            this.infos.Add(info);
                        });
                    }
                    else
                    {
                        Dispatcher.Invoke(() =>
                        {
                            this.infos.Add(info);
                        });
                    }
                }
                return;
                Dispatcher.Invoke(() =>
                {
                    string dateStr = string.Empty;
                    try
                    {
                        dateStr = DateTime.Parse(info.updateTime).ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    catch
                    {
                        dateStr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    }
                    try
                    {
                        string model = table?.CbProduct?.SelectedItem?.ToString();
                        sql = $@"INSERT INTO serialData (sn,model,station,position,step,limitDown,limitUp,unit,value,status,finalStatus,time,resultId)
VALUES ('{sn}','{model}','','{this.title}','{info.step}','{info.limitDown}','{info.limitUp}','{info.unit}','{info.value}','{info.result}',
NULL,'{dateStr}','{visualTestId}');";
                        helper.Execute(sql);
                    }
                    catch (Exception ex)
                    {
                        ViewControl.Logger.Error($"Save DB Test Data Error. {sql}", ex);
                    }
                });
            }
            catch (Exception ex)
            {
                ViewControl.Logger.Error($"Add Test Data Error. {sql}", ex);
            }
        }
        public void ClearInfo()
        {
            allInfos.Clear();
            queue = new ConcurrentQueue<Info>();
            var list = new ObservableCollection<Info>(queue);
            this.infos = list;
            if (window != null) window.UpdateSource(this.infos);
        }
        //private Chart waterChart = null;
        //private Chart electricChart = new Chart(LangUtil.Get("Tr.CurrentChart"), false, 20)
        //{
        //    Height = 120
        //};
        //private Chart vChart = new Chart(LangUtil.Get("Tr.VoltChart"), false, 20)
        //{
        //    Height = 120
        //};
        private LiveChart[] charts = new LiveChart[0];
        //private LiveChart waterChart = null;
        //private LiveChart electricChart = new LiveChart("子板电流,电流(A);母板电流,电流(A)") //new string[] { "子板电流", "模板电流" }
        //{
        //    MinHeight = 120
        //};
        //private LiveChart vChart = new LiveChart("子板电压,电压(V);母板电压,电压(V)") //new string[] { "子板电压", "模板电压" }
        //{
        //    MinHeight = 120
        //};
        public void AddWaterData(double temp, double backTemp, double pressure)
        {
            //waterChart?.AddData(0, "水箱温度", temp);
            //waterChart?.AddData(0, "回水温度", backTemp);
            //waterChart?.AddData(1, "流量", pressure);
            //waterChart?.AddData("水箱温度", temp);
            //waterChart?.AddData("回水温度", backTemp);
            //waterChart?.AddData("流量", pressure);
        }
        public void AddElectricData(double data)
        {
            //electricChart.AddData("", data);
        }
        public void AddVData(double data)
        {
            //vChart.AddData("", data);
        }
        public void ClearChart()
        {
            foreach (var chart in charts)
            {
                chart?.Clear();
            }
        }
        //public void ClearWaterData()
        //{
        //    waterChart?.Clear();
        //}
        //public void ClearElectricData()
        //{
        //    electricChart.Clear();
        //}
        //public void ClearVData()
        //{
        //    vChart.Clear();
        //}
        public void SaveElectricDataToCSV(string filePath)
        {
            try
            {
                List<double> datas = charts[1]?.GetSingleData("");
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();  //文件不存在,创建文件
                }
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = this.lang("Tr.CurrentChart");
                    sw.WriteLine(title);
                    if (datas != null)
                    {
                        for (int i = 0; i < datas.Count; i++)
                        {
                            sw.WriteLine(datas[i].ToString());
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        public void SaveVDataToCSV(string filePath)
        {
            try
            {
                List<double> datas = charts[2]?.GetSingleData("");
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();  //文件不存在,创建文件
                }
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = this.lang("Tr.VoltChart");
                    sw.WriteLine(title);
                    if (datas != null)
                    {
                        for (int i = 0; i < datas.Count; i++)
                        {
                            sw.WriteLine(datas[i].ToString());
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
        private void NormalCSV(string filePath)
        {
            try
            {
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();  //文件不存在,创建文件
                }
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = $"{this.lang("Test.Name")},{this.lang("Test.Value")},{this.lang("Test.LimitDown")},{this.lang("Test.LimitUp")},{this.lang("Test.Unit")},{this.lang("Test.Result")},{this.lang("Test.TestTime")}";
                    sw.WriteLine(title);
                    foreach (var info in allInfos)
                    {
                        string row = $"{info.step},{info.value},{info.limitDown},{info.limitUp},{info.unit},{info.result},{info.updateTime}";
                        sw.WriteLine(row);
                    }
                }
            }
            catch (Exception ex)
            {
                ViewControl.Logger.Error($"Cell[{title}] SaveInfoToCSV Error.", ex);
            }
        }
        private void ReverseCSV(string filePath)
        {
            try
            {
                if (allInfos == null || allInfos.Count < 4) return;
                Dictionary<string, int> columnMap = new Dictionary<string, int>();
                int colPoint = 0;
                List<string> titleRow = new List<string>();
                List<string[]> datas = new List<string[]>();
                void AddTitle(string title)
                {
                    if (titleRow.IndexOf(title) < 0)
                    {
                        titleRow.Add(title);
                    }
                }
                // 先设置表头
                for (int row = 0; row < allInfos.Count; row++)
                {
                    var info = allInfos[row];
                    if (IgnoreTestItem.Contains(info.step.ToLower()))
                    {
                        continue;
                    }
                    string title = $"{info.step}{(string.IsNullOrEmpty(info.unit) ? "" : $"({info.unit})")}";
                    AddTitle("测试时间");
                    AddTitle(title);
                    if (!string.IsNullOrEmpty(info.limitDown))
                    {
                        string key2 = $"{info.step}下限";
                        AddTitle(key2);
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}上限";
                        AddTitle(key2);
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}测试结果";
                        AddTitle(key2);
                    }
                    //if (!string.IsNullOrEmpty(info.updateTime))
                    //{
                    //    string key2 = $"{info.step}测试时间";
                    //    AddTitle(key2);
                    //}
                }
                int rowPoint = -1;
                for (int row = 0; row < allInfos.Count; row++)
                {
                    var info = allInfos[row];
                    if (IgnoreTestItem.Contains(info.step.ToLower()))
                    {
                        continue;
                    }
                    string title = $"{info.step}{(string.IsNullOrEmpty(info.unit) ? "" : $"({info.unit})")}";
                    int col = titleRow.IndexOf(title);
                    if (col == 1)
                    {
                        rowPoint++;
                    }
                    if (datas.Count <= rowPoint)
                    {
                        datas.Add(new string[titleRow.Count]);
                    }
                    var arr = datas[rowPoint];
                    arr[col] = info.value;
                    if (!string.IsNullOrEmpty(info.limitDown))
                    {
                        string key2 = $"{info.step}下限";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.limitDown;
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}上限";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.limitUp;
                    }
                    if (!string.IsNullOrEmpty(info.limitUp))
                    {
                        string key2 = $"{info.step}测试结果";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.result;
                    }
                    if (!string.IsNullOrEmpty(info.updateTime))
                    {
                        string key2 = "测试时间";// $"{info.step}测试时间";
                        int col2 = titleRow.IndexOf(key2);
                        arr[col2] = info.updateTime;
                    }
                }
                FileInfo fi = new FileInfo(filePath);
                if (!fi.Directory.Exists)
                {
                    fi.Directory.Create();  //文件不存在,创建文件
                }
                using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write))
                using (StreamWriter sw = new StreamWriter(fs, System.Text.Encoding.UTF8))
                {
                    string title = string.Join(",", titleRow);
                    sw.WriteLine(title);
                    foreach (var info in datas)
                    {
                        string row = string.Join(",", info);
                        sw.WriteLine(row);
                    }
                }
            }
            catch (Exception ex)
            {
                ViewControl.Logger.Error($"Cell[{title}] SaveInfoToCSV Error.", ex);
            }
        }
        /// <summary>
        /// 保存测试数据到CSV
        /// </summary>
        /// <param name="filePath"></param>
        public void SaveInfoToCSV(string filePath)
        {
            if (ParamSetting.ReverseCSV)
            {
                ReverseCSV(filePath);
            }
            else
            {
                NormalCSV(filePath);
            }
        }
        private Sqlite3Helper CheckSqlHelper(string dateStr = null)
        {
            dateStr = string.IsNullOrEmpty(dateStr) ? DateTime.Now.ToString("yyyyMMdd") : dateStr;
            string dbPath = Path.Combine(ParamSetting.DataLogFolder, $"Data_{dateStr}.db");
            if (!File.Exists(dbPath))
            {
                Sqlite3Helper.CreateDatabase(dbPath);
            }
            var sqliteHelper = new Sqlite3Helper(dbPath);
            sqliteHelper.Execute(@"CREATE TABLE IF NOT EXISTS serialData (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    sn TEXT NOT NULL,
                    model TEXT,
                    station TEXT NOT NULL,
                    step TEXT NOT NULL,
                    position TEXT,
                    limitDown TEXT,
                    limitUp TEXT,
                    unit TEXT,
                    offset TEXT,
                    value TEXT,
                    status TEXT,
                    finalStatus TEXT,
                    consumeTime TEXT,
                    totalConsumeTime TEXT,
                    resultId TEXT,
                    time DATETIME NOT NULL);");
            sqliteHelper.Execute(@"CREATE TABLE IF NOT EXISTS testResult (
                    id INTEGER PRIMARY KEY AUTOINCREMENT,
                    sn TEXT NOT NULL,
                    model TEXT,
                    station TEXT NOT NULL,
                    position TEXT,
                    status TEXT,
                    result TEXT NOT NULL,
                    resultId TEXT,
                    time DATETIME NOT NULL);");
            if (!sqliteHelper.HasData("SELECT 1 FROM pragma_table_info('serialData') WHERE name = 'resultId';"))
            {
                sqliteHelper.Execute("ALTER TABLE serialData ADD resultId TEXT;");
            }
            if (!sqliteHelper.HasData("SELECT 1 FROM pragma_table_info('testResult') WHERE name = 'resultId';"))
            {
                sqliteHelper.Execute("ALTER TABLE testResult ADD resultId TEXT;");
            }
            return sqliteHelper;
        }
        /// <summary>
        /// 保存测试数据到Sqlite
        /// </summary>
        /// <param name="filePath"></param>
        public void SaveInfoToDB()
        {
            Dispatcher.BeginInvoke(new Action(() =>
            {
                try
                {
                    var timestr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    var sql = $"INSERT INTO testResult (sn,station,position,result,time,resultId) VALUES ('{sn}','','{title}','{this.status}','{timestr}','{visualTestId}');";
                    helper.Execute(sql);
                    helper.Dispose();
                    helper = null;
                    //                using (var helper = CheckSqlHelper())
                    //                {
                    //                    List<string> sqls = new List<string>();
                    //                    var timestr = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                    //                    foreach (var info in allInfos)
                    //                    {
                    //                        string sql = $@"INSERT INTO serialData (sn,station,step,limitDown,limitUp,unit,value,status,finalStatus,time)
                    //VALUES ('{sn}','','{info.step}','{info.limitDown}','{info.limitUp}','{info.unit}','{info.value}','{info.result}','{this.status}','{timestr}');";
                    //                        sqls.Add(sql);
                    //                    }
                    //                    sqls.Add($"INSERT INTO testResult (sn,station,position,result,time) VALUES ('{sn}','','{title}','{this.status}','{timestr}');");
                    //                    helper.ExecuteBatchSql(sqls);
                    //                }
                }
                catch (Exception ex)
                {
                    ViewControl.Logger.Error($"Cell[{title}] SaveToDB Error.", ex);
                }
            }));
        }
        private void MenuItem_Click(object sender, RoutedEventArgs e)
        {
            var item = sender as MenuItem;
            switch (item?.Name)
            {
                case "clearSNRItem":
                    table.TryClearCellSN(this.index);
                    break;
                case "exportCSVItem":
                    TryExportCSV();
                    break;
                default:
                    break;
            }
        }
        private void TryExportCSV()
        {
            System.Windows.Forms.SaveFileDialog sfd = new System.Windows.Forms.SaveFileDialog
            {
                Filter = "CSV (*.csv)|*.csv"
            };
            if (sfd.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.SaveInfoToCSV(sfd.FileName);
            }
        }
        public void ClearSN()
        {
            sn = string.Empty;
            LightGreen(false, out _);
            LightRed(false, out _);
        }
        public bool LightGreen(bool on, out string msg)
        {
            return S7Context.WriteData(RunTimeVariablePool.DEFAULT_PLC_NAME,
                $"Oven{table.index + 1}_Cell{index + 1}_Light_OK", on, out msg);
        }
        public bool LightRed(bool on, out string msg)
        {
            return S7Context.WriteData(RunTimeVariablePool.DEFAULT_PLC_NAME,
                $"Oven{table.index + 1}_Cell{index + 1}_Light_NG", on, out msg);
        }
    }
}