WP9529 label printer
Print labels on a VSON WP9529 Bluetooth label printer from a PC, without
the phone app: a Python package (pip install wp9529-printer) and a
command-line tool.
Labels can mix a QR code (URL, Wi-Fi details, any text), a large title, smaller text and a Material Design Icon.
The printer's Bluetooth protocol, reverse engineered from the iLabel app, is documented in PROTOCOL.md.
For Home Assistant, see HA-WP9529, an integration built on this package's label renderer. For Homebox asset tags, see Homebox-labeler, which uses this package.
Requirements
- Windows, macOS or Linux with Bluetooth LE
- Python 3.12+
- A WP9529 with 30 × 12 mm die-cut labels (other sizes work with
--length/--gap)
Install
pip install wp9529-printer
This installs the wp9529 module (import wp9529) and the wp9529-label 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.
Turn the printer on and close the phone app or disconnect it from the printer, because the printer only accepts one connection at a time. It doesn't need pairing; the tool finds it automatically.
wp9529-label --info
printer 95:29:12:C2:09:0C: firmware V50
auto power-off after 96 minutes
Printing labels
Any mix of --title (large text), --text, --qr and --icon:
wp9529-label --title Router --text "admin password in the vault" --icon mdi:router-wireless
wp9529-label --qr "WIFI:T:WPA;S:Home;P:secret;;" --text "Guest Wi-Fi"
wp9529-label --title Spices --preview previews
Layout, along the label: QR code, then icon, then text. With no text, the QR
code and icon are centred. On a 30 mm label, an icon next to both a QR code and
text shrinks to about 6 mm, and long text gets shortened with "…". Use
--length 40 on longer labels for more room.
Your own image works too. It must be exactly 96 px wide (the print head); for a 30 mm label it should be 240 px tall, and the top prints first:
wp9529-label --image my_label.png
Options
| Option | Default | Meaning |
|---|---|---|
--title TEXT |
large text | |
--text TEXT |
smaller text, or the only text | |
--qr DATA |
any text to encode as a QR code | |
--icon mdi:NAME |
an MDI icon | |
--image PATH |
print an image 96 px wide | |
--copies N |
1 | copies of each label |
--length MM |
30 | label length |
--gap MM |
8.5 | gap between labels |
--continuous |
continuous tape instead of die-cut labels | |
--density |
normal | light, normal or dark |
--rotate |
90 | use 270 if the text comes out upside down |
--feed N |
0 | extra blank lines after each label |
--preview DIR |
save PNGs to DIR instead of printing | |
--address MAC |
scan | printer Bluetooth address (skips the scan) |
--info |
show the firmware and auto power-off time | |
--power-off MIN |
set how many idle minutes before the printer switches itself off (10–180); the printer remembers it | |
-v |
verbose: log every Bluetooth packet |
python -m wp9529 works the same as wp9529-label.
Using it from Python
import asyncio
from wp9529 import WP9529, asset_tag, render_label
async def main():
img = render_label(title="Router", qr="https://example.com", icon="mdi:router-wireless")
async with WP9529() as printer: # scans for the printer; or WP9529("95:29:12:C2:09:0C")
await printer.print_image(img, density="normal", label_mm=30, gap_mm=8.5)
print(await printer.firmware_version(), await printer.power_off_minutes())
asyncio.run(main())
asset_tag(asset_id, name, url, icon=...) renders the ID + name + QR layout
used for inventory tags.
Home Assistant
The Home Assistant integration lives in its own repository,
HA-WP9529: sensors, settings, a print
form with live preview, a notify entity and the wp9529.print_label action.
Development
The label renderer and its icon font live in src/wp9529/label.py and
src/wp9529/assets/. HA-WP9529 can't install this package inside Home
Assistant, so it carries an identical copy; after changing the renderer, copy
it there too. HA-WP9529's tests fail if the copies differ while both projects
sit side by side.
The tests cover the renderer and the CLI:
pip install -e . pytest
pytest
Releasing
Releases go to PyPI through the Publish workflow, with trusted publishing (no API tokens):
- Bump
versioninpyproject.tomland push. - 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/ wp9529-printer. TestPyPI refuses a version it already has, so bump again to re-test. - 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.
Troubleshooting
"No WP9529 found": the printer is off, asleep, or connected to the phone app (or Home Assistant). Turn it on, close the app and try again.
Labels are shifted or run into the gap: the printer has lost its place on
the roll. Use the printer's own re-align (feed) button, then print again. This
can happen after a job that is longer than the label. Don't change --length
or --gap to compensate.
Text is upside down: add --rotate 270.
Print is too faint or too dark: use --density dark or --density light.
"unknown MDI icon": check the name at pictogrammers.com. The bundled font is version 7.4.47, so icons added after it aren't available.
Files
| Path | What it is |
|---|---|
src/wp9529/ |
the Python package: driver.py (Bluetooth LE, bleak), label.py (renderer), cli.py (wp9529-label), assets/ (MDI icon font 7.4.47, codepoints, license) |
tests/ |
renderer and CLI tests |
tools/scan.py, tools/probe.py |
debugging helpers for finding the printer and sending raw commands |
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 wp9529-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)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| wp9529_printer-0.1.0.tar.gz | 658.2 kB | With provenance | Details for wp9529_printer-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| wp9529_printer-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for wp9529_printer-0.1.0-py3-none-any.whl |
Total release size: 1.3 MB
Release files / wp9529_printer-0.1.0.tar.gz
| Download URL | wp9529_printer-0.1.0.tar.gz |
|---|---|
| Size | 658.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b4d2a6097d76ab7ecd9bb3c309721f60fa201437f38e5a340f244d851e58773b
|
|
BLAKE2b-256 checksum How to use checksums |
ace21034fdff6c55afb8f592b293e319f651310408dafd74ab8834e19ee39183
|
| 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 logRelease files / wp9529_printer-0.1.0-py3-none-any.whl
| Download URL | wp9529_printer-0.1.0-py3-none-any.whl |
|---|---|
| Size | 655.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
111ef3b03f8a678c2efd0ffbabc905c516565ef1ca773ced551a691072244c13
|
|
BLAKE2b-256 checksum How to use checksums |
956e55cea77f7bab11a352f5b9bae12e3504fb3f3bc369809e5af0a50bfd57c8
|
| 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 logSecurity for wp9529-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.
Attestation for wp9529_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 logA 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.