wp9529-printer 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wp9529_printer-0.1.0/LICENSE +25 -0
- wp9529_printer-0.1.0/PKG-INFO +217 -0
- wp9529_printer-0.1.0/README.md +189 -0
- wp9529_printer-0.1.0/pyproject.toml +44 -0
- wp9529_printer-0.1.0/setup.cfg +4 -0
- wp9529_printer-0.1.0/src/wp9529/__init__.py +24 -0
- wp9529_printer-0.1.0/src/wp9529/__main__.py +4 -0
- wp9529_printer-0.1.0/src/wp9529/assets/MDI-LICENSE +20 -0
- wp9529_printer-0.1.0/src/wp9529/assets/materialdesignicons-webfont.ttf +0 -0
- wp9529_printer-0.1.0/src/wp9529/assets/mdi-codepoints.json +1 -0
- wp9529_printer-0.1.0/src/wp9529/cli.py +109 -0
- wp9529_printer-0.1.0/src/wp9529/driver.py +241 -0
- wp9529_printer-0.1.0/src/wp9529/label.py +213 -0
- wp9529_printer-0.1.0/src/wp9529_printer.egg-info/PKG-INFO +217 -0
- wp9529_printer-0.1.0/src/wp9529_printer.egg-info/SOURCES.txt +19 -0
- wp9529_printer-0.1.0/src/wp9529_printer.egg-info/dependency_links.txt +1 -0
- wp9529_printer-0.1.0/src/wp9529_printer.egg-info/entry_points.txt +2 -0
- wp9529_printer-0.1.0/src/wp9529_printer.egg-info/requires.txt +3 -0
- wp9529_printer-0.1.0/src/wp9529_printer.egg-info/top_level.txt +1 -0
- wp9529_printer-0.1.0/tests/test_label.py +26 -0
- wp9529_printer-0.1.0/tests/test_package.py +25 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arttu Mahlakaarto
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
The bundled fonts in src/*/assets keep their own licenses: see MDI-LICENSE
|
|
24
|
+
(Material Design Icons, Pictogrammers Free License) and, where present,
|
|
25
|
+
DejaVu-LICENSE (DejaVu fonts, Bitstream Vera license).
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: wp9529-printer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Driver, label renderer and CLI for the VSON WP9529 Bluetooth LE label printer
|
|
5
|
+
Author: Arttu Mahlakaarto
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/amahlaka/WP9529
|
|
8
|
+
Project-URL: Issues, https://github.com/amahlaka/WP9529/issues
|
|
9
|
+
Project-URL: Protocol, https://github.com/amahlaka/WP9529/blob/main/PROTOCOL.md
|
|
10
|
+
Keywords: label printer,bluetooth,ble,thermal printer,qr code,wp9529,vson
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Printing
|
|
20
|
+
Requires-Python: >=3.12
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
License-File: src/wp9529/assets/MDI-LICENSE
|
|
24
|
+
Requires-Dist: bleak>=0.22
|
|
25
|
+
Requires-Dist: Pillow>=10.1.0
|
|
26
|
+
Requires-Dist: qrcode>=7.4.2
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
|
|
29
|
+
# WP9529 label printer
|
|
30
|
+
|
|
31
|
+
Print labels on a VSON **WP9529** Bluetooth label printer from a PC, without
|
|
32
|
+
the phone app: a Python package (`pip install wp9529-printer`) and a
|
|
33
|
+
command-line tool.
|
|
34
|
+
|
|
35
|
+
Labels can mix a QR code (URL, Wi-Fi details, any text), a large title, smaller
|
|
36
|
+
text and a [Material Design Icon](https://pictogrammers.com/library/mdi/).
|
|
37
|
+
|
|
38
|
+
The printer's Bluetooth protocol, reverse engineered from the iLabel app, is
|
|
39
|
+
documented in [PROTOCOL.md](PROTOCOL.md).
|
|
40
|
+
|
|
41
|
+
For Home Assistant, see [HA-WP9529](https://github.com/amahlaka/HA-WP9529), an
|
|
42
|
+
integration built on this package's label renderer. For Homebox asset tags,
|
|
43
|
+
see [Homebox-labeler](https://github.com/amahlaka/Homebox-labeler), which uses
|
|
44
|
+
this package.
|
|
45
|
+
|
|
46
|
+
## Requirements
|
|
47
|
+
|
|
48
|
+
- Windows, macOS or Linux with Bluetooth LE
|
|
49
|
+
- Python 3.12+
|
|
50
|
+
- A WP9529 with 30 × 12 mm die-cut labels (other sizes work with `--length`/`--gap`)
|
|
51
|
+
|
|
52
|
+
## Install
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install wp9529-printer
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This installs the `wp9529` module (`import wp9529`) and the `wp9529-label` command. To work on the code
|
|
59
|
+
instead, clone this repository and install it editable in a virtual
|
|
60
|
+
environment:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
python -m venv .venv
|
|
64
|
+
```
|
|
65
|
+
```bash
|
|
66
|
+
.venv\Scripts\python -m pip install -e .
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
On macOS/Linux use `.venv/bin/python` instead of `.venv\Scripts\python`.
|
|
70
|
+
|
|
71
|
+
Turn the printer on and **close the phone app or disconnect it from the
|
|
72
|
+
printer**, because the printer only accepts one connection at a time. It
|
|
73
|
+
doesn't need pairing; the tool finds it automatically.
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
wp9529-label --info
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
printer 95:29:12:C2:09:0C: firmware V50
|
|
81
|
+
auto power-off after 96 minutes
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Printing labels
|
|
85
|
+
|
|
86
|
+
Any mix of `--title` (large text), `--text`, `--qr` and `--icon`:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
wp9529-label --title Router --text "admin password in the vault" --icon mdi:router-wireless
|
|
90
|
+
```
|
|
91
|
+
```bash
|
|
92
|
+
wp9529-label --qr "WIFI:T:WPA;S:Home;P:secret;;" --text "Guest Wi-Fi"
|
|
93
|
+
```
|
|
94
|
+
```bash
|
|
95
|
+
wp9529-label --title Spices --preview previews
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Layout, along the label: QR code, then icon, then text. With no text, the QR
|
|
99
|
+
code and icon are centred. On a 30 mm label, an icon next to both a QR code and
|
|
100
|
+
text shrinks to about 6 mm, and long text gets shortened with "…". Use
|
|
101
|
+
`--length 40` on longer labels for more room.
|
|
102
|
+
|
|
103
|
+
Your own image works too. It must be exactly 96 px wide (the print head); for a
|
|
104
|
+
30 mm label it should be 240 px tall, and the top prints first:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
wp9529-label --image my_label.png
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Options
|
|
111
|
+
|
|
112
|
+
| Option | Default | Meaning |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `--title TEXT` | | large text |
|
|
115
|
+
| `--text TEXT` | | smaller text, or the only text |
|
|
116
|
+
| `--qr DATA` | | any text to encode as a QR code |
|
|
117
|
+
| `--icon mdi:NAME` | | an MDI icon |
|
|
118
|
+
| `--image PATH` | | print an image 96 px wide |
|
|
119
|
+
| `--copies N` | 1 | copies of each label |
|
|
120
|
+
| `--length MM` | 30 | label length |
|
|
121
|
+
| `--gap MM` | 8.5 | gap between labels |
|
|
122
|
+
| `--continuous` | | continuous tape instead of die-cut labels |
|
|
123
|
+
| `--density` | normal | `light`, `normal` or `dark` |
|
|
124
|
+
| `--rotate` | 90 | use `270` if the text comes out upside down |
|
|
125
|
+
| `--feed N` | 0 | extra blank lines after each label |
|
|
126
|
+
| `--preview DIR` | | save PNGs to DIR instead of printing |
|
|
127
|
+
| `--address MAC` | scan | printer Bluetooth address (skips the scan) |
|
|
128
|
+
| `--info` | | show the firmware and auto power-off time |
|
|
129
|
+
| `--power-off MIN` | | set how many idle minutes before the printer switches itself off (10–180); the printer remembers it |
|
|
130
|
+
| `-v` | | verbose: log every Bluetooth packet |
|
|
131
|
+
|
|
132
|
+
`python -m wp9529` works the same as `wp9529-label`.
|
|
133
|
+
|
|
134
|
+
## Using it from Python
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
import asyncio
|
|
138
|
+
from wp9529 import WP9529, asset_tag, render_label
|
|
139
|
+
|
|
140
|
+
async def main():
|
|
141
|
+
img = render_label(title="Router", qr="https://example.com", icon="mdi:router-wireless")
|
|
142
|
+
async with WP9529() as printer: # scans for the printer; or WP9529("95:29:12:C2:09:0C")
|
|
143
|
+
await printer.print_image(img, density="normal", label_mm=30, gap_mm=8.5)
|
|
144
|
+
print(await printer.firmware_version(), await printer.power_off_minutes())
|
|
145
|
+
|
|
146
|
+
asyncio.run(main())
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
`asset_tag(asset_id, name, url, icon=...)` renders the ID + name + QR layout
|
|
150
|
+
used for inventory tags.
|
|
151
|
+
|
|
152
|
+
## Home Assistant
|
|
153
|
+
|
|
154
|
+
The Home Assistant integration lives in its own repository,
|
|
155
|
+
[HA-WP9529](https://github.com/amahlaka/HA-WP9529): sensors, settings, a print
|
|
156
|
+
form with live preview, a `notify` entity and the `wp9529.print_label` action.
|
|
157
|
+
|
|
158
|
+
## Development
|
|
159
|
+
|
|
160
|
+
The label renderer and its icon font live in `src/wp9529/label.py` and
|
|
161
|
+
`src/wp9529/assets/`. HA-WP9529 can't install this package inside Home
|
|
162
|
+
Assistant, so it carries an identical copy; after changing the renderer, copy
|
|
163
|
+
it there too. HA-WP9529's tests fail if the copies differ while both projects
|
|
164
|
+
sit side by side.
|
|
165
|
+
|
|
166
|
+
The tests cover the renderer and the CLI:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
pip install -e . pytest
|
|
170
|
+
```
|
|
171
|
+
```bash
|
|
172
|
+
pytest
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Releasing
|
|
176
|
+
|
|
177
|
+
Releases go to [PyPI](https://pypi.org/project/wp9529-printer/) through the
|
|
178
|
+
[Publish workflow](.github/workflows/publish.yml), with trusted publishing (no
|
|
179
|
+
API tokens):
|
|
180
|
+
|
|
181
|
+
1. Bump `version` in `pyproject.toml` and push.
|
|
182
|
+
2. Optional: *Actions → Publish → Run workflow* uploads that build to
|
|
183
|
+
[TestPyPI](https://test.pypi.org/project/wp9529-printer/); try it with
|
|
184
|
+
`pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ wp9529-printer`.
|
|
185
|
+
TestPyPI refuses a version it already has, so bump again to re-test.
|
|
186
|
+
3. Publish a GitHub release with the tag `v` + the version (e.g. `v0.1.1`).
|
|
187
|
+
The workflow checks the tag matches, builds, smoke-tests the wheel and
|
|
188
|
+
uploads it to PyPI.
|
|
189
|
+
|
|
190
|
+
## Troubleshooting
|
|
191
|
+
|
|
192
|
+
**"No WP9529 found"**: the printer is off, asleep, or connected to the phone
|
|
193
|
+
app (or Home Assistant). Turn it on, close the app and try again.
|
|
194
|
+
|
|
195
|
+
**Labels are shifted or run into the gap**: the printer has lost its place on
|
|
196
|
+
the roll. Use the printer's own re-align (feed) button, then print again. This
|
|
197
|
+
can happen after a job that is longer than the label. Don't change `--length`
|
|
198
|
+
or `--gap` to compensate.
|
|
199
|
+
|
|
200
|
+
**Text is upside down**: add `--rotate 270`.
|
|
201
|
+
|
|
202
|
+
**Print is too faint or too dark**: use `--density dark` or `--density light`.
|
|
203
|
+
|
|
204
|
+
**"unknown MDI icon"**: check the name at
|
|
205
|
+
[pictogrammers.com](https://pictogrammers.com/library/mdi/). The bundled font
|
|
206
|
+
is version 7.4.47, so icons added after it aren't available.
|
|
207
|
+
|
|
208
|
+
## Files
|
|
209
|
+
|
|
210
|
+
| Path | What it is |
|
|
211
|
+
|---|---|
|
|
212
|
+
| `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) |
|
|
213
|
+
| `tests/` | renderer and CLI tests |
|
|
214
|
+
| `tools/scan.py`, `tools/probe.py` | debugging helpers for finding the printer and sending raw commands |
|
|
215
|
+
| `PROTOCOL.md` | the reverse-engineered printer protocol |
|
|
216
|
+
| `.github/workflows/publish.yml` | build and publish to PyPI / TestPyPI |
|
|
217
|
+
| `LICENSE` | MIT; the bundled fonts keep their own licenses |
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# WP9529 label printer
|
|
2
|
+
|
|
3
|
+
Print labels on a VSON **WP9529** Bluetooth label printer from a PC, without
|
|
4
|
+
the phone app: a Python package (`pip install wp9529-printer`) and a
|
|
5
|
+
command-line tool.
|
|
6
|
+
|
|
7
|
+
Labels can mix a QR code (URL, Wi-Fi details, any text), a large title, smaller
|
|
8
|
+
text and a [Material Design Icon](https://pictogrammers.com/library/mdi/).
|
|
9
|
+
|
|
10
|
+
The printer's Bluetooth protocol, reverse engineered from the iLabel app, is
|
|
11
|
+
documented in [PROTOCOL.md](PROTOCOL.md).
|
|
12
|
+
|
|
13
|
+
For Home Assistant, see [HA-WP9529](https://github.com/amahlaka/HA-WP9529), an
|
|
14
|
+
integration built on this package's label renderer. For Homebox asset tags,
|
|
15
|
+
see [Homebox-labeler](https://github.com/amahlaka/Homebox-labeler), which uses
|
|
16
|
+
this package.
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- Windows, macOS or Linux with Bluetooth LE
|
|
21
|
+
- Python 3.12+
|
|
22
|
+
- A WP9529 with 30 × 12 mm die-cut labels (other sizes work with `--length`/`--gap`)
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pip install wp9529-printer
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This installs the `wp9529` module (`import wp9529`) and the `wp9529-label` command. To work on the code
|
|
31
|
+
instead, clone this repository and install it editable in a virtual
|
|
32
|
+
environment:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
python -m venv .venv
|
|
36
|
+
```
|
|
37
|
+
```bash
|
|
38
|
+
.venv\Scripts\python -m pip install -e .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
On macOS/Linux use `.venv/bin/python` instead of `.venv\Scripts\python`.
|
|
42
|
+
|
|
43
|
+
Turn the printer on and **close the phone app or disconnect it from the
|
|
44
|
+
printer**, because the printer only accepts one connection at a time. It
|
|
45
|
+
doesn't need pairing; the tool finds it automatically.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
wp9529-label --info
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
printer 95:29:12:C2:09:0C: firmware V50
|
|
53
|
+
auto power-off after 96 minutes
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Printing labels
|
|
57
|
+
|
|
58
|
+
Any mix of `--title` (large text), `--text`, `--qr` and `--icon`:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
wp9529-label --title Router --text "admin password in the vault" --icon mdi:router-wireless
|
|
62
|
+
```
|
|
63
|
+
```bash
|
|
64
|
+
wp9529-label --qr "WIFI:T:WPA;S:Home;P:secret;;" --text "Guest Wi-Fi"
|
|
65
|
+
```
|
|
66
|
+
```bash
|
|
67
|
+
wp9529-label --title Spices --preview previews
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Layout, along the label: QR code, then icon, then text. With no text, the QR
|
|
71
|
+
code and icon are centred. On a 30 mm label, an icon next to both a QR code and
|
|
72
|
+
text shrinks to about 6 mm, and long text gets shortened with "…". Use
|
|
73
|
+
`--length 40` on longer labels for more room.
|
|
74
|
+
|
|
75
|
+
Your own image works too. It must be exactly 96 px wide (the print head); for a
|
|
76
|
+
30 mm label it should be 240 px tall, and the top prints first:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
wp9529-label --image my_label.png
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Options
|
|
83
|
+
|
|
84
|
+
| Option | Default | Meaning |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `--title TEXT` | | large text |
|
|
87
|
+
| `--text TEXT` | | smaller text, or the only text |
|
|
88
|
+
| `--qr DATA` | | any text to encode as a QR code |
|
|
89
|
+
| `--icon mdi:NAME` | | an MDI icon |
|
|
90
|
+
| `--image PATH` | | print an image 96 px wide |
|
|
91
|
+
| `--copies N` | 1 | copies of each label |
|
|
92
|
+
| `--length MM` | 30 | label length |
|
|
93
|
+
| `--gap MM` | 8.5 | gap between labels |
|
|
94
|
+
| `--continuous` | | continuous tape instead of die-cut labels |
|
|
95
|
+
| `--density` | normal | `light`, `normal` or `dark` |
|
|
96
|
+
| `--rotate` | 90 | use `270` if the text comes out upside down |
|
|
97
|
+
| `--feed N` | 0 | extra blank lines after each label |
|
|
98
|
+
| `--preview DIR` | | save PNGs to DIR instead of printing |
|
|
99
|
+
| `--address MAC` | scan | printer Bluetooth address (skips the scan) |
|
|
100
|
+
| `--info` | | show the firmware and auto power-off time |
|
|
101
|
+
| `--power-off MIN` | | set how many idle minutes before the printer switches itself off (10–180); the printer remembers it |
|
|
102
|
+
| `-v` | | verbose: log every Bluetooth packet |
|
|
103
|
+
|
|
104
|
+
`python -m wp9529` works the same as `wp9529-label`.
|
|
105
|
+
|
|
106
|
+
## Using it from Python
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
import asyncio
|
|
110
|
+
from wp9529 import WP9529, asset_tag, render_label
|
|
111
|
+
|
|
112
|
+
async def main():
|
|
113
|
+
img = render_label(title="Router", qr="https://example.com", icon="mdi:router-wireless")
|
|
114
|
+
async with WP9529() as printer: # scans for the printer; or WP9529("95:29:12:C2:09:0C")
|
|
115
|
+
await printer.print_image(img, density="normal", label_mm=30, gap_mm=8.5)
|
|
116
|
+
print(await printer.firmware_version(), await printer.power_off_minutes())
|
|
117
|
+
|
|
118
|
+
asyncio.run(main())
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`asset_tag(asset_id, name, url, icon=...)` renders the ID + name + QR layout
|
|
122
|
+
used for inventory tags.
|
|
123
|
+
|
|
124
|
+
## Home Assistant
|
|
125
|
+
|
|
126
|
+
The Home Assistant integration lives in its own repository,
|
|
127
|
+
[HA-WP9529](https://github.com/amahlaka/HA-WP9529): sensors, settings, a print
|
|
128
|
+
form with live preview, a `notify` entity and the `wp9529.print_label` action.
|
|
129
|
+
|
|
130
|
+
## Development
|
|
131
|
+
|
|
132
|
+
The label renderer and its icon font live in `src/wp9529/label.py` and
|
|
133
|
+
`src/wp9529/assets/`. HA-WP9529 can't install this package inside Home
|
|
134
|
+
Assistant, so it carries an identical copy; after changing the renderer, copy
|
|
135
|
+
it there too. HA-WP9529's tests fail if the copies differ while both projects
|
|
136
|
+
sit side by side.
|
|
137
|
+
|
|
138
|
+
The tests cover the renderer and the CLI:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
pip install -e . pytest
|
|
142
|
+
```
|
|
143
|
+
```bash
|
|
144
|
+
pytest
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Releasing
|
|
148
|
+
|
|
149
|
+
Releases go to [PyPI](https://pypi.org/project/wp9529-printer/) through the
|
|
150
|
+
[Publish workflow](.github/workflows/publish.yml), with trusted publishing (no
|
|
151
|
+
API tokens):
|
|
152
|
+
|
|
153
|
+
1. Bump `version` in `pyproject.toml` and push.
|
|
154
|
+
2. Optional: *Actions → Publish → Run workflow* uploads that build to
|
|
155
|
+
[TestPyPI](https://test.pypi.org/project/wp9529-printer/); try it with
|
|
156
|
+
`pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ wp9529-printer`.
|
|
157
|
+
TestPyPI refuses a version it already has, so bump again to re-test.
|
|
158
|
+
3. Publish a GitHub release with the tag `v` + the version (e.g. `v0.1.1`).
|
|
159
|
+
The workflow checks the tag matches, builds, smoke-tests the wheel and
|
|
160
|
+
uploads it to PyPI.
|
|
161
|
+
|
|
162
|
+
## Troubleshooting
|
|
163
|
+
|
|
164
|
+
**"No WP9529 found"**: the printer is off, asleep, or connected to the phone
|
|
165
|
+
app (or Home Assistant). Turn it on, close the app and try again.
|
|
166
|
+
|
|
167
|
+
**Labels are shifted or run into the gap**: the printer has lost its place on
|
|
168
|
+
the roll. Use the printer's own re-align (feed) button, then print again. This
|
|
169
|
+
can happen after a job that is longer than the label. Don't change `--length`
|
|
170
|
+
or `--gap` to compensate.
|
|
171
|
+
|
|
172
|
+
**Text is upside down**: add `--rotate 270`.
|
|
173
|
+
|
|
174
|
+
**Print is too faint or too dark**: use `--density dark` or `--density light`.
|
|
175
|
+
|
|
176
|
+
**"unknown MDI icon"**: check the name at
|
|
177
|
+
[pictogrammers.com](https://pictogrammers.com/library/mdi/). The bundled font
|
|
178
|
+
is version 7.4.47, so icons added after it aren't available.
|
|
179
|
+
|
|
180
|
+
## Files
|
|
181
|
+
|
|
182
|
+
| Path | What it is |
|
|
183
|
+
|---|---|
|
|
184
|
+
| `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) |
|
|
185
|
+
| `tests/` | renderer and CLI tests |
|
|
186
|
+
| `tools/scan.py`, `tools/probe.py` | debugging helpers for finding the printer and sending raw commands |
|
|
187
|
+
| `PROTOCOL.md` | the reverse-engineered printer protocol |
|
|
188
|
+
| `.github/workflows/publish.yml` | build and publish to PyPI / TestPyPI |
|
|
189
|
+
| `LICENSE` | MIT; the bundled fonts keep their own licenses |
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=77"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "wp9529-printer"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Driver, label renderer and CLI for the VSON WP9529 Bluetooth LE label printer"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE", "src/wp9529/assets/*LICENSE"]
|
|
13
|
+
authors = [{ name = "Arttu Mahlakaarto" }]
|
|
14
|
+
keywords = ["label printer", "bluetooth", "ble", "thermal printer", "qr code", "wp9529", "vson"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Environment :: Console",
|
|
18
|
+
"Intended Audience :: End Users/Desktop",
|
|
19
|
+
"Operating System :: OS Independent",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"Topic :: Printing",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"bleak>=0.22",
|
|
28
|
+
"Pillow>=10.1.0",
|
|
29
|
+
"qrcode>=7.4.2",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/amahlaka/WP9529"
|
|
34
|
+
Issues = "https://github.com/amahlaka/WP9529/issues"
|
|
35
|
+
Protocol = "https://github.com/amahlaka/WP9529/blob/main/PROTOCOL.md"
|
|
36
|
+
|
|
37
|
+
[project.scripts]
|
|
38
|
+
wp9529-label = "wp9529.cli:main"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
where = ["src"]
|
|
42
|
+
|
|
43
|
+
[tool.setuptools.package-data]
|
|
44
|
+
wp9529 = ["assets/*"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""VSON WP9529 Bluetooth LE label printer: driver, label renderer and CLI."""
|
|
2
|
+
from .driver import (
|
|
3
|
+
DENSITY,
|
|
4
|
+
POWER_OFF_MAX,
|
|
5
|
+
POWER_OFF_MIN,
|
|
6
|
+
WP9529,
|
|
7
|
+
Info,
|
|
8
|
+
PrinterError,
|
|
9
|
+
find_printer,
|
|
10
|
+
)
|
|
11
|
+
from .label import asset_tag, mdi_glyph, render_label
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"DENSITY",
|
|
15
|
+
"POWER_OFF_MAX",
|
|
16
|
+
"POWER_OFF_MIN",
|
|
17
|
+
"WP9529",
|
|
18
|
+
"Info",
|
|
19
|
+
"PrinterError",
|
|
20
|
+
"asset_tag",
|
|
21
|
+
"find_printer",
|
|
22
|
+
"mdi_glyph",
|
|
23
|
+
"render_label",
|
|
24
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Pictogrammers Free License
|
|
2
|
+
--------------------------
|
|
3
|
+
|
|
4
|
+
This icon collection is released as free, open source, and GPL friendly by
|
|
5
|
+
the [Pictogrammers](http://pictogrammers.com/) icon group. You may use it
|
|
6
|
+
for commercial projects, open source projects, or anything really.
|
|
7
|
+
|
|
8
|
+
# Icons: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
|
|
9
|
+
Some of the icons are redistributed under the Apache 2.0 license. All other
|
|
10
|
+
icons are either redistributed under their respective licenses or are
|
|
11
|
+
distributed under the Apache 2.0 license.
|
|
12
|
+
|
|
13
|
+
# Fonts: Apache 2.0 (https://www.apache.org/licenses/LICENSE-2.0)
|
|
14
|
+
All web and desktop fonts are distributed under the Apache 2.0 license. Web
|
|
15
|
+
and desktop fonts contain some icons that are redistributed under the Apache
|
|
16
|
+
2.0 license. All other icons are either redistributed under their respective
|
|
17
|
+
licenses or are distributed under the Apache 2.0 license.
|
|
18
|
+
|
|
19
|
+
# Code: MIT (https://opensource.org/licenses/MIT)
|
|
20
|
+
The MIT license applies to all non-font and non-icon files.
|
|
Binary file
|