Help decoding 433 mhz RF temperature and humidity sensor

Hi all,

I have an Acurite weather station http://www.acurite.com/weather/weather-stations/acurite-professional-digital-weather-center-with-forecast-temperature-humidity-02010.html which has a wireless sensor outside to transmit temperature and humidity. I've seen lots of people receiving the signals of other weather stations with their arduino and 433mhz rx module. I'd say I'm a novice when it comes to both electronics and programming but figured I'd try and capture the data.

I've recorded a few different signals from the rx module through the line in on my sound card with a voltage divider using Audacity. I've been poking around at it but haven't been able to decode the data and was hoping to get some help. The sensor has a switch to select "channel" A, B or C. I can see the beginning of the capture change based on the position of this switch. From what I can tell the sensor is transmitting the "channel", battery Ok/Low, temperature and humidity. Below are a few captures:

Channel A +23C 35%

Channel A +22C 31%

Channel A +21C 31%

Channel A +1C 40%

The sensor sends that string of data 3 times in a row every ~20 seconds. I'm assuming it's sending it 3 times to ensure that it is received correctly. I've been trying to make sense of it by hand. It always has those 4 long pulses in the beginning. I've just assumed they just marked the beginning of the transmission. So ignoring the 4 longer pulses in the beginning I tried counting the other long pulses as 1 and the short pulses as 0 (and vise versa) but that doesn't make any sense no matter how I look at it.

I was hoping someone with more experience could take a look and point me in the right direction.

Any help is much appreciated.

Cheers,
zang

From a quick glance, look closely at the six pulses around 0.0240. Interpret a short downward spike as 1 and a long downward spike as 0. I can see 100011, 011111, 011111 and 101000 which are binary for 35,31,31 and 40 which corresponds with the humidity percentage. It could be coincidence, you'd need to do more samples to check.

Hi zang! Yes you are on the right track.

I went through this last year with an Acurite rain sensor (model 00899). It was very interesting and not too terribly difficult. I will try to find my notes later, but....

The four rather longer pulses at the beginning and three "repeats" sounds about the same as what I saw. And the longer/shorter pulses indeed were simply 1's and 0's, with no other decoding necessary (e.g. "Manchester" or such).

