This commit is contained in:
2025-11-26 14:39:07 +00:00
parent 791cee91d2
commit e29d104d47
15 changed files with 304 additions and 268 deletions

View File

@@ -5,6 +5,13 @@ using System.Reflection;
namespace AiQ_GUI
{
public enum Level
{
ERROR,
WARNING,
LOG
}
public partial class MainForm : Form
{
// Classes
@@ -19,8 +26,6 @@ namespace AiQ_GUI
private List<CancellationTokenSource> soakCtsList = [];
private List<Task> soakTasks = [];
public const string GoogleDrivePath = @"G:\Shared drives\MAV Production GUI's\AiQ\GUI's\";
// Colours
public static readonly Color BtnColour = Color.FromArgb(70, 65, 80);
public static readonly Color TxBxColour = Color.FromArgb(53, 51, 64);
@@ -36,20 +41,18 @@ namespace AiQ_GUI
private async void AiQGUI_Load(object sender, EventArgs e)
{
Stopwatch stopwatch = Stopwatch.StartNew();
Task? closeProcessesTask = Windows.CloseProcesses(); // Fire and forget closing other apps
Windows.UpdateFirewall();
Task UniDataTask = Task.Run(() => Access.ReadUniData()); // Get universal data
Task<LocalDataStore> LDSWAIT = Task.Run(() => LDS.GetLDS()); // Get and deserialise LDS.json
Task<string> guiVerTask = Task.Run(() => GUIUpdate.FindGUIVersion()); // Get GUI Version
Task<LocalDataStore> LDSWAIT = Task.Run(() => LDS.GetLDS()); // Get and deserialise LDS.json
Task<string> guiVerTask = Task.Run(() => GUIUpdate.FindGUIVersion()); // Get GUI Version
Network.Initialize("admin", "admin"); // Initialise HTTP client
if (await Network.PingIP("8.8.8.8")) // Ping to check if we're online
{
if (!GoogleAPI.Setup())
AddToActionsList("Cannot setup Google API");
AddToActionsList("Cannot setup Google API", Level.WARNING);
}
else
{
@@ -71,6 +74,7 @@ namespace AiQ_GUI
// Load local data store
localDataStore = await LDSWAIT;
Logging.LogMessage("Opening GUI"); // Done after LDS to make sure directory exists.
if (localDataStore == null)
{
AddToActionsList("Could not deserialise LDS.json please help!");
@@ -89,9 +93,6 @@ namespace AiQ_GUI
await CheckHWOnline;
Flags.Start = false;
stopwatch.Stop();
Debug.WriteLine("RunTime " + stopwatch.Elapsed.ToString(@"hh\:mm\:ss\.ff"));
}
private void PopulateUIWithLDS(LocalDataStore lds)
@@ -209,8 +210,8 @@ namespace AiQ_GUI
await CheckDiagsAPIPt2(); // For only final test parts
// Check module has gone to default config
CameraModules.CheckCamModule(DiagsAPI.IRmodule, LblIRModule); // IR
CameraModules.CheckCamModule(DiagsAPI.OVmodule, LblOVModule); // OV
CameraModules.CheckCamModule(DiagsAPI.IRmodule, LblIRModule, CamOnTest); // IR
CameraModules.CheckCamModule(DiagsAPI.OVmodule, LblOVModule, CamOnTest); // OV
// Check voltage and current are OK.
LED.CheckLEDs(DiagsAPI.LedVoltage, LblLEDV, "V", CameraAccessInfo.LED_V); // Voltage
@@ -253,8 +254,8 @@ namespace AiQ_GUI
await CheckDiagsAPIPt1();
// Check module has gone to default config
CameraModules.CheckCamModule(DiagsAPI.IRmodule, LblIRModule); // IR
CameraModules.CheckCamModule(DiagsAPI.OVmodule, LblOVModule); // OV
CameraModules.CheckCamModule(DiagsAPI.IRmodule, LblIRModule, CamOnTest); // IR
CameraModules.CheckCamModule(DiagsAPI.OVmodule, LblOVModule, CamOnTest); // OV
// Check voltage and current are OK.
LED.CheckLEDs(DiagsAPI.LedVoltage, LblLEDV, "V", CameraAccessInfo.LED_V); // Voltage
@@ -286,8 +287,6 @@ namespace AiQ_GUI
{
await PreTestFailed("Diagnostic Failure");
}
}
// ***** Pass/Fails *****
@@ -336,15 +335,11 @@ namespace AiQ_GUI
BtnStartTest.Text = "Test Passed";
PnlQuestion.Visible = false; // just in case this came from an override
Logging.LogMessage("Final Test Passed");
if (CamOnTest.RMANum == 0) // Yap to check if it is not a RMA
{
Access.Stats("Final Tests Passed", CamOnTest.Model);
}
else
{
Access.Stats("RMA Final Tests Passed", CamOnTest.Model);
}
if (CamOnTest.RMANum == 0) // Yap to check if it is not a RMA
Access.Stats("Final Tests Passed", CamOnTest.Model);
else
Access.Stats("RMA Final Tests Passed", CamOnTest.Model);
}
public async Task TestFailed(Button Btn, string ErrMssg)
@@ -354,13 +349,10 @@ namespace AiQ_GUI
Btn.Text = "Test Failed";
if (!(CamOnTest.RMANum != 0)) // Yap to check if it is not a RMA
{
Access.Stats(["Final Tests Failed", ErrMssg], CamOnTest.Model);
}
else
{
Access.Stats("RMA Final Tests Failed", CamOnTest.Model);
}
AddToActionsList(ErrMssg);
string RedLbls = string.Join(Environment.NewLine, PnlLbls.Controls
@@ -400,7 +392,6 @@ namespace AiQ_GUI
GoogleAPI.WriteToSS(oblistCD, "'Approval'!C" + nextRow + ":D" + nextRow, GoogleAPI.spreadsheetId_ModelInfo);
await Teams.SendMssg(Convert.ToString(nextRow), CbBxUserName.Text);
//GoogleAPI.EmailApproval(Convert.ToString(nextRow), CbBxUserName.Text);
string Approved = "";
@@ -514,7 +505,10 @@ namespace AiQ_GUI
AddToActionsList($"{DiagsAPI.MAC} not recognised as NVIDIA MAC address");
}
else
{
lblMac.ForeColor = Color.Red;
AddToActionsList($"{DiagsAPI.MAC} not recognised as a MAC address");
}
// Check timestamp
DateTime dateTime = new(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
@@ -597,9 +591,7 @@ namespace AiQ_GUI
CamOnTest.RMANum = Convert.ToInt32(await DisplayInput("What is the RMA number?"));
if (CamOnTest.RMANum == -1) // Means they chose the 'I don't know' option
{
await TestFailed(BtnStartTest, "Please get RMA number from operations team before continuing");
}
}
}
}
@@ -638,11 +630,7 @@ namespace AiQ_GUI
double CPUround = Math.Round(DiagsAPI.CPUusage); // Check CPU usage isn't near max
LblCPUusage.Text += CPUround + "%";
if (CPUround < 98 && CPUround > 50)
{
LblCPUusage.ForeColor = Color.LightGreen;
}
else if (CPUround <= 50)
if (CPUround <= 50)
{
LblCPUusage.Text += " Unexpectedly low CPU usage";
LblCPUusage.ForeColor = Color.Red;
@@ -652,6 +640,10 @@ namespace AiQ_GUI
LblCPUusage.Text += " Unexpectedly high CPU usage";
LblCPUusage.ForeColor = Color.Red;
}
else
{
LblCPUusage.ForeColor = Color.LightGreen;
}
// Check Vaxtor if it doesn't need or have license OR has and wants one then pass
if (CameraAccessInfo.VaxtorLic == false && DiagsAPI.licenses.raptorKeyID == "Not Licensed" || CameraAccessInfo.VaxtorLic == true && DiagsAPI.licenses.raptorKeyID != "Not Licensed")
@@ -727,7 +719,6 @@ namespace AiQ_GUI
lblSerial.Text += DiagsAPI.serialNumber;
Printer.ZebraIP = localDataStore.ZebraIP;
Printer.PrintGBLbl(); // Print GB label
Printer.PrintSerialLbl(CamOnTest.Model, NewSerial, CameraAccessInfo.Processor); // Print model/serial label
}
@@ -804,7 +795,9 @@ namespace AiQ_GUI
foreach (Camera soakInfo in soakCameraList)
{
TabSoak.Controls.Add(SoakTest.MakeNewCheckbox(soakInfo, YLoc));
CheckBox chkBox = SoakTest.MakeNewCheckbox(soakInfo, YLoc);
TabSoak.Controls.Add(chkBox);
soakInfo.CheckBox = chkBox;
YLoc += 24;
}
@@ -937,15 +930,27 @@ namespace AiQ_GUI
}
// ***** Helper functions *****
public void AddToActionsList(string Mssg, bool IsErr = true)
public void AddToActionsList(string Mssg, Level Lvl = Level.LOG)
{
if (IsErr)
if (Lvl == Level.ERROR)
{
Logging.LogErrorMessage(Mssg);
else
RhTxBxActions.SelectionColor = Color.IndianRed;
}
else if (Lvl == Level.WARNING)
{
Logging.LogWarningMessage(Mssg);
RhTxBxActions.SelectionColor = Color.Orange;
}
else if (Lvl == Level.LOG)
{
Logging.LogMessage(Mssg);
RhTxBxActions.SelectionColor = Color.LightGreen;
}
RhTxBxActions.AppendText(Mssg + Environment.NewLine);
RhTxBxActions.SelectionStart = RhTxBxActions.Text.Length;
RhTxBxActions.SelectionColor = SystemColors.Control;
RhTxBxActions.ScrollToCaret();
}
@@ -1146,7 +1151,7 @@ namespace AiQ_GUI
{
Network.Initialize("developer", SCL.DevPass); // Ensure network is initialized to the right camera
await FlexiAPI.HTTP_Update("GLOBAL--NetworkConfig", SCL.IP, Network_JSON);
Instance.AddToActionsList($"Setting 211 for camera {SCL.IP}", false);
Instance.AddToActionsList($"Setting 211 for camera {SCL.IP}", Level.LOG);
}
catch (Exception ex)
{
@@ -1173,7 +1178,7 @@ namespace AiQ_GUI
{
Network.Initialize("developer", SCL.DevPass); // Ensure network is initialized to the right camera
string RESP = await FlexiAPI.HTTP_Update("GLOBAL--FlexiApplication", SCL.IP, GOD_JSON);
Instance.AddToActionsList($"Setting God mode for camera {SCL.IP} to {newGodModeValue}", false);
Instance.AddToActionsList($"Setting God mode for camera {SCL.IP} to {newGodModeValue}", Level.LOG);
}
catch (Exception ex)
{
@@ -1313,7 +1318,11 @@ namespace AiQ_GUI
{
VaxtorLicResp = JsonConvert.DeserializeObject<VaxtorLic>(ALresponse);
if (VaxtorLicResp.protectionKeyId != string.Empty)
if (VaxtorLicResp.error != string.Empty)
{
AddToActionsList(VaxtorLicResp.error, Level.ERROR);
}
else if (VaxtorLicResp.protectionKeyId != string.Empty)
{
string err = GoogleAPI.UpdateSpreadSheetVaxtor(VaxtorLicResp, Vers.Serial, CamOnTest.Model);
@@ -1327,18 +1336,14 @@ namespace AiQ_GUI
await DisplayOK("Please wait at least a minute before turning off the unit.");
}
else if (VaxtorLicResp.error != string.Empty)
{
RhTxBxCode.AppendText(VaxtorLicResp.error);
}
else
{
AddToActionsList($"Error reading JSON - {ALresponse}");
AddToActionsList($"Error reading JSON - {ALresponse}", Level.ERROR);
}
}
catch
{
AddToActionsList($"Error reading JSON - {ALresponse}");
AddToActionsList($"Error reading JSON - {ALresponse}", Level.ERROR);
return;
}
}
@@ -1574,7 +1579,7 @@ namespace AiQ_GUI
CancellationTokenSource cts = new();
soakCtsList.Add(cts);
soakTasks.Add(SoakTest.StartSoak(SCL, cts.Token));
soakTasks.Add(SoakTest.StartSoak(SCL, SCL.CheckBox, cts.Token));
await Task.Delay(10000);
}
}
@@ -1596,7 +1601,7 @@ namespace AiQ_GUI
continue;
try
{
AddToActionsList($"Setting 211 & God Mode off for camera {SCL.IP}", false);
AddToActionsList($"Setting 211 & God Mode off for camera {SCL.IP}", Level.LOG);
Network.Initialize("developer", SCL.DevPass); // Ensure network is initialized to the right camera
await CameraModules.FactoryResetModules(SCL.IP); // Reset camera modules
@@ -1612,6 +1617,13 @@ namespace AiQ_GUI
{
AddToActionsList("Failed to set all cameras to 211 and god mode off. Reason: " + ex.Message); // In case non AiQ's get caught up
}
if (SCL.CheckBox.ForeColor == Color.Red)
{
DialogResult DR = MessageBox.Show($"CAMERA {SCL.Serial} {SCL.Model} DID NOT PASS SOAK TEST. Check soak test report to see error. Do you want to open the test report", "SOAK TEST FAILED", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
if (DR == DialogResult.Yes)
File.Open(SCL.TestReportLoc, FileMode.Open);
}
}
await Task.Delay(5000); // Wait for 5 seconds to allow the camera to restart
@@ -1619,11 +1631,11 @@ namespace AiQ_GUI
if ((FoundCams.Count == i && FoundCams.Contains("192.168.1.211")) || FoundCams.Count == 1)
{
AddToActionsList("All cameras successfully changed to 211.", false);
AddToActionsList("All cameras successfully changed to 211.", Level.LOG);
}
else
{
AddToActionsList($"Some cameras failed: Found {FoundCams.Count}, expected {i}.", true);
AddToActionsList($"Some cameras failed: Found {FoundCams.Count}, expected {i}.", Level.ERROR);
}
}
}
@@ -1671,59 +1683,7 @@ namespace AiQ_GUI
private async void BtnUploadBlob_Click(object sender, EventArgs e)
{
BtnUploadBlob.BackColor = BtnColour;
const string networkFolderPath = @"G:\Shared drives\MAV Production\MAV_146_AiQ_Mk2\Flexi";
string fileToUpload = null;
if (await DisplayQuestion("Do you want the latest Flexi version from the MAV Production folder?"))
{
fileToUpload = Directory.GetFiles(networkFolderPath, "*.blob").OrderByDescending(File.GetLastWriteTime).FirstOrDefault();
if (fileToUpload == null)
{
AddToActionsList("No .blob file found in the directory.", false);
return;
}
}
else
{
using OpenFileDialog openFileDialog1 = new()
{
InitialDirectory = networkFolderPath,
Filter = "Blob files (*.blob)|*.blob",
FilterIndex = 0
};
if (openFileDialog1.ShowDialog() == DialogResult.OK)
fileToUpload = openFileDialog1.FileName;
else
{
AddToActionsList("File selection cancelled.", false);
return;
}
}
string fileName = Path.GetFileName(fileToUpload);
AddToActionsList($"Selected file to upload: {fileToUpload}", false);
foreach (Camera? cam in soakCameraList.Where(c => c.IsChecked))
{
string apiUrl = $"http://{cam.IP}/upload/software-update/2";
Network.Initialize("developer", cam.DevPass);
await Task.Delay(1000); // Gives extra time to allow for Network to initialize
AddToActionsList($"Uploading to {cam.IP}...", false);
string result = await FlexiAPI.SendBlobFileUpload(apiUrl, fileToUpload, fileName);
// Retry once on transient errors
if (result.Contains("Error while copying content to a stream") || result.Contains("Timeout"))
{
AddToActionsList($"Retrying upload to {cam.IP}...", false);
await Task.Delay(1000);
result = await FlexiAPI.SendBlobFileUpload(apiUrl, fileToUpload, fileName);
}
AddToActionsList($"Upload result for {cam.IP}: {result}", false);
await Task.Delay(500);
}
FlexiAPI.UploadBlob(soakCameraList);
BtnUploadBlob.BackColor = Color.Green;
}
@@ -1743,19 +1703,37 @@ namespace AiQ_GUI
}
// ***** Test & Debug *****
private async void BtnTest_Click(object sender, EventArgs e)
private void BtnTest_Click(object sender, EventArgs e)
{
Stopwatch stopWatchTest = Stopwatch.StartNew();
//StatsExcel excelExporter = new();
//excelExporter.ExportDatabaseToExcel();
string ans = await FlexiAPI.HTTP_Fetch("GLOBAL--Device", "192.168.0.71");
AddToActionsList(ans);
// /api/config-ids - For getting all available config IDs
// Make every log file in the soak log directory into a soak test report PDF
var files = from file in Directory.EnumerateFiles("C:\\ProgramData\\MAV\\AiQ_GUI") select file;
foreach (var file in files)
{
if (file.Contains("SoakLog"))
{
// File name: SoakLog_{Serial}_{Model}.log
string[] parts = file.Split('_', '.').Select(p => p.Trim()).ToArray();
Camera NewCam = new()
{
Model = parts[3],
Serial = parts[2],
};
PDF.CreateSoakTestReport(NewCam, "SoakTestRig", DateTime.Now, file);
}
}
stopWatchTest.Stop();
AddToActionsList("RunTime " + stopWatchTest.Elapsed.ToString(@"hh\:mm\:ss\.ff"));
AddToActionsList("RunTime " + stopWatchTest.Elapsed.ToString(@"hh\:mm\:ss\.ff"), Level.LOG);
}
}
}

