using System.ComponentModel; using System.Diagnostics; using System.Net; using System.Net.NetworkInformation; using System.Text.Json; using System.Text.Json.Serialization; using System.Windows.Forms; using Tmds.MDns; using static robospot_camera_finder.MainForm; namespace robospot_camera_finder { public partial class MainForm : Form { private readonly ServiceBrowser browser = new(); private BindingList all_cameras = new(); public static string cam_username = "admin"; public static string cam_password = "RoboSpot10"; private static string browse_scope = "_rtsp._tcp"; bool is_browsing = false; public class Camera { public Camera(string name, string ip, string location, string serial) { camera_name = name; camera_ip = ip; camera_location = location; camera_serial = serial; } public Camera() { } public string camera_name { get; set; } public string camera_ip { get; set; } public string camera_location { get; set; } public string camera_serial { get; set; } } public MainForm() { InitializeComponent(); bool got_proper_ip = false; foreach (var net_interface in NetworkInterface.GetAllNetworkInterfaces()) { IPInterfaceProperties prop = net_interface.GetIPProperties(); foreach (var ip in prop.UnicastAddresses) { if (ip.Address.ToString().StartsWith("10.")) { if (ip.IPv4Mask.ToString() == "255.0.0.0") { got_proper_ip = true; } } } } if (!got_proper_ip) { DialogResult open_netsettings = MessageBox.Show("No Ethernet interface on the 10.0.0.0/8 subnet found. Cameras might not be detected. Do you want to open network settings ?", "Wrong IP configuration", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1); if (open_netsettings == DialogResult.Yes) { ProcessStartInfo startInfo = new ProcessStartInfo("NCPA.cpl"); startInfo.UseShellExecute = true; Process.Start(startInfo); } } lbMain.DataSource = all_cameras; lbMain.DisplayMember = "camera_name"; lbMain.ValueMember = "camera_ip"; browser.ServiceAdded += (sender, args) => { ServiceAdded(sender, args); }; browser.ServiceChanged += (sender, args) => { ServiceAdded(sender, args); }; browser.ServiceRemoved += (sender, args) => { if (browser.IsBrowsing) { ServiceRemoved(sender, args); } }; browse(true); } private void browse(bool browse_needed) { if (browse_needed) { if (!browser.IsBrowsing) { browser.StartBrowse(browse_scope); is_browsing = true; toolStripStatusDisco.Text = "Discovery : Started"; } } else { if (browser.IsBrowsing) { browser.StopBrowse(); is_browsing = false; toolStripStatusDisco.Text = "Discovery : Stopped"; } } startToolStripMenuItem.Enabled = !browser.IsBrowsing; stopToolStripMenuItem.Enabled = browser.IsBrowsing; } private void ServiceAdded(object sender, ServiceAnnouncementEventArgs args) { foreach (var cam_addr in args.Announcement.Addresses) { if (cam_addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://" + cam_addr + "/stw-cgi/system.cgi?msubmenu=deviceinfo&action=view"); request.Credentials = new NetworkCredential(MainForm.cam_username, MainForm.cam_password); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); string text; using (var sr = new StreamReader(response.GetResponseStream())) { text = sr.ReadToEnd(); } string[] resp_lines = text.Split('\n'); string location_line = Array.Find(resp_lines, line => line.Trim().StartsWith("DeviceLocation=")); string serial_line = Array.Find(resp_lines, line => line.Trim().StartsWith("SerialNumber=")); string location = ""; string serial = ""; if (location_line != null) { location = location_line.Substring("DeviceLocation=".Length).Trim(); } if (serial_line != null) { serial = serial_line.Substring("SerialNumber=".Length).Trim(); } Camera new_camera = new Camera("Camera " + cam_addr + " - " + location + " - " + serial, cam_addr.ToString(), location, serial); add_camera(new_camera); } } } private void add_camera(Camera new_camera) { if (all_cameras.Count == 0) { all_cameras.Add(new_camera); } else { Camera find_cam = all_cameras.FirstOrDefault(cam => cam.camera_serial == new_camera.camera_serial); if (find_cam != null) { int i = all_cameras.IndexOf(find_cam); all_cameras[i] = new_camera; } else { all_cameras.Add(new_camera); } } } private void ServiceRemoved(object sender, ServiceAnnouncementEventArgs args) { foreach (var cam_ip in args.Announcement.Addresses) { if (cam_ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork) { foreach (var camera in all_cameras) { if (cam_ip.ToString() == camera.camera_ip) { all_cameras.Remove(camera); return; } } } } } private void MainForm_FormClosing(object sender, FormClosingEventArgs e) { browser.StopBrowse(); } private void lbMain_MouseDoubleClick(object sender, MouseEventArgs e) { if (lbMain.SelectedItem != null) { toolStripStatusLabel.Text = "Loading camera..."; Camera camera = all_cameras.FirstOrDefault(cam => cam.camera_ip.ToString() == lbMain.SelectedValue.ToString()); Form viewer = new StreamViewer(lbMain.GetItemText(lbMain.SelectedItem), lbMain.SelectedValue.ToString(), camera, this); viewer.Show(); toolStripStatusLabel.Text = ""; } } private void startToolStripMenuItem_Click(object sender, EventArgs e) { browse(true); } private void stopToolStripMenuItem_Click(object sender, EventArgs e) { browse(false); } private void forceReloadToolStripMenuItem_Click(object sender, EventArgs e) { DialogResult result = MessageBox.Show("Are you sure you want to clear discovered cameras and restart the discovery process ?", "Warning", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result == DialogResult.Yes) { browse(false); all_cameras.Clear(); browse(true); } } private void loadToolStripMenuItem_Click(object sender, EventArgs e) { string json = ""; OpenFileDialog openFile = new OpenFileDialog(); openFile.Filter = "json file (*.json)|*.json"; openFile.RestoreDirectory = true; if (openFile.ShowDialog() == DialogResult.OK) { json = File.ReadAllText(openFile.FileName); List cameras_in_file = JsonSerializer.Deserialize>(json); foreach (Camera new_camera in cameras_in_file) { add_camera(new_camera); } } } private void saveToolStripMenuItem_Click(object sender, EventArgs e) { string json = JsonSerializer.Serialize>(all_cameras, new JsonSerializerOptions { WriteIndented = true }); SaveFileDialog saveFile = new SaveFileDialog(); saveFile.Filter = "json file (*.json)|*.json"; saveFile.RestoreDirectory = true; if (saveFile.ShowDialog() == DialogResult.OK) { File.WriteAllText(saveFile.FileName, json); } } private void manualAddToolStripMenuItem_Click(object sender, EventArgs e) { Manual_IP_Form manualForm = new Manual_IP_Form(); if (manualForm.ShowDialog(this) == DialogResult.OK) { string ipAddress = manualForm.ipAddress; Camera camera_to_add = new Camera("Camera " + ipAddress, ipAddress, "", ""); add_camera(camera_to_add); } } } }