Skip to content

Instantly share code, notes, and snippets.

@Techwizz-somboo
Last active March 22, 2025 23:46
Show Gist options
  • Save Techwizz-somboo/4b731878ee06ae2e270aa3a13383b4f2 to your computer and use it in GitHub Desktop.
Save Techwizz-somboo/4b731878ee06ae2e270aa3a13383b4f2 to your computer and use it in GitHub Desktop.
Identifying USB-HID (Weight) Scales

Identify USB-HID Scales

So recently, I was tasked with tasked with integrating USB HID-compliant scales into my company's Electron WMS shipping app. I found it pretty difficult to find good information on identifying USB scales, so I'm making this guide in hopes of helping someone else in the same situation.

This document will give examples on identifying and reading from scales in node.js.

Identify a Scale

This part is actually pretty easy, but it took me a while to figure it out. I found the USB Usage Table spec document which then made it really easy. On page 414 (section 33), you'll find the Scales usage page which is 0x8D (141 in decimal).

Indentify Scales In node.js

The easiest way is to use the node module node-hid, use npm install node-hid to add it to your project.

Add it to your desired js file const HID = require('node-hid');

Implement a function similar to this

function getWeightScales() {
  const devices = HID.devices();

  let scales = [];

  devices.forEach((device) => {
    if (device.usagePage == 141) {
      scales.push(device);
    }
  });

  return scales;
}

This will populate the scales array with all devices in usage Page 141, which should only be USB Scales.

Read from a scale

This describes the bytes you'll read from the HID data.

Byte 0 == Report ID
Byte 1 == Scale Status
Byte 2 == Weight Unit
Byte 3 == Data Scaling (decimal placement) - signed byte is power of 10
Byte 4 == Weight LSB
Byte 5 == Weight MSB

In the HID usage doc, each of the above is listed in order to their IDs.

With scale status, for example, if you go to page 421 (section 33.6), fault is 1, stable @ 0 is 2, etc.

Read From a Scale In node.js

First connect to the device:

var device = new HID.HID(devicePath);

Device path can be found if you list out all currently connected devices

const devices = HID.devices();

You can then of course filter out by usage page 141 for a list of scales.

Do something like this to find your device (if you keep track of the vendor and product id somewhere):

devices.forEach((device) => {
    if (device.vendorId == this.vendorId && device.productId == this.productId) {
        devicePath = device.path;
    }
});

Listen for when data is sent from the scale:

device.on('data', (data) => {
    // handle data
});

You can read from the scale like this:

const LSB = data[4];
const MSB = data[5];
const combinedWeight = (MSB << 8) | LSB;
const scalingFactor = Math.pow(10, (data[3] << 24) >> 24);
let weight = parseFloat(combinedWeight * scalingFactor).toFixed(2);

Of course account for the weight unit it's being sent in and convert it to the unit you want, something like this:

const weightUnit = data[2];

// This converts from kilos & ounces to pounds.
switch (weightUnit) {
    case 3: // Kilos
        weight = parseFloat(parseFloat(weight) * 2.20462262185).toFixed(2);
        break;
    case 11: // Ounces
        weight = parseFloat(parseFloat(weight) * 0.0625).toFixed(2);
        break;
    case 12: // Pounds
    default:
        break;
}

For other weight units, see the HID document listed above on page 419 (section 33.4.1): 1 is Milligram, 2 is Gram, etc.

Conclusion

I hope this document clears out some confusion on reading usb-hid scales. This document also shows there is no reason to store a huge list of vendor ids to guess at what 'might' be a scale, like what most shipping software seems to do. While the examples here use node-hid, the knowledge is portable to any programming language. I hope this proves helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment