Files
Alex CubeandClaude Opus 5.5 9e06f3ebd0 LX-D02 BLE thermal printer: PC, Windows printer, Home Assistant
- printer.py: protocol with flow control (pause / resend / done)
- lxd02.py: print text or pictures from the command line
- windows/: POS-58 driver + local ESC/POS server = a regular Windows printer,
  Explorer menu for pictures
- custom_components/lxd02: Home Assistant integration with a persistent queue

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 16:56:45 +03:00

73 lines
2.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Print on the LX-D02 thermal printer from the PC.
Usage: python lxd02.py "text" [more lines...]
python lxd02.py picture.jpg [more pictures...] (stretched to the tape width)
Set LXD02_MAC=AA:BB:CC:DD:EE:FF to skip the Bluetooth search.
"""
import asyncio
import os
import sys
from pathlib import Path
from bleak import BleakClient, BleakScanner
from PIL import Image, ImageOps
sys.path.insert(0, str(Path(__file__).resolve().parent / "custom_components" / "lxd02"))
from printer import WIDTH, print_payloads, render, to_payloads # noqa: E402
PICTURES = {".jpg", ".jpeg", ".png", ".bmp", ".gif", ".webp", ".tif", ".tiff"}
def picture(path):
"""Any picture -> 1-bit image WIDTH wide. Landscape ones are turned to run
along the tape, so they come out bigger."""
img = ImageOps.exif_transpose(Image.open(path)).convert("RGBA")
white = Image.new("RGBA", img.size, "white")
img = Image.alpha_composite(white, img).convert("L") # transparent -> white, not black
if img.width > img.height:
img = img.rotate(90, expand=True)
img = img.resize((WIDTH, max(2, round(img.height * WIDTH / img.width))), Image.LANCZOS)
return ImageOps.autocontrast(img, cutoff=1).convert("1") # dithering for halftones
async def send(img, mac=None):
mac = mac or os.environ.get("LXD02_MAC")
if not mac:
device = await BleakScanner.find_device_by_name("LX-D02", timeout=20)
if device is None:
raise RuntimeError("LX-D02 not found: is it on and not connected to a phone?")
mac = device.address
for attempt in range(3): # Windows often fails the first connect to a sleeping printer
try:
client = BleakClient(mac, timeout=20)
await client.connect()
break
except Exception:
if attempt == 2:
raise
await asyncio.sleep(2)
try:
await print_payloads(client, mac, to_payloads(img))
finally:
await client.disconnect()
def main(args):
if args and all(Path(a).suffix.lower() in PICTURES and Path(a).is_file() for a in args):
for a in args:
print("printing", a)
asyncio.run(send(picture(a)))
else:
asyncio.run(send(render("\n".join(args) or "Hello, LX-D02!\nПривет с ПК")))
print("ok")
if __name__ == "__main__":
try:
main(sys.argv[1:])
except Exception as err: # started from "Send to": keep the window open to show why
print("ERROR:", err)
if sys.stdin and sys.stdin.isatty():
input("Press Enter to close")
sys.exit(1)