refactor(gui,api,logging): UI layout tweaks, cleanup, and improved diagnostics

- CbBxCamType now spans the full width of CbBxCameraModel
- BtnTest_Click moved to the bottom of AiQ_GUI.cs for easier testing/navigation
- Unused using directives removed across files
- Login credentials factored out and reused in MobileAPI.cs
- VLC.cs Capture function reviewed and superseded by TakeSnapshot
- InsertCamTab implementation updated to avoid use of `var`
- Misleading '// Non-ONVIF cameras' comment corrected
- Added Level.Debug logging, accessible only to developers, for detailed diagnostics
This commit is contained in:
2026-01-15 16:36:17 +00:00
parent 4c74e237c2
commit 4dace8edef
9 changed files with 67 additions and 79 deletions

168
MobileTests/MobileAPI.cs Normal file
View File

@@ -0,0 +1,168 @@
using AiQ_GUI;
using System;
using System.Net.Http;
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace AiQ_GUI.Mobile_Tests
{
public static class MobileAPI
{
// Login credentials
private const string DefaultUsername = "ADMIN";
private const string DefaultPassword = "1234";
public static async Task CheckFirmwareAsync()
{
using HttpClient client = new HttpClient
{
BaseAddress = new Uri($"http://{MainForm.Instance.CamOnTest.IP}")
};
try
{
// Login and get JWT token
string token = await LoginAsync(client, DefaultUsername, DefaultPassword);
// Attach JWT to all requests
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
// Request firmware information
HttpResponseMessage response = await client.GetAsync("/app/v1/system/firmware");
string body = await response.Content.ReadAsStringAsync();
response.EnsureSuccessStatusCode();
JsonElement json = JsonSerializer.Deserialize<JsonElement>(body);
string version = json.GetProperty("version").GetString()?.Trim();
// Compare against expected SRZFirmware from UniversalData
if (string.IsNullOrEmpty(UniversalData.SRZFirmware))
{
MainForm.Instance.AddToActionsList($"Firmware check failed: Expected SRZFirmware not loaded in UniversalData", Level.ERROR);
MainForm.Instance.AddLabelToPanel($"Firmware = {version}", true);
}
else if (version == UniversalData.SRZFirmware)
{
MainForm.Instance.AddLabelToPanel($"Firmware = {version}", false);
}
else
{
MainForm.Instance.AddLabelToPanel($"Firmware = {version}", true);
}
}
catch (Exception ex)
{
MainForm.Instance.AddToActionsList($"Firmware check failed: {ex.Message}", Level.ERROR);
MainForm.Instance.AddLabelToPanel("Firmware = Unknown", true);
}
}
public static async Task ChangeDayNightModeAsync(uint mode)
{
// mode: 0 = Auto, 1 = Day, 2 = Night
string modeName = mode switch
{
0 => "Auto",
1 => "Day",
2 => "Night",
_ => "Unknown"
};
// operatingMode required by firmware (!)
// day -> 1, night -> 0
int operatingMode = mode switch
{
1 => 1, // Day
2 => 0, // Night
_ => 1 // Auto: keep day as safe default
};
using HttpClient client = new HttpClient
{
BaseAddress = new Uri($"http://{MainForm.Instance.CamOnTest.IP}")
};
try
{
// Login
string token = await LoginAsync(client, DefaultUsername, DefaultPassword);
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var payload = new
{
dayNightMode = new
{
mode = mode,
dayToNightSens = 4,
nightToDaySens = 24,
transitionDelay = 20,
operatingMode = operatingMode
}
};
HttpResponseMessage response = await client.PostAsJsonAsync("/app/v1/camera/image", payload);
if (response.IsSuccessStatusCode)
{
MainForm.Instance.AddToActionsList($"Camera set to {modeName} mode successfully",Level.Success);
}
else
{
string error = await response.Content.ReadAsStringAsync();
MainForm.Instance.AddToActionsList($"Failed to set {modeName} mode: {response.StatusCode} - {error}",Level.ERROR);
}
}
catch (Exception ex)
{
MainForm.Instance.AddToActionsList($"Error changing to {modeName} mode: {ex.Message}",Level.ERROR);
}
}
public static async Task SetDayModeAsync()
{
await ChangeDayNightModeAsync(1);
}
public static async Task SetNightModeAsync()
{
await ChangeDayNightModeAsync(2);
}
public static async Task SetAutoModeAsync()
{
await ChangeDayNightModeAsync(0);
}
private static async Task<string> LoginAsync(HttpClient client, string user, string password)
{
var payload = new
{
userId = user,
userPassword = Sha256(password)
};
HttpResponseMessage response = await client.PostAsJsonAsync("/app/v1/login", payload);
response.EnsureSuccessStatusCode();
JsonElement json = await response.Content.ReadFromJsonAsync<JsonElement>();
return json.GetProperty("token").GetString();
}
private static string Sha256(string input)
{
using SHA256 sha = SHA256.Create();
byte[] bytes = sha.ComputeHash(Encoding.UTF8.GetBytes(input));
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
}
}

View File

@@ -0,0 +1,83 @@
using LibVLCSharp.WinForms;
using System;
using System.Threading.Tasks;
namespace AiQ_GUI.Mobile_Tests
{
public static class MobileTests
{
public static async Task RunPreTestAsync()
{
await MobileAPI.CheckFirmwareAsync();// Check firmware version
VLC.Play(MainForm.Instance.VidView);// Test Live Video streaming
await Task.Delay(5000);
VLC.TakeSnapshot(MainForm.Instance.VidView);
if (!VLC.IsPLaying(MainForm.Instance.VidView))// Check Live Video streaming
{
MainForm.Instance.AddToActionsList("Live Video streaming test failed: Video is not playing.", Level.ERROR);
MainForm.Instance.AddLabelToPanel("Live Video = Not Playing", true);
}
else
{
MainForm.Instance.AddLabelToPanel("Live Video = Playing", false);
}
await TestDayNightMode();// Test day/night mode cycling
double dayLuminance = ImageProcessing.GetMeanLuminance(MainForm.Instance.DayImgPcbx.Image); // Calculates the Luminance
double nightLuminance = ImageProcessing.GetMeanLuminance(MainForm.Instance.NightImgPcbx.Image);
MainForm.Instance.DayImage.Text += $" - Luminance: {dayLuminance}%";
MainForm.Instance.NightImage.Text += $" - Luminance: {nightLuminance}%";
if (dayLuminance > nightLuminance)
{
MainForm.Instance.AddLabelToPanel("Day/Night Mode = Passed", false);
}
else
{
MainForm.Instance.AddToActionsList($"Day/Night mode test failed: Day luminance ({dayLuminance}%) is not greater than night luminance ({nightLuminance}%).", Level.ERROR);
MainForm.Instance.AddLabelToPanel("Day/Night Mode = Failed", true);
}
}
public static async Task RunFinalTestAsync()
{
// Placeholder for any final tests if needed in the future
//RunPreTestAsync().Wait();
//SSH.MobiletxtCheck(MainForm.Instance.CamOnTest.IP);// Verify mobile.txt presence
if (SSH.MobiletxtCheck(MainForm.Instance.CamOnTest.IP) == true)
{
MainForm.Instance.AddLabelToPanel("MobileSetup.sh = True", false);
}
else
{
MainForm.Instance.AddToActionsList("MobileSetup.sh test failed: mobile.txt not found on device.", Level.ERROR);
MainForm.Instance.AddLabelToPanel("MobileSetup.sh = False", true);
}
}
private static async Task TestDayNightMode()
{
await MobileAPI.SetDayModeAsync();// Set to Day mode
await Task.Delay(5000);
VLC.TakeSnapshot(MainForm.Instance.VidView, "Mobile_day_snapshot.png");// Take Day Image Snapshot
MainForm.Instance.DayImgPcbx.Image = System.Drawing.Image.FromFile(Path.Combine(LDS.MAVPath, "Mobile_day_snapshot.png"));// Display Day mode snapshot
await MobileAPI.SetNightModeAsync();// Set to Night mode
await Task.Delay(5000);
VLC.TakeSnapshot(MainForm.Instance.VidView, "Mobile_night_snapshot.png");// Take Night Image Snapshot
MainForm.Instance.NightImgPcbx.Image = System.Drawing.Image.FromFile(Path.Combine(LDS.MAVPath, "Mobile_night_snapshot.png"));// Display Night mode snapshot
}
}
}

43
MobileTests/VLC.cs Normal file
View File

@@ -0,0 +1,43 @@
using AiQ_GUI;
using Emgu.CV.Dai;
using LibVLCSharp.Shared;
using LibVLCSharp.WinForms;
using System.IO;
using System.Security.Policy;
internal class VLC
{
public static LibVLC libVLC;
static VLC()
{
// Ensure LibVLC is initialized before first use
Core.Initialize();
libVLC = new LibVLC();
}
public static string SnapshotPath = Path.Combine(LDS.MAVPath, "Mobile_ov_snapshot.png");
public static void Play(VideoView VLCVV)
{
var media = new Media(libVLC, $"rtsp://ADMIN:1234@{MainForm.Instance.CamOnTest.IP}:554/live/main", FromType.FromLocation);
VLCVV.MediaPlayer.Play(media);
}
public static bool IsPLaying(VideoView VLCVV)
{
return VLCVV.MediaPlayer.IsPlaying;
}
public static void TakeSnapshot(VideoView VLCVV, string filename = "Mobile_ov_snapshot.png")
{
string path = Path.Combine(LDS.MAVPath, filename);
VLCVV.MediaPlayer.TakeSnapshot(0, path, 1280, 720);
}
public static void Stop(VideoView VLCVV)
{
VLCVV.MediaPlayer.Stop();
}
}