Skip to main content

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

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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nfc_agent-0.5.2.tar.gz (15.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nfc_agent-0.5.2-py3-none-any.whl (18.5 kB view details)

Uploaded Python 3

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

Hashes for nfc_agent-0.5.2.tar.gz
Algorithm Hash digest
SHA256 98837aabede55cacb77cc17cc8d9e4584ddd455f4700aa34e390d594f6004e72
MD5 bf70357ff0ccaab2b05b1c86a88e9c8f
BLAKE2b-256 f56127f2e0681310f3a5ebd5ac15a6f205cfb62cc82fd2ecabfa0bdeaf1532d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for nfc_agent-0.5.2.tar.gz:

Publisher: sdk-python-release.yml on SimplyPrint/nfc-agent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for nfc_agent-0.5.2-py3-none-any.whl
Algorithm Hash digest
SHA256 b45dd5f0fa2ab0824af70d310e1dfc4e3e2d5eb637dd86b7bac937b54513c9c9
MD5 b820188e8ada6d433cfe759ca9e3d441
BLAKE2b-256 3ab6b844133b8a6b3fc90f1c1ad639304eb2667458af6284b4965c4e1f76a463

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page