Skip to main content

LX-D02 receipt printer

Print on an LX-D02 Bluetooth thermal receipt printer (58 mm paper, sold e.g. as Dolebo, used with the Funny Print app) from a PC, without the phone app. Receipts can be any length and stack an icon, a title, Markdown text (lists, checklists, tables…), a QR code and a picture.

The printer's Bluetooth protocol, reverse engineered from the Funny Print app, is documented in PROTOCOL.md.

For Home Assistant, see the HA-LXD02 integration, which carries a copy of this package's protocol and renderer.

Requirements

  • Windows, macOS or Linux with Bluetooth LE
  • Python 3.12+

Install

pip install lxd02-printer

This installs the lxd02 module (import lxd02) and the lxd02-print command. To work on the code instead, clone this repository and install it editable in a virtual environment:

python -m venv .venv
.venv\Scripts\python -m pip install -e .

On macOS/Linux use .venv/bin/python instead of .venv\Scripts\python.

The printer switches itself off after a few minutes idle, and accepts only one connection: turn it on and close the phone app (and turn off Home Assistant's Stay connected) before printing.

lxd02-print --info

Printing

lxd02-print --icon mdi:coffee --title "Coffee break" --text "Back in 15 minutes"
lxd02-print --title Shopping --file list.md
lxd02-print --qr "WIFI:T:WPA;S:Home;P:secret;;" --title "Guest Wi-Fi"
lxd02-print --image photo.jpg --energy 5
lxd02-print --feed 20
Option Default
--title TEXT large centred heading
--text TEXT body text in Markdown; \n starts a new line, - reads stdin
--file PATH body text from a UTF-8 (Markdown) file
--plain print the text exactly as written, without Markdown
--qr TEXT QR code content
--icon mdi:NAME MDI icon at the top
--image PATH picture, scaled to the paper width and dithered
--size normal text size: small, normal, large
--align left body text: left, center, right
--energy 1-6 printer's darkness; the printer remembers it
--feed MM 0 extra blank paper after the print. On its own (nothing else to print), just advance that much paper
--no-dither hard black/white pictures
--copies N 1
--preview DIR save receipt.png instead of printing
--address MAC scan printer address, e.g. C0:00:00:00:00:48
--info battery, paper and darkness

python -m lxd02 works the same as lxd02-print.

After every job the printer advances about 10 mm of paper by itself, so the last printed line clears the tear bar. Feeds count it: --feed 12 gives 12 mm, and 10 mm is the shortest feed. The first 10–20 mm of a print can come out faint while the print head warms up.

Markdown: lists, checklists, tables

The text is Markdown, so shopping lists, to-dos and notes print formatted:

# Weekend
## Groceries
- [ ] Milk
- [x] Bread
- [ ] Coffee, **dark roast**

## Hardware store
1. Screws *(4 mm)*
2. Wood glue
   - the ~~cheap~~ good one

> Remember the bags!

| Item   | Qty | Price |
|:-------|:---:|------:|
| Apples |  6  |  2.40 |

---
```
Total   6.38
```
Markdown Prints as
# H1, ## H2, ### H3 headings (H1 centred, H1/H2 underlined)
**bold**, *italic* / _italic_, ~~strike~~, `code` inline styles (code on a light gray background)
[text](url) underlined text
- item, * item, 1. item bullet and numbered lists; indent to nest
- [ ] task, - [x] done checkboxes, empty or ticked
> text quote with a bar on the left
``` fenced block monospace box, spaces kept
--- dashed tear line
| a | b | + |---|---| table with a bold header; :--, :-:, --: align columns
![alt](path) picture, relative to the --file

Unlike standard Markdown, every line break is kept. Text uses the bundled DejaVu fonts, so every machine prints identically.

Using it from Python

import asyncio
from lxd02 import LXD02, render_receipt

async def main():
    img = render_receipt(title="Shopping", text="- [ ] Milk\n- [ ] Bread", icon="mdi:cart")
    async with LXD02() as printer:  # scans for the printer; or LXD02("C0:00:00:00:00:48")
        status = await printer.wait_status()
        print(status.battery, status.no_paper)
        await printer.print_image(img, energy=3)
        await printer.feed(20)

asyncio.run(main())

lxd02.protocol.LXD02 is the protocol on its own: give it any connected bleak client (Home Assistant's, for example).

Development

src/lxd02/protocol.py, receipt.py, markdown.py and assets/ are copied unchanged into the HA-LXD02 integration. Change them here, then copy them there; HA-LXD02's tests check the copies match when both projects sit side by side.

The tests cover the protocol against a simulated printer (handshake, hold/resend, out of paper, the automatic feed), the Markdown renderer and the CLI:

pip install -e . pytest pytest-asyncio
pytest

Releasing

Releases go to PyPI through the Publish workflow, with trusted publishing (no API tokens):

  1. Bump version in pyproject.toml and push.
  2. Optional: Actions → Publish → Run workflow uploads that build to TestPyPI; try it with pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ lxd02-printer. TestPyPI refuses a version it already has, so bump again to re-test.
  3. Publish a GitHub release with the tag v + the version (e.g. v0.1.1). The workflow checks the tag matches, builds, smoke-tests the wheel and uploads it to PyPI.

Files

Path What it is
src/lxd02/protocol.py the Bluetooth protocol: handshake, status, darkness, printing, feed
src/lxd02/receipt.py, markdown.py the receipt and Markdown renderer
src/lxd02/client.py a plain bleak connection (scan, connect, unlock)
src/lxd02/cli.py the lxd02-print command
src/lxd02/assets/ DejaVu Sans / Sans Mono fonts and license, MDI icon font 7.4.47 and license
tests/ protocol, renderer and CLI tests
PROTOCOL.md the reverse-engineered printer protocol
.github/workflows/publish.yml build and publish to PyPI / TestPyPI
LICENSE MIT; the bundled fonts keep their own licenses

Metadata

Release files for lxd02-printer 0.1.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 lxd02-printer 0.1.0
File Size Uploaded Provenance Actions
lxd02_printer-0.1.0.tar.gz 1.8 MB With provenance Details for lxd02_printer-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for lxd02-printer 0.1.0
File Interpreter ABI Platform Actions
lxd02_printer-0.1.0-py3-none-any.whl Python 3 none any Details for lxd02_printer-0.1.0-py3-none-any.whl

Total release size: 3.6 MB

Release files / lxd02_printer-0.1.0.tar.gz

Download URL lxd02_printer-0.1.0.tar.gz
Size 1.8 MB
Tags Source
SHA-256 checksum
How to use checksums
9a4e74d9a3b1b9e6ddf2074035df7fe7eaa93168f752a89bdd1e5c544b938cb9
BLAKE2b-256 checksum
How to use checksums
7cf03dd975e3e15873898a869086b36cb8e4d110e44344cf54fc8f1667bc93a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / lxd02_printer-0.1.0-py3-none-any.whl

Download URL lxd02_printer-0.1.0-py3-none-any.whl
Size 1.8 MB
Tags Python 3
SHA-256 checksum
How to use checksums
44bd6d212faeccb769a27ce6c35288277f4fccc757259d3d146759abaa9b5c36
BLAKE2b-256 checksum
How to use checksums
d6018164ff085b5e8e6a43f2408d83d9e1ecd8119c5a22c6f092881b512c9e83
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Security for lxd02-printer 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for lxd02_printer-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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