-
Notifications
You must be signed in to change notification settings - Fork 4
plugin sdk custom entities
Custom entity types extend Security Center with new entity types specific to your plugin. Each custom entity type has its own type descriptor, icons, capabilities, and access privileges.
A custom entity type defines a new category of entities in Security Center. Examples include:
- ATMs monitored for skimming devices and service status
- Evidence lockers with chain-of-custody tracking
- Casino gaming tables with occupancy and activity states
- Drone patrol units reporting position and battery level
- Clean room zones with contamination alerts
Custom entities differ from built-in entities like cameras and doors. You define their structure, behavior, and how they integrate with the Security Center UI.
Register custom entity types through SystemConfiguration.AddOrUpdateCustomEntityType(). Only administrators can register or modify custom entity types.
var systemConfig = (SystemConfiguration)engine.GetEntity(SystemConfiguration.SystemConfigurationGuid);
var descriptor = new CustomEntityTypeDescriptor(
id: new Guid("YOUR-CUSTOM-TYPE-GUID"),
name: "Evidence Locker",
capabilities: CustomEntityTypeCapabilities.IsVisible | CustomEntityTypeCapabilities.HasRunningState,
version: new Version(1, 0, 0));
systemConfig.AddOrUpdateCustomEntityType(descriptor);The id must be a unique GUID that identifies your custom entity type. Use the same GUID consistently across plugin versions.
The version parameter is required but the platform does not act on it. Use it for your own internal versioning to track type definition changes.
Entities do not store their own version. They only store a reference to their type GUID. When you access entity.TypeDescriptor, it fetches the current type descriptor from SystemConfiguration. This means when you update the type descriptor version, all existing entities immediately see the new version.
// Check the registered version before updating
CustomEntityTypeDescriptor registered = systemConfig.GetCustomEntityTypeDescriptor(evidenceLockerTypeGuid);
Version currentPluginVersion = new Version(2, 1, 0);
if (registered == null)
{
// First time registration
var descriptor = new CustomEntityTypeDescriptor(
id: evidenceLockerTypeGuid,
name: "Evidence Locker",
capabilities: CustomEntityTypeCapabilities.IsVisible,
version: currentPluginVersion);
systemConfig.AddOrUpdateCustomEntityType(descriptor);
}
else if (registered.Version < currentPluginVersion)
{
// Type exists with older version - migrate existing entities first
MigrateEntities(registered.Version, currentPluginVersion);
// Then update the type descriptor
registered.Version = currentPluginVersion;
systemConfig.AddOrUpdateCustomEntityType(registered);
}Since the platform does not compare versions, your plugin is responsible for:
- Checking the registered version at startup
- Migrating existing entity data before updating the type descriptor
- Updating the type descriptor after migration completes
Capabilities define what features your custom entity type supports:
| Capability | Description |
|---|---|
None |
No special capabilities |
CreateDelete |
Entities can be created and deleted from Config Tool |
MapSupport |
Entities can be placed on maps |
HasRunningState |
Entities display a running state indicator |
CanBeFederated |
Entities can be federated to other systems |
IsVisible |
Entities appear in the system UI |
MaintenanceMode |
Entities can be put into maintenance mode |
Combine capabilities using bitwise OR:
var capabilities = CustomEntityTypeCapabilities.IsVisible
| CustomEntityTypeCapabilities.HasRunningState
| CustomEntityTypeCapabilities.MapSupport;Set SingleInstance to true to allow only one entity of this type in the directory:
descriptor.SingleInstance = true;Set icons for your custom entity type to distinguish it in the UI:
descriptor.SetLargeIcon(largeBitmap); // For entity browser and details
descriptor.SetSmallIcon(smallBitmap); // For tree views and listsCustom entity types can require specific privileges for view, add, modify, and delete operations. See Defining custom privileges for how to define custom privileges.
// Associate custom privileges with the entity type
descriptor.ViewPrivilege = new SdkPrivilege(viewPrivilegeGuid);
descriptor.AddPrivilege = new SdkPrivilege(addPrivilegeGuid);
descriptor.ModifyPrivilege = new SdkPrivilege(modifyPrivilegeGuid);
descriptor.DeletePrivilege = new SdkPrivilege(deletePrivilegeGuid);You can also set all privileges at once:
descriptor.SetAccessPrivileges(
view: new SdkPrivilege(viewPrivilegeGuid),
add: new SdkPrivilege(addPrivilegeGuid),
delete: new SdkPrivilege(deletePrivilegeGuid),
modify: new SdkPrivilege(modifyPrivilegeGuid));Define which events your custom entity type can generate:
// Support standard Security Center events
descriptor.SupportedEvents = new[]
{
EventType.EntityOnline,
EventType.EntityOffline,
EventType.CustomEvent
};
// Support custom events by ID
descriptor.SupportedCustomEvents = new[] { 1001, 1002, 1003 };Custom entities can have hierarchical relationships with other entities.
The following entity types can be children of a custom entity:
- Area, Camera, Door, Elevator, Zone, IntrusionArea, Sequence, AnalogMonitor, ParkingZone, TilePlugin, TileLayout, CashRegister
- Cardholder, Credential
- VideoUnit, AccessControlUnit, LprUnit, Patroller
- Other custom entities (via
HierarchicalChildCustomTypes)
Note
Device and AccessPoint cannot be added as children of a custom entity.
Define which entity types your custom entity accepts as children:
descriptor.HierarchicalChildTypes = new[]
{
EntityType.Camera,
EntityType.Door
};
descriptor.HierarchicalChildCustomTypes = new[]
{
compartmentTypeGuid,
shelfTypeGuid
};A custom entity can only have Area or another CustomEntity as a parent. See Managing hierarchical relationships for how to add parents programmatically.
Create instances of your custom entity type using CreateCustomEntity():
CustomEntity locker = engine.CreateCustomEntity("Locker A-101", customEntityTypeGuid);To create with a parent entity:
CustomEntity compartment = engine.CreateCustomEntity("Compartment 1", compartmentTypeGuid, lockerGuid);Custom entities provide four storage fields:
| Property | Persistent | Description |
|---|---|---|
Xml |
Yes | Primary configuration storage, persisted to the database |
XmlExtra |
Yes | Secondary configuration storage, persisted to the database |
State |
No | Primary runtime state, cleared when the entity goes offline or the system restarts |
StateExtra |
No | Secondary runtime state, cleared when the entity goes offline or the system restarts |
Despite the property names, these fields accept any string format. You can store XML, JSON, or any serialized data:
var locker = (CustomEntity)engine.GetEntity(lockerGuid);
// XML format
locker.Xml = "<config><compartments>4</compartments></config>";
// JSON format works too
locker.XmlExtra = "{\"firmware\": \"2.1.0\", \"lastSync\": \"2024-01-15T10:30:00Z\"}";
// Runtime state (requires ownership when the entity is owned)
locker.State = "<state><locked>true</locked></state>";Note
State and StateExtra require entity ownership. If the entity is owned by a plugin, only that plugin can modify them; otherwise any user with write access can. Any user with write access can modify Xml and XmlExtra.
Add and remove parent-child relationships:
var locker = (CustomEntity)engine.GetEntity(lockerGuid);
// Add a child entity
locker.AddHierarchicalChild(compartmentGuid);
// Remove a child entity
locker.RemoveHierarchicalChild(compartmentGuid);
// Add a parent (must be Area or CustomEntity)
locker.AddHierarchicalParent(areaGuid);
// Remove a parent
locker.RemoveHierarchicalParent(areaGuid);Custom entity types with the HasRunningState capability can report their operational status. The owning plugin sets the running state when the entity is owned:
var locker = (CustomEntity)engine.GetEntity(lockerGuid);
// Set running state (requires ownership when the entity is owned)
locker.RunningState = State.Running;
locker.RunningState = State.Warning;
locker.RunningState = State.NotRunning;Read the current state:
State currentState = locker.RunningState;
bool isOnline = locker.IsOnline; // true when Running or WarningCustom entity types with the MaintenanceMode capability can be put into maintenance mode. This sets the entity's maintenance state.
var locker = (CustomEntity)engine.GetEntity(lockerGuid);
// Enable maintenance indefinitely
locker.EnableMaintenance("Scheduled firmware update");
// Enable maintenance until a specific time
locker.EnableMaintenance(DateTime.UtcNow.AddHours(2), "Hardware inspection");Check maintenance status:
bool inMaintenance = locker.IsInMaintenance;
bool supportsIt = locker.IsMaintenanceSupported;
DateTime? endTime = locker.MaintenanceEndTime;
string reason = locker.MaintenanceReason;Query for custom entities using EntityConfigurationQuery:
var query = (EntityConfigurationQuery)engine.ReportManager.CreateReportQuery(ReportType.EntityConfiguration);
query.EntityTypeFilter.Add(EntityType.CustomEntity);
query.CustomEntityTypes.Add(customEntityTypeGuid);
QueryCompletedEventArgs results = query.Query();
foreach (DataRow row in results.Data.Rows)
{
Guid entityGuid = (Guid)row["Guid"];
var entity = (CustomEntity)engine.GetEntity(entityGuid);
}Get all registered custom entity types:
var systemConfig = (SystemConfiguration)engine.GetEntity(SystemConfiguration.SystemConfigurationGuid);
IReadOnlyCollection<CustomEntityTypeDescriptor> types = systemConfig.GetCustomEntityTypeDescriptors();
foreach (CustomEntityTypeDescriptor type in types)
{
Console.WriteLine($"{type.Name} (v{type.Version})");
}Get a specific type descriptor:
CustomEntityTypeDescriptor descriptor = systemConfig.GetCustomEntityTypeDescriptor(customEntityTypeGuid);Access the type descriptor from an entity instance:
var entity = (CustomEntity)engine.GetEntity(entityGuid);
CustomEntityTypeDescriptor descriptor = entity.TypeDescriptor;Remove a custom entity type definition:
var systemConfig = (SystemConfiguration)engine.GetEntity(SystemConfiguration.SystemConfigurationGuid);
systemConfig.RemoveCustomEntityType(customEntityTypeGuid);Warning
If any entities of this type exist, RemoveCustomEntityType fails with SdkException (TransactionFailed). Remove or migrate those entities before removing the type descriptor.
Define which properties within Xml or XmlExtra should be included in audit trails when they change:
descriptor.AuditableProperties = new[]
{
new CustomEntityAuditableProperty
{
Path = "config/compartments",
Name = "Compartment Count",
SourceProperty = AuditPropertySource.Xml,
Hints = AuditPropertyHints.Xml
},
new CustomEntityAuditableProperty
{
Path = "firmware",
Name = "Firmware Version",
SourceProperty = AuditPropertySource.XmlExtra,
Hints = AuditPropertyHints.Json
}
};The Path property specifies the location of the auditable value within the serialized data. For XML, include the root node:
-
config/compartments- Targets<config><compartments>in theXmlproperty -
settings/lastSync- Targets<settings><lastSync>in theXmlExtraproperty
For JSON data stored in these fields, use the same path format but set the appropriate hint.
| Value | Description |
|---|---|
Xml |
The auditable property is in the Xml field |
XmlExtra |
The auditable property is in the XmlExtra field |
Combine hints using bitwise OR to control how the audit trail displays the value:
| Hint | Description |
|---|---|
None |
Not valid by itself; use Xml or Json
|
UtcDate |
Format the value as a UTC date |
Collection |
The value is a collection |
Xml |
The data format is XML |
Json |
The data format is JSON |
Use NameKey instead of Name for localized audit trail entries:
new CustomEntityAuditableProperty
{
Path = "config/compartments",
NameKey = "AuditProperty_CompartmentCount",
SourceProperty = AuditPropertySource.Xml
}For localization to work, the NameKey value should exist in the resource manager specified by ResourceManagerTypeName on the type descriptor. If the key cannot be resolved, the audit trail falls back to the Name property, or displays the unknown label if Name is not provided.
Configure localization for your custom entity type to display translated names in the Security Center UI.
- Create a resource file (typically in your workspace module or plugin assembly) with translations for the languages you want to support. Missing translations will fall back to the
Nameproperty. - Set the
ResourceManagerTypeNameto the assembly-qualified name of your resource manager - Use
NameKeyinstead ofNamefor the entity type name
descriptor.ResourceManagerTypeName = typeof(MyPluginResources).AssemblyQualifiedName;
descriptor.NameKey = "EntityType_EvidenceLocker";The assembly containing the resource manager must be loaded on the client machine. This typically happens when your workspace module loads.
Audit trail entries can also be localized by using NameKey on CustomEntityAuditableProperty instead of Name. The key is resolved using the same resource manager.
Note
If the resource assembly is not available on the client, the localized value is not resolved. The audit trail uses Name when provided; otherwise it displays the unknown label.
| Property | Description |
|---|---|
Name |
Display name for the entity type |
NameKey |
Localization key for the name |
Version |
Version number of the type definition |
SingleInstance |
When true, only one entity of this type can exist |
DefaultMapLayerId |
Default map layer for entities of this type |
ResourceManagerTypeName |
Assembly-qualified name of the resource manager for localization |
AuditableProperties |
Properties to include in audit trails |
Store additional metadata in the type descriptor using the indexer:
// Set a custom property
descriptor["MyPlugin.Category"] = "Environmental";
// Get a custom property
string category = descriptor["MyPlugin.Category"];
// Enumerate all properties
foreach (var kvp in descriptor.EnumerateValues())
{
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}The following property keys are reserved for internal use. Setting any of these keys throws an SdkException:
| Reserved Key | Purpose |
|---|---|
SC.Name |
Type display name |
SC.NameKey |
Localization key for name |
SC.Capabilities |
Capability flags |
SC.LargeIcon |
Large icon identifier |
SC.SmallIcon |
Small icon identifier |
SC.SupportedEvents |
Supported event types |
SC.AccessPrivileges |
Access privilege configuration |
SC.ChildCustomEntityTypesSupported |
Allowed child custom entity types |
SC.ChildEntityTypesSupported |
Allowed child entity types |
SC.Version |
Type descriptor version |
SC.ResourceType |
Resource manager type for localization |
SC.AuditProperties |
Auditable property configuration |
SC.SingleInstance |
Single instance restriction |
SC.DefaultMapLayer |
Default map layer identifier |
Use a prefix that does not conflict with the current reserved keys, such as avoiding the SC. prefix.
-
Security Center SDK Developer Guide Overview of the SDK framework and how to build integrations with Security Center.
-
Platform SDK
- Overview Introduction to the Platform SDK and core concepts.
- Connecting to Security Center Step-by-step guide for connecting and authenticating with the SDK.
- SDK Certificates Details certificates, licensing, and connection validation.
- Referencing SDK Assemblies Best practices for referencing assemblies and resolving them at runtime.
- SDK Compatibility Guide Understanding backward compatibility and versioning in the SDK.
- Entity Guide Explains the core entity model, inheritance, and how to work with entities.
- Entity Cache Guide Describes the engine's local entity cache and synchronization.
- Transactions Covers batching operations for performance and consistency.
- Events Subscribing to real-time system events.
- Actions Sending actions to Security Center.
- Security Desk Displaying content on monitors, reading tiles, sending tasks, and messaging operators.
- Custom Events Defining, raising, and subscribing to custom events.
- ReportManager Querying entities and activity data from Security Center.
- ReportManager Query Reference Complete reference of query types, parameters, and response formats.
- Privileges Checking, querying, and setting user privileges.
- Partitions Entity organization and access control through partitions.
- Logging How to configure logging, diagnostics, and debug methods.
-
Plugin SDK
- Overview Introduction to plugin architecture and capabilities.
- Certificates SDK certificate requirements for plugin roles.
- Lifecycle Initialization and disposal patterns.
- Threading Threading model, QueueUpdate, and async patterns.
- State Management Reporting plugin health and diagnostics.
- Configuration Configuration storage and monitoring.
- Restricted Configuration Secure credential storage and admin-only configuration.
- Events Event subscription and handling.
- Queries Query processing and response handling.
- Request Manager Request/response communication with clients.
- Database Database integration and schema management.
- Entity Ownership Understanding plugin-owned entities, running state management, and ownership release.
- Entity Mappings Using EntityMappings for plugin-specific configuration and external system integration.
- Server Management High availability and server failover.
- Custom Privileges Defining and enforcing custom privileges.
- Custom Entity Types Defining and managing plugin-specific entity types.
- Resolving Non-SDK Assemblies Handling third-party dependencies in plugins and workspace modules.
- Deploying Plugins Registering and deploying plugins and workspace modules.
- .NET 8 Support Building plugins with .NET 8 and .NET Standard compatibility.
-
Workspace SDK
- Overview Introduction to client-side UI extensions for Security Desk and Config Tool.
- Certificates SDK certificate requirements for workspace modules.
- Creating Modules Module lifecycle, registration patterns, and assembly resolution.
- Tasks Executable actions, home page entries, and programmatic invocation.
- Pages Page content, lifecycle, descriptors, and navigation.
- Components Dashboard widgets, tiles, maps, credentials, and content builders.
- Tile Extensions Custom tile widgets, views, and properties panels.
- Services Built-in services for dialogs, maps, alarms, badges, and more.
- Contextual Actions Right-click context menu extensions.
- Options Extensions Custom settings pages in application preferences.
- Configuration Pages Entity configuration pages for Config Tool.
- Monitors Multi-monitor support and shared components.
- Shared Components Using monitor and workspace shared UI components.
- Commands Command execution, evaluation, and interception.
- Extending Events Adding custom fields to Security Center events.
- Map Extensions Custom map objects, layers, and providers.
- Timeline Providers Custom timeline event sources for video playback.
- Image Extractors Custom image sources for cardholder photos and custom fields.
- Credential Encoders Encoding credentials with custom encoder components.
- Cardholder Fields Extractors Importing cardholder data from external sources.
- Content Builders Building and customizing tile content in Security Desk.
-
Macro SDK
- Overview How macros work, creating and configuring macro entities, automation, and monitoring.
- Developer Guide Developing macro code with the UserMacro class and Security Center SDK.
-
- Getting Started Setup, authentication, and basic configuration for the Web SDK.
- Referencing Entities Entity discovery, search capabilities, and parameter formats.
- Entity Operations CRUD operations, multi-value fields, and method execution.
- Partitions Managing partitions, entity membership, and user access control.
- Custom Fields Creating, reading, writing, and filtering custom entity fields.
- Custom Card Formats Managing custom credential card format definitions.
- Actions Control operations for doors, cameras, macros, and notifications.
- Events and Alarms Real-time event monitoring, alarm monitoring, and custom events.
- Incidents Incident management, creation, and attachment handling.
- Reports Activity reports, entity queries, and historical data retrieval.
- Tasks Listing and executing saved report tasks.
- Macros Monitoring currently running macros.
- Custom Entity Types Listing, retrieving, and deleting custom entity type descriptors.
- System Endpoints License usage, web tokens, and exception handling.
- Performance Guide Optimization tips and best practices for efficient API usage.
- Reference Entity GUIDs, EntityType enumeration, and EventType enumeration.
- Under the Hood Technical architecture, query reflection, and SDK internals.
- Troubleshooting Common error resolution and debugging techniques.
- Media Gateway Guide Setup and configuration of the Media Gateway role for video streaming.
- Developer Guide Complete guide to integrating GWP for live and playback video streaming.
- API Reference Full API documentation with interfaces, methods, properties, and events.
- Sample Application Comprehensive demo showcasing all GWP features with timeline and PTZ controls.
- Multiplexing Sample Multi-camera grid demo using a shared WebSocket connection.