Documentation
Python Getting Started
The libosdp Python package wraps the C library so you can build and test OSDP devices without writing any C. Install it from PyPI:
pip install libosdp
The package exposes two modules:
osdp— the recommended, Python-friendly API documented here.osdp_sys— a thin wrapper directly over the C API. It is a low-level building block forosdpand is not recommended for direct use.
A Channel to talk over
LibOSDP does not own the transport. You implement a Channel that moves bytes over your wire (serial, TCP, etc.) and hand it to the device. A pyserial-backed channel looks like this:
import serial
from osdp import Channel
class SerialChannel(Channel):
def __init__(self, device: str, speed: int = 115200):
self.dev = serial.Serial(device, speed, timeout=0)
def read(self, max_read: int) -> bytes:
return self.dev.read(max_read)
def write(self, data: bytes) -> int:
return self.dev.write(data)
def flush(self):
self.dev.flush()
def __del__(self):
self.dev.close()
Applications must call into the library frequently (the device runs a background thread that does this for you when you call start()); see Secure Channel for how keying works.
Control Panel mode
A Control Panel (CP) manages one or more Peripheral Devices (PDs). Each PD is described by a PDInfo.
from osdp import ControlPanel, PDInfo, KeyStore, LogLevel, Command, CommandLEDColor
channel = SerialChannel("/dev/ttyUSB0")
# Setting scbk=None puts the PD in install mode; KeyStore.gen_key() provisions
# a random Secure Channel Base Key (SCBK) instead.
pd_info = [
PDInfo(101, channel, scbk=KeyStore.gen_key()),
]
cp = ControlPanel(pd_info, log_level=LogLevel.Debug)
cp.start()
cp.sc_wait_all() # wait until the secure channel is established
led_cmd = {
'command': Command.LED,
'reader': 1,
'led_number': 0,
'control_code': 1,
'on_count': 10,
'off_count': 10,
'on_color': CommandLEDColor.Red,
'off_color': CommandLEDColor.Black,
'temporary': False,
}
while True:
# Pull any event the PD reported
event = cp.get_event(pd_info[0].address)
if event:
print(f"CP: Received event {event}")
# Push a command to PD-101
cp.send_command(pd_info[0].address, led_cmd)
The dictionaries you pass to send_command() are described in Commands; the ones you read from get_event() are described in Events.
Command completion callback (optional)
from osdp import CompletionStatus
def on_command_complete(address, command, status):
if status == CompletionStatus.Ok:
print("command completed")
cp.set_command_completion_handler(on_command_complete)
Peripheral Device mode
A Peripheral Device (PD) answers a CP. Describe it with PDInfo and declare its capabilities.
from osdp import PeripheralDevice, PDInfo, PDCapabilities, Capability, Event, CardFormat
channel = SerialChannel("/dev/ttyUSB0")
# scbk=None puts the PD in install mode (accepts a key from the CP)
pd_info = PDInfo(101, channel, scbk=None)
pd_cap = PDCapabilities([
(Capability.OutputControl, 1, 1),
(Capability.LEDControl, 2, 1),
(Capability.AudibleControl, 1, 1),
(Capability.TextOutput, 1, 1),
])
pd = PeripheralDevice(pd_info, pd_cap)
pd.start()
pd.sc_wait()
card_event = {
'event': Event.CardRead,
'reader_no': 1,
'direction': 1,
'format': CardFormat.ASCII,
'data': bytes([9, 1, 9, 2, 6, 3, 1, 7, 7, 0]),
}
while True:
pd.notify_event(card_event)
cmd = pd.get_command()
if cmd:
print(f"PD: Received command: {cmd}")
Event completion callback (optional)
from osdp import CompletionStatus
def on_event_complete(event, status):
if status == CompletionStatus.Flushed:
print("event removed by flush")
pd.set_event_completion_handler(on_event_complete)
Full examples
Runnable command-line versions of both apps live in the LibOSDP repo: