-
Notifications
You must be signed in to change notification settings - Fork 4
plugin sdk configuration
Plugins store configuration in the Role.SpecificConfiguration property as a serialized string (typically JSON).
PluginDescriptor.SpecificDefaultConfig
↓
Provides default configuration when role is created
↓
Role.SpecificConfiguration
↓
Stored in Security Center database
↓
Plugin reads on startup and monitors for changes
Key points:
- Configuration is stored per-role instance
- Multiple instances of same plugin have separate configurations
- Changes persist across plugin restarts
- Configuration changes trigger
EntitiesInvalidatedevent - Configuration is a string, plugin chooses serialization format
Define defaults in PluginDescriptor.SpecificDefaultConfig:
public class MyPluginDescriptor : PluginDescriptor
{
public override string SpecificDefaultConfig
{
get
{
var config = new PluginConfig
{
ServerUrl = "http://localhost:8080",
PollInterval = 30,
EnableLogging = true,
Timeout = TimeSpan.FromSeconds(10)
};
return JsonConvert.SerializeObject(config);
}
}
}When applied:
- Applied when plugin role is first created in Config Tool
- Not applied to existing roles (preserves customization)
- If
SpecificDefaultConfigreturns empty string, no default applied
Serialization format:
- JSON is recommended (human-readable, well-supported)
- XML is also supported
- Binary formats work but harder to troubleshoot
- Must be string-serializable
Read configuration in OnPluginLoaded():
public class PluginConfig
{
public string ServerUrl { get; set; }
public int PollInterval { get; set; }
public bool EnableLogging { get; set; }
public TimeSpan Timeout { get; set; }
}
protected override void OnPluginLoaded()
{
var config = LoadConfiguration();
ApplyConfiguration(config);
}
private PluginConfig LoadConfiguration()
{
var role = Engine.GetEntity<Role>(PluginGuid);
string configJson = role.SpecificConfiguration;
if (string.IsNullOrEmpty(configJson))
{
Logger.TraceWarning("No configuration found, using defaults");
return CreateDefaultConfiguration();
}
try
{
return JsonConvert.DeserializeObject<PluginConfig>(configJson);
}
catch (Exception ex)
{
Logger.TraceError(ex, "Failed to parse configuration, using defaults");
return CreateDefaultConfiguration();
}
}
private void ApplyConfiguration(PluginConfig config)
{
Logger.TraceInformation($"Applying configuration: ServerUrl={config.ServerUrl}");
m_serverUrl = config.ServerUrl;
m_pollInterval = config.PollInterval;
m_enableLogging = config.EnableLogging;
m_timeout = config.Timeout;
}Best practices:
- Always handle missing/invalid configuration gracefully
- Log configuration values (except secrets)
- Validate configuration values
- Fall back to safe defaults on errors
Plugins can programmatically update their configuration:
private void UpdateConfiguration(PluginConfig config)
{
Engine.TransactionManager.ExecuteTransaction(() =>
{
var role = Engine.GetEntity<Role>(PluginGuid);
role.SpecificConfiguration = JsonConvert.SerializeObject(config);
});
Logger.TraceInformation("Configuration updated");
}When to update:
- In response to request from config page
- After auto-discovery of settings
- To persist runtime state changes
- When defaults need adjustment
Considerations:
- Updates trigger
EntitiesInvalidatedevent - Other plugin instances will see the change
- Changes are immediately visible in Config Tool
- Use transactions to ensure atomicity
Subscribe to EntitiesInvalidated to detect configuration changes:
protected override void OnPluginLoaded()
{
Engine.EntitiesInvalidated += OnEntitiesInvalidated;
// Load initial configuration
var config = LoadConfiguration();
ApplyConfiguration(config);
}
private void OnEntitiesInvalidated(object sender, EntitiesInvalidatedEventArgs e)
{
// Check if our role was updated
var roleUpdate = e.Entities.FirstOrDefault(u => u.EntityGuid == PluginGuid);
if (roleUpdate != null)
{
Logger.TraceDebug("Plugin configuration changed");
// Reload and apply configuration
var config = LoadConfiguration();
ApplyConfiguration(config);
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Engine.EntitiesInvalidated -= OnEntitiesInvalidated;
}
}When fired:
- Configuration changed in Config Tool
- Configuration updated programmatically by SDK client
- Any other role property changed
- Occurs on the engine thread (safe to use Engine)
Validate configuration values:
private PluginConfig LoadConfiguration()
{
var config = ParseConfiguration();
if (!ValidateConfiguration(config, out string error))
{
Logger.TraceError($"Invalid configuration: {error}");
ModifyPluginState(new PluginStateEntry("Configuration",
$"Invalid configuration: {error}") { IsError = true });
return CreateDefaultConfiguration();
}
return config;
}
private bool ValidateConfiguration(PluginConfig config, out string error)
{
if (string.IsNullOrWhiteSpace(config.ServerUrl))
{
error = "ServerUrl is required";
return false;
}
if (!Uri.IsWellFormedUriString(config.ServerUrl, UriKind.Absolute))
{
error = "ServerUrl is not a valid URL";
return false;
}
if (config.PollInterval < 1 || config.PollInterval > 3600)
{
error = "PollInterval must be between 1 and 3600 seconds";
return false;
}
if (config.Timeout < TimeSpan.FromSeconds(1))
{
error = "Timeout must be at least 1 second";
return false;
}
error = null;
return true;
}Validation strategies:
- Validate on load and on change
- Report errors via
ModifyPluginState() - Fall back to safe defaults on validation failure
- Log validation errors
- Don't crash plugin on invalid config
DO NOT store passwords or API keys in SpecificConfiguration - it is stored as plaintext in the database.
For sensitive data, use RestrictedConfiguration instead:
// ❌ WRONG - Plaintext password in SpecificConfiguration
public class PluginConfig
{
public string ServerUrl { get; set; }
public string Password { get; set; } // DON'T DO THIS!
}
// ✅ CORRECT - Use RestrictedConfiguration for credentials
protected override void OnPluginLoaded()
{
// Load non-sensitive config from SpecificConfiguration
var config = LoadConfiguration();
// Load credentials from RestrictedConfiguration
var role = Engine.GetEntity<Role>(PluginGuid);
if (role.RestrictedConfiguration.TryGetPrivateValue("Password", out var securePassword))
{
// Use secure password
InitializeConnection(config.ServerUrl, securePassword);
securePassword.Dispose();
}
}See Plugin SDK Restricted Configuration for secure credential storage.
| Storage | Purpose | Format | Security | Access |
|---|---|---|---|---|
SpecificConfiguration |
General settings | JSON/XML/any string | Plaintext | Anyone with role access |
RestrictedConfiguration.AdminConfigXml |
Admin config | XML | Plaintext | Plugin or administrators |
RestrictedConfiguration (methods) |
Credentials | SecureString | Secure | Plugin only (read), admin (write) |
Best practice: Store non-sensitive configuration in SpecificConfiguration, sensitive credentials in RestrictedConfiguration using GetPrivateValue()/SetPrivateValue() methods.
Handle configuration schema changes between versions:
private PluginConfig LoadConfiguration()
{
var role = Engine.GetEntity<Role>(PluginGuid);
string configJson = role.SpecificConfiguration;
if (string.IsNullOrEmpty(configJson))
return CreateDefaultConfiguration();
try
{
// Try to parse as current version
var config = JsonConvert.DeserializeObject<PluginConfig>(configJson);
// Check if migration needed
if (NeedsMigration(config))
{
config = MigrateConfiguration(config);
// Save migrated configuration
Engine.TransactionManager.ExecuteTransaction(() =>
{
role.SpecificConfiguration = JsonConvert.SerializeObject(config);
});
Logger.TraceInformation("Configuration migrated to new format");
}
return config;
}
catch (Exception ex)
{
Logger.TraceError(ex, "Configuration parse error");
return CreateDefaultConfiguration();
}
}
private bool NeedsMigration(PluginConfig config)
{
// Check for old property or schema version
return config.SchemaVersion < 2;
}
private PluginConfig MigrateConfiguration(PluginConfig config)
{
if (config.SchemaVersion == 1)
{
// Migrate v1 to v2
config.NewProperty = ConvertOldProperty(config.OldProperty);
config.SchemaVersion = 2;
}
return config;
}Migration best practices:
- Include schema version in configuration
- Support migrating from any previous version
- Log migrations
Custom config pages can read/write configuration via RequestManager:
Plugin side:
protected override void OnPluginLoaded()
{
// Use Plugin's protected helper methods to register handlers
AddRequestHandler<GetConfigRequest, PluginConfig>(HandleGetConfig);
AddRequestHandler<SetConfigRequest, SetConfigResponse>(HandleSetConfig);
}
private PluginConfig HandleGetConfig(GetConfigRequest request)
{
return LoadConfiguration();
}
private SetConfigResponse HandleSetConfig(SetConfigRequest request)
{
try
{
if (!ValidateConfiguration(request.Config, out string error))
{
return new SetConfigResponse { Success = false, Error = error };
}
UpdateConfiguration(request.Config);
ApplyConfiguration(request.Config);
return new SetConfigResponse { Success = true };
}
catch (Exception ex)
{
Logger.TraceError(ex, "Failed to update configuration");
return new SetConfigResponse
{
Success = false,
Error = ex.Message
};
}
}See Plugin SDK Request Manager for request/response details.
- Plugin SDK Overview - Plugin architecture
- Plugin SDK Lifecycle - When to load configuration
- Plugin SDK Request Manager - Config page communication
- SDK Transactions - Updating configuration
-
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.