If I were you I would begin by capturing the data as you have by hand. Transcribe the pulses as bits where long-low/short-high is 0 and short-low/long-high is 1 (it could turn out to be opposite but that's how it was in my case). And of course record all the current readings from the base unit that go along with it. Wait for something to change, and repeat.
Something like this

current values --- bits
40,30,21,32   - 00111000 11001110 00111000 11001110 00111000 11001110 00111000 11001110 00111000 11001110 
41,32,20,31   - 11001110 00111000 11001110 00111000 11001110 00111000 11001110 00111000 11001110 00111000 
40,30,21,32   - 00111000 11001110 00111000 11001110 00111000 11001110 00111000 11001110 00111000 11001110 
43,32,20,31   - 11001110 00111000 11001110 00111000 11001110 00111000 11001110 00111000 11001110 00111000

You probably already know this-- but my point is you can probably succeed, and I or others can probably help with the analysis if you need..

How many bits/pulses are you seeing in each of the three repeating groups?

And the coding-- how is your Arduino programming experience?

Cheers,
John

Thanks for the tips. I've made a bit of progress. stimmer was right, i did some more captures and the humidity is in there in straight binary. I can't believe I missed that. I was focusing too much on BCD when initially looking at it. Now temperature seems to be a bit trickier. Here are a few data sets. I'm not sure if I should be looking at the temperature in Celsius or Fahrenheit so I noted down some with both:

A+23C-35%-xxxx1111101101101011010001001 0100011 0000100111001001000111110
A+23C-35%-xxxx1111101101101011010001001 0100011 0000100111001001000111110
A+21C-31%-xxxx1111101101101011010001001 0011111 0000100100111100100011100
A+22C-31%-xxxx1111101101101011010001001 0011111 0000100101000001100100110
A+22C-24%-xxxx1111101101101011010001000 0011000 0000100101000001000011000
A+22C-25%-xxxx1111101101101011010001001 0011001 0000100111000110000100100
A+22C-30%-xxxx1111101101101011010001000 0011110 0000100101000001000100100
A+07C-39%-xxxx1111101101101011010001000 0100111 1000100010101111000010000

A+71F-30%-xxxx1111101101101011010001000 0011110 0000100101000001000100100
A+72F-30%-xxxx1111101101101011010001000 0011110 0000100101000100000101010
A+79F-88%-xxxx1111101101101011010001001 1011000 0000100101101111111110100
A+77F-95%-xxxx1111101101101011010001000 1011111 0000100111100010111101000
A+75F-89%-xxxx1111101101101011010001000 1011001 0000100101010110011000100
A+61F-67%-xxxx1111101101101011010001001 1000011 0000100100001001011111110
A+48F-70%-xxxx1111101101101011010001001 1000110 1000100000111111001101110

xxxx = the 4 long pulses always seen at the start

The beginning is always the same, probably a type of identifier string of bits. I know if i change the sensor to channel B the I get "10111" instead of "11111" for the first 5 bits. I'm guessing the beginning also contains the battery low indicator bit(s). But I haven't been able to verify that yet. The section that's spaced out in the middle is the humidity, which leaves the temperature at the end. I've tried looking at the temperature as BCD and as straight binary numbers in both C and F but I can't make any sense of it.

Hi Zang,

I think it the below is getting pretty close, "T" marking the temperature bits, and "p" is a parity bit. This is very similar to what I remember on my rain gauge.

I have put the decimal equivalents, which may be in arbitrary temperature units easily converted by "y=mx+b".

Cheers,
John

                                          HHHHHHH      ttT pTTTTTTT dec.  
A+23C-35%-xxxx11111011 01101011 01000100 10100011 00001001 11001001 201 00011111
A+23C-35%-xxxx11111011 01101011 01000100 10100011 00001001 11001001 201 00011111
A+21C-31%-xxxx11111011 01101011 01000100 10011111 00001001 00111100 188 10001110
A+22C-31%-xxxx11111011 01101011 01000100 10011111 00001001 01000001 193 10010011
A+22C-24%-xxxx11111011 01101011 01000100 00011000 00001001 01000001 193 00001100
A+22C-25%-xxxx11111011 01101011 01000100 10011001 00001001 11000110 198 00010010
A+22C-30%-xxxx11111011 01101011 01000100 00011110 00001001 01000001 193 00010010
A+07C-39%-xxxx11111011 01101011 01000100 00100111 10001000 10101111  47 00001000

A+71F-30%-xxxx11111011 01101011 01000100 00011110 00001001 01000001 193 00010010
A+72F-30%-xxxx11111011 01101011 01000100 00011110 00001001 01000100 196 00010101 
A+79F-88%-xxxx11111011 01101011 01000100 11011000 00001001 01101111 239 11111010 
A+77F-95%-xxxx11111011 01101011 01000100 01011111 00001001 11100010 226 11110100
A+75F-89%-xxxx11111011 01101011 01000100 01011001 00001001 01010110 214 01100010
A+61F-67%-xxxx11111011 01101011 01000100 11000011 00001001 00001001 137 01111111
A+48F-70%-xxxx11111011 01101011 01000100 11000110 10001000 00111111  63 00110111
                                          HHHHHHH      ttT pTTTTTTT dec.

How does your voltage divider looks like?
I have similar thread here, I'm trying to do just the same with 433 sensor.
http://arduino.cc/forum/index.php/topic,142871.0.html

andriej - i followed this: http://davehouston.net/learn.htm

johncc, I'm getting close. I don't think the temperature values are linear though:

After getting some colder samples I believe that both 8-bit columns after the humidity are 7bits temperature plus 1 parity bit in the beginning, so 14 bits for the temperature value:

-----------pCCCCCCC pIIIIIII pBBBBBBB pHHHHHHH pTTTTTTT pTTTTTTT CHECKSUM?-- TEMP IN BIN    DEC
A:-10C 70% 11111011 01101011 01000100 11000110 10000111 00000110 11111101 -- 00001110000110 902
A:+00C 68% 11111011 01101011 01000100 01000100 10000111 11100111 01011100 -- 00001111100111 999
A:+06C 65% 11111011 01101011 01000100 01000001 10001000 00100010 10010101 -- 00010000100010 1058
A:+12C 61% 11111011 01101011 01000100 10111101 10001000 11100001 11010000 -- 00010001100001 1121
A:+14C 59% 11111011 01101011 01000100 10111011 10001000 01110111 01100100 -- 00010001110111 1143
A:+16C 56% 11111011 01101011 01000100 10111000 00001001 10001000 11110011 -- 00010010001000 1160
A:+18C 55% 11111011 01101011 01000100 10110111 00001001 00010111 10000001 -- 00010010010111 1175
A:+20C 53% 11111011 01101011 01000100 00110101 00001001 10101100 10010100 -- 00010010101100 1196

p=Parity Bit
C=Channel (A, B or C) 
I=Identification string ???
B=Battery OK/Low ???
H=Humidity
T=Arbitrary Temperature value
I'm guessing the last column is a CRC or Checksum but haven't investigated it yet.

But using the y=mx+b linear equation doesn't add up, or I'm doing it wrong :slight_smile: For example using the first and last data bits:
(x,y)
(20,1196)
(-10,902)

20-(-10)=30
1196-902=294
294/30=9
m=9

1196=9(20)+b
1196=180+b
b=1016

So then if i take the +6C sample:
1058=9(x)+1016
42=9x
x=42/9
x=4 (should be 6)

I've also tried it with the Fahrenheit data and i get the same behavior.

We're getting really close though!

I think you have to subtract 1000 and divide by 10 to get Celsius value...
(1000 -1000) / 10.0 = 0.0C

(1143 - 1000) / 10.0 = 14.3C

(1196 - 1000) / 10.0 = 19.6C

Riva Thank-you! Now that I look at the decimal numbers I can obviously see it. Sometimes you get so focused on one thing that it helps to get a second set of eyes to have a fresh look

Hey, that's great!!

I was going to suggest something like Find the Equation of a Line Given That You Know Two Points it Passes Through - WebMath but Riva solved it through inspection :slight_smile:

Cheers,
John

Got a sketch working. Its not the most elegant and needs some work. I need to inspect more than the first 10 bits to determine the channel. But here it is anyways:

byte pin = 13; // from receiver
byte ar[116]; 
byte pos=0; 
unsigned long dur; //array, position in array, pulse duration

void setup() { 
  pinMode(pin, INPUT);
  Serial.begin(9600);
  Serial.flush();
 }

void loop() {
  b: pos=0;
//if the first ten bits are:
//  11111011011 = Channel A
  dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
    dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
      dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
        dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
          dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
            dur = pulseIn(pin, HIGH); if ((dur>225)&&(dur<350)) {ar[pos] = 0; pos++;
              dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
                dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
                  dur = pulseIn(pin, HIGH); if ((dur>225)&&(dur<350)) {ar[pos] = 0; pos++;
                    dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
                      dur = pulseIn(pin, HIGH); if ((dur>380)&&(dur<545)) {ar[pos] = 1; pos++;
                      }else goto b;
                    }else goto b;
                  }else goto b;
                }else goto b;
              }else goto b;
            }else goto b;
          }else goto b;
        }else goto b;
      }else goto b;
    }else goto b;
  }else goto b;
  //first ten bits = 11111011011 if we made it this far it must be valid data so lets continue
  for (int i=1; i <= 46; i++){
  dur = pulseIn(pin, HIGH);
  if ((dur>225)&&(dur<350)){ar[pos] = 0; pos++; }
  if ((dur>380)&&(dur<545)){ar[pos] = 1; pos++; }
  }
  Serial.println();
  Serial.print("Data Received: ");
  for (int pos=0; pos <= 56; pos++){
    Serial.print(ar[pos]);
    }
  Serial.println();
  int hum=0; for (int i=0; i <= 6; i++) {hum=hum << 1; hum=hum+ar[25+i]; Serial.print(ar[25+i]); }
  Serial.print(" ");Serial.print("Humidity: "); Serial.print(hum);Serial.println("%");
  int temp=0; for (int i=0; i <= 14; i++) {if (i==7){i++;}temp=temp << 1; temp=temp+ar[33+i]; Serial.print(ar[33+i]); }
  float realtemp = float(temp - 1000) / float(10);
  Serial.print(" ");Serial.print("Temperature: "); Serial.print(realtemp,1);Serial.println("C");
  pos=0;
}

