Getting All Cameras from Multiple Management Servers

Hi All,

Looking for some advice on the best/quickest way to get all (including disabled) cameras (~7000) from 8 different management servers spread around the country so network latency can be significant. I’ve looked at both the Configuration API walking the trees looking for any Kind.Camera and also getting all of the RecordingServer’s, asking for the Hardware folder and looping over all of the hardware and asking for Cameras.

I see a different number of cameras when doing it each of those ways, neither seeming to match the powershell Get-VmsHardware -filter All

I’ve tried some multi-threading to speed things up as well but I’m not clear on how the MultiEnvironment works and if I login to all 8 servers does Configuration.Instance.GetItems() return for all 8 servers? Or if using Enviroment.Instance.CurrentSite how to specify which site to use?

So, looking any advice for best practices on something like this and how to use multiple mgmt servers.

Thanks!

The current solution I’m using that is working pretty well is using MultiEnviroment and creating a thread for each server and then getting the CameraGroups, recursively walking the groups for nested ones and getting all the Cameras in each group. I was able to get all ~7000 cameras from what ended up actually being 10 servers in about 3 minutes.

Would still be interested in hearing other thoughts on this.

Code snippets:



public static async Task<List<Camera>> Start()
{
    Console.WriteLine("Initializing Milestone SDK...");

    VideoOS.Platform.SDK.Environment.Initialize();
    MultiEnvironment.InitializeUsingUserContext();

    Console.WriteLine($"Starting parallel connection to {ServerList.Count} servers...\n");

    foreach (ServerInfo info in ServerList) {
        Uri uri = new Uri(info.Uri);
        var context = MultiEnvironment.CreateSingleServerUserContext(false, info.User, info.Pass, true, uri);
        if (MultiEnvironment.LoginUserContext(context))
        {
            activeContexts.Add(context);
        }
    }

    List<Camera> cameras = new List<Camera>();
    List<Task> tasks = new List<Task>();

    foreach (var c in activeContexts)
    {
        Task t = Task.Factory.StartNew(() => GetAllCameras(c, cameras));
        tasks.Add(t);
    }

    //// 3. WAIT FOR ALL TO FINISH
    await Task.WhenAll(tasks);

    Console.WriteLine($"\nAll server scans complete. {cameras.Count} cameras found.");
    return cameras;
}


static async Task GetAllCameras(UserContext userContext, List<Camera> mainList)
{
    VideoOS.Platform.ConfigurationItems.ManagementServer managementServer = new VideoOS.Platform.ConfigurationItems.ManagementServer(userContext.Configuration.ServerFQID);

    List<CameraGroup> groups = managementServer.CameraGroupFolder.CameraGroups.ToList();
    List<Camera> cameras = new List<Camera>();
    foreach (CameraGroup group in groups) { 
        GetAllCamerasGroupWalk(group, cameras);
    }
    mainList.AddRange(cameras);
    
}


 static public void GetAllCamerasGroupWalk(CameraGroup group, List<Camera> cams)
 {
     List<CameraGroup> childGroups = group.CameraGroupFolder.CameraGroups.ToList();
     if(childGroups != null && childGroups.Count > 0)
     {
         foreach(CameraGroup childGroup in childGroups)
         {
             GetAllCamerasGroupWalk(childGroup, cams);
         }
     }
     
     List<Camera> cameras = group.CameraFolder.Cameras.ToList();
     if (cameras != null && cameras.Count > 0)
     {
         Console.WriteLine($"Adding {cameras.Count} cameras for group {group.Name}");
         cams.AddRange(cameras);
     }
 }


public class ServerInfo
{
    public string Uri { get; }
    public string User { get; }
    public string Pass { get; }
    public bool IsSecure { get; }

    public ServerInfo(string uri, string user, string pass, bool secure)
    {
        Uri = uri; User = user; Pass = pass; IsSecure = secure;
    }
}

I have one remark. When using CameraGroups you will get all the cameras that are in one or more camera groups, it is possible to have a camera that does not belong to any camera group.
If you want to make sure that you get the cameras that are not in any group an alternative route is:
var cam = mgt.RecordingServerFolder.RecordingServers.FirstOrDefault().HardwareFolder.Hardwares.FirstOrDefault().CameraFolder.Cameras.FirstOrDefault();

Code is for illustration, you want foreach loops instead of finding FirstOrDefault.

Instead of using the Config API there is the Configuration, but this does not include any disabled cameras. For a quick view on this alternative I recommend this topic.