View File

@@ -123,11 +123,8 @@
<metadata name="ToolTipClipboard.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>159, 17</value>
</metadata>
<metadata name="ToolTipAvailable.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="TimerDDC.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>690, 19</value>
<value>531, 18</value>
</metadata>
<metadata name="timerTypeIP.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>305, 17</value>

View File

@@ -16,7 +16,7 @@
<Product>AiQ GUI</Product>
<Authors>MAV Systems Ltd</Authors>
<PackageId>AiQ GUI</PackageId>
<Version>4.4.0</Version>
<Version>4.5.0</Version>
<Description>A GUI to control and test the AiQ</Description>
<Copyright>MAV Systems Ltd 2025</Copyright>
<PackageIcon>MAV - Plain - Blue.png</PackageIcon>

View File

@@ -4,7 +4,7 @@ namespace AiQ_GUI
internal class CameraModules
{
// Chack camera modules are in default state according to what the diagnostics API.
public static void CheckCamModule(Module CamMod, Label Lbl)
public static void CheckCamModule(Module CamMod, Label Lbl, Camera CamOnTest)
{
if (CamMod == null || Lbl == null)
{
@@ -17,7 +17,21 @@ namespace AiQ_GUI
if (CamMod.zoom != 0) // Check camera module is at full wide
errMssg += $"Zoom not at 0 - {CamMod.zoom} ";
if (CamMod.firmwareVer != UniversalData.WonwooFirmware) // Check camera module firmware version is up to date.
bool LessTanOrEqualTo = false;
try
{
LessTanOrEqualTo = Convert.ToDouble(CamMod.firmwareVer) <= Convert.ToDouble(UniversalData.WonwooFirmware);
}
catch
{
MainForm.Instance.AddToActionsList($"{CamMod.firmwareVer} or {UniversalData.WonwooFirmware} could not be converted to a double");
}
if (CamOnTest.RMANum > 0 && LessTanOrEqualTo)
errMssg += $"Firmware: {CamMod.firmwareVer} should be less than or equal to {UniversalData.WonwooFirmware} for RMA {CamOnTest.RMANum}";
else if ((CamOnTest.RMANum == 0 || CamOnTest.RMANum == -1) && CamMod.firmwareVer != UniversalData.WonwooFirmware)
errMssg += $"Firmware: {CamMod.firmwareVer} should be {UniversalData.WonwooFirmware} ";
if (CamMod.expMode != 0) // Auto 0=0x00

View File

@@ -378,7 +378,7 @@ namespace AiQ_GUI
using OpenFileDialog openFileDialog1 = new()
{
InitialDirectory = MainForm.GoogleDrivePath,
InitialDirectory = GoogleAPI.GoogleDrivePath,
Filter = "CSV files (*.csv)|*.csv",
FilterIndex = 0
};
@@ -387,7 +387,7 @@ namespace AiQ_GUI
fileToUpload = openFileDialog1.FileName;
else
{
MainForm.Instance.AddToActionsList("File selection cancelled.", false);
MainForm.Instance.AddToActionsList("File selection cancelled.", Level.WARNING);
return;
}
@@ -396,7 +396,7 @@ namespace AiQ_GUI
if ((isIR && !filename.Contains("IR")) || (!isIR && !filename.Contains("OV")))
{
MainForm.Instance.AddToActionsList($"Incorrect file selected. Expected {(isIR ? "IR" : "OV")} file", false);
MainForm.Instance.AddToActionsList($"Incorrect file selected. Expected {(isIR ? "IR" : "OV")} file", Level.WARNING);
return;
}
@@ -408,7 +408,7 @@ namespace AiQ_GUI
if (parts.Length < 3)
{
MainForm.Instance.AddToActionsList($"Invalid row format at line {i + 1}", false);
MainForm.Instance.AddToActionsList($"Invalid row format at line {i + 1}", Level.WARNING);
continue;
}
@@ -419,21 +419,78 @@ namespace AiQ_GUI
// VISCA format check
if (!RegexCache.VISCAAPIRegex().IsMatch(command))
{
MainForm.Instance.AddToActionsList($"{name}: Invalid VISCA command ({command})", false);
MainForm.Instance.AddToActionsList($"{name}: Invalid VISCA command ({command})", Level.WARNING);
continue; // do not send it if bad
}
string result = await APIHTTPVISCA(ipAddress, command, isIR);
if (result.Contains(expectedResponse))
MainForm.Instance.AddToActionsList($"{name}: Success ({(isIR ? "IR" : "Colour")})", true);
MainForm.Instance.AddToActionsList($"{name}: Success ({(isIR ? "IR" : "Colour")})", Level.LOG);
else
MainForm.Instance.AddToActionsList($"{name}: Unexpected response ({result})", false);
MainForm.Instance.AddToActionsList($"{name}: Unexpected response ({result})", Level.ERROR);
await Task.Delay(150);
}
MainForm.Instance.AddToActionsList($"Upload complete ({(isIR ? "IR" : "Colour")}).", true);
MainForm.Instance.AddToActionsList($"Upload complete ({(isIR ? "IR" : "Colour")}).", Level.LOG);
}
public static async void UploadBlob(List<Camera> soakCameraList)
{
const string networkFolderPath = @"G:\Shared drives\MAV Production\MAV_146_AiQ_Mk2\Flexi";
string fileToUpload = null;
if (await MainForm.Instance.DisplayQuestion("Do you want the latest Flexi version from the MAV Production folder?"))
{
fileToUpload = Directory.GetFiles(networkFolderPath, "*.blob").OrderByDescending(File.GetLastWriteTime).FirstOrDefault();
if (fileToUpload == null)
{
MainForm.Instance.AddToActionsList("No .blob file found in the directory.", Level.ERROR);
return;
}
}
else
{
using OpenFileDialog openFileDialog1 = new()
{
InitialDirectory = networkFolderPath,
Filter = "Blob files (*.blob)|*.blob",
FilterIndex = 0
};
if (openFileDialog1.ShowDialog() == DialogResult.OK)
fileToUpload = openFileDialog1.FileName;
else
{
MainForm.Instance.AddToActionsList("File selection cancelled.", Level.WARNING);
return;
}
}
string fileName = Path.GetFileName(fileToUpload);
MainForm.Instance.AddToActionsList($"Selected file to upload: {fileToUpload}", Level.LOG);
foreach (Camera? cam in soakCameraList.Where(c => c.IsChecked))
{
string apiUrl = $"http://{cam.IP}/upload/software-update/2";
Network.Initialize("developer", cam.DevPass);
await Task.Delay(1000); // Gives extra time to allow for Network to initialize
MainForm.Instance.AddToActionsList($"Uploading to {cam.IP}...", Level.LOG);
string result = await SendBlobFileUpload(apiUrl, fileToUpload, fileName);
// Retry once on transient errors
if (result.Contains("Error while copying content to a stream") || result.Contains("Timeout"))
{
MainForm.Instance.AddToActionsList($"Retrying upload to {cam.IP}...", Level.WARNING);
await Task.Delay(1000);
result = await SendBlobFileUpload(apiUrl, fileToUpload, fileName);
}
MainForm.Instance.AddToActionsList($"Upload result for {cam.IP}: {result}", Level.LOG);
await Task.Delay(500);
}
}
}
@@ -443,10 +500,8 @@ namespace AiQ_GUI
public string version { get; set; } = string.Empty;
public string revision { get; set; } = string.Empty;
public string buildtime { get; set; } = string.Empty;
public string appname { get; set; } = string.Empty;
public string MAC { get; set; } = string.Empty;
public int timeStamp { get; set; }
public string UUID { get; set; } = string.Empty;
public string proquint { get; set; } = string.Empty;
[JsonProperty("Serial No.")]
@@ -510,13 +565,5 @@ namespace AiQ_GUI
public class Property
{
public string Value { get; set; } = string.Empty;
public string datatype { get; set; }
}
public class VaxtorConfig
{
public string id { get; set; }
public long configHash { get; set; }
public Property propMinCharHeight { get; set; }
public Property propMinGlobalConfidence { get; set; }
}
}

