Files
newfolder/CMS2_SEGREGATIE/1. Feanor/HalCheck/HalControle.cs
Wesley Hofman 1232ca80c6 third commit
2025-09-18 14:36:50 +02:00

2284 lines
104 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using Maser.Feanor.Model;
using Maser.Feanor.Biz;
using Maser.Feanor.MIDSInterface;
using System.IO;
using MySqlConnector;
using System.Data.SqlClient;
using OxyPlot;
using OxyPlot.Series;
using OxyPlot.WindowsForms;
using OxyPlot.Legends;
using System.Text.RegularExpressions;
using System.Xml.Linq;
using OxyPlot.Annotations;
using System;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Net.Http;
using System.Threading.Tasks; // Nodig voor async/await
/*
* Transparant --> geen test in kast
* Groen --> test in kast, alles OK
* EUrofins-donker-oranje --> test in kast, iets niet OK
* Eurofins-licht-oranje --> Kast heeft general data error!
* Paars --> Kast heeft geen status!? (dit is niet te bedoeling)
*/
namespace HalCheck
{
public partial class HalControle : Form
{
private PlotModel plotModel;
private PlotView plotView;
private Dictionary<int, List<SensorReading>> sensorValues;
private Dictionary<object, int> sensorAttempts = new Dictionary<object, int>();
// save location for dgvProjects information xml file
string filePath = @"Z:\projects\2025\P250082\sub1\dgvProjects.xml";
bool isLoadingData = true; // Vlag om aan te geven of data wordt geladen
bool lbSensorChanged = false;
bool humidityLOW = false;
List<CabinetStatus> cabinets = new List<CabinetStatus>{ // links/recht , hoogte Color.Purple/Orange/Red
new CabinetStatus { Name = "1120", Position = new Point(430, 470), StatusColor = Color.Purple },
new CabinetStatus { Name = "3094", Position = new Point(520, 470), StatusColor = Color.Purple },
new CabinetStatus { Name = "1865", Position = new Point(620,470), StatusColor = Color.Purple },
new CabinetStatus { Name = "2750", Position = new Point(250, 470), StatusColor = Color.Purple },
new CabinetStatus { Name = "3097", Position = new Point(160, 470), StatusColor = Color.Purple },
new CabinetStatus { Name = "986", Position = new Point(340, 470), StatusColor = Color.Purple },
new CabinetStatus { Name = "1593", Position = new Point(260, 330), StatusColor = Color.Purple },
new CabinetStatus { Name = "1586", Position = new Point(260, 380), StatusColor = Color.Purple },
new CabinetStatus { Name = "2249", Position = new Point(340, 330), StatusColor = Color.Purple },
new CabinetStatus { Name = "2250", Position = new Point(340, 380), StatusColor = Color.Purple },
new CabinetStatus { Name = "2798", Position = new Point(415, 330), StatusColor = Color.Purple },
new CabinetStatus { Name = "2799", Position = new Point(415, 380), StatusColor = Color.Purple },
new CabinetStatus { Name = "2443", Position = new Point(490, 370), StatusColor = Color.Purple },
new CabinetStatus { Name = "77", Position = new Point(560, 370), StatusColor = Color.Purple },
new CabinetStatus { Name = "526", Position = new Point(630, 370), StatusColor = Color.Purple },
new CabinetStatus { Name = "18", Position = new Point(710, 260), StatusColor = Color.Purple },
new CabinetStatus { Name = "2318", Position = new Point(220, 630), StatusColor = Color.Purple },
new CabinetStatus { Name = "2319", Position = new Point(285, 630), StatusColor = Color.Purple },
new CabinetStatus { Name = "2599", Position = new Point(345, 630), StatusColor = Color.Purple },
new CabinetStatus { Name = "3096", Position = new Point(430, 630), StatusColor = Color.Purple },
new CabinetStatus { Name = "3095", Position = new Point(530, 630), StatusColor = Color.Purple },
new CabinetStatus { Name = "1056", Position = new Point(620, 630), StatusColor = Color.Purple },
new CabinetStatus { Name = "3098", Position = new Point(530, 700), StatusColor = Color.Purple },
new CabinetStatus { Name = "3140", Position = new Point(430, 700), StatusColor = Color.Purple },
new CabinetStatus { Name = "38", Position = new Point(830, 300), StatusColor = Color.Purple },
new CabinetStatus { Name = "1232", Position = new Point(830, 400), StatusColor = Color.Purple },
new CabinetStatus { Name = "1233", Position = new Point(830, 500), StatusColor = Color.Purple },
new CabinetStatus { Name = "1238", Position = new Point(1020, 50), StatusColor = Color.Purple },
new CabinetStatus { Name = "1728", Position = new Point(1020, 150), StatusColor = Color.Purple },
new CabinetStatus { Name = "2222", Position = new Point(1020, 260), StatusColor = Color.Purple },
new CabinetStatus { Name = "2546", Position = new Point(1020, 360), StatusColor = Color.Purple },//
new CabinetStatus { Name = "2547", Position = new Point(1020, 410), StatusColor = Color.Purple },//
new CabinetStatus { Name = "3050", Position = new Point(1020,490), StatusColor = Color.Purple },//
new CabinetStatus { Name = "3051", Position = new Point(1020,540), StatusColor = Color.Purple },//
new CabinetStatus { Name = "1880", Position = new Point(1120, 80), StatusColor = Color.Purple },
new CabinetStatus { Name = "987", Position = new Point(1120, 160), StatusColor = Color.Purple },
new CabinetStatus { Name = "847", Position = new Point(1120, 230), StatusColor = Color.Purple },
new CabinetStatus { Name = "947", Position = new Point(1120, 310), StatusColor = Color.Purple },
new CabinetStatus { Name = "680", Position = new Point(1120,380), StatusColor = Color.Purple },
new CabinetStatus { Name = "1281", Position = new Point(1120, 440), StatusColor = Color.Purple },
new CabinetStatus { Name = "1282", Position = new Point(1120,500), StatusColor = Color.Purple },
new CabinetStatus { Name = "1991", Position = new Point(1280, 80), StatusColor = Color.Purple },
new CabinetStatus { Name = "2183", Position = new Point(1280, 160), StatusColor = Color.Purple },
new CabinetStatus { Name = "2420", Position = new Point(1280, 250), StatusColor = Color.Purple },
new CabinetStatus { Name = "3111", Position = new Point(1280, 330), StatusColor = Color.Purple },
new CabinetStatus { Name = "3112", Position = new Point(1280, 380), StatusColor = Color.Purple },
new CabinetStatus { Name = "2745", Position = new Point(1380, 250), StatusColor = Color.Purple },
new CabinetStatus { Name = "2998", Position = new Point(1380, 160), StatusColor = Color.Purple },
new CabinetStatus { Name = "1999", Position = new Point(1185, 630), StatusColor = Color.Purple },
new CabinetStatus { Name = "2325", Position = new Point(1215, 710), StatusColor = Color.Purple },
};
List<RTHSensor> rthSensors = new List<RTHSensor>
{
new RTHSensor { Id = 35, Position = new Point(400, 250) }, // linksboven IP .191
new RTHSensor { Id = 8, Position = new Point(1200, 40) }, // compressor IP .166
new RTHSensor { Id = 31, Position = new Point(1400, 40) }, // rechtsboven IP .187
new RTHSensor { Id = 9, Position = new Point(940, 635) } // cms2 pc IP .167
};
public HalControle()
{
InitializeComponent();
System.Reflection.Assembly ass = System.Reflection.Assembly.GetEntryAssembly(); // report build version
string exe = System.IO.Path.GetFullPath(ass.Location);
DateTime dt = new System.IO.FileInfo(exe).LastWriteTimeUtc;
this.Text = String.Format("Feanor - Halcontrole" + " v{0:0000}{1:00}{2:00}", dt.Year, dt.Month, dt.Day);
obtainActiveProjects();
obtainActiveChambers();
LoadDataFromXML();
tabControl.SelectedTab = tpHal;
timerProjectDataCheck_Tick(null, null); // Direct de eerste tick uitvoeren
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new HalControle());
}
void obtainActiveChambers()
{
try
{
List<Chamber> chambers;
chambers = new Chambers().GetAllActive();
lbChambers.Items.Clear();
foreach (Chamber chamber in chambers)
{
lbChambers.Items.Add(chamber.MIDSandDescription); // MD
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Chambers", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
}
void fixedChambers() // chambers with fixed values, project is not started in CMS --> dummy projects which are invisible (3 LHU chamber + 2 bake ovens)
{
int rowIndex1 = dgvProjects.Rows.Add();
dgvProjects.Rows[rowIndex1].Cells[0].Value = "LHU chamber 2318";
dgvProjects.Rows[rowIndex1].Cells[3].Value = "02318";
dgvProjects.Rows[rowIndex1].Cells[6].Value = "30"; // temp
dgvProjects.Rows[rowIndex1].Cells[7].Value = "60"; // rh
dgvProjects.Rows[rowIndex1].Cells[8].Value = "Climate"; // chamber type
dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
//dgvProjects.Rows[rowIndex1].Visible = false;
rowIndex1 = dgvProjects.Rows.Add();
dgvProjects.Rows[rowIndex1].Cells[0].Value = "LHU chamber 2319";
dgvProjects.Rows[rowIndex1].Cells[3].Value = "02319";
dgvProjects.Rows[rowIndex1].Cells[6].Value = "30"; // temp
dgvProjects.Rows[rowIndex1].Cells[7].Value = "60"; // rh
dgvProjects.Rows[rowIndex1].Cells[8].Value = "Climate"; // chamber type
dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
//dgvProjects.Rows[rowIndex1].Visible = false;
rowIndex1 = dgvProjects.Rows.Add();
dgvProjects.Rows[rowIndex1].Cells[0].Value = "LHU chamber 2599";
dgvProjects.Rows[rowIndex1].Cells[3].Value = "02599";
dgvProjects.Rows[rowIndex1].Cells[6].Value = "30"; // temp
dgvProjects.Rows[rowIndex1].Cells[7].Value = "60"; // rh
dgvProjects.Rows[rowIndex1].Cells[8].Value = "Climate"; // chamber type
dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
//dgvProjects.Rows[rowIndex1].Visible = false;
rowIndex1 = dgvProjects.Rows.Add();
dgvProjects.Rows[rowIndex1].Cells[0].Value = "Oven 1281";
dgvProjects.Rows[rowIndex1].Cells[3].Value = "01281";
dgvProjects.Rows[rowIndex1].Cells[6].Value = "125"; // temp
dgvProjects.Rows[rowIndex1].Cells[7].Value = "N/A"; // rh
dgvProjects.Rows[rowIndex1].Cells[8].Value = "HTOL"; // chamber type
dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
//dgvProjects.Rows[rowIndex1].Visible = false;
rowIndex1 = dgvProjects.Rows.Add();
dgvProjects.Rows[rowIndex1].Cells[0].Value = "Oven 1282";
dgvProjects.Rows[rowIndex1].Cells[3].Value = "01282";
dgvProjects.Rows[rowIndex1].Cells[6].Value = "150"; // temp
dgvProjects.Rows[rowIndex1].Cells[7].Value = "N/A"; // rh
dgvProjects.Rows[rowIndex1].Cells[8].Value = "HTOL"; // chamber type
dgvProjects.Rows[rowIndex1].Cells[9].Value = true; // check
dgvProjects.Rows[rowIndex1].DefaultCellStyle.BackColor = Color.LightGray;
dgvProjects.Rows[rowIndex1].DefaultCellStyle.ForeColor = Color.Black;
//dgvProjects.Rows[rowIndex1].Visible = false;
}
void obtainActiveProjects()
{
List<Project> projects = new List<Project>();
try
{
isLoadingData = true;
dgvProjects.Rows.Clear();
List<Project> list;
list = new Projects().GetAllActive();
Chambers cBiz = new Chambers();
String c = "";
for (int i = 0; i < list.Count; i++)
{
Project p = list[i];
if (p.ProjectDescription == "Maintenance and calibration" )
{
dgvProjects.Rows.Add();
dgvProjects[0, i].Value = String.Format("I{0:00000} sub {1:00} step {2:00}", p.ProjectID, p.SubProject, p.Step);
}
else
{
dgvProjects.Rows.Add();
dgvProjects[0, i].Value = String.Format("P{0:00000} sub {1:00} step {2:00}", p.ProjectID, p.SubProject, p.Step);
}
dgvProjects[8, i].Value = "Unknown";
dgvProjects[2, i].Value = p.StepDescription;
dgvProjects[4, i].Value = p.Customer;
double min = p.Stop == null ? (Time.UTC - p.Start).TotalMinutes : ((DateTime)p.Stop - p.Start).TotalMinutes;
double hrs = Math.Floor(min / 60);
min -= hrs * 60;
dgvProjects[1, i].Value = String.Format("{0:0}h{1:0}", hrs, min);
// Chamber description
try { c = cBiz.GetByPK(p.Chamber).MIDSandDescription; } catch { c = "Chamber not found!"; }
dgvProjects[3, i].Value = c;
dgvProjects.Rows[i].DefaultCellStyle.ForeColor = System.Drawing.SystemColors.ControlText;
System.Drawing.Color rowColor = MIDSinterface.RowColor(cBiz.GetByPK(p.Chamber).MIDS); // obtain row color (from MIDS) for each chamber
dgvProjects.Rows[i].DefaultCellStyle.BackColor = rowColor;
try
{
var xml = XElement.Load(filePath);
if (xml.Elements("Project").FirstOrDefault(k => k.Element("Project")?.Value == dgvProjects[0, i].Value) == null)
{
var result = AnalyzeProject(p.StepDescription, rowColor);
string testtype = result[3].ToString();
dgvProjects[5, i].Value = result[2];
dgvProjects[6, i].Value = result[0];
dgvProjects[7, i].Value = result[1];
dgvProjects[8, i].Value = testtype;
dgvProjects[10, i].Value = result[4];
dgvProjects[11, i].Value = result[5];
// if (row.Cells[9].Value.ToString() == "True") // only check project data if check == True
}
}
catch { }
// only enable check checkbox for P-projects, not for I-projects
if (p.ProjectDescription == "Maintenance and calibration")
dgvProjects[9, i].Value = false;
else
dgvProjects[9, i].Value = true;
}
try
{
foreach (DataGridViewRow row in dgvProjects.Rows)
{
// Controleer of de eerste kolom (bijv. index 0) leeg is
if (row.Cells[0].Value == null || string.IsNullOrEmpty(row.Cells[0].Value.ToString()))
{
// Verwijder de rij
dgvProjects.Rows.Remove(row);
}
}
}
catch {}
}
catch (Exception ex)
{
MessageBox.Show("Could not retrieve projects from database!" + ex.Message, "Projects", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
dgvProjects.ClearSelection();
fixedChambers();
LoadDataFromXML();
isLoadingData = false;
}
}
private void LoadDataFromXML()
{
try
{
isLoadingData = true;
if (!System.IO.File.Exists(filePath))
{
MessageBox.Show($"XML-bestand '{filePath}' niet gevonden.", "Fout", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
var xml = XElement.Load(filePath);
foreach (var project in xml.Elements("Project"))
{
string name = project.Element("Project")?.Value; // Child <Project>
if (string.IsNullOrEmpty(name))
{
MessageBox.Show("Geen waarde gevonden in <Project> tag.", "Waarschuwing", MessageBoxButtons.OK, MessageBoxIcon.Warning);
continue;
}
foreach (DataGridViewRow row in dgvProjects.Rows)
{
if (row.Cells[0].Value?.ToString() == name) // Kolom 1 (Name)
{
row.Cells[5].Value = project.Element("Hours")?.Value ?? string.Empty;
row.Cells[6].Value = project.Element("Temperature")?.Value ?? string.Empty;
row.Cells[7].Value = project.Element("Humidity")?.Value ?? string.Empty;
row.Cells[8].Value = project.Element("Testtype")?.Value ?? string.Empty;
row.Cells[9].Value = project.Element("Check")?.Value ?? string.Empty;
row.Cells[10].Value = project.Element("TempHigh")?.Value ?? string.Empty;
row.Cells[11].Value = project.Element("TempLow")?.Value ?? string.Empty;
break;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Fout bij het laden van XML: {ex.Message}", "Fout", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
isLoadingData = false;
}
}
private void lbChambers_SelectedIndexChanged(object sender, EventArgs e)
{
updateLiveView();
}
private double ParseValidDouble(object value)
{
if (value == null) return 0.0;
string strValue = value.ToString().Trim();
if (string.IsNullOrEmpty(strValue) || strValue == "N/A") return 0.0;
if (double.TryParse(strValue, out double result))
return result;
return 0.0;
}
void updateLiveView()
{
if (lbChambers.SelectedItems.Count == 0)
return;
Cursor.Current = Cursors.WaitCursor;
Chamber chamber;
try
{
chamber = new Chambers().GetAll().ToList().Find(delegate (Chamber c) { return (c.MIDSandDescription == (string)lbChambers.SelectedItem); });
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Chamber", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
// Fill Sensors
if (lbSensorChanged == false)
lbSensors.Items.Clear();
List<Sensor> sensors;
try
{
sensors = new Sensors().GetByChamber(chamber.PK);
if (sensors.Count > 0)
{
lbSensors.SelectedIndexChanged -= lbSensors_SelectedIndexChanged;
int index = 0;
foreach (Sensor s in sensors)
{
if (lbSensorChanged == false)
{
lbSensors.Items.Add(s.ToString());
lbSensors.SetSelected(index, true); // Selecteer dit item direct
}
index++;
}
lbSensors.SelectedIndexChanged += lbSensors_SelectedIndexChanged;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return;
}
lbSensorChanged = false;
int lastHours = 0;
if (int.TryParse(tbLastHours.Text, out lastHours))
{ }
else
{
MessageBox.Show("Voer een geldig aantal uren in.");
}
var sensorValues = new Dictionary<int, List<SensorReading>>(); // Dictionary per sensor
List<string> sensorWithDatalist = new List<string>();
List<string> selectedSensorList = new List<string>();
int sensorid = 0;
foreach (var sensor in sensors)
{
if(!sensor.ToString().Contains("Air"))
if (!lbSensors.SelectedItems.Contains(sensor.ToString()))
{
sensorid++;
continue;
}
if (lbSensors.SelectedItems.Contains(sensor.ToString()))
selectedSensorList.Add(sensor.PK.ToString());
SqlConnection connection = new SqlConnection("Data Source=tcp:10.126.21.47\\FEANOR,1434; Initial Catalog=FEANOR; User ID=sa; Password=resam@123resam; timeout=15; Persist Security Info=True; TrustServerCertificate=True");
try
{
using (connection)
{
string query = string.Empty;
if (chamber.Humidity)
{
query = "SELECT Value, TimeStamp FROM Results WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
}
else
{
query = "SELECT Value, TimeStamp FROM ResultsOudeHal WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
}
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@SensorPK", sensor.PK);
command.Parameters.AddWithValue("@lasthours", lastHours);
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
var readings = new List<SensorReading>(); // Lijst voor de readings van de huidige sensor
while (reader.Read())
{
float resultValue = reader.IsDBNull(0) ? 0.0f : reader.GetFloat(0); // Haal de waarde op, standaard 0 als null
DateTime timestamp = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1); // Haal de timestamp op
readings.Add(new SensorReading
{
Value = resultValue,
Timestamp = timestamp
});
}
if (readings.Count > 0)
{
sensorWithDatalist.Add(lbSensors.Items[sensorid].ToString());
sensorValues[sensor.PK] = readings;
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error for Sensor {sensor.PK}: {ex.Message}");
}
finally { sensorid++; }
}
int viewHours = lastHours;
if (panelPlot.Controls.Count > 0)
{
panelPlot.Controls.Clear();
}
plotModel = new PlotModel
{
Title = "CMS 2 Sensor Data",
};
plotModel.Legends.Add(new Legend
{
LegendPosition = LegendPosition.RightTop, // Plaats de legenda rechtsboven
LegendOrientation = LegendOrientation.Vertical, // Oriëntatie van de legenda
LegendPlacement = LegendPlacement.Outside, // Plaats de legenda buiten de plot
LegendBackground = OxyColors.White, // Achtergrondkleur van de legenda
LegendBorder = OxyColors.Black // Randkleur van de legenda
});
var plotView = new PlotView
{
Model = plotModel,
Dock = DockStyle.Fill
};
panelPlot.Controls.Add(plotView);
plotModel.Series.Clear();
plotModel.Axes.Add(new OxyPlot.Axes.LinearAxis // x-as
{
Position = OxyPlot.Axes.AxisPosition.Bottom,
Title = "Hours since last point [h]",
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.Dot,
StartPosition = 1, // Begin van de as rechts
EndPosition = 0, // Eind van de as links
Minimum = 0, // Begin bij 0 uur (laatste punt)
Maximum = viewHours, // Toon slechts 24 uur in de view
IsPanEnabled = true, // Schakel scrollen/pannen in
IsZoomEnabled = true, // Schakel in- en uitzoomen in
AbsoluteMinimum = 0, // Minimum waarde voor pannen
AbsoluteMaximum = lastHours // Maximum waarde voor pannen
});
var yAxis1 = new OxyPlot.Axes.LinearAxis // y-as 1 voor temp en RH
{
Position = OxyPlot.Axes.AxisPosition.Left,
Title = "Temperature [°C] / RH [%]",
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.Dot,
Minimum = 0,
Maximum = 110,
Key = "TempRH"
};
var yAxis2 = new OxyPlot.Axes.LinearAxis// y-as 1 voor spanning en stroom
{
Position = OxyPlot.Axes.AxisPosition.Right,
Title = "Voltage [V]",
MajorGridlineStyle = LineStyle.Solid,
MinorGridlineStyle = LineStyle.Dot,
Minimum = 0,
Maximum = 30,
Key = "Volt"
};
int sensorCount = 0;
DateTime? lastTimestamp = null;
double maxVoltage = 0.0;
double minVoltage = 0.0;
double maxTempRH = 0.0;
double minTempRH = 0.0;
var sensorValuesSync = new Dictionary<int, List<SensorReading>>(); // Dictionary per sensor
try
{
// Selecteer de eerste sensor als referentie
var referenceSensor = sensorValues.First();
int referenceKey = referenceSensor.Key;
var referenceTimestamps = referenceSensor.Value.Select(r => r.Timestamp).ToList();
// Ga per tijdstip in de referentiesensor door alle andere sensoren heen
foreach (var timestamp in referenceTimestamps)
{
foreach (var sensor in sensorValues)
{
var sensorKey = sensor.Key;
// Maak een nieuwe lijst voor sensorwaarden als deze nog niet bestaat
if (!sensorValuesSync.ContainsKey(sensorKey))
{
sensorValuesSync[sensorKey] = new List<SensorReading>();
}
if (sensorKey == referenceKey)
{
var referenceValue = referenceSensor.Value.First(r => r.Timestamp == timestamp).Value;
sensorValuesSync[sensorKey].Add(new SensorReading
{
Value = referenceValue,
Timestamp = timestamp
});
}
else
{
// Zoek de dichtstbijzijnde waarde binnen 20 seconden
var closestReading = sensor.Value
.Where(r => Math.Abs((r.Timestamp - timestamp).TotalSeconds) <= 20)
.OrderBy(r => Math.Abs((r.Timestamp - timestamp).TotalSeconds))
.FirstOrDefault();
double value = closestReading != null ? closestReading.Value : 0;
// Voeg de gevonden waarde toe aan de sync dictionary
sensorValuesSync[sensorKey].Add(new SensorReading
{
Value = (float)value,
Timestamp = timestamp
});
}
}
}
}
catch{}
sensorValues = sensorValuesSync;
foreach (var sensor in sensorValues.Keys.ToList())
{
var readings = sensorValues[sensor];
if (readings.Count > 1)
readings.RemoveAt(readings.Count - 1);
else
readings.Clear();
}
foreach (var sensor in sensorValues)
{
if(!selectedSensorList.Contains(sensor.Key.ToString()))
{
sensorCount++;
continue;
}
// calibration correction!
var sensorPK = sensor.Key; // Haal de sensor.PK op
double a = 1.0;
double b = 0.0;
try
{
Calibration t = new Calibrations().GetLastCreatedBySensorPK(sensorPK);
if (t != null) // calibration found
{
a = t.Coefficients[1]; // gain
b = t.Coefficients[0]; // offset
}
else // no calibration found
{
a = 1.0; // gain
b = 0.0; // offset
}
}
catch
{
string msg = "Could not retrieve calibrations for sensor ";
}
var series = new LineSeries
{
Title = $"Sensor {sensorCount}",
StrokeThickness = 2,
MarkerType = MarkerType.Circle, // Punt zichtbaar maken
MarkerSize = 2, // Grootte van de punten
};
foreach (var reading in sensor.Value)
{
if (lastTimestamp == null || reading.Timestamp > lastTimestamp)
{
lastTimestamp = reading.Timestamp;
}
}
double hoursSinceNow = 0;
if (lastTimestamp.HasValue)
{
TimeSpan timeSinceLast = DateTime.UtcNow - lastTimestamp.Value;
hoursSinceNow = timeSinceLast.TotalHours;
if (timeSinceLast > TimeSpan.FromMinutes(10))
Console.WriteLine("Laatste meting is meer dan 10 minuten geleden.");
}
if (sensorCount ==0)
{
int cycleCount = 0;
bool upCrossed = false;
bool downCrossed = false;
double uppercountvalue = Double.Parse(tbHighTC.Text);
double lowercountvalue = Double.Parse(tbLowTC.Text);
foreach (var reading in sensor.Value)
{
double hoursSinceLast = (lastTimestamp.Value - reading.Timestamp).TotalHours + hoursSinceNow;
double temperature = (double)(reading.Value * a + b); // Correctie toegepast
series.Points.Add(new DataPoint(hoursSinceLast, temperature));
if (temperature >= uppercountvalue)
upCrossed = true; // Opgaande overgang
if (temperature <= lowercountvalue && upCrossed)
downCrossed = true; // Neergaande overgang
if (upCrossed && downCrossed)
{
cycleCount++; // Volledige cyclus geteld
upCrossed = false;
downCrossed = false;
}
}
lblCycles.Text = string.Format(cycleCount.ToString() + " cycles in last " + tbLastHours.Text + " hours");
}
else
{
foreach (var reading in sensor.Value)
{
double hoursSinceLast = (lastTimestamp.Value - reading.Timestamp).TotalHours + hoursSinceNow;
series.Points.Add(new DataPoint(hoursSinceLast, (double)(reading.Value * a + b))); // CORRECTION!!!!!!!!!!!!!!!!!!!!
}
}
series.Title = sensorWithDatalist[sensorCount];
if (sensorWithDatalist[sensorCount].ToLower().Contains("rh"))
series.Color = OxyColors.DarkBlue;
else if (sensorWithDatalist[sensorCount].ToLower().Contains("air"))
series.Color = OxyColors.Red;
else if (sensorWithDatalist[sensorCount].ToLower().Contains("water"))
series.Color = OxyColors.LightBlue;
if (sensorWithDatalist[sensorCount].ToLower().Contains("voltage")) // koppel sensordata aan juiste as
{
maxVoltage = Math.Max(maxVoltage, series.Points.Max(point => point.Y));
minVoltage = Math.Min(minVoltage, series.Points.Min(point => point.Y));
series.YAxisKey = "Volt";
}
else
{
maxTempRH = Math.Max(maxTempRH, series.Points.Max(point => point.Y));
minTempRH = Math.Min(minTempRH, series.Points.Min(point => point.Y));
series.YAxisKey = "TempRH";
}
plotModel.Series.Add(series);
sensorCount++;
}
//Console.WriteLine("max temp/RH " + maxTempRH.ToString() + " min temp/RH " + minTempRH.ToString());
yAxis1.Maximum = (int)maxTempRH + 10;
yAxis1.Minimum = (int)minTempRH - 10;
yAxis1.AbsoluteMaximum = yAxis1.Maximum;
yAxis1.AbsoluteMinimum = yAxis1.Minimum;
// Console.WriteLine("max voltage " + maxVoltage.ToString() + " min voltage " + minVoltage.ToString());
if (cbVoltageScale.Checked == false)
{
yAxis2.Maximum = (int)maxVoltage + 1;
yAxis2.Minimum = (int)minVoltage - 1;
yAxis2.AbsoluteMaximum = yAxis2.Maximum;
yAxis2.AbsoluteMinimum = yAxis2.Minimum;
}
else
{
yAxis2.Maximum = yAxis1.Maximum;
yAxis2.Minimum = yAxis1.Minimum;
yAxis2.AbsoluteMaximum = yAxis1.AbsoluteMaximum;
yAxis2.AbsoluteMinimum = yAxis1.AbsoluteMinimum;
}
plotModel.Axes.Add(yAxis1);
plotModel.Axes.Add(yAxis2);
if (cbShowEnvelope.Checked == true)
{
if (dgvProjects.Rows.Count > 0)
{
foreach (DataGridViewRow row in dgvProjects.Rows)
{
if (!row.IsNewRow)
{
var chamberValue = row.Cells["dgvProjects_Chamber"].Value;
if (chamberValue != null)
{
if (chamberValue.ToString() == (string)lbChambers.SelectedItem) // chamber has an active project running --> show envelope!
{
Console.WriteLine("project found for " + chamber.MIDS.ToString());
string testtype = row.Cells[8].Value.ToString();
double tempdiff = ParseValidDouble(tbTempDev.Text);
double rhdiff = ParseValidDouble(tbHumidityDev.Text);
double testtemp = ParseValidDouble(row.Cells[6].Value);
double testrh = ParseValidDouble(row.Cells[7].Value);
double settempH = ParseValidDouble(row.Cells["CTempHigh"].Value);
double settempL = ParseValidDouble(row.Cells["CTempLow"].Value);
// steady temperature + humidity
if (testtype.Contains("HAST") || testtype.Contains("THB") || testtype.Contains("THB_cycledbias") || testtype.Contains("Climate"))
{
var tempBand = new RectangleAnnotation
{
MinimumY = testtemp - tempdiff,
MaximumY = testtemp + tempdiff,
MinimumX = double.NegativeInfinity, // Volledige breedte
MaximumX = double.PositiveInfinity, // Volledige breedte
Fill = OxyColor.FromAColor(20, OxyColors.Red) // Doorzichtige rode band
};
plotModel.Annotations.Add(tempBand);
var rhBand = new RectangleAnnotation
{
MinimumY = testrh - rhdiff,
MaximumY = testrh + rhdiff,
MinimumX = double.NegativeInfinity, // Volledige breedte
MaximumX = double.PositiveInfinity, // Volledige breedte
Fill = OxyColor.FromAColor(20, OxyColors.Blue) // Doorzichtige blauwe band
};
plotModel.Annotations.Add(rhBand);
}
// steady temperature
else if (testtype.Contains("HTOL") || testtype.Contains("Bake"))
{
var tempBand = new RectangleAnnotation
{
MinimumY = testtemp - tempdiff,
MaximumY = testtemp + tempdiff,
MinimumX = double.NegativeInfinity, // Volledige breedte
MaximumX = double.PositiveInfinity, // Volledige breedte
Fill = OxyColor.FromAColor(20, OxyColors.Red) // Doorzichtige blauwe band
};
plotModel.Annotations.Add(tempBand);
}
// temperature cycling
else if (testtype.Contains("TC") || testtype.Contains("PTC"))
{
try
{
var tempBandH = new RectangleAnnotation
{
MinimumY = settempH - tempdiff,
MaximumY = settempH + tempdiff,
MinimumX = double.NegativeInfinity, // Volledige breedte
MaximumX = double.PositiveInfinity, // Volledige breedte
Fill = OxyColor.FromAColor(20, OxyColors.Red) // Doorzichtige band
};
plotModel.Annotations.Add(tempBandH);
var tempBandL = new RectangleAnnotation
{
MinimumY = settempL - tempdiff,
MaximumY = settempL + tempdiff,
MinimumX = double.NegativeInfinity, // Volledige breedte
MaximumX = double.PositiveInfinity, // Volledige breedte
Fill = OxyColor.FromAColor(20, OxyColors.Red) // Doorzichtige band
};
plotModel.Annotations.Add(tempBandL);
}
catch {}
}
}
}
}
}
}
}
Cursor.Current = Cursors.Default;
}
private void HalControle_Load(object sender, EventArgs e)
{
}
private void fileSystemWatcher1_Changed(object sender, FileSystemEventArgs e)
{
}
void GeneralDataCheck()
{
Console.WriteLine("general data check started...");
sensorAttempts.Clear();
double Tmin = Double.Parse(tbTmin.Text);
double Tmax = Double.Parse(tbTmax.Text);
double RHmin = Double.Parse(tbRHmin.Text);
double RHmax = Double.Parse(tbRHmax.Text);
double Vmin = Double.Parse(tbVmin.Text);
double Vmax = Double.Parse(tbVmax.Text);
try
{
foreach (var Item in lbChambers.Items)
{
Chamber chamber = new Chambers().GetAll().ToList().Find(c => c.MIDSandDescription == (string)Item);
List<string> sensorname = new List<string>();
if (chamber != null)
{
Console.WriteLine("Checking chamber " + chamber.MIDS);
List<Sensor> sensors;
try
{
sensors = new Sensors().GetByChamber(chamber.PK);
if (sensors.Count > 0)
{
foreach (Sensor s in sensors)
{
sensorname.Add(s.Description);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, String.Format("Sensors in chamber {0:00000}", chamber.MIDS), MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var sensorValues = new Dictionary<int, List<SensorReading>>(); // Dictionary per sensor
List<string> sensorWithDatalist = new List<string>();
int sensorid = 0;
foreach (var sensor in sensors)
{
SqlConnection connection = new SqlConnection("Data Source=tcp:10.126.21.47\\FEANOR,1434; Initial Catalog=FEANOR; User ID=sa; Password=resam@123resam; timeout=15; Persist Security Info=True; TrustServerCertificate=True");
try
{
using (connection)
{
string query = string.Empty;
if (chamber.Humidity)
{
query = "SELECT Value, TimeStamp FROM Results WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
}
else
{
query = "SELECT Value, TimeStamp FROM ResultsOudeHal WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
}
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@SensorPK", sensor.PK);
command.Parameters.AddWithValue("@lasthours", Int32.Parse(tbCheckLastHour.Text));
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
var readings = new List<SensorReading>();
while (reader.Read())
{
float resultValue = reader.IsDBNull(0) ? 0.0f : reader.GetFloat(0); // Haal de waarde op, standaard 0 als null
DateTime timestamp = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1); // Haal de timestamp op
readings.Add(new SensorReading
{
Value = resultValue,
Timestamp = timestamp
});
}
if (readings.Count > 0)
{
//sensorWithDatalist.Add(lbSensors.Items[sensorid].ToString());
sensorValues[sensor.PK] = readings;
}
// calibration correction!
var sensorPK = sensor.PK; // Haal de sensor.PK op
double a = 1.0;
double b = 0.0;
try
{
Calibration t = new Calibrations().GetLastCreatedBySensorPK(sensorPK);
if (t != null) // calibration found
{
a = t.Coefficients[1]; // gain
b = t.Coefficients[0]; // offset
}
else // no calibration found
{
a = 1.0; // gain
b = 0.0; // offset
}
}
catch
{
string msg = "Could not retrieve calibrations for sensor ";
}
foreach (var reading in readings)
{
double value = (double)(reading.Value * a + b);
//Console.WriteLine("SENSORPK " + sensor.PK +" type " + sensorname[sensorid] + $" Value: value}, Timestamp: {reading.Timestamp}");
if (sensorname[sensorid].ToLower().Contains("temperature"))
{
if (value < Tmin || value > Tmax)
{
if (!RowExists(dgvGeneralErrors, sensorPK))
dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
}
}
else if (sensorname[sensorid].ToLower().Contains("rh"))
{
if (value < RHmin || value > RHmax)
{
if (!RowExists(dgvGeneralErrors, sensorPK))
dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
}
}
else if (sensorname[sensorid].ToLower().Contains("voltage"))
{
if (value < Vmin || value > Vmax)
{
if (!RowExists(dgvGeneralErrors, sensorPK))
dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
}
}
}
try
{
//if (sensorValues.Count > 0 && sensorname[sensorid].ToLower().Contains("air temperature"))
if (sensorname[sensorid].ToLower().Contains("air temperature"))
{
DateTime meestRecenteUtc = sensorValues
.SelectMany(kvp => kvp.Value)
.Max(r => r.Timestamp);
TimeZoneInfo nlTz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
DateTime meestRecenteLocal = TimeZoneInfo.ConvertTimeFromUtc(meestRecenteUtc, nlTz);
TimeSpan verschil = DateTime.Now - meestRecenteLocal;
bool ouderDan20Min = verschil.TotalMinutes > 20;
if (ouderDan20Min == true)
{
Console.WriteLine("Meer dan 20 minuten geen data!");
if (!RowExists(dgvGeneralErrors, sensorPK))
dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, 0, 0, sensorname[sensorid], 1);
}
}
}
catch
{
Console.WriteLine("Geen data gevonden voor deze kamer");
if (!RowExists(dgvGeneralErrors, sensorPK))
dgvGeneralErrors.Rows.Add(chamber.MIDS, sensorPK, 0, 0, sensorname[sensorid], 1);
}
sensorid++;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error for Sensor {sensor.PK}: {ex.Message}");
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Chamber", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
// Lees uitgesloten kamernummers vanuit bestand
var excludedChambers = File.ReadAllLines(@"Z:\projects\2020\P201339\sub1\4. Software\1. Feanor\excluded_chambers.txt")
.Select(line => line.Trim())
.Where(line => !string.IsNullOrEmpty(line))
.ToHashSet(); // Snelle lookup
foreach (var cabinet in cabinets)
{
bool generalerror = false;
foreach (DataGridViewRow row in dgvGeneralErrors.Rows)
{
string chambernumber = row.Cells[0].Value?.ToString();
if (!string.IsNullOrEmpty(chambernumber) &&
Int32.TryParse(cabinet.Name, out int cabinetNr) &&
Int32.TryParse(chambernumber, out int chamberNr))
{
// Check of er een error is én het kamernummer NIET is uitgesloten
if (cabinetNr == chamberNr && !excludedChambers.Contains(chambernumber))
{
generalerror = true;
break;
}
}
}
if (generalerror)
cabinet.StatusColor = Color.FromArgb(247, 180, 116);
}
updateOverview();
}
catch (Exception ex)
{
Console.WriteLine("Fout bij het verwerken van fouten: " + ex.Message);
}
Console.WriteLine("general data check finished");
}
int HaalUrenUitTijdsduur(string tijdsduur)
{
if (tijdsduur == null)
return 0;
int indexH = tijdsduur.IndexOf('h');
if (indexH > 0)
{
string urenString = tijdsduur.Substring(0, indexH);
if (int.TryParse(urenString, out int uren))
{
return uren;
}
}
// Als iets misgaat, bijvoorbeeld geen 'h' of geen geldig getal
throw new FormatException("Ongeldige tijdsduurstring. Verwacht formaat '22h50'.");
}
void projectDataCheck()
{
Console.WriteLine("project data check started...");
sensorAttempts.Clear();
try
{
foreach (DataGridViewRow row in dgvProjects.Rows)
{
string chambernumber = row.Cells[3].Value.ToString();
if (row.Cells[9].Value.ToString() == "True") // only check project data if check == True
{
int uren = HaalUrenUitTijdsduur(row.Cells["dgvProjects_Duration"].Value?.ToString()); // haal duration op in volle uren (getal voor de "h")
Chamber chamber = new Chambers().GetAll().ToList().Find(c => c.MIDSandDescription == chambernumber);
List<string> sensorname = new List<string>();
if (chamber != null)
{
Console.WriteLine("Checking chamber " + chamber.MIDS);
List<Sensor> sensors;
try
{
sensors = new Sensors().GetByChamber(chamber.PK);
if (sensors.Count > 0)
{
foreach (Sensor s in sensors)
{
sensorname.Add(s.Description);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, String.Format("Sensors in chamber {0:00000}", chamber.MIDS), MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
var sensorValues = new Dictionary<int, List<SensorReading>>(); // Dictionary per sensor
List<string> sensorWithDatalist = new List<string>();
int sensorid = 0;
SensorReading mostRecentReading = null;
foreach (var sensor in sensors)
{
SqlConnection connection = new SqlConnection("Data Source=tcp:10.126.21.47\\FEANOR,1434; Initial Catalog=FEANOR; User ID=sa; Password=resam@123resam; timeout=15; Persist Security Info=True; TrustServerCertificate=True");
try
{
using (connection)
{
string query = string.Empty;
if (chamber.Humidity)
{
query = "SELECT Value, TimeStamp FROM Results WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
}
else
{
query = "SELECT Value, TimeStamp FROM ResultsOudeHal WHERE SensorPK = @SensorPK AND TimeStamp >= DATEADD(HOUR, -@lasthours, GETUTCDATE()) ORDER BY TimeStamp ASC";
}
SqlCommand command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("@SensorPK", sensor.PK);
command.Parameters.AddWithValue("@lasthours", Int32.Parse(tbCheckLastProjectData.Text));
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
var readings = new List<SensorReading>();
while (reader.Read())
{
float resultValue = reader.IsDBNull(0) ? 0.0f : reader.GetFloat(0); // Haal de waarde op, standaard 0 als null
DateTime timestamp = reader.IsDBNull(1) ? DateTime.MinValue : reader.GetDateTime(1); // Haal de timestamp op
readings.Add(new SensorReading
{
Value = resultValue,
Timestamp = timestamp
});
}
if (sensorname[sensorid].ToLower().Contains("air temperature"))
mostRecentReading = readings.OrderByDescending(r => r.Timestamp).FirstOrDefault();
if (readings.Count > 0)
{
//sensorWithDatalist.Add(lbSensors.Items[sensorid].ToString());
sensorValues[sensor.PK] = readings;
}
// calibration correction!
double a = 1.0;
double b = 0.0;
try
{
Calibration t = new Calibrations().GetLastCreatedBySensorPK(sensor.PK);
if (t != null) // calibration found
{
a = t.Coefficients[1]; // gain
b = t.Coefficients[0]; // offset
}
else // no calibration found
{
a = 1.0; // gain
b = 0.0; // offset
}
}
catch
{
string msg = "Could not retrieve calibrations for sensor ";
}
string testtype = row.Cells[8].Value.ToString();
double tempdiff = ParseValidDouble(tbTempDev.Text);
double rhdiff = ParseValidDouble(tbHumidityDev.Text);
double testtemp = ParseValidDouble(row.Cells[6].Value);
double testrh = ParseValidDouble(row.Cells[7].Value);
// only detect project data after the project runs for 1 hour
int onlyhours = 1;
if(row.Cells[1].Value!= null)
{
Match match = Regex.Match(row.Cells[1].Value.ToString(), @"^(\d+)h");
onlyhours = int.Parse(match.Groups[1].Value);
}
if(onlyhours>=1)
{
// steady temperature + humidity
if (testtype.Contains("HAST") || testtype.Contains("Climate") || testtype.Contains("THB") || testtype.Contains("THB_cycledbias"))
{
foreach (var reading in readings)
{
double value = reading.Value * a + b; // gecorrigeerde waarde!
//Console.WriteLine("SENSORPK " + sensor.PK + " type " + sensorname[sensorid] + $" Value: {value}, Timestamp: {reading.Timestamp}");
if (sensorname[sensorid].ToLower().Contains("air temperature")) // don't check water temperature (not neccessary, only air temp + rh)
{
if (value > (testtemp + tempdiff) || value < (testtemp - tempdiff))
{
//Console.WriteLine("temperature too high/low --> SENSORPK " + sensor.PK + " type " + sensorname[sensorid] + " Value: " + value + " Refvalue: " + testtemp + " +/- " + tempdiff + " Timestamp: " + reading.Timestamp);
if (!RowExists(dgvProjectErrors, sensor.PK))
dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
}
}
else if (sensorname[sensorid].ToLower().Contains("rh"))
{
if (row.Cells[7].Value.ToString() == "N/A")
{
//MessageBox.Show("Invalid RH for " + row.Cells[0].Value.ToString());
break;
}
if (value > (testrh + rhdiff) || value < (testrh - rhdiff))
{
//Console.WriteLine("rh too high/low --> SENSORPK " + sensor.PK + " type " + sensorname[sensorid] + " Value: " + value + " Refvalue: " + testrh + " +/- " + rhdiff + " Timestamp: " + reading.Timestamp);
if (!RowExists(dgvProjectErrors, sensor.PK))
dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
}
}
}
}
// steady temperature
else if (testtype.Contains("HTOL") || testtype.Contains("Bake"))
{
foreach (var reading in readings)
{
double value = reading.Value * a + b; // gecorrigeerde waarde!
//Console.WriteLine("SENSORPK " + sensor.PK + " type " + sensorname[sensorid] + $" Value: {value}, Timestamp: {reading.Timestamp}");
if (sensorname[sensorid].ToLower().Contains("air temperature")) //
{
if (value > (testtemp + tempdiff) || value < (testtemp - tempdiff))
{
//Console.WriteLine("temperature too high/low --> SENSORPK " + sensor.PK + " type " + sensorname[sensorid] + " Value: " + value + " Refvalue: " + testtemp + " +/- " + tempdiff + " Timestamp: " + reading.Timestamp);
if (!RowExists(dgvProjectErrors, sensor.PK))
dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
}
}
}
}
// temperature cycling
// voor TC en PTC wordt er naar de air temp gekeken of de min en max waarde gehaald worden (1 min en 1 max = 1 cycle), wordt er 1 of meer cycles gevonden, goedgekeurd!
else if ((testtype.Contains("TC") || testtype.Contains("PTC")) && sensorname[sensorid].Contains("Air"))
{
// Alle Air-sensormetingen verzamelen
List<double> airTemperatures = new List<double>();
foreach (var reading in readings)
{
double value = reading.Value * a + b; // gecorrigeerde waarde
airTemperatures.Add(value);
}
// Analyseer op cycles: detecteer of beide extremen zijn bereikt
double minThreshold = Double.Parse(row.Cells["CTempLow"].Value.ToString());
double maxThreshold = Double.Parse(row.Cells["CTempHigh"].Value.ToString());
bool minReached = false;
bool maxReached = false;
int cycleCount = 0;
foreach (var value in airTemperatures)
{
if (value <= minThreshold)
minReached = true;
if (value >= maxThreshold)
maxReached = true;
if (minReached && maxReached)
{
cycleCount++;
//Console.WriteLine($"Cycle {cycleCount}: Beide extremen bereikt.");
minReached = false;
maxReached = false;
}
}
if (cycleCount == 0)
{
//Console.WriteLine("Geen volledige cycles met beide extremen gevonden.");
if (!RowExists(dgvProjectErrors, sensor.PK))
dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, readings[0].Timestamp, Math.Round(readings[0].Value, 2), sensorname[sensorid], 1);
}
}
}
// check for falling voltages for all tests except for PTC and THB_cycledbias tests ofcourse (drops with 50%)
double previousValue = 0.0;
// Check voor elke test (behalve PTC-tests)
if (!testtype.Contains("PTC") && !testtype.Contains("THB_cycledbias"))
{
if (sensorname[sensorid].ToLower().Contains("voltage")) // alleen voor spanningskanalen
{
foreach (var reading in readings)
{
double value = reading.Value * a + b; // gecorrigeerde waarde!
//Console.WriteLine("voltage " + value.ToString() + " prevValue " + previousValue.ToString() +" timestamp " + reading.Timestamp.ToString());
// controleer of spanning met meer dan 50% daalt
if (value < previousValue * 0.5)
{
Console.WriteLine("Spanning is meer dan 50% gedaald: " + value);
if (!RowExists(dgvProjectErrors, sensor.PK))
dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, reading.Timestamp, Math.Round(value, 2), sensorname[sensorid], 1);
}
previousValue = value;
}
try
{
DateTime mostRecentTimestamp = mostRecentReading.Timestamp;
// controleer of spanning wegzakt naar 0
if (readings.Count > 0)
{
DateTime lastTimestamp = readings.Last().Timestamp; // Haal de timestamp van de laatste reading
TimeSpan timeDifference = lastTimestamp - mostRecentTimestamp;
if (timeDifference.TotalMinutes < -5)
{
Console.WriteLine("Spanning gedaald naar 0!");
if (!RowExists(dgvProjectErrors, sensor.PK))
dgvProjectErrors.Rows.Add(chamber.MIDS, sensor.PK, lastTimestamp, 0.0, sensorname[sensorid], 1);
}
}
}
catch { }
}
}
sensorid++;
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error for Sensor {sensor.PK}: {ex.Message}");
}
}
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Chamber", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
try
{
foreach (var cabinet in cabinets)
{
Boolean projecterror = false;
Boolean projectprogress = false;
foreach (DataGridViewRow row in dgvProjectErrors.Rows)
{
string chambernumber = row.Cells[0].Value.ToString();
if (Int32.Parse(cabinet.Name) == Int32.Parse(chambernumber))
{
Console.WriteLine("project error in chamber " + cabinet.Name);
#warning controle of test binnen uur geleden gestart is
projecterror = true;
}
}
foreach (DataGridViewRow row in dgvProjects.Rows)
{
string chambernumber = row.Cells[3].Value.ToString();
if (Int32.Parse(cabinet.Name) == Int32.Parse(chambernumber))
{
projectprogress = true;
}
}
if (cabinet.StatusColor != Color.FromArgb(247, 180, 116))
{
if (projecterror == true)
cabinet.StatusColor = Color.FromArgb(238, 126, 16); // eurofins oranje
else if (projectprogress == true)
{
cabinet.StatusColor = Color.FromArgb(34, 177, 76); // bijpassende groene kleur
}
else
{
cabinet.StatusColor = Color.Transparent;
}
}
}
}
catch { }
Console.WriteLine("project data check finished");
}
private bool RowExists(DataGridView dgv, object sensorPK)
{
if (sensorAttempts.ContainsKey(sensorPK))
{
sensorAttempts[sensorPK]++;
}
else
{
sensorAttempts[sensorPK] = 1;
}
foreach (DataGridViewRow row in dgv.Rows)
{
if (row.IsNewRow) continue;
if (row.Cells[1].Value?.Equals(sensorPK) == true)
{
row.Cells[dgv.Columns.Count - 1].Value = sensorAttempts[sensorPK];
return true;
}
}
return false;
}
private void tbGeneralDataInterval_TextChanged(object sender, EventArgs e)
{
try
{
//timerGeneralDataCheck.Interval = Int32.Parse(tbGeneralDataInterval.Text) * 60 * 1000;
}
catch
{
MessageBox.Show("Invalid interval value");
}
}
private void btnGeneralCheck_Click(object sender, EventArgs e)
{
GeneralDataCheck();
}
private void dgvGeneralErrors_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void dgvGeneralErrors_Click(object sender, EventArgs e)
{
if (dgvGeneralErrors.SelectedRows.Count > 0)
{
DataGridViewRow selectedRow = dgvGeneralErrors.SelectedRows[0];
tabControl.SelectedTab = tpDataView;
var roomNumber = selectedRow.Cells[0].Value?.ToString();
if (roomNumber != null)
{
string formattedRoomNumber = int.TryParse(roomNumber, out int roomNum) ? roomNum.ToString("D5") : roomNumber;
if (lbChambers.Items.Contains(formattedRoomNumber))
lbChambers.SelectedItem = formattedRoomNumber;
else
lbChambers.ClearSelected();
}
}
}
private void dgvProjects_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (dgvProjects.SelectedRows.Count > 0)
{
DataGridViewRow selectedRow = dgvProjects.SelectedRows[0];
}
}
static string[] AnalyzeProject(string stepstring, Color backColor)
{
//Console.WriteLine(stepstring);
string temperature = "N/A";
string rh = "N/A";
string duration = "N/A";
string testtype = "N/A";
string tempH = "N/A";
string tempL = "N/A";
if (backColor == Color.FromArgb(191, 226, 248))
testtype = "HAST";
else if (backColor == Color.FromArgb(196, 249, 235))
testtype = "HTOL";
else if (backColor == Color.FromArgb(235, 243, 253))
testtype = "Unknown";
else if (backColor == Color.FromArgb(197, 249, 199)) // Green TC 2 chamber
testtype = "TC";
else if (backColor == Color.Pink) // Pink
testtype = "Unknown";
else if (backColor == Color.FromArgb(208, 195, 249)) // Purple
testtype = "Climate";
else if (backColor == Color.FromArgb(249, 243, 195)) // Yellow TC 1 chamber
testtype = "TC";
else
testtype = "Unknown";
if(testtype=="TC")
{
// Regex om temperaturen zoals "-40 °C" of "+150°C" te vinden
Regex regex = new Regex(@"([-+]?\d+)\s?°C", RegexOptions.IgnoreCase);
MatchCollection matches = regex.Matches(stepstring);
if (matches.Count >= 2)
{
double t1 = double.Parse(matches[0].Groups[1].Value);
double t2 = double.Parse(matches[1].Groups[1].Value);
// Sorteer zodat de laagste waarde tempL is en de hoogste tempH
if (t1 < t2)
{
tempL = t1.ToString();
tempH = t2.ToString();
}
else
{
tempL = t2.ToString();
tempH = t1.ToString();
}
return new string[] { temperature, rh, duration, testtype, tempH, tempL };
}
}
// Regex voor temperatuur (bijv. 125°C, 110±2 °C)
string tempPattern = @"(\d+)(?:±\d+)?\s*°C";
Match tempMatch = Regex.Match(stepstring, tempPattern);
if (tempMatch.Success)
{
temperature = tempMatch.Groups[1].Value;
}
// Regex voor relatieve luchtvochtigheid (bijv. 85% R.H., 85±5% R.H.)
string rhPattern = @"(\d+)(?:±\d+)?\s*%\s*(?:R\.?H\.?|rh)";
Match rhMatch = Regex.Match(stepstring, rhPattern);
if (rhMatch.Success)
{
rh = rhMatch.Groups[1].Value;
}
// Regex voor duur (bijv. 24h, 68 hours, 1 hour)
string durationPattern = @"(\d+)(?:\s*\(\+?-?\d+/-?\d+\))?\s*(?:hours?|hrs?|h)";
Match durationMatch = Regex.Match(stepstring, durationPattern);
if (durationMatch.Success)
{
duration = durationMatch.Groups[1].Value;
}
// Retourneer de resultaten als een array
return new string[] { temperature, rh, duration, testtype, tempH, tempL };
}
private void dgvProjects_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
}
private void tpProjectData_Click(object sender, EventArgs e)
{
}
private void btnProjectDataCheck_Click(object sender, EventArgs e)
{
projectDataCheck();
}
// 1x per 3 minuten ProjectdataCheck en 1x per 30 minuten GeneralDataCheck
private int timerCount = 0;
private void timerProjectDataCheck_Tick(object sender, EventArgs e)
{
Cursor = Cursors.WaitCursor;
obtainActiveProjects();
string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
if ( timerCount % 3 == 0)
projectDataCheck();
if (timerCount % 30 == 0)
GeneralDataCheck();
Cursor = Cursors.Default;
updateOverview();
// Teller verhogen en resetten bij 30 om oneindige groei te voorkomen
timerCount = (timerCount + 1) % 30;
}
private void dgvProjects_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (isLoadingData)
return;
Console.WriteLine("save");
try
{
var xml = new XElement("Projects",
from DataGridViewRow row in dgvProjects.Rows
where !row.IsNewRow // Sla lege rijen over
select new XElement("Project",
dgvProjects.Columns.Cast<DataGridViewColumn>()
.Where(col => row.Cells[col.Index].Value != null) // Voorkom null waarden
.Select(col => new XElement(col.HeaderText, row.Cells[col.Index].Value?.ToString() ?? ""))
)
);
xml.Save(filePath);
}
catch (Exception ex)
{
MessageBox.Show($"Fout bij het opslaan van XML: {ex.Message}", "Fout", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void dgvProjects_DoubleClick(object sender, EventArgs e)
{
if (dgvProjects.SelectedRows.Count > 0)
{
DataGridViewRow selectedRow = dgvProjects.SelectedRows[0];
var roomNumber = selectedRow.Cells[3].Value?.ToString();
if (roomNumber != null)
{
string formattedRoomNumber = int.TryParse(roomNumber, out int roomNum) ? roomNum.ToString("D5") : roomNumber;
if (lbChambers.Items.Contains(formattedRoomNumber))
lbChambers.SelectedItem = formattedRoomNumber;
else
lbChambers.ClearSelected();
}
tabControl.SelectedTab = tpDataView;
updateLiveView();
}
}
private void timerLiveData_Tick(object sender, EventArgs e)
{
if (cbLiveData.Checked == true)
{
updateLiveView();
}
}
private void btnUpdateOverview_Click(object sender, EventArgs e)
{
}
private void StatusIndicator_Click(object sender, MouseEventArgs e)
{
CabinetStatus cabinet = null;
if (sender is Panel panel && panel.Tag is CabinetStatus cab1)
{
cabinet = cab1;
}
else if (sender is Label label && label.Parent is Panel parentPanel && parentPanel.Tag is CabinetStatus cab2)
{
cabinet = cab2;
}
if (cabinet != null)
{
// MessageBox.Show($"Je hebt geklikt op: {cabinet.Name}, Positie: {cabinet.Position}, Kleur: {cabinet.StatusColor}");
string roomNumber = cabinet.Name;
string formattedRoomNumber = int.TryParse(roomNumber, out int roomNum) ? roomNum.ToString("D5") : roomNumber;
if (lbChambers.Items.Contains(formattedRoomNumber))
lbChambers.SelectedItem = formattedRoomNumber;
else
lbChambers.ClearSelected();
tabControl.SelectedTab = tpDataView;
}
}
private System.Drawing.Drawing2D.GraphicsPath RoundedRect(Rectangle bounds, int radius)
{
int diameter = radius * 2;
var path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddArc(bounds.Left, bounds.Top, diameter, diameter, 180, 90);
path.AddArc(bounds.Right - diameter, bounds.Top, diameter, diameter, 270, 90);
path.AddArc(bounds.Right - diameter, bounds.Bottom - diameter, diameter, diameter, 0, 90);
path.AddArc(bounds.Left, bounds.Bottom - diameter, diameter, diameter, 90, 90);
path.CloseFigure();
return path;
}
void updateOverview()
{
// Update RTH-sensoren
List<int> sensorIds = rthSensors.Select(s => s.Id).ToList();
List<(double temperature, double humidity)> sensorData = GetTemperaturesAndHumidity(sensorIds);
for (int i = 0; i < sensorData.Count; i++)
{
rthSensors[i].Temperature = sensorData[i].temperature;
rthSensors[i].Humidity = sensorData[i].humidity;
}
humidityLOW = false;
foreach (var sensor in rthSensors)
{
// Controleer of er al een panel voor deze sensor bestaat
Panel statusIndicator = pcHal.Controls.OfType<Panel>().FirstOrDefault(p => p.Tag is RTHSensor s && s.Id == sensor.Id);
if (statusIndicator == null)
{
// Nieuw statuspanel voor RTH-sensor aanmaken
statusIndicator = new Panel
{
Size = new Size(55, 55),
BackColor = GetColorFromHumidity(sensor.Humidity),
Location = sensor.Position,
Cursor = Cursors.Hand,
Tag = sensor
};
// Maak cirkelvorm
System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
path.AddEllipse(0, 0, statusIndicator.Width, statusIndicator.Height);
statusIndicator.Region = new Region(path);
statusIndicator.Paint += (sender, e) =>
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
e.Graphics.DrawEllipse(Pens.Black, 0, 0, statusIndicator.Width - 1, statusIndicator.Height - 1);
};
// Label
Label sensorLabel = new Label
{
Text = $"{sensor.Temperature:F1}\n{sensor.Humidity:F1}",
ForeColor = Color.Black,
BackColor = Color.Transparent,
TextAlign = ContentAlignment.MiddleCenter,
Dock = DockStyle.Fill,
Font = new Font("Arial", 12, FontStyle.Bold)
};
statusIndicator.Controls.Add(sensorLabel);
pcHal.Controls.Add(statusIndicator);
}
else
{
// Alleen kleur en tekst updaten
statusIndicator.BackColor = GetColorFromHumidity(sensor.Humidity);
Label label = statusIndicator.Controls.OfType<Label>().FirstOrDefault();
if (label != null)
{
label.Text = $"{sensor.Temperature:F1}\n{sensor.Humidity:F1}";
}
}
// Klik-event altijd toevoegen
statusIndicator.MouseClick -= StatusIndicator_Click;
statusIndicator.MouseClick += StatusIndicator_Click;
}
if(humidityLOW==true)
pnlESDwarning.Visible = true;
else
pnlESDwarning.Visible = false;
// Update cabinets
foreach (var cabinet in cabinets)
{
Panel statusIndicator = pcHal.Controls.OfType<Panel>().FirstOrDefault(p => p.Tag is CabinetStatus cab && cab.Name == cabinet.Name);
if (statusIndicator == null)
{
statusIndicator = new Panel
{
Size = new Size(55, 55),
BackColor = Color.Transparent, // <--- Zet BACKGROUND transparant
Location = cabinet.Position,
Cursor = Cursors.Hand,
Tag = cabinet
};
/*
statusIndicator = new Panel
{
Size = new Size(55, 55),
BackColor = cabinet.StatusColor,
Location = cabinet.Position,
Cursor = Cursors.Hand,
Tag = cabinet
};
statusIndicator.Paint += (sender, e) =>
{
e.Graphics.DrawRectangle(Pens.Black, 0, 0, statusIndicator.Width - 1, statusIndicator.Height - 1);
};
*/
//
statusIndicator.Paint += (sender, e) =>
{
var panel = sender as Panel;
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
int radius = 15; // Rondingsstraal
var rect = new Rectangle(0, 0, panel.Width - 1, panel.Height - 1);
using (var path = RoundedRect(rect, radius))
{
using (var brush = new SolidBrush(cabinet.StatusColor))
{
e.Graphics.FillPath(brush, path); // <-- TEKEN GEKLEURDE GEVULDE VORM
}
e.Graphics.DrawPath(Pens.Black, path); // <-- TEKEN RAND
}
};
//
Label numberLabel = new Label
{
Text = cabinet.Name,
ForeColor = Color.Black,
BackColor = Color.Transparent,
TextAlign = ContentAlignment.MiddleCenter,
Dock = DockStyle.Fill,
Font = new Font("Arial", 14, FontStyle.Bold)
};
numberLabel.MouseClick += StatusIndicator_Click; // <- toevoegen
statusIndicator.Controls.Add(numberLabel);
pcHal.Controls.Add(statusIndicator);
}
else
{
//statusIndicator.BackColor = cabinet.StatusColor;
}
statusIndicator.MouseClick -= StatusIndicator_Click;
statusIndicator.MouseClick += StatusIndicator_Click;
}
pcHal.BringToFront();
pcHal.Invalidate();
}
Color GetColorFromHumidity(double humidity)
{
if (humidity < 30)
{
humidityLOW = true;
return Color.FromArgb(205, 45, 45); // rth rood
}
if (humidity >=30) return Color.FromArgb(34, 177, 76); // rth groen
return Color.Red;
}
private void tabControl_SelectedIndexChanged(object sender, EventArgs e)
{
if (tabControl.SelectedTab == tpHal)
{
updateOverview();
}
}
private void pcHal_MouseMove(object sender, MouseEventArgs e)
{
if (false)
Console.WriteLine($"X: {e.X}, Y: {e.Y}");
}
private void bgwGeneralDataCheck_DoWork(object sender, DoWorkEventArgs e)
{
GeneralDataCheck();
}
private void bgwProjectDataCheck_DoWork(object sender, DoWorkEventArgs e)
{
projectDataCheck();
}
private void tbLastHours_TextChanged(object sender, EventArgs e)
{
}
private void tbHourView_TextChanged(object sender, EventArgs e)
{
}
private void cbLiveData_CheckedChanged(object sender, EventArgs e)
{
}
private void cbShowEnvelope_CheckedChanged(object sender, EventArgs e)
{
updateLiveView();
}
private void cbVoltageScale_CheckedChanged(object sender, EventArgs e)
{
updateLiveView();
}
private void tbLastHours_Leave(object sender, EventArgs e)
{
updateLiveView();
}
private void tbHourView_Leave(object sender, EventArgs e)
{
updateLiveView();
}
private void tbLastHours_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
updateLiveView();
}
}
public class SensorReading
{
public float Value { get; set; }
public DateTime Timestamp { get; set; }
}
public class RTHSensor
{
public int Id { get; set; }
public double Temperature { get; set; }
public double Humidity { get; set; }
public Point Position { get; set; } // Positie in de PictureBox
}
public class CabinetStatus
{
public string Name { get; set; }
public Point Position { get; set; }
public Color StatusColor { get; set; }
}
private void tbHourView_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
updateLiveView();
}
}
private void button1_Click(object sender, EventArgs e)
{
tbLastHours.Text = "10";
updateLiveView();
}
private void btn1d_Click(object sender, EventArgs e)
{
tbLastHours.Text = "24";
updateLiveView();
}
private void btn2d_Click(object sender, EventArgs e)
{
tbLastHours.Text = "48";
updateLiveView();
}
private void btn1w_Click(object sender, EventArgs e)
{
tbLastHours.Text = "168";
updateLiveView();
}
// Server acces parameters
const string UserID = "mids_userquery";
const string Password = "23uRUVfq6dXXHMWN";
const string Catalog = "mids_maser";
const string Server = "meeu001sqvp007.itiz-me-eu.local";
private static MySqlConnection GetConnection()
{
try
{
string ConnectionString = String.Format("DataSource={0};Persist Security Info=False;Initial Catalog={1};Connect Timeout=30;Username={2}; Password={3};", Server, Catalog, UserID, Password);
MySqlConnection myConnection = new MySqlConnection();
myConnection.ConnectionString = ConnectionString;
return myConnection;
}
catch (Exception e)
{
throw e;
}
}
private void button2_Click(object sender, EventArgs e)
{
}
private List<(double temperature, double humidity)> GetTemperaturesAndHumidity(List<int> sensorIds)
{
MySqlCommand cmd;
MySqlConnection connection = null;
var results = new List<(double temperature, double humidity)>(); // Lijst om de resultaten op te slaan
try
{
foreach (int sensorId in sensorIds)
{
string query = $"SELECT temperature, humidity FROM `sensor_data` WHERE sensor_id = {sensorId} ORDER BY timestamp DESC LIMIT 1";
// Verbinding maken
connection = GetConnection();
if (connection == null)
{
return results; // Geen verbinding, lege lijst retourneren
}
cmd = new MySqlCommand(query, connection);
connection.Open();
// Voer de query uit
MySqlDataReader reader = cmd.ExecuteReader();
if (reader.HasRows)
{
while (reader.Read())
{
double temperature = reader.IsDBNull(0) ? 0.0 : reader.GetDouble(0);
double humidity = reader.IsDBNull(1) ? 0.0 : reader.GetDouble(1);
// Voeg de opgehaalde waarden toe aan de lijst
results.Add((temperature, humidity));
}
}
reader.Close();
connection.Close();
}
}
catch (MySqlException ex)
{
// Foutmelding voor MySQL
Console.WriteLine("MySQL fout: " + ex.Message);
}
catch (Exception ex)
{
// Algemene foutmelding voor andere fouten
Console.WriteLine("Fout: " + ex.Message);
}
finally
{
if (connection != null)
{
connection.Close();
}
}
return results; // Retourneer de lijst met de opgehaalde waarden
}
private void lbSensors_SelectedIndexChanged(object sender, EventArgs e)
{
lbSensorChanged = true;
updateLiveView();
}
}
}