-
Notifications
You must be signed in to change notification settings - Fork 4
plugin sdk state management
Plugins report their health and operational status to Config Tool using ModifyPluginState().
Plugin detects condition
↓
Calls ModifyPluginState()
↓
Plugin Host aggregates states
↓
Config Tool displays in role diagnostics
↓
Role RunningState updated (green/yellow/red)
Key concepts:
- Multiple state contexts can be active simultaneously
- States appear in Config Tool diagnostics
- Error states change role's RunningState to "Not Running" (red)
- Warning states change role's RunningState to "Warning" (yellow)
- States persist until cleared or plugin restarts
The PluginStateEntry class represents a single state condition:
public class PluginStateEntry
{
public PluginStateEntry(string context, string message);
// Properties (set after construction)
public string Context { get; set; }
public string Message { get; set; }
public string Details { get; set; }
public Exception Exception { get; set; }
public bool IsWarning { get; set; }
public bool IsError { get; set; }
public DiagnosticLogMessageParsingMode GuidParsingMode { get; set; }
}Constructor parameters:
-
context- Unique identifier for this state (e.g., "Connection", "Database"). Cannot be null or empty. -
message- User-friendly description of the state. Set to empty string to clear the context.
Properties (set after construction):
-
IsWarning- Indicates warning state (yellow) -
IsError- Indicates error state (red). When true,IsWarningis ignored. -
Exception- Optional exception details -
Details- Additional detailed message -
GuidParsingMode- Controls how GUIDs in the message and details are parsed and displayed as clickable entity links in Config Tool diagnostics. Defaults toParseAnyGuid.
The GuidParsingMode property controls how GUIDs embedded in state messages are detected and converted to clickable entity links in Config Tool's diagnostics view.
public enum DiagnosticLogMessageParsingMode
{
ParseAnyGuid, // Default - parses GUIDs with or without brackets
ParseGuidsWithBrackets, // Only parses GUIDs wrapped in curly brackets
NoParsing // No GUID parsing, text displayed as plain text
}ParseAnyGuid (default):
Detects GUIDs in any format, with or without curly brackets. Both formats become clickable entity links.
// GUID becomes a clickable link to the camera entity
ModifyPluginState(new PluginStateEntry("Status", $"Camera {cameraGuid} is offline"));ParseGuidsWithBrackets:
Only detects GUIDs explicitly wrapped in curly brackets {...}. Use this when your message contains text that resembles a GUID but is not an entity reference.
// Only the bracketed GUID becomes a clickable link
// "ABC-12345678-DEF" is not parsed as a GUID
var state = new PluginStateEntry("Status",
$"Camera {{{cameraGuid}}} linked to zone ABC-12345678-DEF")
{
GuidParsingMode = DiagnosticLogMessageParsingMode.ParseGuidsWithBrackets
};
ModifyPluginState(state);NoParsing:
Disables all GUID parsing. All text displays as plain text with no clickable links.
// No GUIDs become clickable
var state = new PluginStateEntry("Debug",
"Transaction ID: 12345678-1234-5678-1234-567812345678")
{
GuidParsingMode = DiagnosticLogMessageParsingMode.NoParsing
};
ModifyPluginState(state);When a GUID is parsed, Config Tool resolves it to the entity name and displays it as a clickable link that navigates to that entity.
Call ModifyPluginState() to report or update the plugin role's state:
protected override void OnPluginLoaded()
{
try
{
InitializeConnection();
ModifyPluginState(new PluginStateEntry("Connection", "Connected to external system"));
}
catch (Exception ex)
{
Logger.TraceError(ex, "Connection failed");
ModifyPluginState(new PluginStateEntry("Connection",
"Failed to connect to external system")
{
Exception = ex,
IsError = true
});
}
}Use ModifyEntityState() to report state for entities owned by your plugin. This allows individual entities created by your plugin to display their own diagnostics in Config Tool.
protected void ModifyEntityState(Guid entityId, PluginStateEntry state);
protected void ModifyEntityState(Guid entityId, PluginStateEntry state, bool isRunningStateSettable);Parameters:
-
entityId- The GUID of the entity to attach the state to -
state- The state entry to report -
isRunningStateSettable- When true (default), the entity'sRunningStateis updated based on the state entry. Set to false to report diagnostics without affecting the entity's running state.
Requirements:
- The entity must be owned by your plugin (
entity.OwnerRole == PluginGuid) - Or the entity must be the plugin role itself
For more information about plugin entity ownership, see About plugin entity ownership.
private void UpdateDeviceStatus(Guid deviceEntityId, bool isOnline)
{
if (isOnline)
{
ModifyEntityState(deviceEntityId,
new PluginStateEntry("Status", "Online"));
}
else
{
ModifyEntityState(deviceEntityId,
new PluginStateEntry("Status", "Offline") { IsWarning = true });
}
}
private void ReportDeviceError(Guid deviceEntityId, Exception ex)
{
ModifyEntityState(deviceEntityId,
new PluginStateEntry("Status", "Communication error")
{
Exception = ex,
IsError = true
});
}Use isRunningStateSettable = false when you want to display diagnostic information without changing the entity's running state indicator:
// Report statistics without affecting the entity's green/yellow/red state
ModifyEntityState(deviceEntityId,
new PluginStateEntry("Statistics", $"Processed {count} events today"),
isRunningStateSettable: false);ModifyPluginState() is a convenience method that calls ModifyEntityState() with the plugin's own GUID:
// These are equivalent:
ModifyPluginState(new PluginStateEntry("Connection", "Connected"));
ModifyEntityState(PluginGuid, new PluginStateEntry("Connection", "Connected"));Indicates normal operation:
ModifyPluginState(new PluginStateEntry("Connection", "Connected"));
ModifyPluginState(new PluginStateEntry("Database", "Database operational"));
ModifyPluginState(new PluginStateEntry("Hardware", "All devices online"));Effect on role:
- Role shows green (Running) if no error/warning states
- State appears in diagnostics as informational
Indicates degraded operation:
ModifyPluginState(new PluginStateEntry("Connection",
"Intermittent connection issues") { IsWarning = true });
ModifyPluginState(new PluginStateEntry("Hardware",
"2 of 10 devices offline") { IsWarning = true });
ModifyPluginState(new PluginStateEntry("Performance",
"Query response time exceeds threshold") { IsWarning = true });Effect on role:
- Role shows yellow (Warning)
- State appears in diagnostics with warning icon
- Plugin continues to operate
When to use:
- Recoverable errors
- Degraded performance
- Partial failures
- Approaching limits
Indicates critical failure:
ModifyPluginState(new PluginStateEntry("Connection",
"Cannot connect to external system") { Exception = ex, IsError = true });
ModifyPluginState(new PluginStateEntry("Database",
"Database connection lost") { Exception = ex, IsError = true });
ModifyPluginState(new PluginStateEntry("License",
"License validation failed") { IsError = true });Effect on role:
- Role shows red (Not Running)
- State appears in diagnostics with error icon
- Plugin may be non-functional
When to use:
- Connection failures
- Database errors
- License/certificate issues
- Critical resource unavailable
Use different context strings for different subsystems:
// Multiple contexts can be active simultaneously
ModifyPluginState(new PluginStateEntry("Connection", "Connected"));
ModifyPluginState(new PluginStateEntry("Database", "Connected"));
ModifyPluginState(new PluginStateEntry("Hardware", "All devices online"));
ModifyPluginState(new PluginStateEntry("License", "Valid"));Common context names:
-
"Connection"- External system connectivity -
"Database"- Database status -
"Hardware"- Hardware device status -
"License"- Licensing status -
"Configuration"- Configuration validation -
"Performance"- Performance metrics -
"Startup"- Initialization status
Context best practices:
- Use descriptive, consistent names
- One context per subsystem
- Clear context scope
- Don't use too many contexts (5-10 max)
Clear a state by setting empty message:
// Report warning
ModifyPluginState(new PluginStateEntry("Connection",
"Slow response") { IsWarning = true });
// Later, when resolved
ModifyPluginState(new PluginStateEntry("Connection", string.Empty));When to clear:
- Condition resolved
- Subsystem recovered
- Error no longer applicable
Important
- Must use same context string to clear
- Empty message clears the state
- Cleared states don't appear in diagnostics
- All states cleared on plugin restart
Report progress during initialization:
protected override void OnPluginLoaded()
{
ModifyPluginState(new PluginStateEntry("Startup", "Initializing..."));
try
{
InitializeConnection();
ModifyPluginState(new PluginStateEntry("Startup", "Connection initialized"));
LoadConfiguration();
ModifyPluginState(new PluginStateEntry("Startup", "Configuration loaded"));
// Clear startup state when complete
ModifyPluginState(new PluginStateEntry("Startup", string.Empty));
// Report operational state
ModifyPluginState(new PluginStateEntry("Status", "Plugin ready"));
}
catch (Exception ex)
{
ModifyPluginState(new PluginStateEntry("Startup",
"Initialization failed") { Exception = ex, IsError = true });
}
}Update states as conditions change:
private void OnConnectionStateChanged(bool connected)
{
if (connected)
{
ModifyPluginState(new PluginStateEntry("Connection", "Connected"));
}
else
{
ModifyPluginState(new PluginStateEntry("Connection",
"Disconnected") { IsWarning = true });
// Attempt reconnection
Task.Run(() => AttemptReconnect());
}
}
private async Task AttemptReconnect()
{
for (int i = 0; i < 3; i++)
{
ModifyPluginState(new PluginStateEntry("Connection",
$"Reconnecting... (attempt {i + 1}/3)") { IsWarning = true });
if (await TryConnectAsync())
{
ModifyPluginState(new PluginStateEntry("Connection", "Reconnected"));
return;
}
await Task.Delay(TimeSpan.FromSeconds(5));
}
ModifyPluginState(new PluginStateEntry("Connection",
"Reconnection failed") { IsError = true });
}The Plugin Host aggregates all plugin states:
Aggregation rules:
- Any error state → Role shows red (Not Running)
- Any warning state (no errors) → Role shows yellow (Warning)
- All success/cleared states → Role shows green (Running)
Example:
// Plugin reports multiple states
ModifyPluginState(new PluginStateEntry("Connection", "Connected")); // Green
ModifyPluginState(new PluginStateEntry("Database", "Connected")); // Green
ModifyPluginState(new PluginStateEntry("Hardware",
"1 device offline") { IsWarning = true }); // Yellow
// Role overall state: Yellow (Warning) because of hardware warningPath: System → Roles → [Plugin Role] → Diagnostics
What's displayed:
- Role's aggregated RunningState (green/yellow/red icon)
- List of all active states by context
- State messages
- Timestamps
- Exception details (if provided)
States are NOT:
- Persisted in database
- Available through SDK queries
- Visible to end users (Config Tool only)
private void MonitorConnection()
{
if (IsConnected())
{
ModifyPluginState(new PluginStateEntry("Connection", "Connected"));
}
else if (IsConnecting())
{
ModifyPluginState(new PluginStateEntry("Connection",
"Connecting...") { IsWarning = true });
}
else
{
ModifyPluginState(new PluginStateEntry("Connection",
"Disconnected") { IsError = true });
}
}private void ValidateAndApplyConfiguration(PluginConfig config)
{
if (!ValidateConfiguration(config, out string error))
{
ModifyPluginState(new PluginStateEntry("Configuration",
$"Invalid configuration: {error}") { IsError = true });
return;
}
ModifyPluginState(new PluginStateEntry("Configuration", string.Empty));
ApplyConfiguration(config);
}private void MonitorPerformance()
{
var metrics = GetPerformanceMetrics();
if (metrics.AverageResponseTime > TimeSpan.FromSeconds(5))
{
ModifyPluginState(new PluginStateEntry("Performance",
$"Slow response time: {metrics.AverageResponseTime.TotalSeconds:F2}s")
{ IsWarning = true });
}
else
{
ModifyPluginState(new PluginStateEntry("Performance", string.Empty));
}
}- Plugin SDK Overview - Plugin architecture
- Plugin SDK Lifecycle - When to report states
- About plugin entity ownership - Understanding which entities support ModifyEntityState
- Plugin SDK Database - Database state reporting
- Logging - Complementary logging
-
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.
- About access control in the Web SDK Concepts, relationships, and common access-control operations.
- About video in the Web SDK Concepts, relationships, configuration, and common video operations.
- Users and user groups Creating users, managing group membership, and assigning privileges.
- 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.