View File

@@ -1,12 +1,12 @@
using Google.Apis.Auth.OAuth2;
using Google.Apis.Gmail.v1;
//using Google.Apis.Gmail.v1;
using Google.Apis.Services;
using Google.Apis.Sheets.v4;
using Google.Apis.Sheets.v4.Data;
using Google.Apis.Util.Store;
using System.Net.Mail;
using System.Net.Mime;
using System.Reflection;
//using System.Net.Mail;
//using System.Net.Mime;
//using System.Reflection;
namespace AiQ_GUI
{
@@ -18,6 +18,7 @@ namespace AiQ_GUI
static readonly string credPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
public const string spreadsheetId_ModelInfo = "1bCcCr4OYqfjmydt6UqtmN4FQETezXmZRSStJdCCcqZM";
public const string DrivePath = @"G:\Shared drives\MAV Production GUI's\"; // Path to google shared drive
public const string GoogleDrivePath = @"G:\Shared drives\MAV Production GUI's\AiQ\GUI's\";
// Startup and make necessary connections to Google servers and make sure user is logged in
public static bool Setup()
@@ -284,75 +285,76 @@ namespace AiQ_GUI
return valuesRMA.Count + 2; // Gets the amount of rows, offsets for start from 1 error and adds one to be next row
}
public static void EmailApproval(string ApprovalRow, string User)
{
FileStream GmailStream = new($"{DrivePath}R50IQ\\creds.json", FileMode.Open, FileAccess.Read);
string[] ScopesGmail = [GmailService.Scope.GmailSend];
// DEPRECATED
//public static void EmailApproval(string ApprovalRow, string User)
//{
// FileStream GmailStream = new($"{DrivePath}R50IQ\\creds.json", FileMode.Open, FileAccess.Read);
// string[] ScopesGmail = [GmailService.Scope.GmailSend];
using (GmailStream)
{
string credPathGmail = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart.json");
credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.FromStream(GmailStream).Secrets, ScopesGmail, "user", CancellationToken.None, new FileDataStore(credPathGmail, true)).Result;
GmailStream.Close();
}
// using (GmailStream)
// {
// string credPathGmail = Path.Combine(credPath, ".credentials/gmail-dotnet-quickstart.json");
// credential = GoogleWebAuthorizationBroker.AuthorizeAsync(GoogleClientSecrets.FromStream(GmailStream).Secrets, ScopesGmail, "user", CancellationToken.None, new FileDataStore(credPathGmail, true)).Result;
// GmailStream.Close();
// }
// Build the MIME message with attachment
using MailMessage mail = new();
mail.From = new MailAddress("me");
mail.To.Add("richard.porter@mav-systems.com");
mail.To.Add("bradley.relyea@mav-systems.com");
mail.To.Add("bradley.born@mav-systems.com");
mail.Subject = "Approval required";
mail.Body = $"Dear Rich,<br><br>Camera needs approval<br>" +
$"https://docs.google.com/spreadsheets/d/1bCcCr4OYqfjmydt6UqtmN4FQETezXmZRSStJdCCcqZM/edit#gid=1931079354&range=A{ApprovalRow}" +
$"<br><br><br>Thanks,<br><br>{User}";
mail.IsBodyHtml = true;
// // Build the MIME message with attachment
// using MailMessage mail = new();
// mail.From = new MailAddress("me");
// mail.To.Add("richard.porter@mav-systems.com");
// mail.To.Add("bradley.relyea@mav-systems.com");
// mail.To.Add("bradley.born@mav-systems.com");
// mail.Subject = "Approval required";
// mail.Body = $"Dear Rich,<br><br>Camera needs approval<br>" +
// $"https://docs.google.com/spreadsheets/d/1bCcCr4OYqfjmydt6UqtmN4FQETezXmZRSStJdCCcqZM/edit#gid=1931079354&range=A{ApprovalRow}" +
// $"<br><br><br>Thanks,<br><br>{User}";
// mail.IsBodyHtml = true;
// Attach the log file if it exists
string logFilePath = LDS.MAVPath + Logging.LogFileName;
if (File.Exists(logFilePath))
{
Attachment logAttachment = new(logFilePath, MediaTypeNames.Text.Plain);
logAttachment.Name = Logging.LogFileName;
mail.Attachments.Add(logAttachment);
}
// // Attach the log file if it exists
// string logFilePath = LDS.MAVPath + Logging.LogFileName;
// if (File.Exists(logFilePath))
// {
// Attachment logAttachment = new(logFilePath, MediaTypeNames.Text.Plain);
// logAttachment.Name = Logging.LogFileName;
// mail.Attachments.Add(logAttachment);
// }
// Save the MIME message to a stream
using MemoryStream ms = new();
SmtpClient smtpClient = new(); // Only used to access the internal Write method
Type mailWriterType = typeof(SmtpClient).Assembly.GetType("System.Net.Mail.MailWriter");
object? mailWriter = Activator.CreateInstance(
mailWriterType,
BindingFlags.Instance | BindingFlags.NonPublic,
null,
[ms, true],
null);
// // Save the MIME message to a stream
// using MemoryStream ms = new();
// SmtpClient smtpClient = new(); // Only used to access the internal Write method
// Type mailWriterType = typeof(SmtpClient).Assembly.GetType("System.Net.Mail.MailWriter");
// object? mailWriter = Activator.CreateInstance(
// mailWriterType,
// BindingFlags.Instance | BindingFlags.NonPublic,
// null,
// [ms, true],
// null);
typeof(MailMessage).InvokeMember(
"Send",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
null,
mail,
[mailWriter, true, true]);
// typeof(MailMessage).InvokeMember(
// "Send",
// BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
// null,
// mail,
// [mailWriter, true, true]);
ms.Position = 0;
byte[] rawBytes = ms.ToArray();
// ms.Position = 0;
// byte[] rawBytes = ms.ToArray();
GmailService service = new(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
// GmailService service = new(new BaseClientService.Initializer()
// {
// HttpClientInitializer = credential,
// ApplicationName = ApplicationName,
// });
Google.Apis.Gmail.v1.Data.Message newMsg = new()
{
Raw = Convert.ToBase64String(rawBytes)
.Replace("+", "-")
.Replace("/", "_")
.Replace("=", "")
};
// Google.Apis.Gmail.v1.Data.Message newMsg = new()
// {
// Raw = Convert.ToBase64String(rawBytes)
// .Replace("+", "-")
// .Replace("/", "_")
// .Replace("=", "")
// };
service.Users.Messages.Send(newMsg, "me").Execute();
}
// service.Users.Messages.Send(newMsg, "me").Execute();
//}
}
}

