Documentation
Commands
Commands travel from a Control Panel to a PD. In Python each command is a frozen dataclass in the osdp.commands module. You construct one with keyword arguments and hand it to ControlPanel.submit_command:
from osdp import commands, BuzzerControlCode
cp.submit_command(101, commands.Buzzer(
reader=0,
control_code=BuzzerControlCode.DefaultTone,
on_count=10,
off_count=10,
rep_count=3,
))
Every field is validated in the constructor, so an out-of-range value or an over-long buffer raises immediately, at the line where you built the command, rather than being truncated on its way into a packet. Byte and string fields have documented maximum lengths (commands.MAX_TEXT_LEN, MAX_MFG_DATA_LEN, and so on) sourced from the C library.
A PD may also return a command from its command handler to answer a query inline — most commonly a Status reply to a status request.
Reader output
Output
Drive a digital output line. Its control_code is an OutputControlCode:
Set the state of an output line.
Example:
>>> cmd = Output(output_no=0, control_code=OutputControlCode.TemporaryOn,
... timer_count=30)
>>> cmd.timer_count
30intOutputControlCodeWhat an `Output` command does to the output line.
NopPermanentOffPermanentOnPermanentOffAllowTimedPermanentOnAllowTimedTemporaryOnTemporaryOffLED
Control a reader LED. An LED command carries a temporary block, a permanent block, or both; each is described by the helper dataclasses below. Counts are in units of 100ms, and within a block on_count and off_count cannot both be zero.
Control a reader LED.
An LED carries two independent parameter blocks. Setting only `permanent` changes the LED until something else changes it; setting only `temporary` overrides it for a while. Setting both at once is how a temporary state is cancelled and a new permanent state applied in the same command.
A block whose control code is Nop does nothing, so it is normalised to None; passing neither block is an error.
Example:
Flash red for two seconds, then go back to whatever it was:
>>> cmd = LED(temporary=TemporaryLEDParams(on_color=LEDColor.Red,
... on_count=5, off_count=5,
... timer_count=20))
>>> cmd.permanent is None
True
Cancel a running temporary state and go steady green, in one command:
>>> cmd = LED(
... temporary=TemporaryLEDParams(
... control_code=TemporaryLEDControlCode.Cancel),
... permanent=PermanentLEDParams(on_color=LEDColor.Green,
... on_count=1),
... )
>>> cmd.temporary.control_code.name
'Cancel'intNoneThe temporary half of an LED command.
A temporary state runs for `timer_count` and then gives way to whatever permanent state the LED was in.
Example:
>>> params = TemporaryLEDParams(on_color=LEDColor.Red, on_count=10,
... off_count=10, timer_count=20)
>>> params.on_color.name
'Red'TemporaryLEDControlCodeintLEDColorcontrol_codeThe permanent half of an LED command.
A permanent state persists until it is changed. It has no timer; that is what makes it permanent.
Example:
A steady green: light up, and never blink off.
>>> params = PermanentLEDParams(on_color=LEDColor.Green, on_count=1)
>>> params.control_code.name
'Set'
Both durations zero is rejected; the PD would refuse such a command.
>>> PermanentLEDParams(on_color=LEDColor.Green)
Traceback (most recent call last):
ValueError: PermanentLEDParams: on_count and off_count cannot both be zero when the control code is Set. For a steady color use on_count=1, off_count=0PermanentLEDControlCodeintLEDColorcontrol_codeEach block's control code selects whether it takes effect; colors are LEDColor values:
What the temporary block of an `LED` command does.
NopCancelSetWhat the permanent block of an `LED` command does.
NopSetColors a reader LED can be set to.
BlackRedGreenAmberBlueMagentaCyanWhiteBuzzer
Sound the reader's buzzer. Its control_code is a BuzzerControlCode:
Control a reader's audible output.
Example:
>>> cmd = Buzzer(control_code=BuzzerControlCode.DefaultTone,
... on_count=2, off_count=2, rep_count=3)
>>> cmd.rep_count
3intBuzzerControlCodeWhat a `Buzzer` command does.
NoToneOffDefaultToneText
Show text on a reader's display. Its control_code is a TextControlCode:
Show a message on a reader's display.
Example:
>>> cmd = Text(control_code=TextControlCode.PermanentNoWrap,
... data="PLEASE WAIT")
>>> cmd.offset_row
1intTextControlCodestrHow a `Text` command displays its message.
PermanentNoWrapPermanentWrapTemporaryNoWrapTemporaryWrapConfiguration
Comset / ComsetDone
Change a PD's address and baud rate. A PD acknowledges by returning a ComsetDone from its command handler.
Change the PD's address and baud rate.
The PD applies the change after replying, so the CP must reconfigure its own channel to match or it will lose the device.
Example:
>>> cmd = Comset(address=42, baud_rate=115200)
>>> cmd.address
42intTells a PD app that a Comset it received has taken effect.
Delivered to a PD's command handler by the library. Apps never submit this.
Example:
>>> cmd = ComsetDone(address=42, baud_rate=115200)
>>> cmd.baud_rate
115200intKeyset
Set the Secure Channel Base Key (SCBK) on a PD. See Secure Channel for how keying and install mode work.
Install a new secure channel base key on the PD.
The PD stores the key and uses it for every subsequent secure channel handshake, so losing it means losing the device.
Example:
>>> cmd = Keyset(data=bytes(range(16)))
>>> cmd.type
1intbytesData and status
Manufacturer
Send a vendor-specific payload.
Send a vendor-specific command.
A PD may answer inline by returning a `events.ManufacturerReply`, `events.ManufacturerStatus` or `events.ManufacturerError` from its command handler.
Example:
>>> cmd = Manufacturer(vendor_code=0x00030201, data=b"\\x01\\x02")
>>> cmd.data
b'\\x01\\x02'intbytesFile Transfer
Begin or cancel a file transfer to the PD. Register a FileOps first so the library can read the file. The flags field is a FileTxFlag:
Start, or cancel, a file transfer to the PD.
The file's contents come from the file ops registered with `register_file_ops()`; this command only starts the process.
Example:
>>> cmd = FileTransfer(id=1)
>>> cancel = FileTransfer(id=1, flags=FileTxFlag.Cancel)
>>> bool(cancel.flags & FileTxFlag.Cancel)
TrueintFileTxFlagFlags for a `FileTransfer` command.
CancelSmartcard
Talk to a smartcard attached to the PD. PivData retrieves a PIV object; GenAuth and CrAuth run a cryptographic challenge against the card. The payloads travel as multi-part messages and the PD answers with the matching events.PivData / events.GenAuth / events.CrAuth carrying the reassembled reply. See Smartcard Commands for the full flow.
Retrieve the contents of a PIV object from the PD's smartcard.
The PD answers with an `events.PivData` carrying the reassembled object data; replies larger than one OSDP packet travel as multi-part messages transparently.
Example:
>>> cmd = PivData(oid=b"\\x5f\\xc1\\x02", element=7)
>>> cmd.oid
b'_\\xc1\\x02'bytesintDirect a general-authenticate challenge to the PD's smartcard.
The challenge travels as a multi-part message; the PD answers with an `events.GenAuth` carrying the reassembled response.
Example:
>>> cmd = GenAuth(algorithm=0xA7, key=0x9E, data=b"challenge")
>>> len(cmd.data)
9intbytesDirect a challenge/response sequence to the PD's smartcard.
Identical shape to `GenAuth`; the PD answers with an `events.CrAuth`.
intbytesStatus
Request a status report, or (from a PD) carry one back. The type is a StatusReportType:
Query the PD's status, or a PD's answer to that query.
A CP submits this with an empty `report` to ask. A PD answers by returning a Status with one report byte per entry from its command handler.
Example:
>>> query = Status(type=StatusReportType.Input)
>>> query.report
b''
A PD answering with three input contacts, the middle one active:
>>> reply = Status(type=StatusReportType.Input, report=bytes([0, 1, 0]))
>>> len(reply.report)
3StatusReportTypebytesWhich set of status bits a status report carries.
InputOutputLocalReaderNotification
Library-generated notification delivered as a command on the PD side when notifications are enabled. The type is a NotificationType:
A library notification delivered to a PD app.
Produced by the library, not by a peer, when `LibFlag.EnableNotification` is set. Apps never submit this. The CP-side equivalent is `events.Notification`, which has the same shape.
Example:
>>> note = Notification(type=NotificationType.PeripheralDeviceStatus,
... online=True)
>>> note.type.name
'PeripheralDeviceStatus'NotificationTypeintboolKind of library notification.
Each type carries its own typed fields on `osdp.events.Notification` / `osdp.commands.Notification`; this discriminator selects which are valid.
CommandSecureChannelStatusPeripheralDeviceStatusMultipartStartMultipartProgressMultipartDonePdIdBiometrics
BioRead / BioMatch
Ask a reader to capture a biometric (BioRead) or match one against a supplied template (BioMatch). type is a BioType and format a BioFormat. A captured template larger than one packet is only carried when both roles opt in to multi-part biometric replies:
Ask a reader to capture a biometric and return the template.
The PD answers with an `events.BioRead`.
Example:
>>> cmd = BioRead(type=BioType.RightThumbPrint,
... format=BioFormat.AnsiIncits378, quality=200)
>>> cmd.type.name
'RightThumbPrint'intBioTypeBioFormatAsk a reader to scan a biometric and match it against a template.
The PD answers with an `events.BioMatch` carrying the match score.
Example:
>>> cmd = BioMatch(type=BioType.RightThumbPrint,
... format=BioFormat.AnsiIncits378, quality=200,
... data=b"template")
>>> len(cmd.data)
8intBioTypeBioFormatbytesWhich biometric a reader should capture or match.
NotSpecifiedRightThumbPrintRightIndexFingerPrintRightMiddleFingerPrintRightRingFingerPrintRightLittleFingerPrintLeftThumbPrintLeftIndexFingerPrintLeftMiddleFingerPrintLeftRingFingerPrintLeftLittleFingerPrintRightIrisScanRightRetinaScanLeftIrisScanLeftRetinaScanFullFaceImageRightHandGeometryLeftHandGeometryEncoding of a biometric template.
NotSpecifiedRawPGMAnsiIncits378See also
- Control Panel — how commands are submitted and completed.
- Events — the payloads a PD sends back.
- API Reference — the remaining enums and supporting types.