Reading a Dymo USB scale using Python

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:

import usb.core
import usb.util

VENDOR_ID = 0x0922
PRODUCT_ID = 0x8003

# find the USB device
device = usb.core.find(idVendor=VENDOR_ID,
                       idProduct=PRODUCT_ID)

# use the first/default configuration
device.set_configuration()
# first endpoint
endpoint = device[0][(0,0)][0]

# read a data packet
attempts = 10
data = None
while data is None and attempts > 0:
    try:
        data = device.read(endpoint.bEndpointAddress,
                           endpoint.wMaxPacketSize)
    except usb.core.USBError as e:
        data = None
        if e.args == ('Operation timed out',):
            attempts -= 1
            continue

print data

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[4] + (256 * data[5])

In pounds/ounces mode:

ounces = scaling_factor * (data[4] + (256 * data[5]))

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[4] + data[5] * 256

if data[2] == DATA_MODE_OUNCES:
    ounces = raw_weight * scaling_factor
    weight = "%s oz" % ounces
elif data[2] == DATA_MODE_GRAMS:
    grams = raw_weight
    weight = "%s g" % grams

print weight

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!

60 thoughts on “Reading a Dymo USB scale using Python”

  1. Thanks for posting the code and analyzing the data packet! I’m attempting to run the code, however, it doesn’t work on my Windows 7 64 bit machine.
    I’ve looked but haven’t found a 64 bit version of libusb-win32. Any suggestions?
    Thanks,
    Kevin

    1. Kevin, my development machine is running Win 7 64-bit. All libusb-win32 versions from 1.2.0.0 onward support 64-bit Windows. Did you remember to install a device filter using the libusb-win32 Filter Wizard?

  2. Hello,

    GOOD WORK! My modification (Dymo scale working like a keyboard) sends the weight to the active window (for example excel) and hit enter.

    Source code (uses SendKeysCtypes):
    import usb.core
    import usb.util
    import SendKeysCtypes
    import os, time

    VENDOR_ID = 0x0922
    PRODUCT_ID = 0x8006

    DATA_MODE_GRAMS = 2
    DATA_MODE_OUNCES = 11

    # find the USB device
    device = usb.core.find(idVendor=VENDOR_ID,
    idProduct=PRODUCT_ID)

    # use the first/default configuration
    device.set_configuration()
    # first endpoint
    endpoint = device[0][(0,0)][0]

    last_raw_weight = 0
    last_raw_weight_stable = 4

    while True:

    time.sleep(.5)

    try:
    data = None
    data = device.read(endpoint.bEndpointAddress,
    endpoint.wMaxPacketSize)
    except usb.core.USBError as e:
    data = None

    if data != None:

    raw_weight = data[4] + data[5] * 256

    # +/- 2g
    if raw_weight > 0 and abs(raw_weight-last_raw_weight) 0 and raw_weight != last_raw_weight :
    last_raw_weight_stable = 4
    last_raw_weight = raw_weight

    if raw_weight > 0 and last_raw_weight_stable >= 0:
    last_raw_weight_stable -= 1

    if raw_weight > 0 and last_raw_weight_stable == 0:
    if data[2] == DATA_MODE_OUNCES:
    ounces = raw_weight * 0.1
    weight = “%s oz” % ounces
    elif data[2] == DATA_MODE_GRAMS:
    grams = raw_weight
    weight = “%s g” % grams

    SendKeysCtypes.SendKeys(weight+'{ENTER}’, 0)

  3. I am trying to do this exact same thing. I was able to run it on windows and it works well. I put the same code on the raspberry pi and it gives an error at
    device.set_configuration()
    I am using Linux “weezy”

      1. USBError _str_error[ret]….
        Access denied insuffiecient permissions

        Was there any set up I had to do. I simply plugged the scale in and installed pyusb and ran. Am I forgetting something

        1. Okay so I ran it from the terminal and now I am getting another error saying resource busy.

          I apologize for my stupid question, first time with Linux, raspberry pi and python

          1. It’s a good question. There’s probably some configuration or permissions issue.

            You could try running it in the terminal with ‘sudo’:
            sudo python dymo_scale_script.py

            I should have some time next week to look into this more.

  4. This is very helpful! However, it does not address the possibility that the scale gets turned off, then back on while the script is running. How would I alter my script to continue to run if it disconnects?

    1. Good question. I haven’t had time to look into it yet. You’ll have to see if the connection handle can be freed after the device disappears from the bus. If not, it may not be possible. I’ve had problems with serial devices on Windows where if they are disconnected from the USB while my Python process is running, the ports cannot be closed and then cannot be reopened once they are reconnected, without restarting the process.

  5. I’m currently looking for a scale to use for continious monitoring, and the Dymo is one of my favorites. However, the auto-shutdown feature in it scares me a bit, since scales will be deployed, and I need some reliability.

    Can the auto-shutdown be disabled, or can the scale be turned on again via the serial link?

    1. For the Dymo M10 scale I have, the auto-shutdown feature is not enabled when the scale is USB-powered. Mine has been on for hours and I haven’t touched it. I think auto-shutdown is only enabled when the scale is powered by batteries.

      1. Hello,

        Just the answer I was hoping for. I’ll order one ASAP, and start developing 🙂

        Thanks for your quick reply.

    2. Unfortunately, this does not seem to be the case for me. Mine shuts off after 3 minutes if I just read values continously (e.g. every 20 seconds) wihtout replacing the item on the scale.

          1. Same here. Got one model M10 and another M10-US. Both don’t have batteries, yet one of them auto shuts off and the other doesn’t.

            Can this be changed either in hardware or software?

          2. Just a heads up for some of the scales where you can’t disable the auto-shutoff feature:
            I just got off the phone with Dymo, and the rep there mentioned that there is a batch of scales with bad firmware out there, where the auto-shutoff cannot be disabled. They’re sending me a new scale – I got a S100, YMMV.
            (the python code above works nicely on a Raspberry Pi once you release the kernel driver, thanks for that!)

    3. I’ve been searching for the same thing. I ended up purchasing the M10 and tried to disable the auto-off feature using the instructions for the S100:

      “1. While the scale is off, press and hold kg/lb .
      2. While holding kg lb , press “On”.
      The display shows A.OF and then 0.0 when ready. The scale now remains on until manually turned off.”

      Unfortunately, this didn’t work.

      I contacted Dymo. They said that it doesn’t have the ability to disable the auto-off feature.

      It seems ridiculous that it’s not capable of being disabled since most volume shippers don’t want it to auto-off. So my question is, does the computer communicate with the M10 or is it only one-way communication from scale to computer? If the former, is there any possibility of creating a script that will keep it on?

  6. Hi, i know this is an already 2 year old post, but i hope I can still get some help.

    I try to do the same thing in JAVA with the javahidapi. I am able to get the device (also with deviceById), but then I dont know how to read the data from the scale.

    When I run device.read in a loop I wont get any data from the scale. Do I have to first write a command to the scale?

    I just dont know how I can communicate with the M10. What does it want me to send, what does it send to me?

    Yes I’m really desperate to post here :P, but I have been stuck with this problem for hours now.

  7. The 4th element that has the value ‘255’ when reading ounces is actually a scale factor. 255 interpreted as a signed value is -1. This indicates that the value `raw_weight = data[4] + data[5] * 256` is actually in tenths of ounces, i.e., ounces * 10^-1. A value of 254, or -2, would mean that the scale provides values in hundredths of ounces, 10^-2.

    1. There sample code to read HID POS scales from Android https://github.com/devunwired/accessory-samples/blob/master/ScaleMonitor/src/com/examples/usb/scalemonitor/ScaleActivity.java

      I tried it with a Dymo M5 but only ever get
      03 04 0B FF 00 00
      Seems like reportId, status, unit and scaling work fine
      but the weight is always zero
      also unit never changes (when pressing the button)

      Running the python code (on linux) throws (75, u’Overflow’) when reading from the usb device :/

      Did anyone get the Dymo M5 working?

      or do only the more expensive scales support USB HID POS :/

  8. Forgive me if this is totally impossible … I have not done any programming since an intro course in college in the mid-90s, except for a little bit of Excel macros and SQL querying when doing data analysis. Would it be possible, in Excel running on Windows 8, to write a macro which would take in the weight data directly from the scale? What a great post, if the lazy Excel trick doesn’t work you may just inspire me to finally try using Linux. Thanks much!

  9. Sorry Carol, I’m unable to give an Excel integrated solution. Anyhow you may use the python code to add values to a CSV file and then import the data into Excel. Probably there is also a way to execute an Excel macro which will call some external python script. So this could all be started/executed from within Excel.
    HTH!

    I have a question too. I am using a Dymo S400 scale and want to monitor the weight of one of my bee-hives from spring on until honey harvest. I am using an Raspberry Pi to do so. Unfortunately the scale will only measure weight after lifting the hive at first, then turn on the scale and then putting the hive back on the scale… I would prefer a solution without lifting the hive at all. Anyone know a way how to do it. Probably with a scale from another manufacturer? Many thanks in advance!

  10. This fails to work on OS X since the kernel grabs exclusive access to all HID devices. Running the script via sudo did not work.

    I was able to get a python script to read from a Dymo scale on OS X, but I needed to install hidapi, Cython, and the hidapi interface:


    brew install hidapi
    pip install cython
    pip install hidapi

  11. Hello Sir
    I having metteler toledo scale reader but I am not able to get scale values in windows 7 .I am using programming language python

  12. Hello Steven, or anyone else who can help,

    I know this is an ancient thread but I have been working with the DYMO M25 for a while now using a LabVIEW based VISA driver with which I can see the same 6 elements as you describe (when I’m not having connectivity issues which I think has something to do with LV not closing the connection properly).

    Anyway, were you ever able to read negative numbers? I am trying to measure push/pull torques so I would like to use both directions of the load cell. I tried to artificially bias by tare-ing with 10lbs but that doesn’t work. The second element indicates “2” for zero or stable, “4” in the positive direction, and “5” in the negative direction but the weight always reads zero (even though the scale display measures the negative values). Any help would be great!

  13. Steven, Thank you so much for sharing your code on how to do this!

    I’m using python version 2.7.3 and pyusb version 1.0 on 64-bit Windows (which I’m running via vmware on a mac).

    I’m getting the following error from the device.read() command:
    raise USBError(errmsg, ret)
    usb.core.USBError: [Errno None] libusb0-dll:err [_usb_reap_async] timeout error

    Has anyone else experienced this? Thank you!
    -Kristin

  14. Hallo
    I want to pick up the weight of the scale of a timer job in Access 2013, and write to the database.
    Can I put this code in Access 2013?

    1. You need to first be able to read in python into access, but you should find code for that on-line pretty easy. If a post above will help a lot for entering the data more like a keypad.

      Dominik Rusiecki
      AUGUST 8, 2012 AT 10:46 AM
      Hello,

      GOOD WORK! My modification (Dymo scale working like a keyboard) sends the weight to the active window (for example excel) and hit enter.

      Source code (uses SendKeysCtypes):
      import usb.core
      import usb.util
      import SendKeysCtypes
      import os, time

      VENDOR_ID = 0x0922
      PRODUCT_ID = 0x8006

      DATA_MODE_GRAMS = 2
      DATA_MODE_OUNCES = 11

      # find the USB device
      device = usb.core.find(idVendor=VENDOR_ID,
      idProduct=PRODUCT_ID)

      # use the first/default configuration
      device.set_configuration()
      # first endpoint
      endpoint = device[0][(0,0)][0]

      last_raw_weight = 0
      last_raw_weight_stable = 4

      while True:

      time.sleep(.5)

      try:
      data = None
      data = device.read(endpoint.bEndpointAddress,
      endpoint.wMaxPacketSize)
      except usb.core.USBError as e:
      data = None

      if data != None:

      raw_weight = data[4] + data[5] * 256

      # +/- 2g
      if raw_weight > 0 and abs(raw_weight-last_raw_weight) 0 and raw_weight != last_raw_weight :
      last_raw_weight_stable = 4
      last_raw_weight = raw_weight

      if raw_weight > 0 and last_raw_weight_stable >= 0:
      last_raw_weight_stable -= 1

      if raw_weight > 0 and last_raw_weight_stable == 0:
      if data[2] == DATA_MODE_OUNCES:
      ounces = raw_weight * 0.1
      weight = “%s oz” % ounces
      elif data[2] == DATA_MODE_GRAMS:
      grams = raw_weight
      weight = “%s g” % grams

      SendKeysCtypes.SendKeys(weight+'{ENTER}’, 0)

  15. > “The 2nd element indicates whether the value is stable.”

    I think it might rather refer to whether the reading is zero (or tarred) or not.

  16. hello ,
    thank you for sharing this with us but i tried this code on Dymo M25 and this Error appear to me !!
    the scale work normally “HID\VID_0922&PID_8003”
    and it`s readings are displayed on the official driver
    any help please ?
    “Traceback (most recent call last):
    File “C:/Users/ahmed/Desktop/wight1.py”, line 12, in
    device.set_configuration()
    AttributeError: ‘NoneType’ object has no attribute ‘set_configuration'”

      1. Hi Alfredo,

        If you get “‘NoneType’ object has no attribute ‘set_configuration'” that means the call to usb.core.find() failed to find a device with the given vendor ID and product PID.

        Maybe your scale has a different vendor and product ID, or some other software or driver is preventing PyUSB from connecting to it.

  17. About auto-power off “feature” I have 2 model M5 (to 5kg EU model) first that works perfectly without auto power off USB product id is 0x8005 same model but with power off is 0x8003.
    Hope somebody can find a hack to disable the auto power off.

  18. so it looks like the second index is a multiplier. 2 means tarred (0), 4 means positive value, 5 means negative value.

  19. On the off chance anyone is still monitoring this post, I have a question. First, though, I want to thank Steven for posting this. Within half an hour, I was reading from my ES2500 scale! I work in IT, at a company that ships a great deal of packages. Part of my job is maintaining our shipping software, and as I’m blind, I have to find some inventive ways to make my computer and tools accessible. I therefore wanted a way to find out what the scale was reading since I can’t see the display, and now I can.

    The problem I’m running into is in the weight values. Again, ES2500U, an Endicia scale. I use the data[4]+data[5]*256 method, then multiply by the factor for ounces, but I get wildly inaccurate values. An eight-pound book, for instance, weighs many tons, according to the script. Is there another way to interpret the weight data that anyone has found? I’ve even contacted Endicia, but they weren’t able to offer any information. Thanks!

    1. I figured it out. It’s basically what Steven said, so I’m not sure where I went wrong yesterday. For anyone with an ES2500U scale, my script is below:

      from pywinusb import hid

      mode_ounces = 11
      mode_grams = 2
      vendorID = 0x1446
      productID = 0x6A78
      scale = hid.HidDeviceFilter(vendor_id = vendorID, product_id = productID).get_devices()[0]
      previousOutput = “”

      def handleRawData(data):
      global previousOutput
      if data[1] != 4:
      output = “Scale movement.”
      units = data[2] #2 or 11
      factor = data[3] #the accuracy of the scale, in the form 10**(factor-256)
      rawWeight = data[4] + data[5] * 256 #why 256? Who knows, but it works.
      if units == mode_ounces:
      ouncesFactor = 10 ** (factor – 256)
      weight = (data[4] + (data[5] * 256)) * ouncesFactor
      output = “{weight} pounds”.format(weight=weight/16)
      elif units == mode_grams:
      output = “{weight} grams”.format(weight=rawWeight)
      else:
      output = “Unrecognized units indicator.”
      if output == previousOutput: #do nothing, so we don’t get flooded with identical messages
      return None
      else:
      print output
      previousOutput = output
      return None

      scale.open()
      scale.set_raw_data_handler(handleRawData) #make our function handle the data from the scale

      cmd = “”
      while cmd.lower() != “q”:
      cmd = raw_input(“press Q to quit, or any other key to read:\n”)

  20. Does anyone know if there is actually computer integration support for the DYMO 400 s or if it is just false advertisement?

    I’m trying to figure out what the Product ID is so I can have the scale communicate with my FEDEX ship client software.

    So far I have “Vendor ID: 0922 / Product ID: ?”.

    Thanks in advance for the feedback. Trying to make lemonade out of a lemon of a purchase for my shipping department! 🙂

  21. This is exactly what I needed, I actually had some code written myself, but was having a hard time with actually reading the USB scale, I connected OK and established and interface/endpoint but couldn’t figure out the read part. 9 years later the code still found its way to a very grateful person 🙂 good work and THANKS!!

Leave a Reply

Your email address will not be published. Required fields are marked *