View File

@@ -184,9 +184,9 @@ namespace AiQ_GUI
public string IP { get; set; } = string.Empty;
public int RMANum { get; set; } = 0;
public string FlexiVersion { get; set; } = string.Empty; // Flexi version
public string Processor { get; set; } = string.Empty; // Nano, Xavier, Orin or Pi?
public string ModuleManufacturer { get; set; } = string.Empty; // KT&C or Wonwoo
public bool IsChecked { get; set; } // Is it checked for soak test?
public CheckBox CheckBox { get; set; } = new CheckBox();
public string TestReportLoc { get; set; } = string.Empty; // Location of test report file
}
// Static class for global flags

8
LDS.cs
View File

@@ -17,15 +17,10 @@ namespace AiQ_GUI
try
{
if (!Directory.Exists(MAVPath)) // Check the AiQ folder exists in ProgramData and if it doesn't then create it
{
Directory.CreateDirectory(MAVPath);
}
if (!File.Exists(MAVPath + LDSFileName)) // Check the LDS file exists and if it doesn't then create it
{
// Save a blank version of the JSON
File.WriteAllText(MAVPath + LDSFileName, DefaultJSON);
}
File.WriteAllText(MAVPath + LDSFileName, DefaultJSON); // Save a blank version of the JSON
StreamReader file = new(MAVPath + LDSFileName);
string Content = file.ReadToEnd();
@@ -37,7 +32,6 @@ namespace AiQ_GUI
{
MainForm.Instance.AddToActionsList("Error loading Local Data Store");
return null; // Return null to indicate failure
}
}

