Skip to content

Framework changelog

Adapter-facing changes in Pq.Adapters.Framework between server releases. Versions match the server tags. Newest on top.

Only what affects building an adapter is listed here: the framework's public API, the source generator, the YAML schemas, and the diagnostics. Server internals are out of scope.

Changes that need an edit to an existing adapter have a numbered record with exact steps under Framework breaking changes.

v1.17.4 — 2026-09-23

Added

  • FireControlOutput test (revision) state. The function gains the state fire.test and the actions FireControlTestStarted (→ fire.test, emits pq.event.fire.test.started) and FireControlTestEnded (→ control.off, emits pq.event.fire.test.completed), so an adapter can report an output under test.

v1.17.3 — 2026-09-22

No changes to the adapter surface.

v1.17.2 — 2026-09-21

No changes to the adapter surface.

v1.17.1 — 2026-09-21

No changes to the adapter surface.

v1.17.0 — 2026-09-21

⚠ Breaking changes

  • lpr_camera category renamed to vca_camera in the adapter-registration schema. Breaks: an adapter.yaml that declares category: lpr_camera no longer validates. Migration: change the category to vca_camera.
  • Unknown keys in adapter YAML are rejected. Breaks: a misspelled or obsolete property in adapter-registration.yaml, the functions, access-model or commands YAML fails the build with PQA002 (error) instead of being silently ignored. Migration: remove or correct the key the diagnostic names.
  • TCP transport no longer takes a device address. Breaks: ConnectChannel(address, host, port, …), Disconnect(address), GetChannel(address) and the parameterless Disconnect() / GetChannel() on SingleTcpTransportBase are gone, and a TCP transport with address_type always generates SingleTcpTransportBase. Migration: call ConnectChannel(host, port, router, ct), keep the returned channel, and disconnect with await channel.Disconnect().
  • FrameBase.IsUnsolicited removed. Breaks: an adapter frame that overrides it no longer compiles. Migration: return MatchResult.OutOfBand from MatchResponse for frames the device pushes on its own.
  • ProtocolChannel.TcpConnection removed. Breaks: code that wrote raw bytes through channel.TcpConnection.Write(…). Migration: use channel.SendOutOfBand(frame, ct) (or SendOutOfBand in TcpProtocolBase).
  • A custom transport is single-device; several devices per transport need multiplex. Breaks: a custom transport that binds routers by address (Bind/Resolve per device) generates a single-device base, so every device shares one router and events land on the wrong device with no error. Migration: set transport: type: multiplex in adapter-registration.yaml; single-device custom transports need no change. See 0001.
  • PlaybackRelayRegistry.Add and Clear take the owning device. Breaks: Add(transactionId, relay) and Clear() no longer compile. Migration: call Add(device.DeviceId, transactionId, relay) and Clear(deviceId).

Added

  • multiplex transport type (schema enum tcp / custom / multiplex) with base classes MultiplexTransportBase<TAddress, TEvent> (routes several devices by address) and SingleDeviceTransportBase<TAddress, TEvent> (one device, no address bookkeeping).
  • MatchResult.OutOfBand — return it for a frame the device may send at any time (poll, heartbeat, push). The channel hands it to the unmatched-frame handlers without a warning and keeps waiting for the reply.
  • SendOutOfBand(frame, ct) on ProtocolChannel and TcpProtocolBase — writes straight to the wire, bypassing the request queue; use it for teardown frames and replies to device-initiated frames.
  • ProtocolChannel.Disconnect(), and an optional parser argument on ConnectChannel so an adapter can keep per-connection parser state (for example a session cipher).
  • Inline string length in YAML property types: pin: string[4] (exact) or pin: string[4, 6] (range), in the access model and in function properties. The framework drops out-of-range values before upload and reports them as ValueOutOfRange.
  • PQA033 (warning): an access-model pin: string property without a length warns. The warning does not fail a build with warnings-as-errors.
  • Diagnostic help pages on docs.protequ.com for PQA001–PQA010, PQA014, PQ0001, PQ0002 and TD001–TD003; every PQA, PQC, PQ and TD diagnostic links to its page.
  • QrCode credentials reach access synchronization as the bare decoded text, like Pin and LicensePlate; no image is uploaded.

Changed

  • MatchResult.Continue no longer drops the connection; the channel delivers the frame to the unmatched-frame handlers and keeps waiting.
  • Logs written inside a device tree carry PanelId and Panel (name plus short id), so one filter on the panel catches the whole tree.

Fixed

  • One device disconnecting no longer tears down the playback relays of the adapter's other devices.
  • Recorded-video playback no longer stays blank after the stream reconnects: a reopened session resumes from the last requested position, and a closing session no longer blocks its reconnecting viewer.

v1.16.0 — 2026-09-17

Added

  • FrameBase.IsUnsolicited — override it to true on frames the device pushes on its own. The channel then does not match them to a pending Send; it delivers them on the unmatched path so the adapter can decode them. Defaults to false, existing frames unchanged.
  • lpr_camera category in the adapter-registration schema — for a channel whose product is licence-plate recognition. An ordinary video channel stays camera.

v1.15.6 — 2026-09-13

No changes to the adapter surface.

v1.15.5 — 2026-09-11

Fixed

  • Events recovered from a device's history (offline backfill, history poll) now carry the time the event actually happened in the audit, instead of the moment they were read back. Live events were already correct.

v1.15.4 — 2026-09-10

Added

  • New remote-operator event variants: pq.event.intrusion.bypassed.remote, pq.event.intrusion.bypassed.cleared.remote, pq.event.intrusion.alarm.acknowledged.remote, pq.event.safety.emergency.evacuation.remote, …evacuation.cleared.remote, …lockdown.remote, …lockdown.cleared.remote.
  • New function actions for remote operator control across the intrusion and safety functions: EvacuationRemote, EvacuationClearedRemote, LockdownRemote, LockdownClearedRemote, BypassedRemote, BypassCancelledRemote, AlarmAcknowledged, AlarmAcknowledgedRemote.
  • New public members on RtspPlaybackSession: ServedVideoTrack (the track the session settled on) and IsOpen.

Changed

  • Video preset events pq.event.video.preset.activated and …preset.stored now accept an optional personId, so an operator-issued preset command can be attributed. Adapters that do not pass it are unaffected.

v1.15.3 — 2026-09-04

Added

  • New fire.disabled state for fire panels — status only. The disabled address publishes its own pq.event.fire.address.disabled, so the panel-level state does not duplicate it.

v1.15.2 — 2026-09-03

No changes to the adapter surface.

v1.15.1 — 2026-09-02

Added

  • New AuthenticatedProtocol function for devices with an authenticated application session, exposing states protocol.authenticated, protocol.authentication.failed, protocol.handshake.failed (plus matching pq.state.protocol.* statuses).
  • New access_sync_enabled property (bool, default true) on the AccessSynchronization function. Turn it off and the adapter stops writing cardholders, credentials, holidays and antipassback to the panel; switch it back on and run Reset to discard what the panel gained meanwhile.
  • Property types may now be declared as whole-type arrays (e.g. guid[], card_format[]) and resolve to a typed array. An array whose element type is unknown is now rejected at build time.

Fixed

  • The pq.event.device.unresolved (unknown/unconfigured device) event now accepts the optional attribution params unresolvedAddress, personId, credentialId, credentialInfo, rawData — so an unknown-card event can carry the person, credential and raw card data.

v1.15.0 — 2026-08-31

No changes to the adapter surface.