Overview
Specifications
Product:
Info | URL |
---|---|
Website | https://www.acurite.com/kbase/thermometers/00606_Thermometer.html |
Manual | https://www.acurite.com/media/manuals/00606-instructions.pdf |
Transmitter:
Specification | Value |
---|---|
Model | 00606TXA1 |
FCC ID | RNE606TXA1 |
Receiver:
Specification | Value |
---|---|
Model | 00606TXA1 |
FCC ID | RNE606TXA1 |
RTL_433 Reverse Engineering
Using rtl_433:
> rtl_433
Output:
rtl_433 version 19.08-18-g8eecdbb branch master at 201909241811 inputs file rtl_tcp RTL-SDR Use -h for usage help and see https://triq.org/ for documentation. Trying conf file at "rtl_433.conf"... Trying conf file at "/Users/john.mehan/.config/rtl_433/rtl_433.conf"... Trying conf file at "/usr/local/etc/rtl_433/rtl_433.conf"... Trying conf file at "/etc/rtl_433/rtl_433.conf"... Consider using "-M newmodel" to transition to new model keys. This will become the default someday. A table of changes and discussion is at https://github.com/merbanan/rtl_433/pull/986. Registered 108 out of 138 device decoding protocols [ 1-4 8 11-12 15-17 19-21 23 25-26 29-36 38-60 63 67-71 73-100 102-103 108-116 119 121 124-128 131-138 ] Found Rafael Micro R820T tuner Exact sample rate is: 250000.000414 Hz [R82XX] PLL not locked! Sample rate set to 250000 S/s. Tuner gain set to Auto. Tuned to 433.920MHz. _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ time : 2019-10-03 11:08:26 model : Acurite 606TX Sensor id : 120 Battery : OK Temperature: 25.9 C Integrity : CHECKSUM
> rtl
Detected OOK package 2019-10-03 11:49:46 Analyzing pulses... Total count: 237, width: 744.45 ms (186112 S) Pulse width distribution: [ 0] count: 237, width: 508 us [496;516] ( 127 S) Gap width distribution: [ 0] count: 154, width: 1932 us [1924;1944] ( 483 S) [ 1] count: 70, width: 3884 us [3876;3896] ( 971 S) [ 2] count: 5, width: 468 us [460;476] ( 117 S) [ 3] count: 6, width: 8520 us [8516;8532] (2130 S) [ 4] count: 1, width: 708 us [708;708] ( 177 S) Pulse period distribution: [ 0] count: 154, width: 2440 us [2432;2456] ( 610 S) [ 1] count: 70, width: 4392 us [4380;4408] (1098 S) [ 2] count: 5, width: 972 us [972;980] ( 243 S) [ 3] count: 6, width: 9032 us [9028;9040] (2258 S) [ 4] count: 1, width: 1220 us [1220;1220] ( 305 S) Level estimates [high, low]: 15939, 1378 RSSI: -0.1 dB SNR: 10.6 dB Noise: -10.7 dB Frequency offsets [F1, F2]: 18554, 0 (+70.8 kHz, +0.0 kHz) Guessing modulation: Pulse Position Modulation with fixed pulse width Attempting demodulation... short_width: 468, long_width: 708, reset_limit: 8536, sync_width: 0 Use a flex decoder with -X 'n=name,m=OOK_PPM,s=468,l=708,g=712,r=8536' pulse_demod_ppm(): Analyzer Device bitbuffer:: Number of rows: 25 [00] { 0} : [01] { 0} : [02] { 0} : [03] { 0} : [04] { 0} : [05] { 0} : [06] { 0} : [07] { 0} : [08] { 0} : [09] { 0} : [10] { 0} : [11] { 0} : [12] { 0} : [13] { 0} : [14] { 0} : [15] { 0} : [16] { 0} : [17] { 0} : [18] { 0} : [19] { 0} : [20] { 0} : [21] { 0} : [22] { 0} : [23] { 0} : [24] { 0} : ... Maximum number of rows reached. Message is likely truncated.
So, this is showing us that it detected OOK modulation but when it tries to convert to bits, it fails...
What is an OOK package?
On Off Keying is a form of Amplitude Shift Keying (ASK) limited to two values. If you use ASK with only two values, you are essentially using OOK.
Finding the Bits
Install Let's install Universal Radio Hacker.
> pip3 install urh
Running URH
> urh
From the initial window, select File → Record Signal
Click Start button and once you noticed your signal, click Stop and Save. Close the window
The Interpretation Screen should appear.
- zoom in on the first burst.
- Set the signal view to Demodulated.
Looking at the entire signal, we see that it sends the identical information 7 times.
This particular signal starts every bit by turning ON the RF signal and then turning if off for either 2 or 4 milliseconds. Staying off for 2 ms signifies a value of 0 while staying off for 4 ms signifies a value of 1.
What we deduced from looking at the signal:
Pulse | Delay |
---|---|
On Pulse | 0.5 ms |
0 value | 2 ms off between On Pulse |
1 value | 4 ms off between On Pulse |
Stop Pulse | 0.5 ms |
9 ms delay between repeats repeat the whole thing a total of 7 times. |
If we look at just one of the pulses, we see that it contains 32 bits or 4 bytes:
We received the following data:
1110 0110 1000 0001 0011 0110 0001 0011 (E6 81 36 13 hex)
The Protocol
The protocol for this device is publish at the following URL:
http://www.osengr.org/WxShield/Downloads/Weather-Sensor-RF-Protocols.pdf
Details
The protocol for the AcuRite 00606TX is:
All in nibbles (4 bits).
Rolling Code(2), Status(1), Temperature (signed binary), Hash Code
Data being sent:
Nible | Purpose | Our Value | Description |
---|---|---|---|
1-2 | Rolling Code | E6 | The rolling code randomly generated when the transmitter powers up. After the receiver receives it's first rolling code, it will not accept messages with a different code unless rebooted. |
3 | Status | 8 | A status of 8 signifies that the batter is ok. The status nibble's MSB is a "battery okay" flag which is normally one. It goes to zero when the battery drops below about 2.6 volts or so. |
4-6 | Temperature | 136 | The temperature with 1 decimal place. A temperature of 31.0C = 31.0*10 = 310 dec = 136 hex |
7-8 | Hash | 13 | Hash computed using |
Checksum/Hash
This sensor does not use a simple checksum or even a more advanced CRC. Instead data integrity is verified by a hash code, generated by multiplying the message bits with the byte sequence generated by a linear feedback shift register (LFSR). This algorithm has been referred to as "an LFSR-based Toeplitz hash" in some of the literature.
Hash Algorithm
1. Generate LSFR sequence equal to the length of the message.
In our case, our message is 32 bits long, so we will need 32 values.
- Start with an 8-bit register initialized to the value 0x7C (0111 1100)
- Generate a number of values equal to the message size in bits by repeating the following operations once for each bit.
• Rotate the register right one bit.
• If the bit shifted out of the LSB and into the MSB during the rotation was a one, then exclusive-or the value 0x18 into the register (i.e. flip the state of bits 3 and 4). Do this after the rotate operation.
• The register value after these two operations is the sequence value to be stored. Perform these steps once for each bit in the message. If the message contains 40 bits for example (as with the F007TH message) then you will need to generate a sequence of 40 bytes. Because this sequence does not depend on the data message contents and can be pre-computed once and stored to save time.
Start Value | Shift Right | XOR with 0x18 if MSB =1 (flip bits 3 and 4) | Xor | Value | |
---|---|---|---|---|---|
1 | 0111 1100 (0x7C) | → 0011 1110 | NO | - | 0011 1110 (0x3e) |
2 | 0011 1110 (0x3e) | → 0001 1111 | NO | - | 0001 1111 (0x1f) |
3 | 0001 1111 (0x1f) | → 1000 1111 | YES | xor 0x18 | 1001 0111 (0x97) |
4 | 1001 0111 (0x97) | → 1100 1011 | YES | xor 0x18 | 1101 0011 (0xd3) |
5 | 1101 0011 (0xd3) | → 1110 1001 | YES | xor 0x18 | 1111 0001 (0xf1) |
... | |||||
32 | 1000 0110 (0x86) | → 0100 0011 | NO | - | 0100 0011 (0x43) |
Values
2. Combines the LSFR sequence with message bits to form the final hash value
To compute the message hash value, sequence through the 24 message bits in the order they were received. Since everything here is big-endian, that means proceeding from MSB to LSB. Start by initializing the hash register to the value 0x00. As the message bits are read, for every bit in the message that is a one, exclusive-or the corresponding value (+5) from the LSFR sequence into the hash register.
For example, if the 10th bit is a one, then take the 15th value from the LFSR sequence and exclusive-or it into the hash register. If the message were all zeros, then nothing would be added to the hash register and the result would be the initial value of 0x00.
From MSB to LSB for message 1110 0110 1000 0001 0011 0110 (E6 81 36 hex)
Register Value | Index | Value | Value=1? | Calculation | New Register Value (xor with LSFR Sequence starting at the 5th (0xF1) |
---|---|---|---|---|---|
00 | 23 -MSB | 1 | Yes | 00 xor f1 | f1 |
f1 | 22 | 1 | Yes | f1 xor e0 | 11 |
11 | 21 | 1 | Yes | 11 xor 70 | 61 |
... | |||||
13 | 0 | 0 | No | - | 13 |
Hash Code
#define MESSAGE_SIZE 32 #define OFFSET 4 uint8_t LSFR_sequence[MESSAGE_SIZE] = {0}; void calculateLSFR() { int i; uint8_t reg = 0x7C; uint8_t temp_reg = 0; for (i = 0; i < MESSAGE_SIZE; i++) { temp_reg = reg & 0x01; reg >>= 1; reg |= (temp_reg << 7); if (temp_reg) { reg ^= 0x18; } LSFR_sequence[i] = reg; //printf("%02x\n", LSFR_sequence[i]); } } uint8_t combineLSFR(uint8_t len, uint8_t *data) { uint8_t hash_reg = 0; // not 0x64 int byte_idx, bit_idx; uint8_t byte, bit; //printf("***COMBINE\n"); for (byte_idx = 0; byte_idx < len; byte_idx++) { for (bit_idx = 7; bit_idx >= 0; bit_idx--) { bit = (data[byte_idx] & (1 << bit_idx)) >> bit_idx; if (bit) { hash_reg ^= LSFR_sequence[byte_idx * 8 + (7 - bit_idx) + OFFSET]; //printf("[%d]: %02x\n", byte_idx * 8 + (7 - bit_idx), hash_reg); } bit = 0; } } return hash_reg; } uint8_t Checksum(int length, uint8_t *buff) { calculateLSFR(); return combineLSFR(length, buff); }
Sending Temperatures to the Receiver
In an effort to send our own temperatures to the receiver, we put together a program running on an ESP8266 (Wemos mini) connected with RF transmitter.
Transmitter Code
const int TX_PIN = 4; // ESP8266 pin D2 typedef struct { boolean power; int duration; // micro seconds } signal; const signal SHORT_ON { true, 500 }; const signal SHORT_OFF { false, 2000 }; const signal LONG_ON { true, 850 }; // not used const signal LONG_OFF { false, 4000 }; const signal STOP_OFF { false, 500 }; const int REST = 9000; // 9 ms gap // Here's a temperature of 24.5 forever... // signal sig_1 [] { SHORT_ON, // start bit SHORT_OFF, SHORT_ON, // a zero (0) bit LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit LONG_OFF, SHORT_ON, // a one (1) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit // LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit SHORT_OFF, SHORT_ON, // a zero (0) bit LONG_OFF, SHORT_ON, // a one (1) bit SHORT_OFF, SHORT_ON, // a zero (0) bit LONG_OFF, SHORT_ON, // a one (1) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit SHORT_OFF, SHORT_ON, // a zero (0) bit LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit LONG_OFF, SHORT_ON, // a one (1) bit SHORT_OFF, SHORT_ON, // a zero (0) bit STOP_OFF, SHORT_ON // stop bit }; void doTransmission(signal array[67]) { Serial.println("Doing transmission..."); for (int burst = 1; burst <= 7; burst++) { for (int idx = 0; idx < 66; ++idx ) { // payload digitalWrite(TX_PIN, array[idx].power); delayMicroseconds( array[idx].duration ); } delayMicroseconds(REST); // rest between bursts } } void setup ( void ) { pinMode(TX_PIN, OUTPUT); Serial.begin ( 115200 ); } void loop ( void ) { Serial.println("Sending..."); doTransmission(sig_1); delay(10000); }
References
Reference | URL |
---|---|
RF Protocol | http://www.osengr.org/WxShield/Downloads/Weather-Sensor-RF-Protocols.pdf |
FCC Info | https://fccid.io/RNE606TXA1 |
On Off Keying | https://www.youtube.com/watch?v=w6V9NyXwohI |