View File

@@ -1,6 +1,4 @@
using System.Diagnostics;
namespace AiQ_GUI
namespace AiQ_GUI
{
internal class Logging
{
@@ -43,7 +41,7 @@ namespace AiQ_GUI
}
catch (Exception ex)
{
Debug.WriteLine($"Error logging message: {ex.Message}");
MainForm.Instance.AddToActionsList($"Error logging message: {ex.Message}");
}
}
}

View File

@@ -122,10 +122,8 @@ namespace AiQ_GUI
int rowsAffected = cmd.ExecuteNonQuery();
// Execute the command and get the number of rows affected
//if (rowsAffected > 0) // If one or more rows were updated
// AddToActionsList($"Updated {TypeOfTest} for {modelNumber}");
//else
// AddToActionsList($"No rows found for {modelNumber}");
if (rowsAffected == 0) // If one or more rows were updated
MainForm.Instance.AddToActionsList($"No rows affected for {modelNumber}");
}
conn.Close();
}
@@ -162,10 +160,8 @@ namespace AiQ_GUI
int rows = cmd.ExecuteNonQuery();
conn.Close();
//if (rows > 0)
// AddToActionsList($"DiagsStats inserted ({rows} row) for model '{model}' on {DateTime.Now:yyyy-MM-dd}");
//else
// AddToActionsList("No rows inserted into DiagsStats (unexpected).");
if (rows == 0)
MainForm.Instance.AddToActionsList("No rows inserted into DiagsStats (unexpected).");
}
}

