AccessSynchronization¶
Overview¶
Access control data synchronization between PQ Server and device (credential upload/download, access level sync, offline database management). The adapter implements synchronization logic based on device capabilities.
- Added in: PQ Framework 2.0
- Namespace:
Pq.Adapters.Framework
When to Use¶
- Access control panels with offline credential storage
- Smart locks with local user databases
- Door controllers with cached credentials
- Biometric readers with template storage
- Any device requiring credential synchronization
States¶
Synchronization Lifecycle¶
| State | Status id | Description |
|---|---|---|
SyncIdle |
access.sync.idle |
No synchronization in progress |
SyncActive |
access.sync.active |
Synchronization operation in progress |
SyncFailed |
access.sync.failed |
Synchronization failed, error condition |
SyncIdle is the hidden default state: SetSyncIdle(ct) publishes no status string, so the function reports as cleared.
Actions¶
No predefined actions. The adapter implements synchronization logic using:
- Custom actions for sync events
- State transitions via base class methods
- Command handlers for sync requests
Common Adapter-Defined Actions¶
Adapters typically implement these patterns:
SyncStarted(timestamp) (adapter-defined)
- Transition to
SyncActivestate - Begin credential upload/download operation
SyncCompleted(timestamp, credentialCount) (adapter-defined)
- Transition to
SyncIdlestate - Log synchronization success with statistics
SyncFailed(timestamp, errorMessage) (adapter-defined)
- Transition to
SyncFailedstate - Log synchronization failure with error details
Properties¶
| Property | Type | Default | Description |
|---|---|---|---|
access_sync_enabled |
bool | true |
Synchronize access rights to this device. |
When access_sync_enabled is off, the framework writes nothing to the panel: no cardholders,
credentials, PINs, access levels, time zones or holidays, no antipassback zone configuration, and no
memory wipe. Synchronize and Reset commands answer Ignored, and the device stops publishing
pq.event.access.synchronization.restore_needed. The switch covers antipassback too — its zones
reference persons the panel never receives, so it has no separate switch.
The gate sits in the framework above the adapter's Transform and CreateCommands, so an adapter needs
no code of its own to honour it.
Stored address mappings survive the switch, because they also resolve protocol card addresses back to PQ
person identities at event time. Switching back on therefore runs an ordinary differential sync against
mappings that may describe a panel someone else has changed meanwhile; run Reset to wipe the panel and
rebuild it from PQ.
Any further synchronization configuration is adapter-specific — declare it as a device property in
adapter-registration.yaml.
YAML Example¶
device_types:
- type_id: AccessControlPanel
name: "Access Control Panel"
functions:
AccessSynchronization:
ConnectionBase:
properties:
sync_mode:
type: "string"
default: "auto"
description: "Synchronization mode: auto, manual, scheduled"
batch_size:
type: "int"
default: 100
range: [1, 1000]
description: "Credentials per batch operation"
offline_capacity:
type: "int"
default: 10000
description: "Maximum offline credentials supported"
- type_id: SmartLock
name: "Smart Door Lock"
functions:
AccessSynchronization:
Door:
properties:
sync_interval_hours:
type: "int"
default: 24
description: "Hours between automatic synchronization"
Code Usage¶
public class AccessPanelThing : Thing
{
public AccessSynchronizationFunction Sync { get; }
protected override async Task OnSyncRequested(CancellationToken ct)
{
// transition to active state
await Sync.TransitionToAsync("access.sync.active", ct);
try
{
// adapter-specific sync logic
var credentials = await GetPendingCredentials(ct);
await UploadToDevice(credentials, ct);
// transition to idle on success
await Sync.TransitionToAsync("access.sync.idle", ct);
Logger.LogInformation("Synchronized {Count} credentials", credentials.Count);
}
catch (Exception ex)
{
// transition to failed on error
await Sync.TransitionToAsync("access.sync.failed", ct);
Logger.LogError(ex, "Synchronization failed");
}
}
private async Task<List<Credential>> GetPendingCredentials(CancellationToken ct)
{
// fetch from PQ Server API
return await ApiClient.GetCredentialsAsync(DeviceId, ct);
}
private async Task UploadToDevice(List<Credential> credentials, CancellationToken ct)
{
// adapter-specific device communication
foreach (var batch in credentials.Chunk(BatchSize))
{
await DeviceClient.UploadCredentialsAsync(batch, ct);
}
}
}
Extended Construction¶
AccessSynchronization uses extended construction (extended_construction: true). The framework provides:
public class AccessSynchronizationFunction : FunctionBase
{
// framework provides constructor with Thing reference
public AccessSynchronizationFunction(Thing thing)
: base(thing)
{
}
// adapter implements synchronization logic
public async Task SyncCredentials(List<Credential> credentials, CancellationToken ct)
{
await TransitionToAsync("access.sync.active", ct);
// sync implementation
}
}
Synchronization Patterns¶
Full Sync (Initial/Manual)¶
- Device reports firmware version, capacity, current count
- Server compares hashes, determines delta
- Upload new/changed credentials
- Remove deleted credentials
- Verify integrity
Incremental Sync (Automatic)¶
- Device polls for changes since last sync
- Server returns delta (adds/updates/deletes)
- Device applies changes
- Device confirms completion
Person Profiles¶
Access synchronization can include adapter-specific per-person settings declared in
access-model.yaml under person_profiles. Use this for panel user flags such as
user level, menu type, dual-code mode, or group-selection permission.
When person_profiles is declared, the generated synchronization base calls:
Generated AccessModel.PersonAccess contains typed profile properties, for example
person.UserProfile. Adapter code should read those properties directly. The
generated mapper applies YAML defaults and validates required profile fields before
Transform() runs.
Event-Driven Sync (Real-Time)¶
- Server publishes credential change event
- Adapter receives event, filters by device
- Adapter pushes change to device immediately
- Device acknowledges change
Notes¶
- No Predefined Actions: Adapters define custom actions based on device protocol
- State Tracking: Framework tracks sync state, adapter handles transitions
- Error Recovery: Adapter implements retry logic, partial sync, rollback
- Capacity Management: Check device capacity before sync operations
- Conflict Resolution: Server is authoritative, device reflects server state
- Performance: Use batch operations, parallel upload when supported
See Also¶
- Functions: AntipassbackSynchronization - Antipassback zone configuration sync
- Functions: TimeSynchronization - Clock synchronization
- Functions: Door - Access control door
- Functions: Reader - Credential reader