Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Device dependent margins/config #54

Merged
merged 27 commits into from
Jul 4, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d73626d
Add "DYMO LabelMANAGER PC II" device ID
FaBjE Jun 15, 2024
06f61ea
Add 24mm tape type
FaBjE Jun 16, 2024
3aecdc7
device specific init WIP
FaBjE Jun 18, 2024
1872e40
Add DeviceConfig class for each printer
FaBjE Jun 20, 2024
1b279b3
Please mypy...
FaBjE Jun 20, 2024
2353512
Fix usb device recognition
FaBjE Jun 21, 2024
dcc6234
Calculate margins instead of using lookup table
FaBjE Jun 21, 2024
040f2c2
Force sending an "exact printhead width" bitmap to the printer
FaBjE Jun 21, 2024
f907b8b
Fix config not updated when device set
FaBjE Jun 21, 2024
d64c977
Tested on LabelManager PnP
FaBjE Jun 21, 2024
a7def5e
replace all camels with snakes
FaBjE Jun 22, 2024
d8dcb3d
Cleanup supported device list syntax
FaBjE Jun 23, 2024
4fc8b68
Convert device config to dataclass
FaBjE Jun 23, 2024
1d36049
Convert labeler device-config to property
FaBjE Jun 23, 2024
d8b3b6d
Move get_tape_print_size_and_margins_px to labeler class tape_print_p…
FaBjE Jun 23, 2024
13fa9b9
Revert GUI supported_tape_sizes type
FaBjE Jun 23, 2024
424ec34
Remove fixed default tapesize (take highest supported as default)
FaBjE Jun 23, 2024
d342a04
Shorten matches_device_id function
FaBjE Jun 23, 2024
1786928
Fix code convention in if statement
FaBjE Jun 23, 2024
16d82e8
Shorten if statement
FaBjE Jun 23, 2024
e239867
Shorten if statement
FaBjE Jun 23, 2024
b390217
Let get_device_config_by_id raise exception if not supported
FaBjE Jun 23, 2024
0bdf8fd
Remove var / shorten line
FaBjE Jun 23, 2024
a4ed930
fix comment
FaBjE Jun 23, 2024
fdf3538
Clear up comment block
FaBjE Jun 23, 2024
0fa7ad5
Fix wrong var name
FaBjE Jun 23, 2024
7246473
Remove constant DPI values and calculations
FaBjE Jun 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/labelle/gui/gui.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def _init_elements(self) -> None:
self._device_manager = DeviceManager()
self._dymo_labeler = DymoLabeler()
self._settings_toolbar.update_labeler_context(
supported_tape_sizes=self._dymo_labeler.SUPPORTED_TAPE_SIZES_MM,
supported_tape_sizes=self._dymo_labeler.labeler_supported_tape_sizes,
installed_tape_size=self._dymo_labeler.tape_size_mm,
minimum_horizontal_margin_mm=self._dymo_labeler.minimum_horizontal_margin_mm,
)
Expand Down
2 changes: 1 addition & 1 deletion src/labelle/gui/q_settings_toolbar.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def _init_elements(self) -> None:

def update_labeler_context(
self,
supported_tape_sizes: tuple[int, ...],
supported_tape_sizes: list[int],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really needed? In case the list is constant, it would be better as a convention to prefer tuple over list

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The amount of supported tape sizes varies from printer to printer. I got an error that I tried to change the "tuple" size. A quick google search gave this as a solution. If there is a better solution please elaborate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, tuples are "immutable" so you should always generate a new one instead of modifying an old one.

Copy link
Contributor Author

@FaBjE FaBjE Jun 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed (It didn´t complain this time)

Edit:
Sorry, had to revert this:

src/labelle/gui/gui.py:66: error: Argument "supported_tape_sizes" to "update_labeler_context" of "QSettingsToolbar" has incompatible type "list[int]"; expected "tuple[int, ...]"  [arg-type]
Found 1 error in 1 file (checked 46 source files)

installed_tape_size: int,
minimum_horizontal_margin_mm: float,
) -> None:
Expand Down
59 changes: 48 additions & 11 deletions src/labelle/lib/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,56 @@
"WARNING: This device is not confirmed to work with this software. Please "
"report your experiences in https://github.com/labelle-org/labelle/issues/4"
)


