Enhancing Metadata Management in VPS Toolkit: Adding Multiple Entries to Hardware Using C#

How can I add multiple metadata entries to a single hardware using the C# language? ( VPS Toolkit sample → VpsConfiguration → VpsConfiguration.csproj → VpsCameraBuilder.cs)

mipsdk-samples-vps/VPSToolkit/VpsConfiguration/VpsConfiguration/Admin/VpsCameraBuilder.cs at main · milestonesys/mipsdk-samples-vps (github.com)

With modification de code :

“”"

public static void BuildCameraForEachChild(

Item itemSelectedCameraGroup,

string cameraFormat,

string cameraGroupName,

string cameraSuffix,

string metadataGroupName,

string metadataSuffix,

string managementServerUrl,

string vpsServiceUrls,

string gstreamerPipelineConfig)

{

List cameraItems = itemSelectedCameraGroup.GetChildren();

string cameraNameH = “VPS_CAM”;

string username = string.Empty; // Setting username empty will create the hardware with the rights of the user running the recording server

string password = string.Empty;

Guid recordingServerId = none;

ManagementServer managementServer = new ManagementServer(Configuration.Instance.ServerFQID.ServerId);

foreach (Item cameraItem in cameraItems)

{

if (cameraItem.FQID.Kind == Kind.Camera && cameraItem.FQID.FolderType == [FolderType.No](https://FolderType.No "https://FolderType.No"))

{

   recordingServerId = cameraItem.FQID.ParentId;

}

}

Guid hardwareId = AddHardware(managementServerUrl, recordingServerId, username, password, cameraNameH, cameraGroupName, metadataGroupName);

Hardware hardware = new Hardware(EnvironmentManager.Instance.MasterSite.ServerId, $“Hardware[{hardwareId.ToString()}]”);

hardware.Name = cameraNameH;

hardware.Enabled = true;

hardware.Save();

//…

MetadataGroup metadataGroup = managementServer.MetadataGroupFolder.MetadataGroups.FirstOrDefault(g => g.Name == metadataGroupName);

if (metadataGroup == null)

{

// Create the metadata group if it does not already exist

AddDeviceGroupServerTask task = managementServer.MetadataGroupFolder.AddDeviceGroup();

task.GroupName = metadataGroupName;

task.GroupDescription = "";

ServerTask result = task.Execute();

while (true)

{

  StateEnum state = result.State;

  if (state == StateEnum.Error || state == StateEnum.Success)

  {

    break;

  }

  System.Threading.Thread.Sleep(500);

  result.UpdateState();

}

if (result.State != StateEnum.Error)

{

  metadataGroup = new MetadataGroup(Configuration.Instance.ServerFQID.ServerId, result.Path);

}

}

var cameraName= “”;

var namemeta = “”;

cameraName = cameraFormat;

foreach (Item cameraItem in cameraItems)

{

if (cameraItem.FQID.Kind == Kind.Camera && cameraItem.FQID.FolderType == [FolderType.No](https://FolderType.No "https://FolderType.No"))

{

  if (cameraName == cameraFormat)

  {

    cameraName = cameraFormat.Replace("##[#CAMERA\_NAME](javascript:void\(0\); "#CAMERA_NAME")###", [cameraItem.Name](https://cameraItem.Name "https://cameraItem.Name"));

    namemeta = [cameraItem.Name](https://cameraItem.Name "https://cameraItem.Name");

  }

  BuildOneCamera(cameraItem, managementServer, hardwareId, metadataGroup, hardware, cameraName, cameraGroupName, cameraSuffix, metadataGroupName, metadataSuffix, managementServerUrl, vpsServiceUrls, gstreamerPipelineConfig);

}

}

}

public static void BuildOneCamera(Item itemSelectedCamera,

ManagementServer managementServer,

Guid hardwareId,

MetadataGroup metadataGroup,

Hardware hardware,

string hardwareName,

string cameraGroupName,

string cameraSuffix,

string metadataGroupName,

string metadataSuffix,

string managementServerUrl,

string vpsServiceUrls,

string gstreamerPipelineConfig)

{

// get an instance of the source camera first, if it’s been deleted this will throw an exception

Camera sourceCamera = new Camera(itemSelectedCamera.FQID);

// Populate the camera device in the new hardware with relevant properties

ConfigureHardware(hardware, itemSelectedCamera.FQID.ObjectId.ToString(), vpsServiceUrls, gstreamerPipelineConfig);

// Name and enable the new metadata device

var metadata = new Metadata(itemSelectedCamera.FQID.ServerId, hardware.MetadataFolder.Metadatas.First().Path.ToString())

{

 //Metadata metadata = hardware.MetadataFolder.Metadatas.First();

 Name = $"{hardwareName} - {metadataSuffix}",

 Enabled = true

};

metadata.Save();

// Add the new metadata device to a specific metadata group.

// Don’t fail if the metadata group was not created. It does not prevent the process from running, it is merely convenience for the end user.

metadataGroup?.MetadataFolder.AddDeviceGroupMember(metadata.Path);

// Set the newly created metadata device as “related metadata device” for the original source camera device.

// This will cause the computed metadata’s bounding boxes to appear in the Smart Client.

ClientSettings clientSettings = sourceCamera.ClientSettingsFolder.ClientSettings.FirstOrDefault();

clientSettings.Related += $“,{metadata.Path}”;

clientSettings.Save();

}

“”"

Problem :

Result code with modified

I have a little difficulty getting an overview of this code, but as I read it BuildOneCamera will be called for every camera in itemSelectedCameraGroup passed to BuildCameraForEachChild and that one will add the metadata device as a related metadata to the camera, so the end result will be that the metadata becomes related to all cameras in the group, which seems incorrect.

Again, I am not sure I get this right, but if I do, I think that it is the “foreach (Item cameraItem in cameraItems)” loop at the end of BuildCameraForEachChild that is the issue and BuildOneCamera should instead only be called for the camera corresponding to the metadata.

Greetings,

To address this, how about we modify the code to ensure that each itemSelectedCamera can handle more than one metadata entry? For every camera, we loop through different metadata entries and make the connections accordingly.

In short, my plan is to jazz up the code so that each camera can jive with multiple metadata entries, giving us more wiggle room to play with metadata in the VPS Toolkit.

You are free to do that. There is no restrictions as such on how many related metadata devices you can add to each camera.

Thank you for the information. I’m interested in understanding how we can add multiple metadata entries using C#. Could you provide insights or guidelines on the approach we should take to accomplish this within the codebase?

I am not sure I entirely understand your question as your code to my understand already does that (although maybe not with the mapping you are looking for). I just tested and the following (very similar to yours) works fine for adding all existing metadata devices in the first available group to the list of related devices for the provided camera:

       ManagementServer managementServer = new ManagementServer(EnvironmentManager.Instance.MasterSite.ServerId);

       var clientSetting = camera.ClientSettingsFolder.ClientSettings.FirstOrDefault();

       foreach (var metadata in managementServer.MetadataGroupFolder.MetadataGroups.FirstOrDefault().MetadataFolder.Metadatas)

       {

           if (!string.IsNullOrEmpty(clientSetting.Related))

               clientSetting.Related += ",";

           clientSetting.Related += metadata.Path;

       }

       clientSetting.Save();

I appreciate the clarification. What I aim to achieve is to ensure that each camera has a single metadata entry associated with it, all within a single hardware device. To accomplish this, I’m looking to iterate through each camera and assign a single metadata entry to its related devices list, ensuring a one-to-one relationship between cameras and metadata entries, all under a single hardware device

As I see it you already have all the pieces for doing that. I would suggest setting the camera as related device for the metadata as well in order to more easily keep track of which metadata has been assigned to which camera. You can do that in pretty much the same way as you do for the cameras, but it is just not visible in the Management Client.

I’d like to understand how we can add metadata to the hardware using C#. Could you provide guidance on the steps or methods we can employ to achieve this within our codebase?

I am not an expert on the VPS driver, but if you can make the ‘device side’ answer back with the updated number of metadata channels, you can call Hardware.UpdateHardware() to have XProtect update the number of channels. The task returned by UpdateHardware will contain a session ID which should be used in a subsequent call to UpdateHardware(sessionId) in order to confirm the update.