View File

@@ -23,7 +23,7 @@ namespace AiQ_GUI
DateTime? lastStatsRun = null;
try
{
using (OleDbCommand cmdPeriod = new OleDbCommand("SELECT LastStatsRun FROM UniversalData", conn))
using (OleDbCommand cmdPeriod = new("SELECT LastStatsRun FROM UniversalData", conn))
{
object res = cmdPeriod.ExecuteScalar();
if (res != null && res != DBNull.Value)
@@ -37,7 +37,7 @@ namespace AiQ_GUI
}
// ==================== MAIN STATS EXPORT ====================
string selectColumns = @"
const string selectColumns = @"
ModelNumber,
[Total Tests Run],
[Pre Tests Passed],
@@ -125,7 +125,7 @@ namespace AiQ_GUI
DateTime monthStart = new(now.Year, now.Month, 1);
DateTime nextMonth = monthStart.AddMonths(1);
string diagsQuery = @"
const string diagsQuery = @"
SELECT
[Date],
[Model],
@@ -136,36 +136,33 @@ namespace AiQ_GUI
FROM DiagsStats
WHERE [Date] >= ? AND [Date] < ?";
using (OleDbCommand diagsCmd = new OleDbCommand(diagsQuery, conn))
using (OleDbCommand diagsCmd = new(diagsQuery, conn))
{
diagsCmd.Parameters.Add(new OleDbParameter { OleDbType = OleDbType.Date, Value = monthStart });
diagsCmd.Parameters.Add(new OleDbParameter { OleDbType = OleDbType.Date, Value = nextMonth });
using (OleDbDataAdapter diagsAdapter = new OleDbDataAdapter(diagsCmd))
using OleDbDataAdapter diagsAdapter = new(diagsCmd);
DataTable diagsTable = new();
diagsAdapter.Fill(diagsTable);
if (diagsTable.Rows.Count > 0)
{
DataTable diagsTable = new();
diagsAdapter.Fill(diagsTable);
int startRow = (ws.LastRowUsed()?.RowNumber() ?? 0) + 3;
if (diagsTable.Rows.Count > 0)
{
int startRow = (ws.LastRowUsed()?.RowNumber() ?? 0) + 3;
ws.Cell(startRow, 1).Value = "Diags Stats (Current Month)";
ws.Cell(startRow, 1).Style.Font.Bold = true;
ws.Cell(startRow, 1).Style.Font.FontSize = 12;
ws.Cell(startRow, 1).Value = "Diags Stats (Current Month)";
ws.Cell(startRow, 1).Style.Font.Bold = true;
ws.Cell(startRow, 1).Style.Font.FontSize = 12;
ws.Cell(startRow + 1, 1).InsertTable(diagsTable, "Diags_Stats", true);
ws.Columns().AdjustToContents();
ws.Cell(startRow + 1, 1).InsertTable(diagsTable, "Diags_Stats", true);
ws.Columns().AdjustToContents();
MainForm.Instance.AddToActionsList($"Added DiagsStats ({diagsTable.Rows.Count} rows) starting at row {startRow}.");
}
MainForm.Instance.AddToActionsList($"Added DiagsStats ({diagsTable.Rows.Count} rows) starting at row {startRow}.");
}
}
// ==================== SAVE MAIN SHEET ====================
workbook.SaveAs(exportPath);
MainForm.Instance.AddToActionsList($"Added {sheetName} to workbook: {exportPath}");
workbook.Dispose();
// ==================== BACKUP TABLE (ALWAYS, BEFORE RESET) ====================
@@ -199,7 +196,7 @@ namespace AiQ_GUI
{
try
{
string resetSql = @"
const string resetSql = @"
UPDATE AiQ SET
[Total Tests Run] = 0,
[Pre Tests Passed] = 0,

View File

@@ -32,10 +32,8 @@ namespace AiQ_GUI
UP = await PingIP("10.10.10.137");
await Task.Delay(500);
if (i >= 5)
{
//MainForm.Instance.AddToActionsList($"Could not initialise new network with USER: {username} & PSWD: {password}");
return; // Try 5 times max
}
i++;
}
}

13
PDF.cs
View File

@@ -167,7 +167,6 @@ namespace AiQ_GUI
}
List<string> logLines = File.Exists(logFilePath) ? File.ReadAllLines(logFilePath).ToList() : new List<string>();
List<string> errorLines = logLines.Where(l => l.Contains("[ERROR]")).ToList();
List<string> warningLines = logLines.Where(l => l.Contains("[WARNING]")).ToList();
@@ -337,7 +336,17 @@ namespace AiQ_GUI
renderer.PdfDocument.Options.Layout = PdfWriterLayout.Compact;
// Construct save path
string fullPath = TestRecordDir + CamSoak.Model + $"\\SoakTestReport_{CamSoak.Model}_{CamSoak.Serial}_{pcTime:dd-MM-yyyy_HH-mm-ss}" + (CamSoak.RMANum != 0 ? $" RMA{CamSoak.RMANum}" : "") + ".pdf";
string SaveDir = TestRecordDir + CamSoak.Model;
if (!Directory.Exists(TestRecordDir))
{
SaveDir = Path.Combine(LDS.MAVPath, "SoakTestRecords"); // Gets local folder if the main TestRecordDir is not found (no google drive).
if (!Directory.Exists(SaveDir))
Directory.CreateDirectory(SaveDir);
}
string fullPath = Path.Combine(SaveDir, $"SoakTestReport_{CamSoak.Model}_{CamSoak.Serial}_{pcTime:dd-MM-yyyy_HH-mm-ss}" + (CamSoak.RMANum != 0 ? $" RMA{CamSoak.RMANum}" : "") + ".pdf");
//string fullPath = TestRecordDir + CamSoak.Model + $"\\SoakTestReport_{CamSoak.Model}_{CamSoak.Serial}_{pcTime:dd-MM-yyyy_HH-mm-ss}" + (CamSoak.RMANum != 0 ? $" RMA{CamSoak.RMANum}" : "") + ".pdf";
renderer.PdfDocument.Save(fullPath);
Logging.LogMessage("Soak Test PDF saved to " + fullPath);