# Supported USB device ID enumeration
class SUPPORTED_DEVICE_ID(Enum):
LABELMANAGER_PC = 0x0011
LABELPOINT_350 = 0x0015
LABELMANAGER_PC_II = 0x001C
LABELMANAGER_PNP_NO_MODE_SWITCH = 0x1001
LABELMANAGER_PNP_MODE_SWITCH = 0x1002
LABELMANAGER_420P_NO_MODE_SWITCH = 0x1003
LABELMANAGER_420P_MODE_SWITCH = 0x1004
LABELMANAGER_280P_NO_MODE_SWITCH = 0x1005
LABELMANAGER_280P_MODE_SWITCH = 0x1006
LABELMANAGER_WIRELESS_PNP_NO_MODE_SWITCH = 0x1007
LABELMANAGER_WIRELESS_PNP_MODE_SWITCH = 0x1008
MOBILE_LABELER = 0x1009


# fmt: off
# Very bad I know, but it keeps a loop of removing the line breaks and errroring
FaBjE marked this conversation as resolved.
Show resolved Hide resolved

SUPPORTED_PRODUCTS = {
0x0011: "DYMO LabelMANAGER PC",
0x0015: "LabelPoint 350",
0x1001: "LabelManager PnP (no mode switch)",
0x1002: "LabelManager PnP (mode switch)",
0x1003: f"LabelManager 420P (no mode switch) {UNCONFIRMED_MESSAGE}",
0x1004: f"LabelManager 420P (mode switch) {UNCONFIRMED_MESSAGE}",
0x1005: "LabelManager 280 (no mode switch)",
0x1006: "LabelManager 280 (no mode switch)",
0x1007: f"LabelManager Wireless PnP (no mode switch) {UNCONFIRMED_MESSAGE}",
0x1008: f"LabelManager Wireless PnP (mode switch) {UNCONFIRMED_MESSAGE}",
0x1009: f"MobileLabeler {UNCONFIRMED_MESSAGE}",
SUPPORTED_DEVICE_ID.LABELMANAGER_PC:
"DYMO LabelMANAGER PC",
SUPPORTED_DEVICE_ID.LABELPOINT_350:
"LabelPoint 350",
SUPPORTED_DEVICE_ID.LABELMANAGER_PC_II:
"DYMO LabelMANAGER PC II",
SUPPORTED_DEVICE_ID.LABELMANAGER_PNP_NO_MODE_SWITCH:
"LabelManager PnP (no mode switch)",
SUPPORTED_DEVICE_ID.LABELMANAGER_PNP_MODE_SWITCH:
"LabelManager PnP (mode switch)",
SUPPORTED_DEVICE_ID.LABELMANAGER_420P_NO_MODE_SWITCH:
f"LabelManager 420P (no mode switch) {UNCONFIRMED_MESSAGE}",
SUPPORTED_DEVICE_ID.LABELMANAGER_420P_MODE_SWITCH:
f"LabelManager 420P (mode switch) {UNCONFIRMED_MESSAGE}",
SUPPORTED_DEVICE_ID.LABELMANAGER_280P_NO_MODE_SWITCH:
"LabelManager 280 (no mode switch)",
SUPPORTED_DEVICE_ID.LABELMANAGER_280P_MODE_SWITCH:
"LabelManager 280 (no mode switch)",
SUPPORTED_DEVICE_ID.LABELMANAGER_WIRELESS_PNP_NO_MODE_SWITCH:
f"LabelManager Wireless PnP (no mode switch) {UNCONFIRMED_MESSAGE}",
SUPPORTED_DEVICE_ID.LABELMANAGER_WIRELESS_PNP_MODE_SWITCH:
f"LabelManager Wireless PnP (mode switch) {UNCONFIRMED_MESSAGE}",
SUPPORTED_DEVICE_ID.MOBILE_LABELER:
f"MobileLabeler {UNCONFIRMED_MESSAGE}",
}
# fmt: on


DEV_VENDOR = 0x0922

PRINTER_INTERFACE_CLASS = 0x07
Expand Down
4 changes: 3 additions & 1 deletion src/labelle/lib/devices/device_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from usb.core import NoBackendError, USBError

from labelle.lib.constants import (
SUPPORTED_DEVICE_ID,
SUPPORTED_PRODUCTS,
UNCONFIRMED_MESSAGE,
)
Expand Down Expand Up @@ -80,7 +81,8 @@ def find_and_select_device(self, patterns: list[str] | None = None) -> UsbDevice
LOG.debug(dev.device_info)
dev = devices[0]
if dev.is_supported:
msg = f"Recognized device as {SUPPORTED_PRODUCTS[dev.id_product]}"
msg = f"Recognized device as \
{SUPPORTED_PRODUCTS[SUPPORTED_DEVICE_ID(dev.id_product)]}"
else:
msg = f"Unrecognized device: {hex(dev.id_product)}. {UNCONFIRMED_MESSAGE}"
LOG.debug(msg)
Expand Down
70 changes: 65 additions & 5 deletions src/labelle/lib/devices/dymo_labeler.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@
import array
import logging
import math
from typing import Any

