Skip to content

Instantly share code, notes, and snippets.

@tresf
Last active May 5, 2024 04:13
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tresf/898ab2d4d259aef2d4f7 to your computer and use it in GitHub Desktop.
Save tresf/898ab2d4d259aef2d4f7 to your computer and use it in GitHub Desktop.
Read weight from a USB scale
<html>
<!--
Author: A. Tres Finocchiaro, tres.finocchiaro@gmail.com
License: LGPL 2.1
Depends: QZ Tray 2.0.0-alpha1+
-->
<!-- Note: jquery is not needed in alpha2 -->
<script type="text/javascript" src="js/dependencies/jquery-1.11.3.min.js"></script>
<!-- Note: rsvp can be overriden via qz.setPromiseType(...) TODO: Get usage from @bberenz -->
<script type="text/javascript" src="js/dependencies/rsvp-3.1.0.min.js"></script>
<script type="text/javascript" src="js/qz-tray.js"></script>
<script>
// Scale manufacturers
var mt = {
vendor: '0x0EB8',
product: '0xF000',
device: '0x00',
endpoint: '0x81',
};
var dymo = {
vendor: '0x0922',
product: '0x8009',
device: '0x00',
endpoint: '0x82',
};
// FIXME: Verify with physical scale
var stamps = {
vendor: '0x1446', // or '0x6A73'
product: '0xF000',
device: '0x00',
endpoint: '0x81',
};
var scale = mt;
var err = function(e) { console.error(e); }
var release = function() {
qz.usb.releaseDevice(scale.vendor, scale.product).catch(function(e) {
console.error(e);
});
}
qz.websocket.connect().then(function() {
return qz.usb.claimDevice(scale.vendor, scale.product, scale.device);
}).catch(err).then(function() {
return qz.usb.readData(scale.vendor, scale.product, scale.endpoint, '8');
}).then(function(data) {
// Get status
var status = parseInt(data[1], 16);
switch(status) {
case 1: // fault
case 5: // underweight
case 6: // overweight
case 7: // calibrate
case 8: // re-zero
status = 'error'; break;
case 3:
status = 'busy'; break;
case 2: // stable at zero
case 4: // stable non-zero
default:
status = 'stable';
}
// Get precision
var precision = parseInt(data[3], 16);
precision = precision ^ -256; // unsigned to signed
// Get weight
data.splice(0,4);
data.reverse();
weight = parseInt(data.join(''), 16);
// Apply precision
weight *= Math.pow(10, precision);
weigth = weight.toFixed(Math.abs(precision));
// Get units
var units = parseInt(data[2], 16);
switch(units) {
case 3:
units = 'kg'; break;
case 11: // ounces
units = 'oz'; break;
case 12:
default:
units = 'lbs';
}
alert(status + ": " + weight + units);
}).then(release).catch(release);
</script>
</html>
@akberenz
Copy link

akberenz commented Jan 5, 2016

I don't see the point of the empty sendData call, so it probably can be removed.
Chaining promises will save you horizontal space, plus you can combine similar catches.

qz.websocket.connect().then(function() {
    return qz.usb.claimDevice(scale.vendor, scale.product, scale.device)
}).catch(err).then(function(){
    return qz.usb.readData(scale.vendor, scale.product, scale.endpoint, '8');
}).then(function(data){
    // .. data parsing ..
}).catch(release);

Here both connect and claimDevice will use the err catch function if they fail, and only readData will use the release catch on failure.

@akberenz
Copy link

akberenz commented Jan 5, 2016

In trying to find an explanation for the previous readings that come through, I happened on information that the scale precision is also sent through the raw data, at index 3 as an unsigned byte. Converting to signed yields a negative number such that weight * 10^[signed_value] yeilds the correct weight.

// Get precision
var precision = parseInt(data[3], 16);
precision = precision ^ -256; //unsigned to signed

// Get weight
...

weight *= Math.pow(10, precision);
weight = weight.toFixed(Math.abs(precision));

@tresf
Copy link
Author

tresf commented Jan 8, 2016

@bberenz Done, and done, thanks.

FYI, I don't think GitHub sends notices on Gists, so I'm attempting to tag you instead. 👍

@ProPixelMedia
Copy link

Anyone have a recommendation for a USB scale that this would work with? Would this also work with a Bluetooth scale?

@tresf
Copy link
Author

tresf commented May 5, 2024

@ProPixelMedia this proof of concept is now part of QZ Tray. https://github.com/qzind/tray/blob/master/js/qz-tray.js

With regards to HID communications, all scales use the same protocol. Bluetooth might use the HID protocol or it may use a serial protocol. Serial protocols differ.

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