From 8770469fd4b05e036c947a051eff4aa3c5d0d419 Mon Sep 17 00:00:00 2001 From: Bradley Born Date: Fri, 16 Jan 2026 11:42:34 +0000 Subject: [PATCH] - AddToActionsList(Level.DEBUG) method has been changed to only visible when ChBXDevLog is true to avoid DEVS always having it on. - added Level.DEBUG logs throughout selenium and soak test. Due to having prior issues with selenium and Soaktest - Bug fix in LDS.cs this stops a crossthread exception as its trying to write to AddToActionsList before it loads. --- AiQ_GUI.Designer.cs | 15 +++++++++++++++ AiQ_GUI.cs | 33 +++++++++++++++++++++++++++------ LDS.cs | 3 ++- Soak/Selenium.cs | 22 ++++++++++++++++++++++ Soak/SoakTest.cs | 9 +++++++++ 5 files changed, 75 insertions(+), 7 deletions(-) diff --git a/AiQ_GUI.Designer.cs b/AiQ_GUI.Designer.cs index 819e7d1..dc25246 100644 --- a/AiQ_GUI.Designer.cs +++ b/AiQ_GUI.Designer.cs @@ -152,6 +152,7 @@ namespace AiQ_GUI TimerFlash = new System.Windows.Forms.Timer(components); RhTxBxActions = new RichTextBox(); CbBxCamType = new ComboBox(); + ChBxDevLog = new CheckBox(); ((System.ComponentModel.ISupportInitialize)PicBxMAV).BeginInit(); ((System.ComponentModel.ISupportInitialize)PicBxAiQ).BeginInit(); ((System.ComponentModel.ISupportInitialize)PicBxIRF2).BeginInit(); @@ -1936,12 +1937,25 @@ namespace AiQ_GUI CbBxCamType.TabIndex = 241; CbBxCamType.SelectedIndexChanged += CbBxCamType_SelectedIndexChanged; // + // ChBxDevLog + // + ChBxDevLog.AutoSize = true; + ChBxDevLog.BackColor = Color.FromArgb(53, 51, 64); + ChBxDevLog.Location = new Point(430, 359); + ChBxDevLog.Name = "ChBxDevLog"; + ChBxDevLog.Size = new Size(74, 19); + ChBxDevLog.TabIndex = 242; + ChBxDevLog.Text = "Dev Logs"; + ChBxDevLog.UseVisualStyleBackColor = false; + ChBxDevLog.Visible = false; + // // MainForm // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; BackgroundImage = Properties.Resources.homepage_banner; ClientSize = new Size(932, 970); + Controls.Add(ChBxDevLog); Controls.Add(RhTxBxActions); Controls.Add(CbBxCamType); Controls.Add(LblGUIVers); @@ -2148,5 +2162,6 @@ namespace AiQ_GUI public PictureBox NightImgPcbx; public PictureBox DayImgPcbx; private Button BtnPlayVLC; + private CheckBox ChBxDevLog; } } diff --git a/AiQ_GUI.cs b/AiQ_GUI.cs index b5ef007..92a43dd 100644 --- a/AiQ_GUI.cs +++ b/AiQ_GUI.cs @@ -162,7 +162,7 @@ namespace AiQ_GUI CbBxGain.SelectedIndex = lds.Gain; if (lds.User == "Bradley" || lds.User == "Sophie") - BtnTest.Visible = true; + BtnTest.Visible = ChBxDevLog.Visible = true; TxBxCheckValid(TxBxPsuIP); // Set save button color if valid } @@ -396,6 +396,7 @@ namespace AiQ_GUI { // Update the serial number register with new cameras details // Cam description is in model drop down 6 digit model num + 3 for " - " + AddToActionsList($"Allocating serial for model {CamOnTest.Model} from spreadsheet", Level.DEBUG); string NewSerial = GoogleAPI.UpdateSpreadSheetPreTest(CameraAccessInfo.SpreadsheetID, Vers, CbBxCameraModel.Text.Substring(9), CamOnTest.Model); if (NewSerial.Contains("ERROR")) @@ -409,15 +410,24 @@ namespace AiQ_GUI return; } + AddToActionsList($"Allocated serial: {NewSerial} for model {CamOnTest.Model}", Level.DEBUG); + // Set serial and model into camera string[,] TEST_JSON = { { "propSerialNumber", NewSerial }, { "propMavModelNumber", CamOnTest.Model } }; + AddToActionsList($"Sending JSON update to camera {CamOnTest.IP}: Serial={NewSerial}, Model={CamOnTest.Model}", Level.DEBUG); + string JSONResponse = await FlexiAPI.HTTP_Update("GLOBAL--FlexiApplication", CamOnTest.IP, TEST_JSON); if (!JSONResponse.Contains(NewSerial) || !JSONResponse.Contains(CamOnTest.Model)) { + AddToActionsList($"JSON response validation failed. Expected serial: {NewSerial}, model: {CamOnTest.Model}", Level.DEBUG); AddToActionsList("Could not set model or serial numbers into camera.", Level.ERROR); await PreTestFailed("Failed To Set Model Or Serial Number"); } + else + { + AddToActionsList($"Successfully set serial and model in camera", Level.DEBUG); + } TestingFunctions.DiagsAPI.modelNumber = CamOnTest.Model; // Update Diags and labels TestingFunctions.DiagsAPI.serialNumber = NewSerial; @@ -548,6 +558,7 @@ namespace AiQ_GUI { CamOnTest.IP = ipOnly; // Always store clean IP CbBxFoundCams.BackColor = BtnColour; + AddToActionsList($"Camera selected: {ipOnly} (Onvif: {isOnvif})", Level.DEBUG); // ONVIF cameras: webpage only if (isOnvif) @@ -560,12 +571,13 @@ namespace AiQ_GUI // AiQ cameras if (!await Network.PingIP(ipOnly)) { + AddToActionsList($"Failed to ping camera at {ipOnly}", Level.DEBUG); CbBxFoundCams.BackColor = Color.Red; return; } BtnSecret.Enabled = true; - + AddToActionsList($"Retrieving API versions from {ipOnly}", Level.DEBUG); Vers = await FlexiAPI.GetVersions(ipOnly); // Wont be filled out before the pre test but needed for final test @@ -579,6 +591,7 @@ namespace AiQ_GUI if (Vers == null) // Flexi not running or not AiQ { AddToActionsList("Failed to get API from camera. Flexi not running yet or not an AiQ", Level.WARNING); + AddToActionsList($"API request returned null for {ipOnly}", Level.DEBUG); return; } @@ -654,8 +667,8 @@ namespace AiQ_GUI // ***** Helper functions ***** public void AddToActionsList(string Mssg, Level Lvl = Level.LOG) { - // DEBUG messages only visible to Bradley - if (Lvl == Level.DEBUG && CbBxUserName.Text != "Bradley") + // DEBUG messages only visible to Bradley and is checked + if (Lvl == Level.DEBUG && !ChBxDevLog.Checked) return; if (Lvl == Level.ERROR) @@ -1315,21 +1328,26 @@ namespace AiQ_GUI soakCtsList.Clear(); soakTasks.Clear(); + int soakCount = 0; foreach (Camera SCL in soakCameraList) { if (!SCL.IsChecked) continue; + soakCount++; + AddToActionsList($"Starting soak test for camera {soakCount}: {SCL.Serial} ({SCL.Model}) at {SCL.IP}", Level.DEBUG); CancellationTokenSource cts = new(); soakCtsList.Add(cts); soakTasks.Add(SoakTest.StartSoak(SCL, cts)); await Task.Delay(10000); } + AddToActionsList($"Soak test initiated for {soakCount} camera(s)", Level.DEBUG); } else { BtnSoak.BackColor = BtnColour; // Reset button colour BtnSoak.Text = "Start Soak"; + AddToActionsList($"Stopping soak test - cancelling {soakCtsList.Count} task(s)", Level.DEBUG); foreach (CancellationTokenSource cts in soakCtsList) cts.Cancel(); soakCtsList.Clear(); @@ -1338,6 +1356,7 @@ namespace AiQ_GUI string[,] Network_JSON = { { "propDHCP", "false" }, { "propHost", "192.168.1.211" }, { "propNetmask", "255.255.255.0" }, { "propGateway", "192.168.1.1" } }; string[,] GOD_JSON = { { "propGodMode", "false" } }; + AddToActionsList($"Finalizing soak: resetting {soakCameraList.Where(c => c.IsChecked).Count()} camera(s) to 211 and disabling God mode", Level.DEBUG); foreach (Camera SCL in soakCameraList.Where(c => c.IsChecked)) // only checked cameras { if (!SCL.IsChecked) @@ -1346,6 +1365,7 @@ namespace AiQ_GUI { 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 + AddToActionsList($"Resetting modules for {SCL.Serial}", Level.DEBUG); await CameraModules.FactoryResetModules(SCL.IP); // Reset camera modules string GOD = await FlexiAPI.HTTP_Update("GLOBAL--FlexiApplication", SCL.IP, GOD_JSON); @@ -1354,10 +1374,12 @@ namespace AiQ_GUI // Update GLOBAL--NetworkConfig with fixed IP and turn off DHCP await FlexiAPI.HTTP_Update("GLOBAL--NetworkConfig", SCL.IP, Network_JSON); + AddToActionsList($"Successfully configured {SCL.Serial} for 211 static IP", Level.DEBUG); i--; // Decriment count becuase they will stack into 211 } catch (Exception ex) { + AddToActionsList($"Configuration failed for {SCL.Serial}: {ex.Message}", Level.DEBUG); AddToActionsList("Failed to set all cameras to 211 and god mode off. Reason: " + ex.Message, Level.ERROR); // In case non AiQ's get caught up } @@ -1497,13 +1519,12 @@ public static Label MakeNewLabel(string text, bool isRed, int yLoc) //VLC.Play(VidView); //await Task.Delay(5000); //VLC.TakeSnapshot(VidView); - SSH.MobiletxtCheck("100.118.196.113"); + //SSH.MobiletxtCheck("100.118.196.113"); // await MobileAPI.SetDayModeAsync(); AddToActionsList("RunTime " + stopWatchTest.Elapsed.ToString(@"hh\:mm\:ss\.ff"), Level.DEBUG); } - } } diff --git a/LDS.cs b/LDS.cs index 7ffa46a..26f9e5e 100644 --- a/LDS.cs +++ b/LDS.cs @@ -30,7 +30,7 @@ namespace AiQ_GUI } catch // If file can't deserialise { - MainForm.Instance.AddToActionsList($"Error loading Local Data Store", Level.WARNING); + Logging.LogMessage($"Error loading Local Data Store"); // Have to log this somewhere else as MainForm wont be loaded and you will get a crossthread error return null; // Return null to indicate failure } } @@ -46,6 +46,7 @@ namespace AiQ_GUI catch (Exception ex) { MainForm.Instance.AddToActionsList($"Error saving Local Data Store: {ex.Message}", Level.WARNING); + } } } diff --git a/Soak/Selenium.cs b/Soak/Selenium.cs index 88ee13a..a1eb91c 100644 --- a/Soak/Selenium.cs +++ b/Soak/Selenium.cs @@ -11,11 +11,13 @@ namespace AiQ_GUI { try { + MainForm.Instance.AddToActionsList($"Navigating to {url}", Level.DEBUG); driver.Navigate().GoToUrl(url); // Wait until the document is fully loaded WebDriverWait wait = new(driver, TimeSpan.FromSeconds(10)); wait.Until(d => ((IJavaScriptExecutor)d).ExecuteScript("return document.readyState").Equals("complete")); + MainForm.Instance.AddToActionsList($"Page loaded successfully: {url}", Level.DEBUG); } catch (WebDriverTimeoutException) { @@ -26,6 +28,7 @@ namespace AiQ_GUI // Retrieves lates element ID for Shutter,iris, gain and IR public static ElementID GetElementIds(ChromeDriver driver) { + MainForm.Instance.AddToActionsList($"Retrieving element IDs from page", Level.DEBUG); ElementID elementID = new() { modeId = GetLatestElementIdContaining("Mode_", driver), @@ -35,6 +38,7 @@ namespace AiQ_GUI irLevelId = GetLatestElementIdContaining("CameraControls_", driver), CamAct = GetLatestElementIdContaining("CameraActivity_", driver) }; + MainForm.Instance.AddToActionsList($"Element IDs retrieved: Mode={elementID.modeId}, Shutter={elementID.shutterId}, Iris={elementID.irisId}", Level.DEBUG); return elementID; } @@ -70,6 +74,7 @@ namespace AiQ_GUI wait.Until(d => loginBtn.Displayed && loginBtn.Enabled); loginBtn.Click(); + MainForm.Instance.AddToActionsList($"Login button clicked, waiting for authentication", Level.DEBUG); MainForm.Instance.AddToActionsList($"Switched user and logged in.", Level.Success); } @@ -85,12 +90,15 @@ namespace AiQ_GUI { try { + MainForm.Instance.AddToActionsList($"Attempting to click element: {elementID}", Level.DEBUG); WebDriverWait wait = new(driver, TimeSpan.FromSeconds(10)); IWebElement element = wait.Until(driver => driver.FindElement(By.Id(elementID))); element.Click(); + MainForm.Instance.AddToActionsList($"Element clicked successfully: {elementID}", Level.DEBUG); } catch { + MainForm.Instance.AddToActionsList($"Failed to click {elementID}, refreshing page and retrying...", Level.DEBUG); if (tryagain) { driver.Navigate().Refresh(); @@ -108,6 +116,7 @@ namespace AiQ_GUI { try { + MainForm.Instance.AddToActionsList($"Initializing ChromeDriver with temp profile...", Level.DEBUG); ChromeOptions options = new(); options.AddArguments("--app=data:,", "--window-size=960,1040", @@ -121,6 +130,7 @@ namespace AiQ_GUI // Use a unique temporary profile to avoid conflicts string tempProfile = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); options.AddArguments($"--user-data-dir={tempProfile}"); + MainForm.Instance.AddToActionsList($"Chrome temp profile: {tempProfile}", Level.DEBUG); // manual driver path string driverPath = @"C:\ProgramData\MAV\AiQ_GUI"; @@ -129,6 +139,7 @@ namespace AiQ_GUI ChromeDriver driver = new(service, options); driver.Manage().Timeouts().PageLoad = TimeSpan.FromSeconds(5); + MainForm.Instance.AddToActionsList($"ChromeDriver initialized successfully", Level.DEBUG); return driver; } @@ -146,10 +157,14 @@ namespace AiQ_GUI IWebElement element = wait.Until(driver => driver.FindElement(By.Id(fullId))); await Logging.LogMessage($"Changing dropdown {fullId} to value: {value}", SoakLogFile); + MainForm.Instance.AddToActionsList($"Dropdown change: {fullId} -> {value}", Level.DEBUG); await Task.Delay(fullId.Contains("Mode_") ? 4000 : 200); if (value == element.GetAttribute("value")) + { + MainForm.Instance.AddToActionsList($"Dropdown {fullId} already set to {value}, no change needed", Level.DEBUG); return; // No change needed setting is already correct + } SelectElement select = new(element); @@ -157,7 +172,14 @@ namespace AiQ_GUI await Task.Delay(500); // Wait for the change to take effect if (!await Checkflashline(driver, CamAct)) + { + MainForm.Instance.AddToActionsList($"Flashline check failed after changing {fullId}", Level.DEBUG); Logging.LogWarningMessage("Bad flashline after changing: " + fullId, SoakLogFile); + } + else + { + MainForm.Instance.AddToActionsList($"Flashline OK after dropdown change", Level.DEBUG); + } } // Monitors the flashline element's color to determine success (green) or failure (red) of a camera diff --git a/Soak/SoakTest.cs b/Soak/SoakTest.cs index 67ffbd6..e6de30c 100644 --- a/Soak/SoakTest.cs +++ b/Soak/SoakTest.cs @@ -15,6 +15,7 @@ namespace AiQ_GUI string SoakLogFile = $"SoakLog_{CamInfo.Serial}_{CamInfo.Model}.log"; ChromeDriver driver = null; + MainForm.Instance.AddToActionsList($"Soak test started for {CamInfo.Serial} ({CamInfo.Model}) at {CamInfo.IP}", Level.DEBUG); try { @@ -24,18 +25,22 @@ namespace AiQ_GUI // Keep retrying until connected or cancelled bool connected = false; + int attemptCount = 0; while (!connected && !token.IsCancellationRequested) { try { + attemptCount++; // Attempt initial connection and navigation to setup tab Selenium.GoToUrl($"http://{CamInfo.IP}", driver); Selenium.SwitchUser(driver); Selenium.ClickElementByID("tabSetup", driver); + MainForm.Instance.AddToActionsList($"Successfully connected to {CamInfo.IP} on attempt {attemptCount}", Level.DEBUG); connected = true; } catch (Exception ex) { + MainForm.Instance.AddToActionsList($"Connection attempt {attemptCount} failed for {CamInfo.IP}: {ex.Message}", Level.DEBUG); SoakError($"Initial connection failed: {ex.Message}", SoakLogFile, CamInfo.CheckBox); MainForm.Instance.AddToActionsList($"[{CamInfo.IP}] Initial connection failed:{ex.Message}", Level.ERROR); @@ -52,20 +57,24 @@ namespace AiQ_GUI } catch (Exception ex) { + MainForm.Instance.AddToActionsList($"Failed to get element IDs from {CamInfo.IP}: {ex.Message}", Level.DEBUG); SoakError($"Failed to get element IDs: {ex.Message}", SoakLogFile, CamInfo.CheckBox); return; } int lastHour = DateTime.Now.Hour; + int loopCount = 0; while (!token.IsCancellationRequested) { try { + loopCount++; string TheString = "Selenium string: " + driver.Manage().Window.Size; // Fails out if Window doesn't exist. } catch { + MainForm.Instance.AddToActionsList($"Driver window lost, cancelling soak for {CamInfo.Serial}", Level.DEBUG); CTS.Cancel(); continue; }