Skip to main content

Python module for interacting with ATC BLE firmware on OEPL e-paper tags

Project description

Tests PyPI Python Version

py-atc-ble-oepl

Python library for interacting with ATC BLE firmware over Bluetooth Low Energy.

Installation

uv add py-atc-ble-oepl

For the CLI:

uv add "py-atc-ble-oepl[cli]"

Or run the CLI directly without installing into a project:

uvx --from "py-atc-ble-oepl[cli]" atc-ble scan

CLI

atc-ble scan [--timeout 30] [--json]
atc-ble info  --device ADDR [--timeout 60] [--json]
atc-ble led   --device ADDR [--duration 5]
atc-ble upload --device ADDR IMAGE [--dither-mode burkes] [--fit contain] [--rotate 0] [--no-compress]

Scan for nearby devices:

$ atc-ble scan
┌──────────────────────────────────────┬───────────────┬──────────┐
│ Address                              │ Name          │     RSSI │
├──────────────────────────────────────┼───────────────┼──────────┤
│ 5F4CEF52-A1CD-E2EE-011F-F27129B8D4A9 │ ATC_911943    │  -61 dBm │
└──────────────────────────────────────┴───────────────┴──────────┘

Show device info:

$ atc-ble info --device 5F4CEF52-A1CD-E2EE-011F-F27129B8D4A9
5F4CEF52-A1CD-E2EE-011F-F27129B8D4A9
├── Display
│   ├── Resolution    184 × 384
│   └── Color         BWY
└── Hardware
    ├── OEPL type     0x0060
    ├── Screen type   2  (350 HS BWY UC Inverted)
    └── ...

Flash the LED to identify a device physically:

$ atc-ble led --device 5F4CEF52-A1CD-E2EE-011F-F27129B8D4A9
LED done → ATC_911943

Upload an image:

$ atc-ble upload --device 5F4CEF52-... photo.jpg
Upload complete.

ATC tags advertise infrequently — the default --timeout for device commands is 60 s. On macOS the address is a UUID, not a MAC address.

Python API

Discover devices

from py_atc_ble_oepl import discover_atc_devices

devices = await discover_atc_devices(timeout=30.0)
for d in devices:
    print(f"{d.name}  {d.mac_address}  {d.rssi} dBm")

Upload an image

from py_atc_ble_oepl import ATCDevice

async with ATCDevice("AA:BB:CC:DD:EE:FF") as device:
    success = await device.upload_image("photo.jpg")

upload_image accepts a file path (str), raw bytes, or a PIL Image. It automatically:

  • queries device capabilities (dimensions, color scheme)
  • resizes and fits the image
  • dithers to the display's color palette (MONO / BWR / BWY / BWRY)
  • compresses and uploads over BLE

Image options

from py_atc_ble_oepl import ATCDevice, FitMode, Rotation
from epaper_dithering import DitherMode

async with ATCDevice("AA:BB:CC:DD:EE:FF") as device:
    await device.upload_image(
        "photo.jpg",
        dither_mode=DitherMode.BURKES,   # default
        fit=FitMode.COVER,               # STRETCH / CONTAIN / COVER / CROP
        rotate=Rotation.ROTATE_90,       # 0 / 90 / 180 / 270
        compress=True,                   # default
    )

Read device info

from py_atc_ble_oepl import ATCDevice

async with ATCDevice("AA:BB:CC:DD:EE:FF") as device:
    caps = device._capabilities        # DeviceCapabilities
    cfg  = device.device_config        # DeviceConfig (full hardware settings)
    print(f"{caps.width}x{caps.height}  {caps.color_scheme}")
    print(f"OEPL type 0x{cfg.hw_type:04X}  screen_type {cfg.screen_type}")

Pass a discovered device to avoid re-scanning

On macOS bleak can only connect to a device it has already seen during a scan. Passing the BLEDevice object from discovery skips a second scan:

from py_atc_ble_oepl import discover_atc_devices, ATCDevice

devices = await discover_atc_devices(timeout=30.0)
if devices:
    async with ATCDevice(devices[0].mac_address, ble_device=devices[0].ble_device) as device:
        await device.upload_image("photo.jpg")

API reference

ATCDevice

ATCDevice(mac_address, ble_device=None, auto_interrogate=True, connection_timeout=60.0)
Method / Property Description
async interrogate() Query device capabilities (called automatically on connect)
async flash_led(duration=5.0) Flash the LED for duration seconds to identify the device
async upload_image(image, ...) Upload and display an image
width, height Display dimensions in pixels (None before interrogation)
color_scheme ColorScheme enum value (None before interrogation)
device_config DeviceConfig dataclass with full hardware settings

discover_atc_devices(timeout=30.0)

Scans for ATC BLE devices (manufacturer ID 0x1337). Returns list[DiscoveredDevice].

DeviceCapabilities

Field Type Description
width int Display width in pixels
height int Display height in pixels
color_scheme int 0=MONO, 1=BWR, 2=BWY, 3=BWRY

DeviceConfig

Full hardware configuration from the 0011 dynamic config read. Key fields:

Field Type Description
hw_type int OEPL tag type (hex)
screen_type int ATC screen driver type (1–47)
screen_w, screen_h int Physical display dimensions
screen_colors int Color count
black_invert, second_color_invert bool Color plane polarity
epd_pinout, led_pinout, nfc_pinout, flash_pinout dataclass or None GPIO pin assignments

Acknowledgements

This library is based on the work of Aaron (atc1441) - creator of the ATC BLE firmware and the original web uploader for ATC BLE e-paper tags. The BLE protocol implemented here is derived entirely from that web uploader.

Development

git clone https://github.com/OpenDisplay-org/py-atc-ble-oepl.git
cd py-atc-ble-oepl
uv sync --all-extras

uv run pytest tests/ -v
uv run ruff check .
uv run mypy src/py_atc_ble_oepl

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

py_atc_ble_oepl-0.3.0.tar.gz (100.4 kB view details)

Uploaded Source

Built Distribution

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

py_atc_ble_oepl-0.3.0-py3-none-any.whl (38.1 kB view details)

Uploaded Python 3

File details

Details for the file py_atc_ble_oepl-0.3.0.tar.gz.

File metadata

  • Download URL: py_atc_ble_oepl-0.3.0.tar.gz
  • Upload date:
  • Size: 100.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for py_atc_ble_oepl-0.3.0.tar.gz
Algorithm Hash digest
SHA256 0cb4928e3508bab6e73372456e49d7b1e8c4c97d6ff520cfc19e15489bf17c2f
MD5 4efd611d20f5a67efdadb0502f831ecd
BLAKE2b-256 500055584c2eed6161a2baf63a683e54224920b912467f0a740b243f458c2907

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_atc_ble_oepl-0.3.0.tar.gz:

Publisher: release.yml on OpenDisplay/py-atc-ble-oepl

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

File details

Details for the file py_atc_ble_oepl-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: py_atc_ble_oepl-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 38.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for py_atc_ble_oepl-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b7243b5a2a9ea84659561c551800102d7fca2e5ff3f9916209953eb70eae7a1d
MD5 2884dcbea8182068cff1c48aeb6a580e
BLAKE2b-256 330862c21ba83e0b341dddda811a305ded32650c4d9b53473182c3a2edc786a9

See more details on using hashes here.

Provenance

The following attestation bundles were made for py_atc_ble_oepl-0.3.0-py3-none-any.whl:

Publisher: release.yml on OpenDisplay/py-atc-ble-oepl

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