For an experimental project I’m working on, I wanted to read the weight from a DYMO M10 digital postal scale with USB support. I expected the scale to show up as a virtual COM port, since older digital scales used RS232 for their computer interface,but the scale shows up as a USB HID (Human Interface Device) in Windows.
I found Micah Carrick’s site which shows how to read from a MagTek credit card reader in Linux using PyUSB 1.0. Like the DYMO M10, the MagTek reader uses the USB HID device class so the basic method for getting data from the device is the same.
The first step is to install PyUSB 1.0. Unzip the contents of the archive from the PyUSB sourceforge page and run python setup.py install.
Using PyUSB on Windows requires installing a suitable backend such as libusb-win32. After installing libusb-win32, it’s necessary to install a device filter for the scale. Connect the USB scale to the computer and press the power button. Windows should detect the scale and install the device driver automatically. The DYMO M10 shows up in Device Manager as a “USB Input Device” with vendor ID 0922 and product ID 8003.
Using the libusb-win32 Filter Wizard, install a device filter for the scale. It will show up in the list as “vid:0922 pid:8003 rev:0100 USB Input Device”.
Now it’s possible to read data from the scale using the usb module in Python:
VENDOR_ID = 0x0922
PRODUCT_ID = 0x8003
# find the USB device
device = usb.core.find(idVendor=VENDOR_ID,
# use the first/default configuration
# first endpoint
endpoint = device[(0,0)]
# read a data packet
attempts = 10
data = None
while data is None and attempts > 0:
data = device.read(endpoint.bEndpointAddress,
except usb.core.USBError as e:
data = None
if e.args == ('Operation timed out',):
attempts -= 1
The data packet is a 6-element array; for example:
array('B', [3, 2, 11, 255, 0, 0])
The 1st element has always had the value 3 in my tests, so I’m not sure what it does.
The 2nd element indicates whether the value is stable.
The 3rd element (value 11 in the example above) is probably a flag byte. The only values I have observed so far are 2 and 11. A value of 2 indicates that the scale is in kg mode, and a value of 11 indicates that the scale is in lbs/ounces mode. Curiously, whenever the scale reads 0, it seems to indicate lbs/oz mode.
Thanks to Daniel Rice (see his comment below), we now know what the 4th element (index 3) is for; it’s for calculating the scaling factor when reading in ounces. In the above example it has a value of 255. This is in fact the signed value -1, which indicates that the raw value is in tenths, due to a scaling factor of 10^-1 or 0.1. For a value of 254, the scaling factor is 10^-2, or 0.01. I’ll refer to this value as scaling_factor below.
The elements at indices 4 and 5 are used to calculate the weight.
In kg mode:
grams = data + (256 * data)
In pounds/ounces mode:
ounces = scaling_factor * (data + (256 * data))
If you check the mode, you can just convert to whatever unit you need no matter what mode the scale is in.
DATA_MODE_GRAMS = 2
DATA_MODE_OUNCES = 11
raw_weight = data + data * 256
if data == DATA_MODE_OUNCES:
ounces = raw_weight * scaling_factor
weight = "%s oz" % ounces
elif data == DATA_MODE_GRAMS:
grams = raw_weight
weight = "%s g" % grams
The scale is capable of reading negative values if you zero it and then remove the weight, but I haven’t yet figured out how to get negative weight values yet. The scale itself displays the correct value, but the data packet reads as if it were zero, except the second array element has a value of 5 instead of 2.
I also haven’t figured out how to determine when the reading has stabilized. Nicholas Piasecki’s article on reading a Stamps.com USB scale in C# says that the 2nd element in that scale’s data packet reads 4 when the value is stable, but 4 is all I observe when reading a positive non-zero weight value, even when the values are changing rapidly.
I hope this information has been useful to you. If you have any questions or have anything to add, please post a comment!