lxd02-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.
- lxd02_printer-0.1.0/LICENSE +25 -0
- lxd02_printer-0.1.0/PKG-INFO +228 -0
- lxd02_printer-0.1.0/README.md +199 -0
- lxd02_printer-0.1.0/pyproject.toml +44 -0
- lxd02_printer-0.1.0/setup.cfg +4 -0
- lxd02_printer-0.1.0/src/lxd02/__init__.py +15 -0
- lxd02_printer-0.1.0/src/lxd02/__main__.py +4 -0
- lxd02_printer-0.1.0/src/lxd02/assets/DejaVu-LICENSE +78 -0
- lxd02_printer-0.1.0/src/lxd02/assets/DejaVuSans-Bold.ttf +0 -0
- lxd02_printer-0.1.0/src/lxd02/assets/DejaVuSans.ttf +0 -0
- lxd02_printer-0.1.0/src/lxd02/assets/DejaVuSansMono-Bold.ttf +0 -0
- lxd02_printer-0.1.0/src/lxd02/assets/DejaVuSansMono.ttf +0 -0
- lxd02_printer-0.1.0/src/lxd02/assets/MDI-LICENSE +20 -0
- lxd02_printer-0.1.0/src/lxd02/assets/materialdesignicons-webfont.ttf +0 -0
- lxd02_printer-0.1.0/src/lxd02/assets/mdi-codepoints.json +1 -0
- lxd02_printer-0.1.0/src/lxd02/cli.py +107 -0
- lxd02_printer-0.1.0/src/lxd02/client.py +49 -0
- lxd02_printer-0.1.0/src/lxd02/markdown.py +532 -0
- lxd02_printer-0.1.0/src/lxd02/protocol.py +242 -0
- lxd02_printer-0.1.0/src/lxd02/receipt.py +114 -0
- lxd02_printer-0.1.0/src/lxd02_printer.egg-info/PKG-INFO +228 -0
- lxd02_printer-0.1.0/src/lxd02_printer.egg-info/SOURCES.txt +27 -0
- lxd02_printer-0.1.0/src/lxd02_printer.egg-info/dependency_links.txt +1 -0
- lxd02_printer-0.1.0/src/lxd02_printer.egg-info/entry_points.txt +2 -0
- lxd02_printer-0.1.0/src/lxd02_printer.egg-info/requires.txt +3 -0
- lxd02_printer-0.1.0/src/lxd02_printer.egg-info/top_level.txt +1 -0
- lxd02_printer-0.1.0/tests/test_cli.py +23 -0
- lxd02_printer-0.1.0/tests/test_markdown.py +105 -0
- lxd02_printer-0.1.0/tests/test_protocol.py +158 -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,228 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lxd02-printer
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Driver, receipt/Markdown renderer and CLI for the LX-D02 Bluetooth LE thermal receipt printer
|
|
5
|
+
Author: Arttu Mahlakaarto
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/amahlaka/LX-D02
|
|
8
|
+
Project-URL: Issues, https://github.com/amahlaka/LX-D02/issues
|
|
9
|
+
Project-URL: Protocol, https://github.com/amahlaka/LX-D02/blob/main/PROTOCOL.md
|
|
10
|
+
Keywords: receipt printer,bluetooth,ble,thermal printer,markdown,lx-d02
|
|
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/lxd02/assets/DejaVu-LICENSE
|
|
24
|
+
License-File: src/lxd02/assets/MDI-LICENSE
|
|
25
|
+
Requires-Dist: bleak>=0.22
|
|
26
|
+
Requires-Dist: Pillow>=10.1.0
|
|
27
|
+
Requires-Dist: qrcode>=7.4.2
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
# LX-D02 receipt printer
|
|
31
|
+
|
|
32
|
+
Print on an **LX-D02** Bluetooth thermal receipt printer (58 mm paper, sold
|
|
33
|
+
e.g. as Dolebo, used with the Funny Print app) from a PC, without the phone
|
|
34
|
+
app. Receipts can be any length and stack an icon, a title, Markdown text
|
|
35
|
+
(lists, checklists, tables…), a QR code and a picture.
|
|
36
|
+
|
|
37
|
+
The printer's Bluetooth protocol, reverse engineered from the Funny Print app,
|
|
38
|
+
is documented in [PROTOCOL.md](PROTOCOL.md).
|
|
39
|
+
|
|
40
|
+
For Home Assistant, see the **HA-LXD02** integration, which carries a copy of
|
|
41
|
+
this package's protocol and renderer.
|
|
42
|
+
|
|
43
|
+
## Requirements
|
|
44
|
+
|
|
45
|
+
- Windows, macOS or Linux with Bluetooth LE
|
|
46
|
+
- Python 3.12+
|
|
47
|
+
|
|
48
|
+
## Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install lxd02-printer
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
This installs the `lxd02` module (`import lxd02`) and the `lxd02-print` command. To work on the code
|
|
55
|
+
instead, clone this repository and install it editable in a virtual
|
|
56
|
+
environment:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python -m venv .venv
|
|
60
|
+
```
|
|
61
|
+
```bash
|
|
62
|
+
.venv\Scripts\python -m pip install -e .
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
On macOS/Linux use `.venv/bin/python` instead of `.venv\Scripts\python`.
|
|
66
|
+
|
|
67
|
+
The printer switches itself off after a few minutes idle, and accepts only one
|
|
68
|
+
connection: turn it on and close the phone app (and turn off Home Assistant's
|
|
69
|
+
**Stay connected**) before printing.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
lxd02-print --info
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Printing
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
lxd02-print --icon mdi:coffee --title "Coffee break" --text "Back in 15 minutes"
|
|
79
|
+
```
|
|
80
|
+
```bash
|
|
81
|
+
lxd02-print --title Shopping --file list.md
|
|
82
|
+
```
|
|
83
|
+
```bash
|
|
84
|
+
lxd02-print --qr "WIFI:T:WPA;S:Home;P:secret;;" --title "Guest Wi-Fi"
|
|
85
|
+
```
|
|
86
|
+
```bash
|
|
87
|
+
lxd02-print --image photo.jpg --energy 5
|
|
88
|
+
```
|
|
89
|
+
```bash
|
|
90
|
+
lxd02-print --feed 20
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
| Option | Default | |
|
|
94
|
+
|---|---|---|
|
|
95
|
+
| `--title TEXT` | | large centred heading |
|
|
96
|
+
| `--text TEXT` | | body text in Markdown; `\n` starts a new line, `-` reads stdin |
|
|
97
|
+
| `--file PATH` | | body text from a UTF-8 (Markdown) file |
|
|
98
|
+
| `--plain` | | print the text exactly as written, without Markdown |
|
|
99
|
+
| `--qr TEXT` | | QR code content |
|
|
100
|
+
| `--icon mdi:NAME` | | MDI icon at the top |
|
|
101
|
+
| `--image PATH` | | picture, scaled to the paper width and dithered |
|
|
102
|
+
| `--size` | `normal` | text size: `small`, `normal`, `large` |
|
|
103
|
+
| `--align` | `left` | body text: `left`, `center`, `right` |
|
|
104
|
+
| `--energy 1-6` | printer's | darkness; the printer remembers it |
|
|
105
|
+
| `--feed MM` | 0 | extra blank paper after the print. On its own (nothing else to print), just advance that much paper |
|
|
106
|
+
| `--no-dither` | | hard black/white pictures |
|
|
107
|
+
| `--copies N` | 1 | |
|
|
108
|
+
| `--preview DIR` | | save `receipt.png` instead of printing |
|
|
109
|
+
| `--address MAC` | scan | printer address, e.g. `C0:00:00:00:00:48` |
|
|
110
|
+
| `--info` | | battery, paper and darkness |
|
|
111
|
+
|
|
112
|
+
`python -m lxd02` works the same as `lxd02-print`.
|
|
113
|
+
|
|
114
|
+
After every job the printer advances about **10 mm** of paper by itself, so
|
|
115
|
+
the last printed line clears the tear bar. Feeds count it: `--feed 12` gives
|
|
116
|
+
12 mm, and 10 mm is the shortest feed. The first 10–20 mm of a print can come
|
|
117
|
+
out faint while the print head warms up.
|
|
118
|
+
|
|
119
|
+
## Markdown: lists, checklists, tables
|
|
120
|
+
|
|
121
|
+
The text is Markdown, so shopping lists, to-dos and notes print formatted:
|
|
122
|
+
|
|
123
|
+
````markdown
|
|
124
|
+
# Weekend
|
|
125
|
+
## Groceries
|
|
126
|
+
- [ ] Milk
|
|
127
|
+
- [x] Bread
|
|
128
|
+
- [ ] Coffee, **dark roast**
|
|
129
|
+
|
|
130
|
+
## Hardware store
|
|
131
|
+
1. Screws *(4 mm)*
|
|
132
|
+
2. Wood glue
|
|
133
|
+
- the ~~cheap~~ good one
|
|
134
|
+
|
|
135
|
+
> Remember the bags!
|
|
136
|
+
|
|
137
|
+
| Item | Qty | Price |
|
|
138
|
+
|:-------|:---:|------:|
|
|
139
|
+
| Apples | 6 | 2.40 |
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
```
|
|
143
|
+
Total 6.38
|
|
144
|
+
```
|
|
145
|
+
````
|
|
146
|
+
|
|
147
|
+
| Markdown | Prints as |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `# H1`, `## H2`, `### H3` | headings (H1 centred, H1/H2 underlined) |
|
|
150
|
+
| `**bold**`, `*italic*` / `_italic_`, `~~strike~~`, `` `code` `` | inline styles (`code` on a light gray background) |
|
|
151
|
+
| `[text](url)` | underlined text |
|
|
152
|
+
| `- item`, `* item`, `1. item` | bullet and numbered lists; indent to nest |
|
|
153
|
+
| `- [ ] task`, `- [x] done` | checkboxes, empty or ticked |
|
|
154
|
+
| `> text` | quote with a bar on the left |
|
|
155
|
+
| ```` ``` ```` fenced block | monospace box, spaces kept |
|
|
156
|
+
| `---` | dashed tear line |
|
|
157
|
+
| `\| a \| b \|` + `\|---\|---\|` | table with a bold header; `:--`, `:-:`, `--:` align columns |
|
|
158
|
+
| `` | picture, relative to the `--file` |
|
|
159
|
+
|
|
160
|
+
Unlike standard Markdown, every line break is kept. Text uses the bundled
|
|
161
|
+
DejaVu fonts, so every machine prints identically.
|
|
162
|
+
|
|
163
|
+
## Using it from Python
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
import asyncio
|
|
167
|
+
from lxd02 import LXD02, render_receipt
|
|
168
|
+
|
|
169
|
+
async def main():
|
|
170
|
+
img = render_receipt(title="Shopping", text="- [ ] Milk\n- [ ] Bread", icon="mdi:cart")
|
|
171
|
+
async with LXD02() as printer: # scans for the printer; or LXD02("C0:00:00:00:00:48")
|
|
172
|
+
status = await printer.wait_status()
|
|
173
|
+
print(status.battery, status.no_paper)
|
|
174
|
+
await printer.print_image(img, energy=3)
|
|
175
|
+
await printer.feed(20)
|
|
176
|
+
|
|
177
|
+
asyncio.run(main())
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`lxd02.protocol.LXD02` is the protocol on its own: give it any connected
|
|
181
|
+
bleak client (Home Assistant's, for example).
|
|
182
|
+
|
|
183
|
+
## Development
|
|
184
|
+
|
|
185
|
+
`src/lxd02/protocol.py`, `receipt.py`, `markdown.py` and `assets/` are copied
|
|
186
|
+
unchanged into the HA-LXD02 integration. Change them here, then copy them
|
|
187
|
+
there; HA-LXD02's tests check the copies match when both projects sit side by
|
|
188
|
+
side.
|
|
189
|
+
|
|
190
|
+
The tests cover the protocol against a simulated printer (handshake,
|
|
191
|
+
hold/resend, out of paper, the automatic feed), the Markdown renderer and the
|
|
192
|
+
CLI:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
pip install -e . pytest pytest-asyncio
|
|
196
|
+
```
|
|
197
|
+
```bash
|
|
198
|
+
pytest
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Releasing
|
|
202
|
+
|
|
203
|
+
Releases go to [PyPI](https://pypi.org/project/lxd02-printer/) through the
|
|
204
|
+
[Publish workflow](.github/workflows/publish.yml), with trusted publishing (no
|
|
205
|
+
API tokens):
|
|
206
|
+
|
|
207
|
+
1. Bump `version` in `pyproject.toml` and push.
|
|
208
|
+
2. Optional: *Actions → Publish → Run workflow* uploads that build to
|
|
209
|
+
[TestPyPI](https://test.pypi.org/project/lxd02-printer/); try it with
|
|
210
|
+
`pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ lxd02-printer`.
|
|
211
|
+
TestPyPI refuses a version it already has, so bump again to re-test.
|
|
212
|
+
3. Publish a GitHub release with the tag `v` + the version (e.g. `v0.1.1`).
|
|
213
|
+
The workflow checks the tag matches, builds, smoke-tests the wheel and
|
|
214
|
+
uploads it to PyPI.
|
|
215
|
+
|
|
216
|
+
## Files
|
|
217
|
+
|
|
218
|
+
| Path | What it is |
|
|
219
|
+
|---|---|
|
|
220
|
+
| `src/lxd02/protocol.py` | the Bluetooth protocol: handshake, status, darkness, printing, feed |
|
|
221
|
+
| `src/lxd02/receipt.py`, `markdown.py` | the receipt and Markdown renderer |
|
|
222
|
+
| `src/lxd02/client.py` | a plain `bleak` connection (scan, connect, unlock) |
|
|
223
|
+
| `src/lxd02/cli.py` | the `lxd02-print` command |
|
|
224
|
+
| `src/lxd02/assets/` | DejaVu Sans / Sans Mono fonts and license, MDI icon font 7.4.47 and license |
|
|
225
|
+
| `tests/` | protocol, renderer and CLI tests |
|
|
226
|
+
| `PROTOCOL.md` | the reverse-engineered printer protocol |
|
|
227
|
+
| `.github/workflows/publish.yml` | build and publish to PyPI / TestPyPI |
|
|
228
|
+
| `LICENSE` | MIT; the bundled fonts keep their own licenses |
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# LX-D02 receipt printer
|
|
2
|
+
|
|
3
|
+
Print on an **LX-D02** Bluetooth thermal receipt printer (58 mm paper, sold
|
|
4
|
+
e.g. as Dolebo, used with the Funny Print app) from a PC, without the phone
|
|
5
|
+
app. Receipts can be any length and stack an icon, a title, Markdown text
|
|
6
|
+
(lists, checklists, tables…), a QR code and a picture.
|
|
7
|
+
|
|
8
|
+
The printer's Bluetooth protocol, reverse engineered from the Funny Print app,
|
|
9
|
+
is documented in [PROTOCOL.md](PROTOCOL.md).
|
|
10
|
+
|
|
11
|
+
For Home Assistant, see the **HA-LXD02** integration, which carries a copy of
|
|
12
|
+
this package's protocol and renderer.
|
|
13
|
+
|
|
14
|
+
## Requirements
|
|
15
|
+
|
|
16
|
+
- Windows, macOS or Linux with Bluetooth LE
|
|
17
|
+
- Python 3.12+
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install lxd02-printer
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
This installs the `lxd02` module (`import lxd02`) and the `lxd02-print` command. To work on the code
|
|
26
|
+
instead, clone this repository and install it editable in a virtual
|
|
27
|
+
environment:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
python -m venv .venv
|
|
31
|
+
```
|
|
32
|
+
```bash
|
|
33
|
+
.venv\Scripts\python -m pip install -e .
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
On macOS/Linux use `.venv/bin/python` instead of `.venv\Scripts\python`.
|
|
37
|
+
|
|
38
|
+
The printer switches itself off after a few minutes idle, and accepts only one
|
|
39
|
+
connection: turn it on and close the phone app (and turn off Home Assistant's
|
|
40
|
+
**Stay connected**) before printing.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
lxd02-print --info
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Printing
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
lxd02-print --icon mdi:coffee --title "Coffee break" --text "Back in 15 minutes"
|
|
50
|
+
```
|
|
51
|
+
```bash
|
|
52
|
+
lxd02-print --title Shopping --file list.md
|
|
53
|
+
```
|
|
54
|
+
```bash
|
|
55
|
+
lxd02-print --qr "WIFI:T:WPA;S:Home;P:secret;;" --title "Guest Wi-Fi"
|
|
56
|
+
```
|
|
57
|
+
```bash
|
|
58
|
+
lxd02-print --image photo.jpg --energy 5
|
|
59
|
+
```
|
|
60
|
+
```bash
|
|
61
|
+
lxd02-print --feed 20
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
| Option | Default | |
|
|
65
|
+
|---|---|---|
|
|
66
|
+
| `--title TEXT` | | large centred heading |
|
|
67
|
+
| `--text TEXT` | | body text in Markdown; `\n` starts a new line, `-` reads stdin |
|
|
68
|
+
| `--file PATH` | | body text from a UTF-8 (Markdown) file |
|
|
69
|
+
| `--plain` | | print the text exactly as written, without Markdown |
|
|
70
|
+
| `--qr TEXT` | | QR code content |
|
|
71
|
+
| `--icon mdi:NAME` | | MDI icon at the top |
|
|
72
|
+
| `--image PATH` | | picture, scaled to the paper width and dithered |
|
|
73
|
+
| `--size` | `normal` | text size: `small`, `normal`, `large` |
|
|
74
|
+
| `--align` | `left` | body text: `left`, `center`, `right` |
|
|
75
|
+
| `--energy 1-6` | printer's | darkness; the printer remembers it |
|
|
76
|
+
| `--feed MM` | 0 | extra blank paper after the print. On its own (nothing else to print), just advance that much paper |
|
|
77
|
+
| `--no-dither` | | hard black/white pictures |
|
|
78
|
+
| `--copies N` | 1 | |
|
|
79
|
+
| `--preview DIR` | | save `receipt.png` instead of printing |
|
|
80
|
+
| `--address MAC` | scan | printer address, e.g. `C0:00:00:00:00:48` |
|
|
81
|
+
| `--info` | | battery, paper and darkness |
|
|
82
|
+
|
|
83
|
+
`python -m lxd02` works the same as `lxd02-print`.
|
|
84
|
+
|
|
85
|
+
After every job the printer advances about **10 mm** of paper by itself, so
|
|
86
|
+
the last printed line clears the tear bar. Feeds count it: `--feed 12` gives
|
|
87
|
+
12 mm, and 10 mm is the shortest feed. The first 10–20 mm of a print can come
|
|
88
|
+
out faint while the print head warms up.
|
|
89
|
+
|
|
90
|
+
## Markdown: lists, checklists, tables
|
|
91
|
+
|
|
92
|
+
The text is Markdown, so shopping lists, to-dos and notes print formatted:
|
|
93
|
+
|
|
94
|
+
````markdown
|
|
95
|
+
# Weekend
|
|
96
|
+
## Groceries
|
|
97
|
+
- [ ] Milk
|
|
98
|
+
- [x] Bread
|
|
99
|
+
- [ ] Coffee, **dark roast**
|
|
100
|
+
|
|
101
|
+
## Hardware store
|
|
102
|
+
1. Screws *(4 mm)*
|
|
103
|
+
2. Wood glue
|
|
104
|
+
- the ~~cheap~~ good one
|
|
105
|
+
|
|
106
|
+
> Remember the bags!
|
|
107
|
+
|
|
108
|
+
| Item | Qty | Price |
|
|
109
|
+
|:-------|:---:|------:|
|
|
110
|
+
| Apples | 6 | 2.40 |
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
```
|
|
114
|
+
Total 6.38
|
|
115
|
+
```
|
|
116
|
+
````
|
|
117
|
+
|
|
118
|
+
| Markdown | Prints as |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `# H1`, `## H2`, `### H3` | headings (H1 centred, H1/H2 underlined) |
|
|
121
|
+
| `**bold**`, `*italic*` / `_italic_`, `~~strike~~`, `` `code` `` | inline styles (`code` on a light gray background) |
|
|
122
|
+
| `[text](url)` | underlined text |
|
|
123
|
+
| `- item`, `* item`, `1. item` | bullet and numbered lists; indent to nest |
|
|
124
|
+
| `- [ ] task`, `- [x] done` | checkboxes, empty or ticked |
|
|
125
|
+
| `> text` | quote with a bar on the left |
|
|
126
|
+
| ```` ``` ```` fenced block | monospace box, spaces kept |
|
|
127
|
+
| `---` | dashed tear line |
|
|
128
|
+
| `\| a \| b \|` + `\|---\|---\|` | table with a bold header; `:--`, `:-:`, `--:` align columns |
|
|
129
|
+
| `` | picture, relative to the `--file` |
|
|
130
|
+
|
|
131
|
+
Unlike standard Markdown, every line break is kept. Text uses the bundled
|
|
132
|
+
DejaVu fonts, so every machine prints identically.
|
|
133
|
+
|
|
134
|
+
## Using it from Python
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
import asyncio
|
|
138
|
+
from lxd02 import LXD02, render_receipt
|
|
139
|
+
|
|
140
|
+
async def main():
|
|
141
|
+
img = render_receipt(title="Shopping", text="- [ ] Milk\n- [ ] Bread", icon="mdi:cart")
|
|
142
|
+
async with LXD02() as printer: # scans for the printer; or LXD02("C0:00:00:00:00:48")
|
|
143
|
+
status = await printer.wait_status()
|
|
144
|
+
print(status.battery, status.no_paper)
|
|
145
|
+
await printer.print_image(img, energy=3)
|
|
146
|
+
await printer.feed(20)
|
|
147
|
+
|
|
148
|
+
asyncio.run(main())
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`lxd02.protocol.LXD02` is the protocol on its own: give it any connected
|
|
152
|
+
bleak client (Home Assistant's, for example).
|
|
153
|
+
|
|
154
|
+
## Development
|
|
155
|
+
|
|
156
|
+
`src/lxd02/protocol.py`, `receipt.py`, `markdown.py` and `assets/` are copied
|
|
157
|
+
unchanged into the HA-LXD02 integration. Change them here, then copy them
|
|
158
|
+
there; HA-LXD02's tests check the copies match when both projects sit side by
|
|
159
|
+
side.
|
|
160
|
+
|
|
161
|
+
The tests cover the protocol against a simulated printer (handshake,
|
|
162
|
+
hold/resend, out of paper, the automatic feed), the Markdown renderer and the
|
|
163
|
+
CLI:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
pip install -e . pytest pytest-asyncio
|
|
167
|
+
```
|
|
168
|
+
```bash
|
|
169
|
+
pytest
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Releasing
|
|
173
|
+
|
|
174
|
+
Releases go to [PyPI](https://pypi.org/project/lxd02-printer/) through the
|
|
175
|
+
[Publish workflow](.github/workflows/publish.yml), with trusted publishing (no
|
|
176
|
+
API tokens):
|
|
177
|
+
|
|
178
|
+
1. Bump `version` in `pyproject.toml` and push.
|
|
179
|
+
2. Optional: *Actions → Publish → Run workflow* uploads that build to
|
|
180
|
+
[TestPyPI](https://test.pypi.org/project/lxd02-printer/); try it with
|
|
181
|
+
`pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ lxd02-printer`.
|
|
182
|
+
TestPyPI refuses a version it already has, so bump again to re-test.
|
|
183
|
+
3. Publish a GitHub release with the tag `v` + the version (e.g. `v0.1.1`).
|
|
184
|
+
The workflow checks the tag matches, builds, smoke-tests the wheel and
|
|
185
|
+
uploads it to PyPI.
|
|
186
|
+
|
|
187
|
+
## Files
|
|
188
|
+
|
|
189
|
+
| Path | What it is |
|
|
190
|
+
|---|---|
|
|
191
|
+
| `src/lxd02/protocol.py` | the Bluetooth protocol: handshake, status, darkness, printing, feed |
|
|
192
|
+
| `src/lxd02/receipt.py`, `markdown.py` | the receipt and Markdown renderer |
|
|
193
|
+
| `src/lxd02/client.py` | a plain `bleak` connection (scan, connect, unlock) |
|
|
194
|
+
| `src/lxd02/cli.py` | the `lxd02-print` command |
|
|
195
|
+
| `src/lxd02/assets/` | DejaVu Sans / Sans Mono fonts and license, MDI icon font 7.4.47 and license |
|
|
196
|
+
| `tests/` | protocol, renderer and CLI tests |
|
|
197
|
+
| `PROTOCOL.md` | the reverse-engineered printer protocol |
|
|
198
|
+
| `.github/workflows/publish.yml` | build and publish to PyPI / TestPyPI |
|
|
199
|
+
| `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 = "lxd02-printer"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Driver, receipt/Markdown renderer and CLI for the LX-D02 Bluetooth LE thermal receipt printer"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.12"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE", "src/lxd02/assets/*LICENSE"]
|
|
13
|
+
authors = [{ name = "Arttu Mahlakaarto" }]
|
|
14
|
+
keywords = ["receipt printer", "bluetooth", "ble", "thermal printer", "markdown", "lx-d02"]
|
|
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/LX-D02"
|
|
34
|
+
Issues = "https://github.com/amahlaka/LX-D02/issues"
|
|
35
|
+
Protocol = "https://github.com/amahlaka/LX-D02/blob/main/PROTOCOL.md"
|
|
36
|
+
|
|
37
|
+
[project.scripts]
|
|
38
|
+
lxd02-print = "lxd02.cli:main"
|
|
39
|
+
|
|
40
|
+
[tool.setuptools.packages.find]
|
|
41
|
+
where = ["src"]
|
|
42
|
+
|
|
43
|
+
[tool.setuptools.package-data]
|
|
44
|
+
lxd02 = ["assets/*"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""LX-D02 Bluetooth LE thermal receipt printer: driver, receipt/Markdown renderer and CLI."""
|
|
2
|
+
from .client import LXD02, find_printer
|
|
3
|
+
from .protocol import AUTO_FEED_MM, ENERGY_MAX, ENERGY_MIN, PrinterError, Status
|
|
4
|
+
from .receipt import render_receipt
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"AUTO_FEED_MM",
|
|
8
|
+
"ENERGY_MAX",
|
|
9
|
+
"ENERGY_MIN",
|
|
10
|
+
"LXD02",
|
|
11
|
+
"PrinterError",
|
|
12
|
+
"Status",
|
|
13
|
+
"find_printer",
|
|
14
|
+
"render_receipt",
|
|
15
|
+
]
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
2
|
+
Upstream-Name: DejaVu fonts
|
|
3
|
+
Upstream-Author: Stepan Roh <src@users.sourceforge.net> (original author),
|
|
4
|
+
see /usr/share/doc/fonts-dejavu-core/AUTHORS for full list
|
|
5
|
+
Source: https://dejavu-fonts.github.io/
|
|
6
|
+
|
|
7
|
+
Files: *
|
|
8
|
+
Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved.
|
|
9
|
+
Bitstream Vera is a trademark of Bitstream, Inc.
|
|
10
|
+
DejaVu changes are in public domain.
|
|
11
|
+
License: bitstream-vera
|
|
12
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
13
|
+
of the fonts accompanying this license ("Fonts") and associated
|
|
14
|
+
documentation files (the "Font Software"), to reproduce and distribute the
|
|
15
|
+
Font Software, including without limitation the rights to use, copy, merge,
|
|
16
|
+
publish, distribute, and/or sell copies of the Font Software, and to permit
|
|
17
|
+
persons to whom the Font Software is furnished to do so, subject to the
|
|
18
|
+
following conditions:
|
|
19
|
+
.
|
|
20
|
+
The above copyright and trademark notices and this permission notice shall
|
|
21
|
+
be included in all copies of one or more of the Font Software typefaces.
|
|
22
|
+
.
|
|
23
|
+
The Font Software may be modified, altered, or added to, and in particular
|
|
24
|
+
the designs of glyphs or characters in the Fonts may be modified and
|
|
25
|
+
additional glyphs or characters may be added to the Fonts, only if the fonts
|
|
26
|
+
are renamed to names not containing either the words "Bitstream" or the word
|
|
27
|
+
"Vera".
|
|
28
|
+
.
|
|
29
|
+
This License becomes null and void to the extent applicable to Fonts or Font
|
|
30
|
+
Software that has been modified and is distributed under the "Bitstream
|
|
31
|
+
Vera" names.
|
|
32
|
+
.
|
|
33
|
+
The Font Software may be sold as part of a larger software package but no
|
|
34
|
+
copy of one or more of the Font Software typefaces may be sold by itself.
|
|
35
|
+
.
|
|
36
|
+
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
|
37
|
+
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
|
38
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
|
39
|
+
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
|
40
|
+
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
|
|
41
|
+
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
|
42
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
|
43
|
+
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
|
|
44
|
+
FONT SOFTWARE.
|
|
45
|
+
.
|
|
46
|
+
Except as contained in this notice, the names of Gnome, the Gnome
|
|
47
|
+
Foundation, and Bitstream Inc., shall not be used in advertising or
|
|
48
|
+
otherwise to promote the sale, use or other dealings in this Font Software
|
|
49
|
+
without prior written authorization from the Gnome Foundation or Bitstream
|
|
50
|
+
Inc., respectively. For further information, contact: fonts at gnome dot
|
|
51
|
+
org.
|
|
52
|
+
|
|
53
|
+
Files: debian/*
|
|
54
|
+
Copyright: (C) 2005-2006 Peter Cernak <pce@users.sourceforge.net>
|
|
55
|
+
(C) 2006-2011 Davide Viti <zinosat@tiscali.it>
|
|
56
|
+
(C) 2011-2013 Christian Perrier <bubulle@debian.org>
|
|
57
|
+
(C) 2013 Fabian Greffrath <fabian+debian@greffrath.com>
|
|
58
|
+
License: GPL-2+
|
|
59
|
+
This program is free software; you can redistribute it
|
|
60
|
+
and/or modify it under the terms of the GNU General Public
|
|
61
|
+
License as published by the Free Software Foundation; either
|
|
62
|
+
version 2 of the License, or (at your option) any later
|
|
63
|
+
version.
|
|
64
|
+
.
|
|
65
|
+
This program is distributed in the hope that it will be
|
|
66
|
+
useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
67
|
+
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
68
|
+
PURPOSE. See the GNU General Public License for more
|
|
69
|
+
details.
|
|
70
|
+
.
|
|
71
|
+
You should have received a copy of the GNU General Public
|
|
72
|
+
License along with this package; if not, write to the Free
|
|
73
|
+
Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
74
|
+
Boston, MA 02110-1301 USA
|
|
75
|
+
.
|
|
76
|
+
On Debian systems, the full text of the GNU General Public
|
|
77
|
+
License version 2 can be found in the file
|
|
78
|
+
/usr/share/common-licenses/GPL-2'.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|