Update README, format MAC filtering a bit
This commit is contained in:
parent
c9d465c644
commit
b5e9202b50
26
README.md
26
README.md
@ -18,17 +18,25 @@ The label dimensions are 12 millimeter in height, however the printable area is
|
||||
|
||||
</details>
|
||||
|
||||
## Compatibility
|
||||
|
||||
* DYMO LetraTag LT-200B
|
||||
|
||||
Seems to be this is the only printer by DYMO that uses Bluetooth. If you know or own a DYMO printer that you believe needs to be supported, don't hesitate to open a new issue.
|
||||
|
||||
This project depends on [`bleak`](https://pypi.org/project/bleak/) for Bluetooth communication, therefore you can only use this project on system where `bleak` is supported. Thus, either; Linux distribution with BlueZ >= 5.43 support, MacOS with at least version 10.11 or Windows build 16299 or greater is required.
|
||||
|
||||
## Installation
|
||||
|
||||
```
|
||||
python -m pip install --upgrade https://github.com/ysfchn/dymo-bluetooth/archive/refs/heads/main.zip
|
||||
```
|
||||
|
||||
Python 3.10 or up is targeted, but 3.9 should work too. It depends on `bleak` for Bluetooth communication, and `pillow` for importing images from files. If `python-barcode` is installed, it can be used to print barcodes.
|
||||
Python 3.10 or up is targeted, but 3.9 should work too. It depends on `bleak` for Bluetooth communication, and `pillow` for importing images from files. If `python-barcode` is installed (optional), it can be used to print barcodes.
|
||||
|
||||
## Usage
|
||||
|
||||
There is a small CLI to print image files in a nearby printer.
|
||||
There is a small CLI to print image files to a nearby printer.
|
||||
|
||||
```
|
||||
python -m dymo_bluetooth --help
|
||||
@ -49,7 +57,7 @@ async def main():
|
||||
|
||||
# Images needs to be stretched by at least 2 times like
|
||||
# how its mobile app does, otherwise printer will render
|
||||
# the labels too thin.
|
||||
# the labels too narrow.
|
||||
canvas = canvas.stretch_image(2)
|
||||
|
||||
# Get a list of printers.
|
||||
@ -62,7 +70,7 @@ async def main():
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
## Disclaimer
|
||||
## License & Disclaimer
|
||||
|
||||
This program is licensed under [MIT License](./LICENSE).
|
||||
|
||||
@ -101,7 +109,7 @@ DIRECTIVE[2] = 1B + COMMAND_TYPE[1]
|
||||
| Command | Character | = Code point (hex) | = Code point (decimal) | Notes |
|
||||
|:------:|:-------------------:|:------------------:|:------------:|:-------:|
|
||||
| [`START`](#start-command) | `s` | `0x73` | `115` | Start command. Each payload starts with this directive. |
|
||||
| [`MEDIA_TYPE`](#media_type-command) | `M` | `0x4d` | `77` | ? |
|
||||
| [`MEDIA_TYPE`](#media_type-command) | `M` | `0x4d` | `77` | |
|
||||
| [`PRINT_DENSITY`](#print_density-command) | `C` | `0x43` | `67` | Seems unused. |
|
||||
| [`PRINT_DATA`](#print_data-command) | `D` | `0x44` | `68` | Defines the image that will be printed, see below for byte format. |
|
||||
| [`FORM_FEED`](#form_feed-command) | `E` | `0x45` | `69` | Follows after `PRINT_DATA`. |
|
||||
@ -125,7 +133,7 @@ This command follows with 1 byte containing a number of some type (?) to be set
|
||||
When this number has set to anything, the printer should advertise this number when searching for Bluetooth devices nearby. (not tested) So I guess it was planned to be used for some sort of casette checking & changing casette type, so printer can hold this value even when its turned off.
|
||||
|
||||
```
|
||||
MEDIA_TYPE[3] = DIRECTIVE[2] + ??
|
||||
MEDIA_TYPE[3] = DIRECTIVE[2] + XX
|
||||
```
|
||||
|
||||
#### `PRINT_DENSITY` command
|
||||
@ -236,7 +244,7 @@ The ninth byte of the header is the checksum of the header, and it is calculated
|
||||
```
|
||||
PARTIAL_HEADER[8] = FF F0 + MAGIC[2] + PAYLOAD_LENGTH[4]
|
||||
|
||||
CHECKSUM = SUM(PARTIAL_HEADER) & 0xFF
|
||||
CHECKSUM[1] = SUM(PARTIAL_HEADER) & 0xFF
|
||||
|
||||
HEADER[9] = PARTIAL_HEADER[8] + CHECKSUM
|
||||
```
|
||||
@ -256,13 +264,13 @@ Chunking needs to be start right after [`HEADER`](#header), so only the header i
|
||||
Each chunk must contain its index before chunk data itself followed by. The chunk data can be smaller than 500, but it can only contain maximum 500 bytes, inclusive. In the end, you will have the full chunk to be sent over Bluetooth which contains the index and the data.
|
||||
|
||||
```
|
||||
CHUNK[0...501] = CHUNK_INDEX[1] + CHUNK_DATA[0...500]
|
||||
CHUNK[1...501] = CHUNK_INDEX[1] + CHUNK_DATA[0...500]
|
||||
```
|
||||
|
||||
The last chunk must contain the [`MAGIC`](#magic-value) value appended end of the chunk.
|
||||
|
||||
```
|
||||
CHUNK[0...503] = CHUNK_INDEX[1] + CHUNK_DATA[0...500] + MAGIC[2]
|
||||
CHUNK[1...503] = CHUNK_INDEX[1] + CHUNK_DATA[0...500] + MAGIC[2]
|
||||
```
|
||||
|
||||
#### Set media type
|
||||
|
@ -41,20 +41,22 @@ PRINT_REPLY_UUID = "be3dd652-{uuid}-42f1-99c1-f0f749dd0678".format(uuid = "2b3d"
|
||||
UNKNOWN_UUID = "be3dd653-{uuid}-42f1-99c1-f0f749dd0678".format(uuid = "2b3d")
|
||||
|
||||
|
||||
def is_espressif(mac : str):
|
||||
def is_espressif(input_mac : str):
|
||||
"""
|
||||
Returns True if given MAC address is in the range of Espressif Inc.
|
||||
Returns True if given MAC address is from a valid DYMO printer.
|
||||
The mac address blocks are owned by Espressif Inc.
|
||||
"""
|
||||
start_block = 0x58_CF_79 << 24
|
||||
end_block = start_block + (1 << 24) # Exclusive
|
||||
mac_value = int(mac.replace(":", ""), base = 16)
|
||||
if (mac_value >= start_block) and (mac_value < end_block):
|
||||
return True
|
||||
start_block = 0xDC_54_75 << 24
|
||||
end_block = start_block + (1 << 24) # Exclusive
|
||||
mac_value = int(mac.replace(":", ""), base = 16)
|
||||
if (mac_value >= start_block) and (mac_value < end_block):
|
||||
return True
|
||||
mac_blocks = [
|
||||
"58:CF:79",
|
||||
# Confirmed in pull request #2
|
||||
"DC:54:75"
|
||||
]
|
||||
check_mac = int(input_mac.replace(":", ""), base = 16)
|
||||
for mac in mac_blocks:
|
||||
start_block = int(mac.replace(":", ""), base = 16) << 24
|
||||
end_block = start_block + (1 << 24) # Exclusive
|
||||
if (check_mac >= start_block) and (check_mac < end_block):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
@ -121,7 +121,7 @@ class Canvas:
|
||||
|
||||
# Get the byte containing the pixel value of given coordinates.
|
||||
x_offset = math.ceil((x * Canvas.HEIGHT) / 8)
|
||||
y_offset = 3 - math.floor(y / 8)
|
||||
y_offset = ((self.HEIGHT) // 8) - 1 - math.floor(y / 8)
|
||||
self.buffer.seek(x_offset + y_offset)
|
||||
|
||||
# Check if there is a bit value in given line.
|
||||
@ -142,7 +142,7 @@ class Canvas:
|
||||
|
||||
# Get the byte containing the pixel value of given coordinates.
|
||||
x_offset = math.ceil((x * Canvas.HEIGHT) / 8)
|
||||
y_offset = 3 - math.floor(y / 8)
|
||||
y_offset = ((self.HEIGHT) // 8) - 1 - math.floor(y / 8)
|
||||
self.buffer.seek(x_offset + y_offset)
|
||||
|
||||
# Get the one of four slices in line in the given coordinates. Add the bit in
|
||||
@ -208,7 +208,7 @@ class Canvas:
|
||||
"""
|
||||
self.buffer.seek(0, SEEK_END)
|
||||
cur = self.buffer.tell()
|
||||
return math.ceil(cur / 4)
|
||||
return math.ceil(cur / (self.HEIGHT // 8))
|
||||
|
||||
def get_size(self):
|
||||
"""
|
||||
@ -222,7 +222,7 @@ class Canvas:
|
||||
"""
|
||||
self.buffer.seek(0)
|
||||
image = self.buffer.read()
|
||||
return image + (b"\x00" * (self.buffer.tell() % 4))
|
||||
return image + (b"\x00" * (self.buffer.tell() % (self.HEIGHT // 8)))
|
||||
|
||||
def empty(self):
|
||||
"""
|
||||
|
@ -5,6 +5,10 @@ authors = [{ name = "ysfchn" }]
|
||||
license.file = "LICENSE"
|
||||
readme = "README.md"
|
||||
classifiers = [
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Topic :: Printing",
|
||||
"Private :: Do Not Upload"
|
||||
]
|
||||
dependencies = [
|
||||
|
Loading…
x
Reference in New Issue
Block a user