From 5c5e5fcc23ea39f158e91c817fdae0fe338be929 Mon Sep 17 00:00:00 2001 From: Jens Jensen Date: Sun, 7 Sep 2014 18:59:58 -0500 Subject: [PATCH] support for acurite5n1 --- src/rtl_433.c | 138 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 138 insertions(+) diff --git a/src/rtl_433.c b/src/rtl_433.c index c878224e..2f49322e 100755 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -424,6 +424,134 @@ static int ws2000_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS]) { return 1; } +// ** Acurite 5n1 functions ** + +const float acurite_winddirections[] = + { 337.5, 315.0, 292.5, 270.0, 247.5, 225.0, 202.5, 180, + 157.5, 135.0, 112.5, 90.0, 67.5, 45.0, 22.5, 0.0 }; + +static int acurite_raincounter = 0; + +static int acurite_crc(uint8_t row[BITBUF_COLS], int cols) { + // sum of first n-1 bytes modulo 256 should equal nth byte + int i; + int sum = 0; + for ( i=0; i < cols; i++) + sum += row[i]; + if ( sum % 256 == row[cols] ) + return 1; + else + return 0; +} + +static int acurite_detect(uint8_t *pRow) { + int i; + if ( pRow[0] != 0x00 ) { + // invert bits due to wierd issue + for (i = 0; i < 8; i++) + pRow[i] = ~pRow[i] & 0xFF; + pRow[0] |= pRow[8]; // fix first byte that has mashed leading bit + + if (acurite_crc(pRow, 7)) + return 1; // passes crc check + } + return 0; +} + +static float acurite_getTemp (uint8_t highbyte, uint8_t lowbyte) { + // range -40 to 158 F + int highbits = (highbyte & 0x0F) << 7 ; + int lowbits = lowbyte & 0x7F; + int rawtemp = highbits | lowbits; + float temp = (rawtemp - 400) / 10.0; + return temp; +} + +static int acurite_getWindSpeed (uint8_t highbyte, uint8_t lowbyte) { + // range: 0 to 159 kph + int highbits = ( highbyte & 0x1F) << 3; + int lowbits = ( lowbyte & 0x70 ) >> 4; + int speed = highbits | lowbits; + return speed; +} + +static float acurite_getWindDirection (uint8_t byte) { + // 16 compass points, ccw from (NNW) to 15 (N) + int direction = byte & 0x0F; + return acurite_winddirections[direction]; +} + +static int acurite_getHumidity (uint8_t byte) { + // range: 1 to 99 %RH + int humidity = byte & 0x7F; + return humidity; +} + +static int acurite_getRainfallCounter (uint8_t highbyte, uint8_t lowbyte) { + // range: 0 to 99.99 in, 0.01 in incr., rolling counter? + int highbits = (highbyte & 0x3F) << 7 ; + int lowbits = lowbyte & 0x7F; + int raincounter = highbits | lowbits; + return raincounter; +} + +static int acurite5n1_callback(uint8_t bb[BITBUF_ROWS][BITBUF_COLS]) { + // acurite 5n1 weather sensor decoding for rtl_433 + // Jens Jensen 2014 + int i; + uint8_t *buf = NULL; + // run through rows til we find one with good crc (brute force) + for (i=0; i < BITBUF_ROWS; i++) { + if (acurite_detect(bb[i])) { + buf = bb[i]; + break; // done + } + } + + if (buf) { + // decode packet here + fprintf(stderr, "Detected Acurite 5n1 sensor\n"); + if (debug_output) { + for (i=0; i < 8; i++) + fprintf(stderr, "%02X ", buf[i]); + fprintf(stderr, "CRC OK\n"); + } + + if ((buf[2] & 0x0F) == 1) { + // wind speed, wind direction, rainfall + + float rainfall = 0.00; + int raincounter = 0; + if (acurite_raincounter > 0) { + // track rainfall difference after first run + raincounter = acurite_getRainfallCounter(buf[5], buf[6]); + rainfall = ( raincounter - acurite_raincounter ) * 0.01; + } else { + // capture starting counter + acurite_raincounter = raincounter; + } + + fprintf(stderr, "wind speed: %d kph, ", + acurite_getWindSpeed(buf[3], buf[4])); + fprintf(stderr, "wind direction: %0.1f deg., ", + acurite_getWindDirection(buf[4])); + fprintf(stderr, "rain gauge: %0.2f in.\n", rainfall); + + } else if ((buf[2] & 0x0F) == 8) { + // wind speed, temp, RH + fprintf(stderr, "wind speed: %d kph, ", + acurite_getWindSpeed(buf[3], buf[4])); + fprintf(stderr, "temp: %2.1f F, ", + acurite_getTemp(buf[4], buf[5])); + fprintf(stderr, "humidity: %d% RH\n", + acurite_getHumidity(buf[6])); + } + } + //if (debug_output) + // debug_callback(bb); + return 1; +} + // timings based on samp_rate=1024000 r_device rubicson = { @@ -527,6 +655,15 @@ r_device steffen = { /* .json_callback = */ &steffen_callback, }; +r_device acurite5n1 = { + /* .id = */ 10, + /* .name = */ "Acurite 5n1 Weather Station", + /* .modulation = */ OOK_PWM_P, + /* .short_limit = */ 300/4, + /* .long_limit = */ 1000/4, + /* .reset_limit = */ 15000/4, + /* .json_callback = */ &acurite5n1_callback, +}; struct protocol_state { int (*callback)(uint8_t bits_buffer[BITBUF_ROWS][BITBUF_COLS]); @@ -1391,6 +1528,7 @@ int main(int argc, char **argv) register_protocol(demod, &elv_ws2000); register_protocol(demod, &waveman); register_protocol(demod, &steffen); + register_protocol(demod, &acurite5n1); if (argc <= optind-1) { usage();