View File

@@ -159,10 +159,7 @@ namespace AiQ_GUI
await Task.Delay(500); // Wait for the change to take effect
if (!await Checkflashline(driver, CamAct))
{
Logging.LogWarningMessage("Bad flashline after changing: " + fullId, SoakLogFile);
MainForm.Instance.AddToActionsList("Bad flashline after changing: " + fullId);
}
}
// Monitors the flashline element's color to determine success (green) or failure (red) of a camera

View File

@@ -7,7 +7,7 @@ namespace AiQ_GUI
internal class SoakTest
{
// Main soak test loop: Randomise dropdowns, run luminance test every hour, power cycle at 7am
public static async Task StartSoak(Camera CamInfo, CancellationToken token)
public static async Task StartSoak(Camera CamInfo, CheckBox CkBx, CancellationToken token)
{
if (CamInfo.Serial == "N/A")
CamInfo.Serial = "UNKNOWN"; // If serial is not set, set it to UNKNOWN. Cannot have N/A in file names.
@@ -34,7 +34,7 @@ namespace AiQ_GUI
}
catch (Exception ex)
{
Logging.LogErrorMessage($"Initial connection failed: {ex.Message}", SoakLogFile);
SoakError($"Initial connection failed: {ex.Message}", SoakLogFile, CamInfo.CheckBox);
MainForm.Instance.AddToActionsList($"[{CamInfo.IP}] Initial connection failed: {ex.Message}");
// Wait 10 seconds before trying again
@@ -50,7 +50,7 @@ namespace AiQ_GUI
}
catch (Exception ex)
{
Logging.LogErrorMessage($"Failed to get element IDs: {ex.Message}", SoakLogFile);
SoakError($"Failed to get element IDs: {ex.Message}", SoakLogFile, CamInfo.CheckBox);
return;
}
@@ -72,7 +72,7 @@ namespace AiQ_GUI
// Retry ping until camera responds or cancelled
while (!await Network.PingIP(CamInfo.IP) && !token.IsCancellationRequested)
{
Logging.LogErrorMessage($"Camera did not respond after restart.", SoakLogFile);
SoakError($"Camera did not respond after restart.", SoakLogFile, CamInfo.CheckBox);
await Task.Delay(TimeSpan.FromMinutes(1), token); // Retry after delay of 1 minute
}
@@ -86,7 +86,7 @@ namespace AiQ_GUI
}
catch (Exception ex)
{
Logging.LogErrorMessage($"Error during power cycle: {ex.Message}", SoakLogFile);
SoakError($"Error during power cycle: {ex.Message}", SoakLogFile, CamInfo.CheckBox);
}
}
@@ -96,11 +96,11 @@ namespace AiQ_GUI
Logging.LogMessage($"Hour changed to {currentHour}, running ImageCheck.", SoakLogFile);
try
{
ImageCheck(driver, SoakLogFile, CamInfo.IP, CamInfo.DevPass, elementID);
ImageCheck(driver, SoakLogFile, CamInfo, elementID);
}
catch (Exception ex)
{
Logging.LogErrorMessage($"ImageCheck failed: {ex.Message}", SoakLogFile);
SoakError($"ImageCheck failed: {ex.Message}", SoakLogFile, CamInfo.CheckBox);
}
lastHour = currentHour;
}
@@ -119,7 +119,7 @@ namespace AiQ_GUI
}
catch (Exception ex)
{
Logging.LogErrorMessage($"ChangeRandomDropdown failed: {ex.Message}", SoakLogFile);
SoakError($"ChangeRandomDropdown failed: {ex.Message}", SoakLogFile, CamInfo.CheckBox);
}
try
@@ -144,6 +144,8 @@ namespace AiQ_GUI
if (SoakTestPath != null)
{
CamInfo.TestReportLoc = SoakTestPath;
// Delete the soak test log file if the report was created successfully
try
{
@@ -152,7 +154,7 @@ namespace AiQ_GUI
}
catch (Exception ex)
{
Logging.LogErrorMessage($"Failed to delete soak log file: {ex.Message}{Environment.NewLine}Please delete if you find this.", SoakLogFile);
SoakError($"Failed to delete soak log file: {ex.Message}{Environment.NewLine}Please delete if you find this.", SoakLogFile, CamInfo.CheckBox);
}
// Find the final test report PDF for this camera
@@ -198,7 +200,7 @@ namespace AiQ_GUI
}
// Capture's bright and dark images, then compares their luminance to verify sufficient contrast and adds results to the log
public static async Task LuminescenceMean(string FullID, ChromeDriver driver, string[] SettingMinMax, string SoakLogFile, string IP, string DevPass, string CamAct)
public static async Task LuminescenceMean(string FullID, ChromeDriver driver, string[] SettingMinMax, string SoakLogFile, Camera CamInfo, string CamAct)
{
string controlType = FullID.Split('_')[0]; // Extract control type from FullID (e.g. "Shutter_1234" → "Shutter")
@@ -208,7 +210,7 @@ namespace AiQ_GUI
await Task.Delay(500);
// Take bright image
Image ImageBright = await ImageProcessing.GetProcessedImage("Infrared", IP, DevPass);
Image ImageBright = await ImageProcessing.GetProcessedImage("Infrared", CamInfo.IP, CamInfo.DevPass);
if (ImageBright == null)
{
Logging.LogWarningMessage($"Bright image is null for {controlType} at setting {SettingMinMax[0]}", SoakLogFile);
@@ -222,7 +224,7 @@ namespace AiQ_GUI
await Task.Delay(500);
// Take dark image
Image ImageDark = await ImageProcessing.GetProcessedImage("Infrared", IP, DevPass);
Image ImageDark = await ImageProcessing.GetProcessedImage("Infrared", CamInfo.IP, CamInfo.DevPass);
if (ImageDark == null)
{
Logging.LogWarningMessage($"Dark image is null for {controlType} at setting {SettingMinMax[1]}", SoakLogFile);
@@ -236,9 +238,10 @@ namespace AiQ_GUI
if (Bright_Lum < Dark_Lum * 1.01)
{
Logging.LogErrorMessage(
SoakError(
$"Insufficient luminance contrast. Bright: {Bright_Lum:F2}, Dark: {Dark_Lum:F2} | Type: {controlType} | Bright Setting: {SettingMinMax[0]}, Dark Setting: {SettingMinMax[1]}",
SoakLogFile
SoakLogFile,
CamInfo.CheckBox
);
}
else
@@ -251,7 +254,7 @@ namespace AiQ_GUI
}
// Performs a series of camera control adjustments and luminance checks to verify image settings functionality
public async static void ImageCheck(ChromeDriver driver, string SoakLogFile, string IP, string DevPass, ElementID elementID)
public async static void ImageCheck(ChromeDriver driver, string SoakLogFile, Camera CamInfo, ElementID elementID)
{
await Selenium.Dropdown_Change(elementID.modeId, "Manual", driver, SoakLogFile, elementID.CamAct);
await Selenium.Dropdown_Change(elementID.shutterId, "1/1000", driver, SoakLogFile, elementID.CamAct);
@@ -259,11 +262,11 @@ namespace AiQ_GUI
await Selenium.Dropdown_Change(elementID.irisId, "F4.0", driver, SoakLogFile, elementID.CamAct);
await Selenium.Dropdown_Change(elementID.irLevelId, "Safe", driver, SoakLogFile, elementID.CamAct);
await LuminescenceMean(elementID.shutterId, driver, ["1/100", "1/10000"], SoakLogFile, IP, DevPass, elementID.CamAct); // Check Shutter goes from min to max
await LuminescenceMean(elementID.shutterId, driver, ["1/100", "1/10000"], SoakLogFile, CamInfo, elementID.CamAct); // Check Shutter goes from min to max
await Selenium.Dropdown_Change(elementID.shutterId, "1/1000", driver, SoakLogFile, elementID.CamAct); // Reset to default
await LuminescenceMean(elementID.irisId, driver, ["F2.0", "F16"], SoakLogFile, IP, DevPass, elementID.CamAct); // Check iris goes from min to max
await LuminescenceMean(elementID.irisId, driver, ["F2.0", "F16"], SoakLogFile, CamInfo, elementID.CamAct); // Check iris goes from min to max
await Selenium.Dropdown_Change(elementID.irisId, "F4.0", driver, SoakLogFile, elementID.CamAct); // Reset to default
await LuminescenceMean(elementID.gainId, driver, ["20dB", "0dB"], SoakLogFile, IP, DevPass, elementID.CamAct); // Check gain goes from min to max
await LuminescenceMean(elementID.gainId, driver, ["20dB", "0dB"], SoakLogFile, CamInfo, elementID.CamAct); // Check gain goes from min to max
}
public async static Task ChangeRandomDropdown(ChromeDriver driver, string SoakLogFile, ElementID elementID)
@@ -319,6 +322,12 @@ namespace AiQ_GUI
return dynamicButton;
}
private static void SoakError(string ErrMssg, string LogFile, CheckBox CkBx)
{
Logging.LogErrorMessage(ErrMssg, LogFile);
CkBx.ForeColor = Color.Red;
}
}
public class ElementID