import usb
from PIL import Image
from usb.core import NoBackendError, USBError

from labelle.lib.constants import ESC, SYN
from labelle.lib.constants import ESC, SUPPORTED_DEVICE_ID, SYN
from labelle.lib.devices.usb_device import UsbDevice, UsbDeviceError
from labelle.lib.utils import mm_to_px

Expand Down Expand Up @@ -240,23 +241,81 @@ class DymoLabeler:

LABELER_DISTANCE_BETWEEN_PRINT_HEAD_AND_CUTTER_MM = 8.1
LABELER_PRINT_HEAD_HEIGHT_MM = 8.2
SUPPORTED_TAPE_SIZES_MM = (19, 12, 9, 6)
DEFAULT_TAPE_SIZE_MM = 12

# Default supported tape sizes
labeler_supported_tape_sizes: list

# Default printer head size in dots
labeler_print_head_width_pixels: int

# Default printer margins (for each tape size)
# { tapeSizeMm : (firstVisiblePixel, lastVisiblePixel) }
labeler_label_vertical_margins: dict[int, Any]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe something like:

labeler_label_vertical_margins: dict[int, tuple[int, int]]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am wondering what "first" and "last" mean here regarding visible pixels. I don't know offhand which pixel ordering is being used, so it would be helpful to be more explicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tomers Thanks, will try again. Had some linter issues with this...

@maresb Me neither (at the time) Now I know it is "first visible pixel from the top" I will extend the comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is outdated btw


def __init__(
self,
tape_size_mm: int | None = None,
device: UsbDevice | None = None,
):
if tape_size_mm is None:
tape_size_mm = self.DEFAULT_TAPE_SIZE_MM
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still relevant? Is DEFAULT_TAPE_SIZE_MM supported by all printer models? I guess we should choose the first available tape size for the model instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not really happy about this either, but the whole software kind of relies on it (also with the GUI)
Maybe I should convert it to take the smallest or largest supported tape size?

Copy link
Contributor Author

@FaBjE FaBjE Jun 23, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed it, it now takes the highest supported size if not set.
Maybe this would make a good "user preference" in the future.

if tape_size_mm not in self.SUPPORTED_TAPE_SIZES_MM:

self._device = device

# --- Set options based on printer type ---
if self._device is not None:
if self._device.id_product == SUPPORTED_DEVICE_ID.LABELMANAGER_PC:
self.labeler_print_head_width_pixels = 128
self.labeler_supported_tape_sizes = [19, 12, 9, 6]
self.labeler_label_vertical_margins = {
6: (11, 51),
9: (1, 62),
12: (0, 63),
19: (0, 0),
}

elif self._device.id_product == SUPPORTED_DEVICE_ID.LABELMANAGER_PC_II:
self.labeler_print_head_width_pixels = 128
self.labeler_supported_tape_sizes = [24, 19, 12, 9, 6]
self.labeler_label_vertical_margins = {
6: (11, 51),
9: (1, 62),
12: (0, 63),
19: (0, 0),
24: (0, 0),
}

else:
# Defaults (For most printers)
self.labeler_print_head_width_pixels = 64
self.labeler_supported_tape_sizes = [12, 9, 6]
self.labeler_label_vertical_margins = {
6: (11, 51),
9: (1, 62),
12: (0, 63),
}
else:
# Simulator (supports everything)
self.labeler_print_head_width_pixels = 128
self.labeler_supported_tape_sizes = [24, 19, 12, 9, 6]
self.labeler_label_vertical_margins = {
6: (11, 51),
9: (1, 62),
12: (0, 63),
19: (0, 0),
24: (0, 0),
}

# --- End set options based on printer type ---

# Check if selected tape size is supported by printer
if tape_size_mm not in self.labeler_supported_tape_sizes:
raise ValueError(
f"Unsupported tape size {tape_size_mm}mm. "
f"Supported sizes: {self.SUPPORTED_TAPE_SIZES_MM}"
f"Supported sizes: {self.labeler_supported_tape_sizes}"
)
self.tape_size_mm = tape_size_mm
self._device = device

@property
def height_px(self):
Expand All @@ -277,6 +336,7 @@ def minimum_horizontal_margin_mm(self):

@property
def labeler_margin_px(self) -> tuple[float, float]:
# ToDo: Use preset margins here instead of this calculation
vertical_margin_mm = max(
0, (self.tape_size_mm - self.LABELER_PRINT_HEAD_HEIGHT_MM) / 2
)
Expand Down