Reading a USB Stamps.com scale

Update: I now have an improved C version of this program: usbscale.

I got suckered into one of those hard-to-cancel Stamps.com trials. The upside is that they give you a $10 USB 5 lb. scale to use with their software. The downside is that they want you to only use it with their software, and the company that makes the scale has since taken down their free USB-scale program.

The good news, as Nicholas Piasecki and some Linux users figured out, is that the USB scale conforms to the USB HID specifications, which helpfully standardize how USB scales should work (no joke).

So, this little Perl hack reads from the Stamps.com scale by accessing the hidraw# interface that Linux provides. In my case, I have hidraw4 hard-coded into the script itself. Basically, it loops until it reads a good value from the scale, at which point it prints out the weight and exits.

Edit: This code is now a Gist on GitHub.

#!/usr/bin/perl

# I hereby release this script into the public domain.

use bytes;

my $data;

#prevents us from repeating messages
my $waitingflag = 0;

while (1) {

    $data = `cat /dev/hidraw4 | head -c 7`;

    my $report = ord(substr($data, 1, 1));
    my $status = ord(substr($data, 2, 1));
    my $unit   = ord(substr($data, 3, 1));
    my $exp    = ord(substr($data, 4, 1));
    my $lsb    = ord(substr($data, 5, 1));
    my $msb    = ord(substr($data, 6, 1));
    my $weight = ($msb * 255 + $lsb) / 10;
    if($exp != 255 && $exp != 0) {
        $weight ^= $exp;
    }
    #print "$report $status $unit $exp $weight\n";

    if($report != 0x03) {
      die "Error reading scale data!\n";
    }

    if($status == 0x01) {
      die "Scale reports FAULT!\n";
    } elsif ($status == 0x02 || $weight == 0) {
        if($waitingflag != 0x02) {
            print "Zero'd...\n";
            $waitingflag = 0x02;
        }
    } elsif ($status == 0x03) {
        if($waitingflag != 0x03) {
            print "Weighing...\n";
            $waitingflag = 0x03;
        }
    } elsif ($status == 0x04) {
        my $unitName = "units";
        if($unit == 11) {
            $unitName = "ounces";
        } elsif ($unit == 12) {
            $unitName = "pounds";
        }
        print "$weight $unitName\n";
        last;
    } elsif ($status == 0x05) {
        if($waitingflag != 0x05) {
            print "Scale reports Under Zero...\n";
            $waitingflag = 0x05;
        }
    } elsif ($status == 0x06) {
        if($waitingflag != 0x06) {
            print "Scale reports Over Weight!\n";
            $waitingflag = 0x06;
        }
    } elsif ($status == 0x07) {
        if($waitingflag != 0x07) {
            print "Scale reports Calibration Needed!\n";
            $waitingflag = 0x07;
        }
    } elsif ($status == 0x08) {
        if($waitingflag != 0x08) {
            print "Scale reports Re-zeroing Needed!\n";
            $waitingflag = 0x08;
        }
    } else {
        die "Unknown status code: $status\n";
    }

}

10 thoughts on “Reading a USB Stamps.com scale”

  1. Hi!

    I created a warning system for our office coffee pot using your script so I thought a thanks would be in order.

    Also it was posted to a perl mailinglist by someone other than me, and they made some suggestions for simplifying the code (and corrected a bug I added): http://www.perlmonks.org/?node_id=886566

    Check it out at http://graph.no

    I referenced your blog and github in the source/references.txt link at the bottom.

  2. Hi Eric,

    you said “and the company that makes the scale has since taken down their free USB-scale program” – can you pls provide the name of the company that makes the scale / link to their site?

    Thank you

Leave a Reply

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>