Python SDK for NFC Agent - read and write NFC cards via local nfc-agent server
Project description
NFC Agent Python SDK
Python SDK for interacting with NFC readers via the nfc-agent local server.
Installation
pip install nfc-agent
Requirements
- Python 3.9+
- Running nfc-agent server
Quick Start
REST API (Simple Operations)
import asyncio
from nfc_agent import NFCClient
async def main():
async with NFCClient() as client:
# List readers
readers = await client.get_readers()
print(f"Found {len(readers)} reader(s)")
# Read card
try:
card = await client.read_card(0)
print(f"Card UID: {card.uid}")
print(f"Card Type: {card.type}")
if card.data:
print(f"Data: {card.data}")
except Exception as e:
print(f"No card present: {e}")
asyncio.run(main())
Synchronous Usage
from nfc_agent import NFCClient
with NFCClient() as client:
readers = client.get_readers_sync()
card = client.read_card_sync(0)
print(f"Card UID: {card.uid}")
WebSocket (Real-time Events)
import asyncio
from nfc_agent import NFCWebSocket
async def main():
async with NFCWebSocket() as ws:
# Subscribe to reader events
await ws.subscribe(0)
@ws.on_card_detected
def handle_card(event):
print(f"Card detected: {event.card.uid}")
@ws.on_card_removed
def handle_removed(event):
print(f"Card removed from reader {event.reader}")
# Keep running
await asyncio.sleep(60)
asyncio.run(main())
Card Polling
import asyncio
from nfc_agent import NFCClient
async def main():
async with NFCClient() as client:
poller = client.poll_card(0, interval=0.5)
@poller.on_card
def handle_card(card):
print(f"Card: {card.uid}")
@poller.on_removed
def handle_removed():
print("Card removed")
await poller.start()
await asyncio.sleep(30)
poller.stop()
asyncio.run(main())
API Reference
NFCClient
REST API client for simple request/response operations.
from nfc_agent import NFCClient
# With context manager (recommended)
async with NFCClient(base_url="http://127.0.0.1:32145", timeout=5.0) as client:
...
# Or sync
with NFCClient() as client:
...
Methods
| Method | Description |
|---|---|
get_readers() |
List available NFC readers |
read_card(reader_index, *, refresh=False) |
Read card metadata + NDEF. Fast — use for detection/polling. Pass refresh=True to bypass cache. |
write_card(reader_index, *, data, data_type, url) |
Write data to a card |
get_version() |
Get agent version information |
is_connected() |
Check if agent is running |
poll_card(reader_index, *, interval) |
Create a card poller |
MIFARE Classic
| Method | Description |
|---|---|
read_mifare_block(reader_index, block, *, key, key_type) |
Read 16-byte block |
write_mifare_block(reader_index, block, *, data, key, key_type) |
Write 16-byte block |
write_mifare_blocks(reader_index, blocks, *, key, key_type) |
Batch write blocks |
derive_uid_key_aes(reader_index, aes_key) |
Derive key from UID |
aes_encrypt_and_write_block(...) |
AES encrypt and write |
write_mifare_sector_trailer(...) |
Write sector trailer |
MIFARE Ultralight / NTAG
| Method | Description |
|---|---|
read_ultralight_page(reader_index, page, *, password) |
Read 4-byte page |
write_ultralight_page(reader_index, page, *, data, password) |
Write 4-byte page |
write_ultralight_pages(reader_index, pages, *, password) |
Batch write pages |
NFCWebSocket
WebSocket client for real-time communication and events.
from nfc_agent import NFCWebSocket
async with NFCWebSocket(
url="ws://127.0.0.1:32145/v1/ws",
timeout=5.0,
auto_reconnect=True,
reconnect_interval=3.0,
secure=False # Use wss:// for HTTPS pages
) as ws:
...
Methods
All methods from NFCClient, plus:
| Method | Description |
|---|---|
subscribe(reader_index, *, include_raw=False) |
Subscribe to card events. Pass include_raw=True to also receive on_card_data events with full memory dump. |
unsubscribe(reader_index) |
Unsubscribe from events |
read_card_full(reader_index) |
Unified read — metadata + NDEF + full raw memory dump. Slow — call once on demand, not in a poll loop. |
dump_card(reader_index) |
Raw memory dump only (pages for NTAG, blocks for MIFARE Classic; no NDEF metadata) |
erase_card(reader_index) |
Erase NDEF data |
lock_card(reader_index) |
Permanently lock card |
set_password(reader_index, password) |
Set NTAG password |
remove_password(reader_index, password) |
Remove NTAG password |
write_records(reader_index, records) |
Write multiple NDEF records |
health() |
Health check |
Events
@ws.on_card_detected
def handle_card(event):
print(event.card.uid)
@ws.on_card_data
def handle_data(event):
# event.pages (NTAG) or event.blocks (MIFARE Classic)
print(event.pages)
@ws.on_card_removed
def handle_removed(event):
print(f"Removed from reader {event.reader}")
@ws.on_connected
def handle_connected():
print("Connected")
@ws.on_disconnected
def handle_disconnected():
print("Disconnected")
@ws.on_error
def handle_error(error):
print(f"Error: {error}")
CardPoller
Polls a reader for card presence.
poller = client.poll_card(reader_index, interval=1.0)
@poller.on_card
def handle_card(card):
print(card.uid)
@poller.on_removed
def handle_removed():
print("Removed")
@poller.on_error
def handle_error(e):
print(f"Error: {e}")
await poller.start()
# ...
poller.stop()
Types
from nfc_agent import (
Reader,
Card,
CardDataType,
VersionInfo,
HealthInfo,
CardDetectedEvent,
CardRemovedEvent,
MifareKeyType,
MifareBlockData,
UltralightPageData,
NDEFRecord,
)
Exceptions
from nfc_agent import (
NFCAgentError, # Base exception
ConnectionError, # Connection failed
CardError, # Card operation failed
APIError, # API returned error
TimeoutError, # Request timed out
ReaderError, # Reader issue
)
Examples
Write URL to Card
async with NFCClient() as client:
await client.write_card(0, data="https://example.com", data_type="url")
Write Text to Card
async with NFCClient() as client:
await client.write_card(0, data="Hello World", data_type="text")
Write JSON to Card
import json
async with NFCClient() as client:
data = json.dumps({"user_id": 123, "name": "Alice"})
await client.write_card(0, data=data, data_type="json")
Read MIFARE Classic Block
from nfc_agent import MifareKeyType
async with NFCClient() as client:
block = await client.read_mifare_block(
0,
block=4,
key="FFFFFFFFFFFF",
key_type=MifareKeyType.A
)
print(f"Block {block.block}: {block.data}")
Monitor Multiple Readers
async with NFCWebSocket() as ws:
# Subscribe to all readers
readers = await ws.get_readers()
for i, reader in enumerate(readers):
await ws.subscribe(i)
print(f"Subscribed to {reader.name}")
@ws.on_card_detected
def handle(event):
print(f"Reader {event.reader}: {event.card.uid}")
await asyncio.sleep(300)
Development
# Install dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Lint
ruff check src tests
# Type check
mypy src
License
MIT
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 nfc_agent-0.5.2.tar.gz.
File metadata
- Download URL: nfc_agent-0.5.2.tar.gz
- Upload date:
- Size: 15.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
98837aabede55cacb77cc17cc8d9e4584ddd455f4700aa34e390d594f6004e72
|
|
| MD5 |
bf70357ff0ccaab2b05b1c86a88e9c8f
|
|
| BLAKE2b-256 |
f56127f2e0681310f3a5ebd5ac15a6f205cfb62cc82fd2ecabfa0bdeaf1532d9
|
Provenance
The following attestation bundles were made for nfc_agent-0.5.2.tar.gz:
Publisher:
sdk-python-release.yml on SimplyPrint/nfc-agent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nfc_agent-0.5.2.tar.gz -
Subject digest:
98837aabede55cacb77cc17cc8d9e4584ddd455f4700aa34e390d594f6004e72 - Sigstore transparency entry: 1042193846
- Sigstore integration time:
-
Permalink:
SimplyPrint/nfc-agent@d8177dff3b165e29fe8fa7c3275f513b85eff69a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/SimplyPrint
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-python-release.yml@d8177dff3b165e29fe8fa7c3275f513b85eff69a -
Trigger Event:
push
-
Statement type:
File details
Details for the file nfc_agent-0.5.2-py3-none-any.whl.
File metadata
- Download URL: nfc_agent-0.5.2-py3-none-any.whl
- Upload date:
- Size: 18.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b45dd5f0fa2ab0824af70d310e1dfc4e3e2d5eb637dd86b7bac937b54513c9c9
|
|
| MD5 |
b820188e8ada6d433cfe759ca9e3d441
|
|
| BLAKE2b-256 |
3ab6b844133b8a6b3fc90f1c1ad639304eb2667458af6284b4965c4e1f76a463
|
Provenance
The following attestation bundles were made for nfc_agent-0.5.2-py3-none-any.whl:
Publisher:
sdk-python-release.yml on SimplyPrint/nfc-agent
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nfc_agent-0.5.2-py3-none-any.whl -
Subject digest:
b45dd5f0fa2ab0824af70d310e1dfc4e3e2d5eb637dd86b7bac937b54513c9c9 - Sigstore transparency entry: 1042193916
- Sigstore integration time:
-
Permalink:
SimplyPrint/nfc-agent@d8177dff3b165e29fe8fa7c3275f513b85eff69a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/SimplyPrint
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
sdk-python-release.yml@d8177dff3b165e29fe8fa7c3275f513b85eff69a -
Trigger Event:
push
-
Statement type: