USB Scale Hacking

A while ago I purchased some Radio Shack USB scales on clearance for $5 each. I had always intended to get around to futzing with them but haven’t until just last night. Linux made it way too easy.

Plugging it in, I see the device identifies itself as some quasi-proprietary HID device.

Bus 002 Device 008: ID 2233:6323 RadioShack Corporation USB Electronic Scale
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0
  bDeviceProtocol         0
  bMaxPacketSize0         8
  idVendor           0x2233 RadioShack Corporation
  idProduct          0x6323 USB Electronic Scale
  bcdDevice            1.00
  iManufacturer           1
  iProduct                2
  iSerial                 0
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           34
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          4
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              100mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           1
      bInterfaceClass         3 Human Interface Device
      bInterfaceSubClass      0 No Subclass
      bInterfaceProtocol      0 None
      iInterface              0
      ** UNRECOGNIZED:  09 21 10 01 00 01 22 22 00
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            3
          Transfer Type            Interrupt
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0008  1x 8 bytes
        bInterval              10

Graciously, Linux hooked it up as a raw hid device…

usb 2-1: new low speed USB device using ohci_hcd and address 8
usb 2-1: configuration #1 chosen from 1 choice
generic-usb 0003:2233:6323.0006: hiddev99,hidraw4: USB HID v1.10
   Device [RadioShack Corporation USB Electronic Scale]
   on usb-0000:00:0b.0-1/input0

I decided to have a peek at what it output:

caskey@arnold:~$ sudo cat /dev/hidraw4 |hexdump -C
00000000  ab 12 13 81 32 a0 e0 d5  ab 12 13 81 32 a0 e0 d5  |....2.......2...|
00000010  ab 12 13 81 32 a0 e0 d5  ab 12 13 81 32 a0 e0 d6  |....2.......2...|
^C

Looks like 8 bytes repeating over and over again about every 250ms. The only thing that changes is the last two bytes. Just guessing, I wrote a little perl program to pull out those two bytes and interpret them as a signed short. I tried it both little and big endian and the numbers ramp up smoothly when I treat it as a big endian number.

Zero appears to hover around -7978, and if I subtract that out, I get a value that hangs around zero, then goes up when I put something on it. Unfortunately I don’t have any calibrated weights so I randomly placed my leatherman and a post-it note to see how sensitive it was.

My leatherman registered at “383″ units, while a post-it note was between 1 and 2 units. The data is noisy as the values bounce back and forth by +/-2 or so units. I worked a bit of smoothing into my perl program and tried a few more things.

A dead 7ah SLA battery came in at 6472/6473 units, and my coffee cup full of pens was 2103 units. I really wanted to know what these units were. Therefore I tried to think of what I had which would have a reliable weight. After a bit of googling, I discovered that a US nickel nominally weights 5 grams. Since it is late at night and my wife’s asleep, I raided her coin jar for nickels.

Obviously any given nickel is likely to weigh +/- some amount, so I took 10 of them and placed them on the scale. They came out to exactly 128 units. *bing* the light goes on. I fished out another 10 and it came in at 258. That was some pretty strong evidence that the two bytes are 100-grams and 1/256th of 100 grams each. I took the number and modified my program to print out the “units” divided by 256 and adjusted to Kg.

My leatherman now came out as 0.149 Kg, and the twenty nickels coins came out to 0.1009 Kg. Darn close in my book. I’m sure this scale is no good for such fine measurements, but I’m happy.

After all that, I remembered that I had a 1Lb weight from an old exercise cuff lying in a shoebox. I put that on my scale and it read out:

W: (-6815/112.787110749634)   '1163' -> 1161.2    0.4535 Kg   or 0.99 Lbs
W: (-6817/118.757755212152)   '1161' -> 1161.1    0.4535 Kg   or 0.99 Lbs
W: (-6816/124.439867451545)   '1162' -> 1161.1    0.4535 Kg   or 0.99 Lbs
W: (-6815/129.847874078967)   '1163' -> 1161.2    0.4535 Kg   or 0.99 Lbs

And in the world of cheap USB scales, that’s perfectly fine for me.

Oh, and here’s the really dirty perl code I used:

caskey@arnold:~$ sudo cat /dev/hidraw4 | ./scalecat
caskey@arnold:~$ cat scalecat
#!/usr/bin/perl

my $ALP = 0.1;
my $CORR = -7978;
my $MOVINGAVG = 0.0;
my @weight = (0, 0, 0, 0, 0, );
my $wta = 0;
while(1) {
  read STDIN, $foo, 8;
  my($a,$b,$c,$d,$e,$f,$w) =  unpack("C6s>", $foo);
  my($wt) = $w - $CORR;
  $MOVINGAVG = (0.95 * $MOVINGAVG) + (0.01 * $wt);
  if(int($MOVINGAVG) == $wt && $CORR != $w) {
    print "*** ZEROING ***\n";
    $CORR = $w;
  }
  if(($wta-$wt)**2 < 9) {
    $wta= (int(10*(($wt * ($ALP)) + ($wta *(1.0-$ALP)))))/10;
  } else {
    print "+++ SKIP +++\n";
    $wta = $wt;
  }
  my $kg = (int(($wta/256.0)*1000))/10000;
  my $lb = (int(($kg/0.45359237)*100))/100;
  print "W: ($w/$MOVINGAVG)   '$wt' -> $wta    $kg Kg   or $lb Lbs\n";
}

I love it when projects are quick and easy. This was nothing like trying to get the Griffin Powermate to work a few years ago. Linux does the heavy lifting and presents me with the data in a nice easy to play with format.

2 Responses to “USB Scale Hacking”

  1. Iestyn Lewis Says:

    This could not be more timely. I grabbed one of these scales for demonstrations at work last week. Thank you for decoding the output format, I doubt I would have figured that out on my own.

  2. caskey Says:

    I’m glad it was of use to you. I hope your demo goes well.

Leave a Reply