Skip to main content

pepper_c1

Python driver for the Eccel Pepper C1 RFID reader made by Eccel Technology Ltd.

Supports communication over UART and TCP, and covers MIFARE Classic, MIFARE Ultralight, MIFARE DESFire, and ICODE tag families.

Compatibility

Module UART TCP MIFARE Classic MIFARE Ultralight MIFARE DESFire ICODE
Pepper C1 ✓ ✓ ✓ ✓ ✓ ✓
Pepper C2 ✓ — ✓ ✓ — ✓

Pepper C2 modules communicate over UART only and do not support the MIFARE DESFire command set (mfdf_* methods). All other commands work identically to the C1.

Installation

pip install pepper_c1

Quick start

from pepper_c1 import PepperC1, UARTTransport

with PepperC1(UARTTransport('/dev/ttyUSB0', baudrate=115200)) as reader:
    print(reader.get_version())
    count = reader.get_tag_count()
    if count:
        uid_info = reader.get_uid()  # returns [type, param, uid_bytes...]
        print(f"Tag UID: {uid_info[2:].hex()}")

MIFARE Classic example

from pepper_c1 import PepperC1, UARTTransport
from pepper_c1.commands import KEY_TYPE_MIFARE

with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
    reader.get_tag_count()
    reader.activate_tag()
    reader.set_key(0, KEY_TYPE_MIFARE, bytes([0xFF] * 12))  # key A + key B

    original = reader.mf_read_block(5)
    print(f"Block 5: {original.hex()}")

    reader.mf_write_block(5, b'\x01' * 16)
    print(f"Readback: {reader.mf_read_block(5).hex()}")

    reader.mf_write_block(5, original)  # restore

MIFARE Ultralight example

from pepper_c1 import PepperC1, UARTTransport

with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
    reader.get_tag_count()
    reader.activate_tag()

    original = reader.mfu_read_page(4)
    print(f"Page 4: {original.hex()}")

    reader.mfu_write_page(4, b'\x01\x02\x03\x04')
    print(f"Readback: {reader.mfu_read_page(4).hex()}")

    reader.mfu_write_page(4, original)  # restore

MIFARE DESFire example

from pepper_c1 import PepperC1, UARTTransport
from pepper_c1.commands import KEY_TYPE_AES128

with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
    # DESFire does not need activate_tag
    reader.get_tag_count()
    reader.mfdf_select_app(bytes([0x00, 0x00, 0x00]))  # select PICC master app
    reader.set_key(0, KEY_TYPE_AES128, bytes(16))       # all-zero = factory default
    reader.mfdf_auth_aes(key_no=0, key_slot=0)

    app_ids = reader.mfdf_get_app_ids()
    for aid in app_ids:
        print(f"AID: {aid.hex()}")

ICODE example

from pepper_c1 import PepperC1, UARTTransport

with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
    # ICODE (ISO 15693) does not need activate_tag
    reader.get_tag_count()
    reader.get_uid()

    original = reader.icode_read_block(5)
    print(f"Block 5: {original.hex()}")

    reader.icode_write_block(5, b'\x01\x02\x03\x04')
    print(f"Readback: {reader.icode_read_block(5).hex()}")

    reader.icode_write_block(5, original)  # restore

Antenna multiplexer example

For readers with multiple antennas, use set_active_antenna() to switch between them (1–8):

import time
from pepper_c1 import PepperC1, UARTTransport

with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
    while True:
        for antenna in range(1, 9):
            reader.set_active_antenna(antenna)
            count = reader.get_tag_count()
            if count:
                uid_info = reader.get_uid()
                tag_type = uid_info[0]
                uid = uid_info[2:].hex().upper()
                print(f"Antenna {antenna}: type=0x{tag_type:02X}  UID={uid}")
            else:
                print(f"Antenna {antenna}: --")

See tools/mux_example.py for the full CLI script with transport selection and configurable dwell time.

Firmware update (OTA)

import math
from pepper_c1 import PepperC1, TCPTransport
from pepper_c1.commands import Command

fw_data    = open("Pepper_C1_2.56.2249.bin", "rb").read()
chunk_size = 1024
num_frames = math.ceil(len(fw_data) / chunk_size)

with PepperC1(TCPTransport('192.168.100.1', 1234), response_timeout=2.0) as reader:
    reader._timeout = 5.0
    reader.send_command(Command.OTA_BEGIN)

    reader._timeout = 2.0
    for i in range(num_frames):
        chunk = fw_data[i * chunk_size : (i + 1) * chunk_size]
        reader.send_command(Command.OTA_FRAME, chunk)
        print(f"\r  {(i + 1) * 100 // num_frames}%  frame {i + 1}/{num_frames}", end="")

    print()
    reader._timeout = 5.0
    reader.send_command(Command.OTA_FINISH)
    reader.reboot()

See tools/firmware_update.py for the full script with progress bar and CLI options.

TCP transport

from pepper_c1 import PepperC1, TCPTransport

# Connect via TCP before opening UART — closing UART may reset the device
with PepperC1(TCPTransport('192.168.100.1', 1234)) as reader:
    print(reader.get_version())
    count = reader.get_tag_count()
    if count:
        uid_info = reader.get_uid()
        print(f"Tag UID: {uid_info[2:].hex()}")

Error handling

from pepper_c1 import PepperC1, UARTTransport, CommandError, TransportError

try:
    with PepperC1(UARTTransport('/dev/ttyUSB0')) as reader:
        reader.get_tag_count()
        reader.get_uid()
except TransportError as e:
    print(f"Connection failed: {e}")
except CommandError as e:
    print(f"Device error: {e}")

Protocol

The Pepper C1 uses a binary framing protocol over serial or TCP:

[0xF5] [LEN_L] [LEN_H] [LEN_L^0xFF] [LEN_H^0xFF] [PAYLOAD...] [CRC_L] [CRC_H]

CRC is CCITT-16 computed over the payload only. Low-level access is available via PepperC1.send_command(cmd, data).

Metadata

Release files for pepper-c1 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pepper-c1 0.2.0
File Size Uploaded
pepper_c1-0.2.0.tar.gz 21.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pepper-c1 0.2.0
File Interpreter ABI Platform
pepper_c1-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 40.2 kB

Release files / pepper_c1-0.2.0.tar.gz

Download URL pepper_c1-0.2.0.tar.gz
Size 21.8 kB
Tags Source
SHA-256 checksum
How to use checksums
3c48fad4ab82c5e88571cecae3d1963a812b8e6496b00e5b1756ba80b1467c4c
BLAKE2b-256 checksum
How to use checksums
247633ec060dd06990331e09fb13e127fa2f8d578519dfe31ff93e1f35703530
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.8.3

Release files / pepper_c1-0.2.0-py3-none-any.whl

Download URL pepper_c1-0.2.0-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
acc1143661b11398f27d23b480638a8263e2ff8960d102f841791439531e9769
BLAKE2b-256 checksum
How to use checksums
2c8f6bf7a9fae71c5aefeed678e0024bcf3fc865afc9f67666ebec35fa92953e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.8.3

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page