Output is:

Data Received: 111110110110101101000100001011100000100111010001101100100
0101110 Humidity: 46%
00010011010001 Temperature: 23.3C

Unfortunately your code doesn't work for my sensor so I'll have to work with it a little bit longer.
Anyway, good that you've managed to decode it.

Share your knownledge with author of this library, so it will spread with other users!
https://bitbucket.org/fuzzillogic/433mhzforarduino/wiki/Home

I've found that once the sensor is at a bit of a distance I occasionally get incorrect data. Which I can understand since I'm not performing and type of validation. I have zero experience with CRCs and checksums. Can anyone point me to how to verify it by hand?

I believe that the last column is the CRC or checksum

-----------CCCCCCCCCCCCCCCC BBBBBBBB pHHHHHHH pTTTTTTT pTTTTTTT
A -18C-63% 1111101101101011 01000100 00011110 00001001 01000001 00010010
A -17C 56% 1111101101101011 01000100 10111000 00000110 10111011 00100011
A -10C 70% 1111101101101011 01000100 11000110 10000111 00000110 11111101
A   0C 68% 1111101101101011 01000100 01000100 10000111 11100111 01011100 
A   6C 65% 1111101101101011 01000100 01000001 10001000 00100010 10010101
A  12C 61% 1111101101101011 01000100 10111101 10001000 11100001 11010000
A  14C 59% 1111101101101011 01000100 10111011 10001000 01110111 01100100
A  16C 56% 1111101101101011 01000100 10111000 00001001 10001000 11110011
A  18C 55% 1111101101101011 01000100 10110111 00001001 00010111 10000001
A  20C 53% 1111101101101011 01000100 00110101 00001001 10101100 10010100

C=Channel/Identification String
B=Battery Ok/Low (haven't verified)
H=Humidity
T=Temperature (x-1000)/10
p=Parity Bit

Channel/ID String:
A=1111101101101011
B=1011101101101011
C=0011101000110010

What I did is read all three copies of the "message" and then compare using strncmp() or memcmp(). If I got any two of three that agreed, I considered it valid...

Cheers,
John

The last column appears to be literally a checksum - it's the sum of the first 6 bytes after splitting the channel ID into two bytes, ignoring overflow.

ex. 1st row:
(0b11111011 + 0b01101011 + 0b01000100 + 0b00011110 + 0b00001001 + 0b01000001) & 0xff == 0b00010010

I only looked at the first 3 rows though - try checking the others to be sure

Thanks johncc and stimmer!. I'll play around with both of those ideas.

Guys, could you please take a look at our try to do the same - decode the 433 sensor data?
Whole thread is here, but the most important parts are on the last page:
http://arduino.cc/forum/index.php/topic,142871.30.html

Whole code gathered and some decoded is here:

We need a fresh look on it... Especially the CRC part and battery/the first patterns.