//####################################################################################################### //## This Plugin is only for use with the RFLink software package ## //## Plugin-41 LaCrosse ## //####################################################################################################### /*********************************************************************************************\ * This plugin takes care of decoding LaCrosse weatherstation outdoor sensors * It also works for all non LaCrosse sensors that follow this protocol. * Lacrosse WS2355, WS3600 and compatibles * * Author : StuntTeam * Support : http://sourceforge.net/projects/rflink/ * License : This code is free for use in any open source project when this header is included. * Usage of any parts of this code in a commercial application is prohibited! ********************************************************************************************* * Changelog: v1.0 initial release ********************************************************************************************* * Technical information: * Partially based on http://makin-things.com/articles/decoding-lacrosse-weather-sensor-rf-transmissions/ * * WS2355 * Each packet is 52 bits long. 4 different packet formats are transmitted. They are composed of: * * data 0 1 2 3 4 5 6 7 8 9 10 * 1) 0000 1001 01 00 00100010 01111000 01010011 0011 10101100 0001 0+9+4+2+2+7+8+5+3+3+A+C=41 = 1 * 2) 0000 1001 00 01 00100010 01111000 01010000 1101 10101111 1000 0+9+1+2+2+7+8+5+0+D+A+F=48 = 8 * 3) 0000 1001 00 10 00100010 01111000 00001000 1100 11110111 1000 * 4) 0000 1001 01 11 00100010 01111000 00000000 1100 11111111 1101 * SSSS PPPP QR AA BBBBBBBB CCCCCCCC DDDDDDDD dddd EEEEEEEE FFFF * 0000 1001 01 01 01100110 01011110 10001000 1001 01110111 0100 * 0000 1001 00 11 01100110 01011110 00000000 1101 11111111 0110 * 0000 1001 01 00 01100110 01011110 01000110 1000 10111001 0010 * 0000 1001 00 01 01100110 01011110 01100111 1001 10011000 000 9+1+6+6+5+E+6+7+9+9+8=50 missing bit is 0 0000 1001 01 11 01100110 01011110 00000000 1001 11111111 011 9+7+6+6+5+E+0+0+9+F+F=56 missing bit is 0 * S = Sync * P = Preamble (1001 for WS2300, 0110 for WS3600?) * A = packet type 00=TEMP, 01=HUM, 10=RAIN, 11=WIND * B = Rolling Code * C = Flags * D = 12 bit value depending on the device/packet type * E = Inverted data * F = Checksum * Q = 0/1 1=windpacket reports windgust 0=windpacket reports windspeed * R = Error checking bit * * TEMP Dd = temperature - 30 degrees offset, 12 bits, 0x533 - 0x300 = 0x233 = 23.3 degrees * HUM D = humidity value, 8 bits, 0x50 = RH of 50 * RAIN D = number of tips * 0.508mm (range=0-4095, Once the count reaches 4095 it wraps back to 0. Powerloss results in a reset of the count) * WIND d = Wind direction (0-15 in 22.5 degrees steps) D= wind speed * * Sample: * 20;D3;DEBUG;Pulses=104;Pulses(uSec)=1400,1300,1325,1300,1325,1275,1350,1150,225,1300,1325,1275,1325,1275,225,1300,1325,1275,225,1275,1350,1275,225,1300,1325,1275,225,1300,225,1275,1350,1275,1350,1275,250,1275,225,1275,1350,1275,1350,1300,225,1300,1350,1275,225,1275,225,1275,225,1275,225,1275,1325,1275,225,1300,1325,1275,1325,1275,1325,1275,250,1275,1350,1275,1325,1300,1325,1275,250,1275,1350,1275,1325,1275,250,1275,1325,1275,250,1275,225,1275,225,1275,1350,1275,225,1275,250,1275,225,1275,1325,1275,250,1275,1350,1300,1325; * 20;D4;DEBUG;Pulses=104;Pulses(uSec)=1400,1275,1350,1275,1350,1275,1325,1150,250,1275,1350,1275,1325,1275,250,1275,1325,1275,1350,1275,225,1275,225,1275,1350,1300,225,1275,225,1275,1350,1275,1325,1275,225,1275,225,1275,1325,1275,1325,1275,250,1275,1350,1300,225,1275,225,1275,225,1275,225,1275,1350,1275,1325,1275,1350,1275,1325,1275,1350,1275,1325,1275,1350,1275,1325,1300,1325,1275,225,1275,225,1275,1350,1275,225,1275,225,1300,225,1275,250,1275,225,1275,225,1275,250,1275,225,1275,225,1275,1350,1275,250,1275,225,1275,1325; * 20;D5;DEBUG;Pulses=104;Pulses(uSec)=1400,1275,1350,1275,1350,1275,1325,1150,225,1275,1350,1275,1325,1275,225,1300,1325,1275,225,1300,1325,1275,1325,1275,1350,1275,225,1300,225,1275,1350,1275,1350,1300,225,1300,225,1275,1350,1275,1325,1275,250,1275,1350,1275,250,1275,225,1275,225,1275,225,1275,1325,1275,1350,1275,250,1275,1325,1275,1350,1275,1350,1275,225,1275,225,1275,1350,1275,225,1300,1325,1275,1325,1275,1350,1275,250,1275,1325,1275,250,1275,250,1275,225,1275,1350,1275,1350,1275,225,1275,1350,1275,1350,1275,225,1275,1325; 20;C3;DEBUG;Pulses=102;Pulses(uSec)=1400,1275,1325,1275,1325,1275,1325,1175,225,1300,1350,1275,1350,1275,225,1300,1325,1300,1325,1275,1325,1300,225,1300,1325,1275,225,1275,225,1300,1325,1275,1325,1275,250,1275,225,1275,1325,1275,1350,1275,225,1275,1325,1275,225,1225,300,1275,250,1275,225,1275,1325,1275,1325,1300,225,1275,225,1275,1325,1300,1325,1275,225,1275,225,1275,225,1275,225,1275,1325,1275,1325,1275,250,1275,250,1275,1325,1275,1350,1275,225,1275,225,1300,1325,1275,1350,1275,1325,1300,1325,1275,1350,1275,1325; 20;E1;DEBUG;Pulses=102;Pulses(uSec)=1425,1275,1325,1275,1325,1275,1350,1150,225,1275,1350,1275,1350,1275,250,1275,1350,1275,225,1275,225,1275,250,1275,1350,1275,225,1300,225,1275,1325,1275,1350,1300,225,1275,225,1275,1350,1275,1325,1300,225,1275,1350,1275,250,1275,225,1275,225,1275,250,1275,1325,1275,1350,1275,1325,1275,1325,1275,1325,1275,1350,1275,1350,1275,1325,1300,1325,1275,250,1275,1325,1275,1325,1275,225,1275,250,1275,225,1275,250,1275,225,1300,225,1275,225,1275,225,1300,225,1275,1350,1275,250,1275,225; \*********************************************************************************************/ #define LACROSSE_PULSECOUNT 104 // also handles 102 pulses! #define LACROSSE_PULSEMID 1000/RAWSIGNAL_SAMPLE_RATE #define LACROSSE_MIDLO 1100/RAWSIGNAL_SAMPLE_RATE #define LACROSSE_MIDHI 1400/RAWSIGNAL_SAMPLE_RATE #ifdef PLUGIN_002 boolean Plugin_002(byte function, char *string) { if ((RawSignal.Number != LACROSSE_PULSECOUNT) && (RawSignal.Number != (LACROSSE_PULSECOUNT-2))) return false; unsigned long bitstream1=0L; // holds first 16 bits unsigned long bitstream2=0L; // holds last 28 bits unsigned int sensordata=0; byte checksum=0; byte bitcounter=0; // counts number of received bits (converted from pulses) byte sensortype=0; byte data[12]; //================================================================================== // get bytes for(int x=1;x < RawSignal.Number;x+=2) { if ((RawSignal.Pulses[x+1] < LACROSSE_MIDLO) || (RawSignal.Pulses[x+1] > LACROSSE_MIDHI)) { if (x+1 < RawSignal.Number) return false; // in between pulse check } if (RawSignal.Pulses[x] > LACROSSE_PULSEMID ){ if (bitcounter < 20) { bitstream1 = (bitstream1 << 1); bitcounter++; // only need to count the first 20 bits } else { bitstream2 = (bitstream2 << 1); } } else { if (bitcounter < 20) { bitstream1 = (bitstream1 << 1) | 0x1; bitcounter++; // only need to count the first 20 bits } else { bitstream2 = (bitstream2 << 1) | 0x1; } } } if (RawSignal.Number == (LACROSSE_PULSECOUNT-2)) bitstream2 = (bitstream2 << 1); // add missing zero bit //================================================================================== // all bytes received, sort data, do sanity checks and make sure checksum is okay //================================================================================== if (bitstream1 == 0) return false; //if ((bitstream1 == 0) && (bitstream2 == 0)) return false; //data[0] = (bitstream1 >> 16) & 0x0f; // prepare nibbles from bit stream //if (data[0] != 0) return false; // just a quick check to make sure the sync bits are correct. they are not needed for the checksum data[0] = (bitstream1 >> 12) & 0x0f; // First nibble if ( (data[0] != 0x09) && (data[0] != 0x06) ) { // type verification return false; // 1001 for WS2300, 0110 for WS3600 } data[1] = (bitstream1 >> 8) & 0x0f; // Various other checks are possible data[2] = (bitstream1 >> 4) & 0x0f; // Like parity checks and bit tests data[3] = (bitstream1 >> 0) & 0x0f; // but false positives do not seem to be a problem data[4] = (bitstream2 >> 28) & 0x0f; data[5] = (bitstream2 >> 24) & 0x0f; data[6] = (bitstream2 >> 20) & 0x0f; data[7] = (bitstream2 >> 16) & 0x0f; data[8] = (bitstream2 >> 12) & 0x0f; data[9] = (bitstream2 >> 8) & 0x0f; data[10]= (bitstream2 >> 4) & 0x0f; //================================================================================== for (byte i=0;i<11;i++){ checksum=checksum + data[i]; // max. value = A5 } checksum=checksum & 0x0f; if (checksum != ((bitstream2)&0x0f)) return false; //================================================================================== // Prevent repeating signals from showing up //================================================================================== sensortype=(data[1])&0x03; // get sensor type from bitstream unsigned long tempval=((checksum)<<8)+sensortype; // sensor type + checksum if( (SignalHash!=SignalHashPrevious) || (RepeatingTimer