python-fi50x
A transport-agnostic Python driver for the FI-50X UHF RFID reader (ISO-18000-6C / EPC Gen2) over its ASCII-over-UART protocol.
The library knows only the reader protocol — framing, the command set, typed responses, error-code handling and CRC-16 verification. It talks to a pluggable transport, so the same driver runs against a real serial port or a scripted fake in tests, and can be wrapped by any service (a RabbitMQ worker, a REST API, a CLI) on top.
- Import name:
fi50x - Distribution name:
python-fi50x(likepython-decouple→import decouple)
Features
- Inventory: single (
Q) and multi-tag (U,U<slotQ>) EPC reads, drained to completion and de-duplicated - Memory read/write (
R/W) with correct hex address/length framing and word-length validation - Tag management: access password (
P), kill (K), lock/unlock (L), select/filter (T) - Read-with-EPC (
UR/QR), TX power and frequency-regulation get/set - Typed results (
Tag,ReadResult,WriteResult) and a typed exception hierarchy for reader error codes - Gen2 CRC-16 verification of EPC reads
TagTrackerhelper to turn inventory sweeps into new/lost tag events- Thread-safe: a transport lock serialises full command/response transactions
Scope note: GPIO, frequency tuning, baud switching, command logging and the AA
binary protocol are not implemented yet. See doc/PROTOCOL.md
for the complete protocol reference.
Installation
pip install python-fi50x
Requires Python ≥ 3.8 and a serial connection to the reader (USB-UART). From source:
git clone https://github.com/pavelkim/python-fi50x
cd python-fi50x
pip install -e .[dev]
Quickstart
from fi50x import RFIDReader, Bank, Regulation
# Open the serial port (default baud 38400).
reader = RFIDReader.open("/dev/ttyUSB0")
print("firmware:", reader.firmware_version())
print("reader id:", reader.refresh_reader_id())
# Optional configuration
reader.set_regulation(Regulation.EU) # 865–868 MHz
reader.set_power_dbm(20) # register = dBm + 2, handled for you
# Inventory — read every tag currently in the field
for tag in reader.inventory().tags:
print(tag.epc, "crc_ok" if tag.crc_valid else "crc?")
# Read 4 words of USER memory, then write two words back
data = reader.read(Bank.USER, address=0, length=4).data
reader.write(Bank.USER, address=0, data="DEADBEEF") # leading zeros preserved
reader.close()
RFIDReader is also a context manager (with RFIDReader.open(port) as reader:).
For tests or non-serial links, construct it directly with a Transport:
RFIDReader(my_transport).
Continuous scanning with new/lost detection
from fi50x import RFIDReader, TagTracker
reader = RFIDReader.open("/dev/ttyUSB0")
tracker = TagTracker(miss_tolerance=2) # tolerate a couple of missed sweeps
for result in reader.stream_inventory(interval=0.1):
delta = tracker.update(tag.epc for tag in result.tags)
for epc in delta.new:
print("+ NEW ", epc)
for epc in delta.lost:
print("- LOST", epc)
A ready-to-run version of this is python-fi50x-scan.py:
./python-fi50x-scan.py --port /dev/ttyUSB0 --mode changes # only new/lost tags
./python-fi50x-scan.py --port /dev/ttyUSB0 --mode stream # every tag, every sweep
./python-fi50x-scan.py --help
Error handling
Reader error codes are raised as typed exceptions (all subclasses of
ReaderError), so callers can react to specific conditions:
from fi50x import MemoryLockedError, InsufficientPowerError, NoTagError
try:
reader.write(Bank.EPC, 2, "30001234")
except MemoryLockedError:
... # bank is locked
except InsufficientPowerError:
... # move the tag closer / raise power and retry
except NoTagError:
... # nothing in the field
Configuration
The example script reads config from CLI flags, falling back to environment
variables (a local .env is loaded if python-decouple
is installed). See .env.example:
| Variable | Default | Meaning |
|---|---|---|
SERIAL_PORT |
/dev/ttyUSB0 |
Serial device |
BAUDRATE |
38400 |
UART baud rate |
TIMEOUT |
0.5 |
Serial read timeout (s) |
TX_POWER |
20 |
TX power in dBm (−2…25) |
REGULATION |
05 |
Regulation code (05 = EU) |
Development
pip install -e .[dev]
pytest # run the test suite (no hardware needed — uses a fake transport)
tox # test across Python versions
tox -e build # build the sdist + wheel into dist/
Tests run entirely against a scripted FakeTransport, so no reader is required.
Protocol reference
The full FI-50X command specification — framing, every command, error codes, regulation and baud tables, examples and the Gen2 memory map — is in doc/PROTOCOL.md. Original vendor datasheets are in doc/.
License
MIT © Pavel Kim
Release files for python-fi50x 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| python_fi50x-0.2.0.tar.gz | 21.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| python_fi50x-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.2 kB
Release files / python_fi50x-0.2.0.tar.gz
| Download URL | python_fi50x-0.2.0.tar.gz |
|---|---|
| Size | 21.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
abbc8eec7cd1179b3ec77be22ca9c84b34de23dacac83bf796d9c3744ada0c2c
|
|
BLAKE2b-256 checksum How to use checksums |
35c4125a7d1e783880a7df6dc5ff098d427f2fb4814c3cb6dec407c6be5c22fa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 9, 2026.
Transparency logRelease files / python_fi50x-0.2.0-py3-none-any.whl
| Download URL | python_fi50x-0.2.0-py3-none-any.whl |
|---|---|
| Size | 19.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fe4db5b77598ff545bc369e2783b6301c445596d71e4d3c08aa108cb8ac5b888
|
|
BLAKE2b-256 checksum How to use checksums |
c5e371f3aebd0e54cb8f36121f95ed52faf64d07725595dacf309ee993510619
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Jul 9, 2026.
Transparency log