-
Notifications
You must be signed in to change notification settings - Fork 51
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
Support for LabelManager 280 #40
Comments
Hi @pschonmann, that's because the Label Manager 280 is different from the LabelManager PnP. It would be nice to support other models like this one, but it would probably take some work. Would you be interested in figuring out and implementing an interface for this model? |
Hi, thanks for fast reply. |
Are you able to make sense of this? I think that figuring out the device IDs is probably the place to start. Although this was almost 10 years ago, and I suspect there's an easier way now. I'd actually like to rewrite this whole project. |
Hi!
And in lsusb i have:
If you have any ideas how to make it work I'd be glad to test them, unfortuantely my skills aren't up to the task of reverse-engineering it from scratch.... |
Hi @Scorcerer, thanks for the detailed logs, that's very helpful. For how to proceed, please see my comments here: #30 (comment) In particular, you should focus on getting usb_modeswitch to work. (The usb_modeswitch tool sends a magical 3-byte packet |
So, i started with:
Afterwards it's still: I also tried:
But same thing, no change. Can it be that a different magic string is needed to make it work? |
@Scorcerer, excellent work! I tried your commands on my LabelManager PnP with the following results: $ lsusb | grep 0922
Bus 001 Device 014: ID 0922:1001 Dymo-CoStar Corp. LabelManager PnP
$ usb_modeswitch --default-vendor 0922 --default-product 1001 --message-content 1B5A01
Look for default devices ...
Found devices in default mode (1)
Access device 014 on bus 001
Error opening the device. Abort
$ sudo usb_modeswitch --default-vendor 0922 --default-product 1001 --message-content 1B5A01
Look for default devices ...
Found devices in default mode (1)
Access device 014 on bus 001
Get the current device configuration ...
Current configuration number is 1
Use interface number 0
with class 3
Error: message endpoint not given or found. Abort
$ sudo usb_modeswitch --default-vendor 0922 --default-product 1001 --message-endpoint 01 --message-content 1B5A01
Look for default devices ...
Found devices in default mode (1)
Access device 014 on bus 001
Get the current device configuration ...
Current configuration number is 1
Use interface number 0
with class 3
Error: response endpoint not given or found. Abort
$ sudo usb_modeswitch --default-vendor 0922 --default-product 1001 --message-endpoint 01 --response-endpoint 01 --message-content 1B5A01
Look for default devices ...
Found devices in default mode (1)
Access device 014 on bus 001
Get the current device configuration ...
Current configuration number is 1
Use interface number 0
with class 3
Use endpoints 0x01 (out) and 0x01 (in)
Looking for active drivers ...
OK, driver detached
Set up interface 0
Use endpoint 0x01 for message sending ...
Trying to send message 1 to endpoint 0x01 ...
OK, message successfully sent
Reset response endpoint 0x01
Could not reset endpoint (probably harmless): -99
Reset message endpoint 0x01
Could not reset endpoint (probably harmless): -99
-> Run lsusb to note any changes. Bye!
$ lsusb | grep 0922
Bus 001 Device 015: ID 0922:1002 Dymo-CoStar Corp. There are a few minor differences which may be worth looking into (like setting the response endpoint). It could certainly be that the magic string is different. I'm honestly no expert on this stuff, and have no idea. If you have access to a Windows machine, maybe you could try to see if you could sniff the message. But then again, if the mode switching string is different, probably all the other control strings are different, so it's probably not worthwhile. |
I just now saw that i posted in wrong lsusb -v codeblock. This is the right one:
I'll try to install it via CUPS with the official driver and let you know about the results (seeing it's reported as printer, maybe it'll "just work" |
|
@Scorcerer, I just took a look at your |
So side-by side it looks like there are minor differences in endpoint addresses and stuff, but both devices announce themselves as printers (mine from the beginning, hours after usb_modeswitch) |
@Scorcerer, how are your Python skills? Can you manage an editable install? (i.e. git clone, and then |
You may be able to get by with simply editing this file. |
Changed like this: (.venv) scor@Hojo ~/Projects/dymoprint $ pip install -e .
|
Looks fundamentally good. With the editable install, you should be able to modify the source code without the need to reinstall. This is the part of code which we need to diagnose. You should be able to run from dymoprint.constants import (
DEV_CLASS,
DEV_NAME,
DEV_NODE,
DEV_PRODUCT,
DEV_VENDOR,
FONT_SIZERATIO,
USE_QR,
QRCode,
e_qrcode,
)
from dymoprint.utils import getDeviceFile
dev = getDeviceFile(DEV_CLASS, DEV_VENDOR, DEV_PRODUCT)
dev For me, the value of |
Haha, actually it's much simpler... First try $ ls -al /sys/bus/hid/devices/*0922*
lrwxrwxrwx 1 root root 0 Jan 25 22:47 /sys/bus/hid/devices/0003:0922:1002.001A -> ../../../devices/pci0000:00/0000:00:14.0/usb1/1-5/1-5.3/1-5.3:1.2/0003:0922:1002.001A That's essentially what |
Hmm, no dice:
Although there are some things in there, looks like printer is not HID-recognized :( |
There's one last thing you could try. If you go back to the original dymoprint they use Python's USB library instead of the device file. |
Hah! reading through https://sbronner.com/dymoprint.html I opted for installing it via CUPS. It freaking works, as in "it pushed out tape when i clicked 'print'" |
Wow, it's been a long time since I've read that text, but after our experience, I finally understand what he is saying! 😂 That's awesome that it responds to CUPS!!! 🎉 No idea about proper labels, i suppose we should learn some CUPS. Also, based on our work above, i think we could put together a very useful document about probing DYMO printers so that others can work on supporting their own devices. What do you think? |
Yup, sounds like a plan :) That means i'm gonna have to figure out how to pritn with LM280 quickly, as i was able to get Rhino 6000 cheaply (it seems it also works with D1 tapes) and it's gonna be the next project :) |
Ping @varac, since they also were interested in the 280. (See #30 (comment)) |
Also, I don't know if it's relevant to CUPS, but this technical manual is a good guide to the commands: BTW, the modeswitch command is <esc> Z <soh>, which sort of fits in with the protocol. |
Hi, trying to use LabelManager 280 via CUPS. I've managed to compile and install the CUPS drivers (Ubuntu detects the LM280 printer when it is connected and powered on) Any suggestions I've might be doing wrong? regarding print command onelinerAlso i've set it as default printer lpstat -p -d
lpoptions -d LabelManager-280 tryied to print text using command as shown HERE with no success. Ubuntu shows that printing in progress, the finished but LM280 did nothing. |
@aleksasp, I think the problem is that the printer is not showing up as a HID device as the current repo expects. If you run ls -al /sys/bus/hid/devices/*0922* then I think you will get "No such file or directory". Could you confirm this? In this case, you may instead have success with the original dymoprint script by Sebastian Bronner. That uses USB directly, instead of the HID virtual file. So I think you just need to add |
@maresb you were right, just had also to change the device class to Below is the output of print(dev.get_active_configuration()) that suggested changing device class to
Added public GIST form my dymoprint version. |
@aleksasp, does it print? 👀 |
@maresb yes it does print. Sorry for not making it clear in the reply. |
@aleksasp, that's excellent!!! Do you need to run with sudo in order to print? Also, do you know to what degree CUPS is necessary? My understanding is that dymoprint replaces CUPS in all cases. I see what happened now with why this repo uses the HID virtual file while the original dymoprint uses PyUSB. The latest version of Sebastian Bronner's dymoprint was from 2016. However, the version on which this repo was based is from 2013. So unfortunately these improvements never got merged in our fork. |
Printing without sudo. It is possibly likely due to appropriate rules file. Will asd that to the gist. Will try to remove CUPS or run the script on different host next week. |
We should consider merging some of these changes, especially the use of PyUSB. Changes added to the newer version of dymoprintdiff --git a/a b/b
index 1491c03..35f5c02 100644
--- a/a
+++ b/b
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/env python3
# === LICENSE STATEMENT ===
# Copyright (c) 2011 Sebastian J. Bronner <waschtl@sbronner.com>
@@ -8,28 +8,14 @@
# this notice are preserved.
# === END LICENSE STATEMENT ===
-# On systems with access to sysfs under /sys, this script will use the three
-# variables DEV_CLASS, DEV_VENDOR, and DEV_PRODUCT to find the device file
-# under /dev automatically. This behavior can be overridden by setting the
-# variable DEV_NODE to the device file path. This is intended for cases, where
-# either sysfs is unavailable or unusable by this script for some reason.
-# Please beware that DEV_NODE must be set to None when not used, else you will
-# be bitten by the NameError exception.
-
-
-DEV_CLASS = 3
-DEV_VENDOR = 0x0922
-DEV_PRODUCT = 0x1002
-DEV_NODE = None
-DEV_NAME = 'Dymo LabelManager PnP'
-FONT_FILENAME = '/usr/share/fonts/truetype/ttf-bitstream-vera/Vera.ttf'
-FONT_SIZERATIO = 7./8
-VERSION = "0.1.0 (2013-07-09)"
+# The following module libraries are not included with python and need to be
+# installed separately:
+# * Pillow (python-pillow or python3-pillow)
+# * PyUSB (python-pyusb, python3-pyusb, python-usb, or python3-usb)
-import Image
-import ImageDraw
-import ImageFont
+from PIL import Image, ImageDraw, ImageFont
+import argparse
import array
import fcntl
import os
@@ -39,6 +25,22 @@ import subprocess
import sys
import termios
import textwrap
+import usb
+
+
+#FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSans.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSans-Bold.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSans-Oblique.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSans-BoldOblique.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSans-ExtraLight.ttf'
+FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSansCondensed.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSansCondensed-Bold.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSansCondensed-Oblique.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/DejaVuSansCondensed-BoldOblique.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/ezra/SILEOT.ttf'
+#FONT_FILENAME = '/usr/share/fonts/TTF/gentium/Gentium-R.ttf' # IPA
+FONT_SIZERATIO = 7./8
+VERSION = "0.2.0 (2016-11-07)"
class DymoLabeler:
@@ -51,242 +53,247 @@ class DymoLabeler:
high-level functions for help. Each function is marked in its docstring
with 'HLF' or 'MLF' in parentheses.
"""
-
_ESC = 0x1b
_SYN = 0x16
_MAX_BYTES_PER_LINE = 8 # 64 pixels on a 12mm tape
-
- def __init__(self, dev):
+ _USB_VENDOR = 0x0922
+ _USB_PRODUCT = (0x1001, 0x1002)
+ # Number of commands to send before waiting for a response. This helps
+ # to avoid timeouts due to differences between data transfer and
+ # printer speeds. I added this because I kept getting "IOError: [Errno
+ # 110] Connection timed out" with long labels. Using dev.default_timeout
+ # (1000) and the transfer speeds available in the descriptors somewhere, a
+ # sensible timeout can also be calculated dynamically.
+ _SYNWAIT = 64
+
+ def __init__(self):
"""Initialize the LabelManager object. (HLF)"""
-
self.cmd = []
self.response = False
- self.bytesPerLine_ = None
- self.dotTab_ = 0
- self.dev = open(dev, 'r+')
-
- def sendCommand(self):
+ self.bytes_per_line_ = None
+ self.dot_tab_ = 0
+
+ # Find and prepare device communication endpoints.
+ dev = usb.core.find(custom_match = lambda d: (d.idVendor ==
+ self._USB_VENDOR and d.idProduct in self._USB_PRODUCT))
+ if dev is None:
+ raise RuntimeError("No USB device matching the following criteria "
+ "was found:\n idVendor: 0x%04x\n idProduct: %s" %
+ (self._USB_VENDOR, ', '.join('0x%04x' % id_ for id_ in
+ self._USB_PRODUCT)))
+ try:
+ dev.set_configuration()
+ except usb.core.USBError as e:
+ if e.errno == 13:
+ # Handle error number 13 (Access denied) by printing
+ # instructions for gaining access.
+ lines = []
+ lines.append("You do not have sufficient access to the "
+ "device. You probably want to add some udev rules in "
+ "/etc/udev/rules.d/dymoprint.rules along the following "
+ "lines:")
+ lines.append("")
+ for id_ in self._USB_PRODUCT:
+ lines.append('ACTION=="add", SUBSYSTEMS=="usb", '
+ 'ATTRS{idVendor}=="%04X", ATTRS{idProduct}=="%04X", '
+ 'MODE="0660", GROUP="users"' % (self._USB_VENDOR, id_))
+ lines.append("")
+ lines.append("Following that, turn your device off and back "
+ "on again to activate the new permissions.")
+ raise RuntimeError('\n'.join(lines))
+ if e.errno == 16:
+ # Handle error number 16 (Resource busy) by ignoring it. It
+ # just means that the configuration has already been set.
+ pass
+ else:
+ # On all other errors, the original exception is simple
+ # re-raised.
+ raise
+ intf = usb.util.find_descriptor(dev.get_active_configuration(),
+ bInterfaceClass=0x3)
+ if dev.is_kernel_driver_active(intf.bInterfaceNumber):
+ dev.detach_kernel_driver(intf.bInterfaceNumber)
+ self.data = usb.util.find_descriptor(intf, custom_match = (lambda e:
+ usb.util.endpoint_direction(e.bEndpointAddress) ==
+ usb.util.ENDPOINT_OUT))
+ self.status = usb.util.find_descriptor(intf, custom_match = (lambda e:
+ usb.util.endpoint_direction(e.bEndpointAddress) ==
+ usb.util.ENDPOINT_IN))
+
+ def send_command(self):
"""Send the already built command to the LabelManager. (MLF)"""
-
if len(self.cmd) == 0:
return
- cmdBin = array.array('B', self.cmd)
- cmdBin.tofile(self.dev)
+ while len(self.cmd) > 0:
+ synCount = 0
+ pos = -1
+ while synCount < self._SYNWAIT:
+ try:
+ pos += self.cmd[pos+1:].index(self._SYN) + 1
+ except ValueError:
+ pos = len(self.cmd)
+ break
+ synCount += 1
+ cmdBin = array.array('B', [self._ESC, ord('A')])
+ cmdBin.tofile(self.data)
+ rspBin = self.status.read(8)
+ rsp = array.array('B', rspBin).tolist()
+ print(rsp, pos, len(self.cmd))
+ cmdBin = array.array('B', self.cmd[:pos])
+ cmdBin.tofile(self.data)
+ self.cmd = self.cmd[pos:]
self.cmd = []
if not self.response:
return
self.response = False
- responseBin = self.dev.read(8)
+ responseBin = self.status.read(8)
response = array.array('B', responseBin).tolist()
return response
- def resetCommand(self):
+ def reset_command(self):
"""Remove a partially built command. (MLF)"""
-
self.cmd = []
self.response = False
- def buildCommand(self, cmd):
+ def build_command(self, cmd):
"""Add the next instruction to the command. (MLF)"""
-
self.cmd += cmd
- def statusRequest(self):
+ def status_request(self):
"""Set instruction to get the device's status. (MLF)"""
-
cmd = [self._ESC, ord('A')]
- self.buildCommand(cmd)
+ self.build_command(cmd)
self.response = True
- def dotTab(self, value):
+ def dot_tab(self, value):
"""Set the bias text height, in bytes. (MLF)"""
-
if value < 0 or value > self._MAX_BYTES_PER_LINE:
raise ValueError
cmd = [self._ESC, ord('B'), value]
- self.buildCommand(cmd)
- self.dotTab_ = value
- self.bytesPerLine_ = None
+ self.build_command(cmd)
+ self.dot_tab_ = value
+ self.bytes_per_line_ = None
- def tapeColor(self, value):
+ def tape_color(self, value):
"""Set the tape color. (MLF)"""
-
if value < 0: raise ValueError
cmd = [self._ESC, ord('C'), value]
- self.buildCommand(cmd)
+ self.build_command(cmd)
- def bytesPerLine(self, value):
+ def bytes_per_line(self, value):
"""Set the number of bytes sent in the following lines. (MLF)"""
-
- if value < 0 or value + self.dotTab_ > self._MAX_BYTES_PER_LINE:
+ if value < 0 or value + self.dot_tab_ > self._MAX_BYTES_PER_LINE:
raise ValueError
- if value == self.bytesPerLine_:
+ if value == self.bytes_per_line_:
return
cmd = [self._ESC, ord('D'), value]
- self.buildCommand(cmd)
- self.bytesPerLine_ = value
+ self.build_command(cmd)
+ self.bytes_per_line_ = value
def cut(self):
"""Set instruction to trigger cutting of the tape. (MLF)"""
-
cmd = [self._ESC, ord('E')]
- self.buildCommand(cmd)
+ self.build_command(cmd)
def line(self, value):
"""Set next printed line. (MLF)"""
-
- self.bytesPerLine(len(value))
+ self.bytes_per_line(len(value))
cmd = [self._SYN] + value
- self.buildCommand(cmd)
+ self.build_command(cmd)
- def chainMark(self):
+ def chain_mark(self):
"""Set Chain Mark. (MLF)"""
-
- self.dotTab(0)
- self.bytesPerLine(self._MAX_BYTES_PER_LINE)
+ self.dot_tab(0)
+ self.bytes_per_line(self._MAX_BYTES_PER_LINE)
self.line([0x99] * self._MAX_BYTES_PER_LINE)
- def skipLines(self, value):
+ def skip_lines(self, value):
"""Set number of lines of white to print. (MLF)"""
-
if value <= 0:
raise ValueError
- self.bytesPerLine(0)
+ self.bytes_per_line(0)
cmd = [self._SYN] * value
- self.buildCommand(cmd)
+ self.build_command(cmd)
- def initLabel(self):
+ def init_label(self):
"""Set the label initialization sequence. (MLF)"""
-
cmd = [0x00] * 8
- self.buildCommand(cmd)
+ self.build_command(cmd)
- def getStatus(self):
+ def get_status(self):
"""Ask for and return the device's status. (HLF)"""
+ self.status_request()
+ response = self.send_command()
+ print(response)
- self.statusRequest()
- response = self.sendCommand()
- print response
-
- def printLabel(self, lines, dotTab):
+ def print_label(self, lines, dot_tab):
"""Print the label described by lines. (HLF)"""
-
- self.initLabel
- self.tapeColor(0)
- self.dotTab(dotTab)
+ self.init_label
+ self.tape_color(0)
+ self.dot_tab(dot_tab)
for line in lines:
self.line(line)
- self.skipLines(56) # advance printed matter past cutter
- self.skipLines(56) # add symmetric margin
- self.statusRequest()
- response = self.sendCommand()
- print response
+ self.skip_lines(56) # advance printed matter past cutter
+ self.skip_lines(56) # add symmetric margin
+ self.status_request()
+ response = self.send_command()
+ print(response)
def die(message=None):
- if message: print >> sys.stderr, message
+ if message: print(message, file=sys.stderr)
sys.exit(1)
def pprint(par, fd=sys.stdout):
rows, columns = struct.unpack('HH', fcntl.ioctl(sys.stderr,
termios.TIOCGWINSZ, struct.pack('HH', 0, 0)))
- print >> fd, textwrap.fill(par, columns)
-
-
-def getDeviceFile(classID, vendorID, productID):
- # find file containing the device's major and minor numbers
- searchdir = '/sys/bus/hid/devices'
- pattern = '^%04d:%04X:%04X.[0-9A-F]{4}$' % (classID, vendorID, productID)
- deviceCandidates = os.listdir(searchdir)
- foundpath = None
- for devname in deviceCandidates:
- if re.match(pattern, devname):
- foundpath = os.path.join(searchdir, devname)
- break
- if not foundpath:
- return
- searchdir = os.path.join(foundpath, 'hidraw')
- devname = os.listdir(searchdir)[0]
- foundpath = os.path.join(searchdir, devname)
- filepath = os.path.join(foundpath, 'dev')
-
- # get the major and minor numbers
- f = open(filepath, 'r')
- devnums = [int(n) for n in f.readline().strip().split(':')]
- f.close()
- devnum = os.makedev(devnums[0], devnums[1])
-
- # check if a symlink with the major and minor numbers is available
- filepath = '/dev/char/%d:%d' % (devnums[0], devnums[1])
- if os.path.exists(filepath):
- return os.path.realpath(filepath)
-
- # check if the relevant sysfs path component matches a file name in
- # /dev, that has the proper major and minor numbers
- filepath = os.path.join('/dev', devname)
- if os.stat(filepath).st_rdev == devnum:
- return filepath
-
- # search for a device file with the proper major and minor numbers
- for dirpath, dirnames, filenames in os.walk('/dev'):
- for filename in filenames:
- filepath = os.path.join(dirpath, filename)
- if os.stat(filepath).st_rdev == devnum:
- return filepath
-
-
-def access_error(dev):
- pprint('You do not have sufficient access to the device file %s:' % dev,
- sys.stderr)
- subprocess.call(['ls', '-l', dev], stdout=sys.stderr)
- print >> sys.stderr
- pprint('You probably want to add a rule in /etc/udev/rules.d along the '
- 'following lines:', sys.stderr)
- print >> sys.stderr, 'SUBSYSTEM=="hidraw", ACTION=="add", ATTRS{idVendor}=="%04X", ATTRS{idProduct}=="%04X", GROUP="plugdev"' % (DEV_VENDOR, DEV_PRODUCT)
- print >> sys.stderr
- pprint('Following that, turn off your device and back on again to '
- 'activate the new permissions.', sys.stderr)
+ print(textwrap.fill(par, columns), file=fd)
def main():
- # get device file name
- if not DEV_NODE:
- dev = getDeviceFile(DEV_CLASS, DEV_VENDOR, DEV_PRODUCT)
- else:
- dev = DEV_NODE
- if not dev:
- die("The device '%s' could not be found on this system." % DEV_NAME)
-
+ # set up argument parsing with usage and help output
+ description = ("This script will print labels on a Dymo LabelManager PnP "
+ "connected to your computer via USB.")
+ parser = argparse.ArgumentParser(
+ description=description)
+ parser.add_argument(
+ '-v', '--version',
+ action='version',
+ version='%(prog)s ' + VERSION
+ )
+ parser.add_argument(
+ 'lines',
+ metavar='line',
+ nargs='+',
+ help=("A single line will be printed at the maximum available size on "
+ "the label. If multiple lines are specified, they will be reduced "
+ "in size to fit the vertical space and will be placed in a "
+ "column."))
+ args = parser.parse_args()
+
# create dymo labeler object
- try:
- lm = DymoLabeler(dev)
- except IOError:
- die(access_error(dev))
-
- # check for any text specified on the command line
- labeltext = [arg.decode(sys.stdin.encoding) for arg in sys.argv[1:]]
- if len(labeltext) == 0: die("No label text was specified.")
+ lm = DymoLabeler()
# create an empty label image
labelheight = lm._MAX_BYTES_PER_LINE * 8
- lineheight = float(labelheight) / len(labeltext)
+ lineheight = float(labelheight) / len(args.lines)
fontsize = int(round(lineheight * FONT_SIZERATIO))
font = ImageFont.truetype(FONT_FILENAME, fontsize)
- labelwidth = max(font.getsize(line)[0] for line in labeltext)
+ labelwidth = max(font.getsize(line)[0] for line in args.lines)
labelbitmap = Image.new('1', (labelwidth, labelheight))
# write the text into the empty image
labeldraw = ImageDraw.Draw(labelbitmap)
- for i, line in enumerate(labeltext):
+ for i, line in enumerate(args.lines):
lineposition = int(round(i * lineheight))
labeldraw.text((0, lineposition), line, font=font, fill=255)
del labeldraw
# convert the image to the proper matrix for the dymo labeler object
labelrotated = labelbitmap.transpose(Image.ROTATE_270)
- labelstream = labelrotated.tostring()
- labelstreamrowlength = labelheight/8 + (1 if labelheight%8 != 0 else 0)
+ labelstream = labelrotated.tobytes()
+ labelstreamrowlength = labelheight//8 + (1 if labelheight%8 != 0 else 0)
if len(labelstream)/labelstreamrowlength != labelwidth:
die('An internal problem was encountered while processing the label '
'bitmap!')
@@ -305,7 +312,7 @@ def main():
del line[-1]
# print the label
- lm.printLabel(labelmatrix, dottab)
+ lm.print_label(labelmatrix, dottab)
if __name__ == '__main__':
@@ -319,3 +326,10 @@ if __name__ == '__main__':
# * allow font size specification with command line option (points, pixels?)
# * provide an option to show a preview of what the label will look like
# * read and write a .dymoprint file containing user preferences
+# * implement errors using exceptions
+# * implement regular output using standard methods
+# * get rid of die()
+# * get rid of pprint()
+# * get rid of access_error()
+# * provide a version that includes its dependent libraries, and a version that
+# uses system libraries I wonder if we still need usbmodeswitch? It's a bit of a hassle to configure it, so it would be great to do without it (#41). |
Excellent!!! Any chance you could make a PR for this repo? Then we could officially support the 280. 🎉 I wonder if this would make it feasible to run this on other operating systems as well... |
#48 made some rough refactoring to use either HID or PyUSB. |
Just to let you know: Also haveing a LabelManager 280 and it works perfectly fine! Regarding the privileges: The device was detected as /dev/usb/lp1 with owner root and group lp. Since I'm member of that lp group on my PC it directly worked out of the box. |
"it" means this dymoprint repo as is? or one of the patches mentioned above? thanks! |
@srl295, there have been some substantial changes to the code since that post. The version at that time was 1.3.0. If you're having trouble you can add more details and/or try downgrading with pipx install --force dymoprint==1.3.0 |
@maresb so would you expect it to work out of the box? |
My expectation would be that it runs for the first time with a permissions error, but the error message should suggest the command to run to fix the permissions error, and then it should work the second time. |
It'd be helpful to know the output you're seeing. |
@maresb worked perfectly You do not have sufficient access to the device. You probably want to add the a udev rule in /etc/udev/rules.d with the following command:
echo 'ACTION=="add", SUBSYSTEMS=="usb", ATTRS{idVendor}=="0922", ATTRS{idProduct}=="1005", MODE="0666"' | sudo tee /etc/udev/rules.d/91-dymo-1005.rules
Next refresh udev with:
sudo udevadm control --reload-rules
sudo udevadm trigger --attr-match=idVendor="0922"
Finally, turn your device off and back on again to activate the new permissions.
If this still does not resolve the problem, you might need to reboot. In case rebooting is necessary, please report this at <https://github.com/computerlyrik/dymoprint/pull/56>. We are still trying to figure out a simple procedure which works for everyone. In case you still cannot connect, or if you have any information or ideas, please post them at that link. i'd recommend closing this as fixed. |
Thanks @srl295! |
Hi i have Linux mint and when run program i got this error message
The device 'Dymo LabelManager PnP' could not be found on this system.
When i print test page in printer dialog, printer works.
Im using Label Manager 280
The text was updated successfully, but these errors were encountered: