Hack IR bathroom scale

I just purchased a wireless(IR) bathroom scale and I want to be able to sniff the IR data to get the value being sent from the scale.

I have hooked up an IR receiver to the arduino and I'm trying to figure out how the data is being encoded in the IR protocol.

I started with using the example IRrecvDump that comes with the IRremote library. Using that and putting ~32.2 pounds of weight on the scale the output from the arduino is:

Raw (76): -10614 500 -500 550 -950 550 -450 550 -950 500 -500 550 -950 500 -500 450 -550 450 -550 450 -1000 550 -950 450 -1000 550 -450 550 -450 550 -950 500 -1000 500 -1000 500 -950 550 -950 500 -950 550 -950 550 -950 500 -1000 500 -950 500 -550 500 -950 500 -950 550 -500 500 -950 550 -950 500 -500 450 -1050 500 -500 500 -500 500 -1000 450 -1000 500 -500 500

every packet seems to be 76 bits long.
I've been reading everything I can find about decoding IR data, most examples are for decoding IR remote helicopters.
I'm now stuck and not sure what I should be doing or trying to decode it.

Any ideas?

Thanks.

Looking at your data, it looks very close to the NEC protocol, described here:

Notice about a 9ms lead. I tried decoding it manually, but parts of it aren't making sense. It should be 9ms high, 550uS low, then the data. Data is 0 = 550uS high and 5500us low, and a 1 = 550uS high and 1500uS low. So, you seem to have a variation.

You can start decoding it by using that information, though. In nearly all protocols I have seen, zero is going to be your 500 and -500 pieces, and one is going to be the 500 and -1000 pieces. The next step is to figure out how that is broken up. Is it 8 bits, 10 bit, 12 bit? The simplest way would be to just be the output of an Analog to digital converter and to do the computations in the remote display. So, the data would be ADC values. But, that could be 8, 10, 12, or 16 bits (or anything really.) So, try to divide the 76 bits up. You should have the first two bits be a header. That leader is used to set the bit rate. So, my best guess is that -10614 and the next 500 are the leader. However, it would make more sense for the 10614 to be high and the 500 to be low. That could just be the way it is being read by your micro, perhaps it is inverted... but then that would make the rest make less sense.

So, anyway, assuming the leader, that leaves you with 74 bits. Since we don't know what bit width the data is, we should be able to at least start with a nibble. So, let's group 4 bits... that would make 18.5 nibbles. Hmm... the .5 part is what confuses me. There could be some stop bits or a checksum in there.

Once you have a theory worked out, test it with 2 weights. Doubling the weights would be make things easier. So, if you are starting with data for 32.2lbs, go to 64.4lbs. Now you have two data points to compare. Look for common parts at the beginning and ends to see if the theory about leader and stop bits works out. Then you are left with the data in the middle which should be easy to decode. Again, zero is going to be the 500, -500 parts, and one is going to be the 500,1000 parts. So, you will have two "bits" for each bit. So whatever you are left with should at least be divisable by 2 evenly.

I realized I probably should have given a little more sample data with my original post. I had been scratching my head for too long and need to take a break when I first posted.

Here is a screen capture from an scope showing the data being captured. Chanel 1 is hooked up to the remote displays ir sensor. Chanel 2 is hooked up to the arduino's IR receiver.

Attached are more formats outputted from the scope.

Here are some more IR dump values.

~13.0 lbs
Could not decode message
Raw (76): -10314 500 -500 500 -1000 500 -500 500 -950 500 -500 500 -1000 550 -450 500 -500 500 -1000 500 -1000 500 -950 550 -950 500 -950 550 -450 550 -950 500 -1000 550 -950 450 -1000 550 -950 500 -950 550 -950 500 -1000 550 -950 450 -1000 550 -950 500 -1000 500 -500 500 -500 500 -500 500 -500 500 -950 500 -500 500 -500 550 -450 550 -450 550 -950 500 -500 500

~22.4 lbs
Could not decode message
Raw (76): -10214 550 -450 550 -950 500 -500 500 -1000 500 -500 500 -1000 500 -450 550 -450 550 -950 550 -450 500 -1000 550 -950 450 -1000 550 -450 550 -950 500 -950 550 -950 500 -1000 550 -950 450 -1000 550 -950 500 -1000 500 -950 500 -1000 550 -950 500 -500 450 -550 500 -950 550 -950 500 -500 500 -500 500 -1000 500 -1000 500 -500 500 -950 550 -500 450 -1000 500

~43.8 lbs
Could not decode message
Raw (76): -10064 550 -450 550 -950 450 -550 500 -950 550 -500 500 -950 500 -500 500 -500 500 -500 500 -1000 500 -950 550 -950 500 -1000 500 -500 500 -1000 450 -1000 500 -1000 500 -1000 500 -950 500 -1000 500 -1000 450 -1000 500 -1000 500 -1000 500 -500 500 -500 500 -950 550 -950 500 -1000 450 -550 500 -500 500 -500 500 -500 500 -500 500 -500 500 -500 500 -1000 450

I'm wondering if the remote display is doing any calculations or if the base unit(scale)is just sending IR of what the LCD display should be showing (which segments).

scale_scope.zip (10.1 KB)

Are you sure you don't have that backwards? The scope and the raw decode you posted don't add up. Right at the beginning it says -10314, which would imply that the signal is low for about 10ms. But we can see it is high for about that long in the scope capture.

BTW, the scope capture makes it MUCH more clear and is what I actually expected.

Again, you are looking at a fairly typical Bi-phase encoded signal. Common in nearly all IR protocols. Your 0 bit is going to be the 1t HIGH/1t LOW, and your 1 bit is going to be the 2t HIGH and 1t LOW. So, to start, we just decode what we have and start trying to make sense of it. I'll look through your files and see if I can do it.

Retroplayer:
Are you sure you don't have that backwards? The scope and the raw decode you posted don't add up. Right at the beginning it says -10314, which would imply that the signal is low for about 10ms. But we can see it is high for about that long in the scope capture.

Would the 38kHz IR receiver i'm using be inverting the signal?

Could be. Not a big deal, though. Take a look at the attached picture. I arranged all your data in excel next to each other highlight the differences between the three samples. Most of the differences are at the end of the data.

I was trying to group them up, but no matter what I keep ending up with some leftover bits. So still scratching my head. The fact that all the difference is at the bottom tells me that it most likely the most significant byte. I imagine that the data would grow upwards as the weight gets more and more.

We are probably dealing with a single precision float, since we need that decimal. That takes 32 bits. And it is probably a count of units. A 'unit' is probably a tenth of a pound. The problem is that at 32 bits, that leaves 5 bits of... what? Does the display have other indicators on it? Perhaps something to indicate kg or lbs?

BTW, what model scale is this? One of the reasons I am helping is that this is something I may be interested in doing myself.

scale.bmp (1.34 MB)

Perhaps we are over-thinking this. What if this data was just a serial representation of the actualy display segments? Then all that would be needed in the remote display would be some shift registers to latch the bits to the display. Unfortunately, that could be all scrambled and completely dependent on how the display is wired up. And they likely would have just wired it up in whatever way the pinouts lined up.

If I look at the data this way, we would have 5 digits with two bits left over (to light up the kg/lb?) One seven segment 'group' is always just zeros in all your samples. And one group is always the same in all samples, even though our data is all different. And we aren't using the major digit in any of your samples.

It may be time to switch things around and start sending some data to the display to see what it does.

EDIT: I just realized that you said that up above. Didn't see that.

I just realized the units selection button is on the remote display which leads me to believe that the scale is more likely sending raw load cell values or some other value and the making the conversion in the display uC. I just tested by apply the majority of the weight on each of the 4 load cells to see how the output varies. This will hopefully determine if the IR is sending discrete data from each of the load cells or calculating the weight and sending that as a value.

Lower Left 12.6 lbs
Raw (76): -10314 500 -500 500 -950 550 -450 550 -950 550 -450 500 -1000 500 -500 500 -500 500 -500 500 -1000 450 -1000 500 -1000 450 -550 500 -500 500 -950 550 -950 550 -950 500 -1000 500 -950 500 -1000 500 -1000 500 -950 550 -950 500 -1000 500 -950 500 -1000 500 -500 500 -500 500 -500 500 -1000 450 -1000 550 -450 550 -950 450 -550 450 -550 500 -500 550 -950 500

Lower Right 18.4 lbs
Raw (76): -10264 550 -450 550 -950 500 -500 450 -1050 500 -500 500 -1000 450 -550 450 -550 500 -950 500 -1000 500 -950 550 -950 550 -950 500 -500 500 -1000 500 -950 500 -1000 500 -950 550 -950 550 -950 500 -1000 500 -950 500 -1000 500 -1000 500 -950 550 -450 550 -950 500 -500 450 -1050 500 -500 500 -1000 450 -1000 500 -1000 450 -1000 550 -950 450 -1050 500 -1000 450

Upper Right 11.8 lbs
Raw (76): -10164 500 -500 550 -950 550 -450 550 -950 500 -500 500 -950 550 -500 450 -550 450 -550 450 -1000 550 -950 450 -1000 550 -450 550 -450 550 -950 550 -950 500 -1000 500 -950 550 -950 550 -900 550 -950 550 -950 500 -1000 500 -950 550 -950 550 -900 550 -450 550 -500 500 -950 550 -950 550 -450 500 -500 500 -1000 500 -500 500 -500 500 -1000 450 -550 500

Upper Left ~14 lbs
Raw (76): -10664 550 -450 500 -1000 550 -450 550 -950 450 -550 450 -1000 550 -450 550 -450 550 -450 550 -950 550 -950 500 -950 550 -450 550 -450 550 -950 500 -1000 550 -950 450 -1000 550 -950 500 -1000 500 -950 500 -1000 550 -950 450 -1000 550 -950 500 -1000 500 -450 550 -450 550 -450 550 -950 500 -500 550 -950 550 -950 450 -550 500 -500 500 -500 500 -1000 450

I will try to get a sample where the value is the same on each of the four load cells. Attached is a CSV of the above data

load_cell_IR.csv (1.49 KB)

I can't find any usefull logic from that data, it is driving me nuts!

Did you have any progress with this?

Cheers,
Kari

how can we use this?

if you got one of this Personal Scales | Sencor
or one from the links above.

you can use this. not the best code, but it works for me.

#define ReceivePin 1     //Receiver data pin = Analog pin 0
const unsigned int upperThreshold = 100;  //upper threshold value
const unsigned int lowerThreshold = 80;  //lower threshold value
int maxSignalLength = 2000;   //Set the maximum length of the signal
int dataCounter = 0;    //Variable to measure the length of the signal

int scount = 0;
int bcount = 0;
int measuring = 0;

byte booleanArray[18];
float  decimalValue = 0;
byte decimal = 0;
int j, temp;

void setup() {
  Serial.begin(115200);

}

void loop() {

  dataCounter = 0;
  while (analogRead(ReceivePin) > upperThreshold && dataCounter < maxSignalLength) dataCounter++;
  while (analogRead(ReceivePin) < lowerThreshold && dataCounter < maxSignalLength);

  if (dataCounter  > 1800 and dataCounter < maxSignalLength  )    measuring = 1;

  if (measuring == 1  ) {
    if (dataCounter < 6) {
      bcount++;
      if (bcount > 14 and bcount < 33 )    booleanArray[bcount - 15] = 1;
    }
    if (dataCounter > 5 and dataCounter < 120) {
      bcount++;
      if (bcount > 14 and bcount < 33 )      booleanArray[bcount - 15] = 0;
    }
    if (dataCounter  > 650 and dataCounter < 700  )
    {
      decimalValue = 0;
      for (int i = sizeof(booleanArray) / sizeof(booleanArray[0]) - 1, j = 0; i > -1; i--) {
        decimalValue += booleanArray[j++] << i;
      }

      if (decimalValue > 0)   {
        Serial.println(decimalValue / 10);
        measuring = 0;
        scount = 0;
        bcount = 0;
        memset(booleanArray, 0, sizeof(booleanArray));
      }
    }

  }
}