Metadata-Version: 2.4
Name: pybrady
Version: 0.1.0
Summary: Python library for Brady label printers (USB, TCP, Bluetooth Classic, BLE)
Project-URL: Homepage, https://gitlab.com/ggiesen/pybrady
Project-URL: Repository, https://gitlab.com/ggiesen/pybrady.git
Project-URL: Issues, https://gitlab.com/ggiesen/pybrady/-/issues
Author: ggiesen
License-Expression: MPL-2.0
License-File: LICENSE
Keywords: bmp51,bmp61,brady,label,m211,m611,printer
Classifier: Development Status :: 2 - Pre-Alpha
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Printing
Classifier: Topic :: System :: Hardware
Requires-Python: >=3.10
Requires-Dist: pillow>=10.0
Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
Provides-Extra: all
Requires-Dist: bleak>=0.22; extra == 'all'
Requires-Dist: lz4>=4.0; extra == 'all'
Requires-Dist: pdf417gen>=0.8; extra == 'all'
Requires-Dist: ppf-datamatrix>=0.2; extra == 'all'
Requires-Dist: python-barcode>=0.15; extra == 'all'
Requires-Dist: pyusb>=1.2; extra == 'all'
Requires-Dist: segno>=1.6; extra == 'all'
Provides-Extra: barcode
Requires-Dist: python-barcode>=0.15; extra == 'barcode'
Provides-Extra: ble
Requires-Dist: bleak>=0.22; extra == 'ble'
Provides-Extra: datamatrix
Requires-Dist: ppf-datamatrix>=0.2; extra == 'datamatrix'
Provides-Extra: lz4
Requires-Dist: lz4>=4.0; extra == 'lz4'
Provides-Extra: pdf417
Requires-Dist: pdf417gen>=0.8; extra == 'pdf417'
Provides-Extra: qr
Requires-Dist: segno>=1.6; extra == 'qr'
Provides-Extra: render
Requires-Dist: pdf417gen>=0.8; extra == 'render'
Requires-Dist: ppf-datamatrix>=0.2; extra == 'render'
Requires-Dist: python-barcode>=0.15; extra == 'render'
Requires-Dist: segno>=1.6; extra == 'render'
Provides-Extra: usb
Requires-Dist: pyusb>=1.2; extra == 'usb'
Description-Content-Type: text/markdown

# pybrady

Python 3.10+ library for communicating with Brady label printers.

> **Status: pre-alpha.** Initial target is the Brady BMP51 over USB. The full framework supports USB, TCP (Wi-Fi / Ethernet), Bluetooth Classic SPP, and BLE across Linux, macOS, and Windows, but only the USB + ESC/BMP path is implemented today.

## Supported printers (planned)

| Model | Protocol | Transports | v0.1 |
|---|---|---|---|
| BMP51, BMP53 | ESC/BMP | USB, TCP, Bluetooth Classic | USB only |
| BMP61 | ESC/BMP | USB, TCP | — |
| M610, M710 | ESC/BMP | USB, TCP, BLE | — |
| M611, i5300, S3700, i7500, i4311, C1-30, MJ811 | JSON/PICL | USB, TCP, BLE | — |
| M211, M511, MM100BT | VGL/STX | BLE | — |

## Install

```bash
pip install 'pybrady[usb]'            # USB support (pyusb)
pip install 'pybrady[ble]'            # BLE support (bleak)
pip install 'pybrady[all]'            # everything
```

## Development

pybrady uses [uv](https://docs.astral.sh/uv/) for environment management, with ruff for lint/format and pytest for tests.

```bash
uv sync --all-extras          # create .venv, install package + all optional deps + dev group
uv run pytest                 # run tests
uv run ruff check             # lint
uv run ruff format            # format
uv run mypy src               # type-check
```

`uv.lock` is committed — `uv sync` produces a reproducible environment across machines. The floor Python version is pinned in `.python-version`; uv will download it automatically if your system Python doesn't match.

## Quick start — CLI

```bash
brady-print --list-models                         # see supported printers
brady-print --text HELLO --dry-run                # validate bytes, print nothing
brady-print --text HELLO --dry-run --save out.prn # save raw bytes for replay
brady-print --text HELLO                          # actually print to a BMP51
```

## Quick start — Python API

```python
import asyncio
from PIL import Image, ImageDraw, ImageFont
from pybrady import BradyPrinter
from pybrady.transport import UsbTransport

async def main():
    img = Image.new("1", (600, 200), 1)            # 2" x 0.67" @ 300 DPI, white
    draw = ImageDraw.Draw(img)
    draw.text((20, 20), "HELLO", fill=0)            # 0 = black

    async with UsbTransport.find_bmp51() as t:
        printer = BradyPrinter(t, model="BMP51")
        await printer.print(img)

asyncio.run(main())
```

## Permissions (Linux)

The kernel `usblp` driver claims Brady printers by default. pybrady detaches it automatically at connection time. To avoid running as root:

```bash
sudo cp packaging/99-brady.rules /etc/udev/rules.d/
sudo udevadm control --reload
sudo udevadm trigger
```

Then replug the printer. The rule uses `TAG+="uaccess"` — systemd-logind grants the active console user ACL access to any Brady USB device, which works out of the box on RHEL/Fedora/Ubuntu/Arch without needing a `plugdev` or similar group.

## License

[MPL 2.0](LICENSE). Modifications to pybrady files must be shared back; importing pybrady from proprietary code is fine.

## Acknowledgements

Protocol specification based on reverse-engineering of the Brady Express Labels Android app. See `/brady_specification.md` for the full byte-level spec used to build this library.
