SDK to communicate with Baltech RFID readers.
Project description
Baltech SDK
Installation
pip install baltech-sdk
Usage
from baltech_sdk import Brp, UsbHid
# Sample code for GetInfo
with Brp(UsbHid()) as brp:
print(brp.Sys_GetInfo())
# This is a shortcut for:
io = UsbHid()
brp = Brp(io, open=False)
brp.open()
print(brp.Sys_GetInfo())
brp.close()
A complete reference of the supported commands can be found here.
Supported IO protocols
from baltech_sdk import Brp, UsbHid, RS232
# USB HID autodetect connected reader
brp = Brp(UsbHid())
# USB HID by serialnumber
brp = Brp(UsbHid(serialnumber=99999999))
# Serial with (optional) custom settings
brp = Brp(RS232("COM1", baudrate=115200, parity=b"N"))
Reader Update
from baltech_sdk import Brp, UsbHid, ReaderUpdater
with Brp(UsbHid(), open=True) as brp:
updater = ReaderUpdater.from_path("firmware.bf3")
# simple upload
updater.run(brp)
# upload with progress
for progress in updater.iter(brp):
print(f"{progress.progress:.0%} ({progress.transferred_bytes} bytes)")
Access Reader Configuration
from baltech_sdk import Config
cfg_src = {(0x0201, 0x02): b'\x01'} # instead of a confDict also a brp object
# can be passed to modify reader's
# configuration directly
cfg = Config(cfg_src)
# set value
cfg.Device_Boot_StartAutoreadAtPowerup("EnableOnce")
# get value
print(cfg.Device_Boot_StartAutoreadAtPowerup.get())
# delete value
cfg.Device_Boot_StartAutoreadAtPowerup.delete()
Templates and BaltechScripts
from baltech_sdk import Config, Template, BaltechScript, TemplateFilter
confdict = {}
cfg = Config(confdict)
cfg.Scripts_Events_OnAccepted(
BaltechScript()
.ToggleInverted("RedLed", RepeatCount=3, Delay=20)
.Toggle("GreenLed", RepeatCount=1, Delay=20)
.DefaultAction()
)
cfg.Autoread_Rule_Template(
0,
Template()
.Static(b"SNR:")
.Serialnr(TemplateFilter(BinToAscii=True, Unpack=True, BinToBcd=True))
)
print(confdict)
Linux or macOS
To use baltech-sdk under Linux or macOS you need to build your own binary of the BaltechSDK and manually set the path to your binary.
from pathlib import Path
from baltech_sdk import set_brp_lib_path
set_brp_lib_path(Path("path/to/brp_lib"))
Custom protocols
Implement your own protocol in Python by subclassing CustomProtocol. Override
only the methods you need; not overriding a method makes it a transparent
passthrough to the layer below. Add the role marker (IoProtocol /
CryptoProtocol) matching where the protocol is meant to be mounted.
A byte-stream I/O transport (here over a TCP socket) overrides send_frame
and recv_frame. recv_frame drives the framing loop: missing_bytes_cb(chunk)
appends chunk and returns how many bytes are still missing (0 = frame complete):
import socket
from baltech_sdk import Brp, CustomProtocol, IoProtocol
from brp_lib.err import BrpTimeoutError
class TcpIo(CustomProtocol, IoProtocol):
INTERFACE_NAME = "IP" # log filename "{interface}-{instance}.html"
def __init__(self, host, port):
super().__init__()
self.host, self.port = host, port
@property
def instance_id(self): # the "{instance}" half (e.g. "IP-192.168.0.42.html")
return self.host
def open(self):
super().open()
self.sock = socket.create_connection((self.host, self.port), timeout=5)
def close(self):
self.sock.close()
super().close()
def send_frame(self, data):
self.sock.sendall(data)
def recv_frame(self, timeout, missing_bytes_cb):
self.sock.settimeout(None if timeout is None else timeout / 1000)
chunk = b""
while True:
n = missing_bytes_cb(chunk) # bytes still missing (0 = complete)
if n == 0:
break
try:
chunk = self.sock.recv(n)
except (socket.timeout, TimeoutError):
raise BrpTimeoutError()
if not chunk:
raise BrpTimeoutError()
with Brp(TcpIo("192.168.0.42", 9999)) as brp:
print(brp.Sys_GetInfo())
(A message/datagram transport that reads whole frames overrides
recv_any_frame(timeout) instead of recv_frame.)
A middle layer transforms whole frames and forwards them to the layer below
via self.base (here a toy obfuscation in the crypto slot). It can also run a
handshake when the stack is opened by extending open: super().open()
brings up the layer below, then exchange frames over it; raise a BrpError
to abort (the stack stays closed):
from baltech_sdk import Brp, UsbHid, CustomProtocol, CryptoProtocol, Layer
from brp_lib.err import OpenIOError
class XorLayer(CustomProtocol, CryptoProtocol):
def open(self):
super().open() # opens the layer below first
self.base.send_frame(b"AUTH-REQ") # negotiated in clear (no XOR)
if self.base.recv_any_frame(2000) != b"AUTH-OK":
raise OpenIOError("handshake rejected")
def send_frame(self, data):
self.base.send_frame(bytes(b ^ 0x5A for b in data))
def recv_any_frame(self, timeout=None):
return bytes(b ^ 0x5A for b in self.base.recv_any_frame(timeout))
brp = Brp(UsbHid())
brp.set_layer(Layer.CRYPTO, XorLayer())
brp.open() # runs XorLayer.open()
For open/close, extend with super() as usual — like every implementor of
an open callback (in C too), an override is responsible for bringing up the
layer below itself, and super().open() does exactly that (forget it and the
handshake send_frame fails on the still-closed base). For data methods,
forward through self.base, never super() — their base implementations are
"not implemented" markers, the layer below is reached via base.
self.base.send_frame / self.base.recv_any_frame exchange raw frames with
the layer directly below. For high-level command negotiation (e.g.
brp.Sys_GetInfo()), run it after brp.open() — those calls need the BRP
framing layer above this one.
Further parameters on connections fors sensible data
Additional Options:
- AES based Encryption can be activated
- Enabled monitoring can be suppressed or extended to plaintext
from baltech_sdk import Brp, UsbHid, SecureChannel
KEY = b'abcdefghijklmnuk'
brp = Brp(UsbHid(),
crypto=SecureChannel(security_level=1, key=KEY), # encrypt communication
monitor="plaintext" # log unencrypted data (if activated by user)
)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file baltech_sdk-5.2026.6.1.tar.gz.
File metadata
- Download URL: baltech_sdk-5.2026.6.1.tar.gz
- Upload date:
- Size: 262.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f051c5f60b50f1b5fc31d834353d9e6e400cd7c53c736cbc32621bc7acc71fca
|
|
| MD5 |
dba5fee4a96515bbcf1b9008474b67d5
|
|
| BLAKE2b-256 |
f60108f4c42035372ac75abbd517a201b7509fe02ee83b845b0f7d98a346a8ed
|
File details
Details for the file baltech_sdk-5.2026.6.1-py3-none-any.whl.
File metadata
- Download URL: baltech_sdk-5.2026.6.1-py3-none-any.whl
- Upload date:
- Size: 266.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1db0b84b389d699eea3463e99d87b75dea6359a6c3215f6cc95c638d4c709053
|
|
| MD5 |
e57f3ebce011444b1aea8132405be17e
|
|
| BLAKE2b-256 |
999a8811fbe81b54ee35bc777ed07caca94482eba9ec6cb0c5ec19481a2f8d82
|