1
0
mirror of https://github.com/seahu/rflink.git synced 2025-12-10 16:07:23 +01:00
Files
rflink_rPi/Plugins/Plugin_043.c
Ondrej Lycka 406093e31d first commit
2017-04-29 03:27:02 +02:00

212 lines
13 KiB
C

//#######################################################################################################
//## This Plugin is only for use with the RFLink software package ##
//## Plugin-43 LaCrosse ##
//#######################################################################################################
/*********************************************************************************************\
* This plugin takes care of decoding LaCrosse weatherstation outdoor sensors
* It also works for all non LaCrosse sensors that follow this protocol.
* Lacrosse TX3-TH Thermo/Humidity, Lacrosse TX4, Lacrosse TX4U
* WS7000-15: Anemometer, WS7000-16: Rain precipitation, WS2500-19: Brightness Luxmeter, WS7000-20: Thermo/Humidity/Barometer
* TFA 30.3125 (temperature + humidity), TFA 30.3120.90 (temperature)
*
* 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:
* Decodes signals from a LaCrosse Weatherstation outdoor unit, (88 pulses, 44 bits, 433 MHz).
* Partially based on http://www.f6fbb.org/domo/sensors/tx3_th.php
*
* Temperature sensor (TX3)
* Each frame is 44 bits long. It is composed of:
* • 2 blocks of four bits = 0A (start sequence)
* • 8 blocks of four bits (data)
* • 1 block of four bits (checksum)
*
* The active values of the frames are explained below:
*
* Example
* 0000 1010 0000 0000 1110 0111 0011 0001 0111 0011 1101
* aaaa aaaa bbbb cccc cccd eeee ffff gggg hhhh iiii jjjj
* 0 A 0 0 7 0 7 3 1 7 3 D
*
* 000a0004070705030705
* 20;d8;LaCrosse;ID=0401;TEMP=00fd;
* 000a0e04070608000608
* 20;d9;LaCrosse;ID=0403;HUM=68;
*
* • a = Start sequence (always 0000 1010)
* • b = Packet type (0=Thermo E=hygro)
* • c = Address of sensor (changes when inserting batteries)
* • d = Parity bit (c+d+e bits sum is even)
* • e-i = Measured values:
* e = tens (x 10)
* f = ones (x 1)
* g = digits (x 0.1) (is zero in case of humidity)
* h = copy of e value
* i = copy of f value
* • j = Checksum (Lower four bits of the sum of all words)
*
* Checksum: (0 + A + 0 + 0 + E + 7 + 3 + 1 + 7 + 3) and F = D D
* Sample:
* 20;11;DEBUG;Pulses=88;Pulses(uSec)=1200,875,1125,875,1125,875,1125,900,400,900,1150,875,400,900,1150,875,1125,875,1125,875,1150,875,1150,875,400,900,400,875,375,900,1150,875,1125,875,400,900,1150,875,1125,875,1125,875,400,900,400,875,1125,900,400,875,1150,875,1150,900,1125,875,1150,875,400,900,400,875,400,900,1150,875,400,900,400,875,1125,875,400,900,1150,900,1125,875,1150,875,375,900,400,900,400,900,400;
* 20;9E;DEBUG;Pulses=88;Pulses(uSec)=1300,925,1225,925,1225,925,1200,925,425,925,1225,925,425,925,1225,925,1225,925,1225,925,1225,925,1225,925,1225,925,425,925,1225,925,1225,925,1225,925,425,925,425,925,1225,925,1225,925,425,925,425,925,425,925,1225,925,425,925,425,925,1225,925,425,925,1225,925,1225,925,1225,925,1225,925,425,925,425,925,425,925,1200,925,425,925,425,925,1225,925,1225,925,425,925,425,925,1225;
* 20;9F;LaCrosse;ID=0403;TEMP=010c;
* 20;A1;DEBUG;Pulses=88;Pulses(uSec)=1325,925,1225,925,1225,925,1225,925,425,925,1225,925,425,925,1225,925,425,925,425,925,425,925,1225,925,1225,925,425,925,1225,925,1225,925,1225,925,425,925,425,925,1225,925,1225,925,425,925,1225,925,425,925,1225,925,425,950,425,925,1225,925,1225,925,1225,925,1225,925,1225,925,1225,925,425,925,1225,925,425,925,1200,925,425,925,425,925,1225,925,425,925,1225,925,1225,925,1225;
* 20;A2;LaCrosse;ID=0403;HUM=56;
* 1275,925,1225,925,1225,925,1200,925,425,925,1225,925,425,925,1225,900,1225,925,1200,925,1225,925,1225,925,1225,925,425,925,1225,925,1200,925,1225,925,425,925,425,900,1225,900,1225,925,425,925,425,925,425,925,1225,900,425,925,1225,925,1225,925,1225,925,425,950,1225,900,425,950,1225,925,425,925,425,900,425,950,1200,900,425,925,1225,925,1225,925,425,925,425,925,425,925,425
20;76;DEBUG;Pulses=88;Pulses(uSec)=810,1440,1200,930,1200,960,1200,930,390,930,1200,930,420,960,1200,930,1200,930,1200,930,1200,930,1200,930,1200,930,420,930,1200,960,1200,930,1200,930,420,930,420,930,1200,930,1200,960,390,930,420,930,420,960,1200,930,390,930,1200,930,420,930,1200,960,1170,930,1200,930,420,930,1200,930,420,930,420,930,420,930,1200,930,420,930,1200,930,420,930,420,930,420,930,1200,930,420,6990;
0000 1010 0000 0100 0110 0111 0101 0001 0111 0101 1101
20;78;DEBUG;Pulses=88;Pulses(uSec)=240,1980,1200,960,1200,960,1200,960,390,930,1200,930,390,960,1200,960,390,930,420,930,420,930,1200,930,1200,960,390,930,1200,930,1200,930,1200,930,420,930,420,930,1200,930,1200,930,420,930,420,930,1200,930,1200,930,420,960,1200,960,390,960,1200,930,1200,930,1200,930,1200,930,1200,930,420,960,390,930,1200,930,1200,960,390,930,1200,930,420,930,420,930,1200,930,1200,930,1200,6990;
0;29;DEBUG;Pulses=86;Pulses(uSec)=1260,930,1200,930,1200,930,420,960,1200,930,420,930,1200,930,1200,930,1200,930,1200,930,1200,930,1200,930,390,930,1200,960,1200,960,1200,930,420,930,390,960,1200,960,1200,930,420,930,420,930,390,960,1200,960,390,930,1200,930,1200,930,1200,930,420,930,420,960,1200,960,1200,930,390,960,390,960,390,930,1200,960,420,930,1200,930,1200,930,1200,930,1200,930,1200,930,1200,6990;
20;2A;DEBUG;Pulses=50;Pulses(uSec)=1200,900,1140,870,390,900,360,900,390,900,1140,930,420,930,1200,930,1200,930,1200,930,420,930,390,960,1200,930,1200,930,390,930,420,960,390,930,1200,930,390,960,1200,960,1200,930,1200,960,1170,930,1200,930,1200,6990;
20;2B;DEBUG;Pulses=86;Pulses(uSec)=1230,960,1200,960,1200,930,390,960,1200,930,420,930,1200,930,420,930,390,960,420,930,1200,930,1200,930,420,930,1200,960,1170,960,1200,930,390,930,420,930,390,930,1200,930,420,930,390,930,1200,960,1200,930,420,930,420,960,390,930,1200,930,1200,930,1200,930,1200,930,1200,930,390,960,390,930,1200,960,1200,930,420,930,420,960,390,930,420,960,390,930,1200,930,420,6990;
* --------------------------------------------------------------------------------------------
* Rain Packet:
* Each frame is 46 bits long. It is composed of:
* 10bits of 0 (start sequence)
* 7 blocks of four bits separated by a bit 1 to be checked and skipped
*
* The 1st bit of each word is LSB, so we have to reverse the 4 bits of each word.
* Example
* 0000 0000 0010 1111 1011 0010 1011 1111 1101
* aaaa bbbb ccc1 ccc2 ccc3 dddd eeee
* 2 F B 2 B F D
*
* a = sensor type (2=Rain meter)
* b = sensor address
* c = rain data (LSB thus the right order is c3 c2 c1)
* d = Check Xor : (2 ^ F ^ B ^ 2 ^ B ^ F) = 0
* e = Check Sum : (const5 + 2 + F + B + 2 + B + F) and F = D
\*********************************************************************************************/
#define LACROSSE43_PULSECOUNT 88
#define LACROSSE43_PULSEMID 750/RAWSIGNAL_SAMPLE_RATE
#define LACROSSE43_PULSEMAX 1350/RAWSIGNAL_SAMPLE_RATE
#define LACROSSE43_PULSEMINMAX 550/RAWSIGNAL_SAMPLE_RATE
#define LACROSSE43_MIDLO 800/RAWSIGNAL_SAMPLE_RATE
#define LACROSSE43_MIDHI 1000/RAWSIGNAL_SAMPLE_RATE
#ifdef PLUGIN_043
boolean Plugin_043(byte function, char *string) {
boolean success=false;
if ( (RawSignal.Number < LACROSSE43_PULSECOUNT - 4) || (RawSignal.Number > LACROSSE43_PULSECOUNT + 4) ) return false;
unsigned long bitstream1=0L; // holds first 16 bits
unsigned long bitstream2=0L; // holds last 28 bits
int temperature=0;
int humidity=0;
byte checksum=0;
byte bitcounter=0; // counts number of received bits (converted from pulses)
byte data[10];
//==================================================================================
// get bytes
for(int x=1;x<RawSignal.Number;x+=2) {
if ((RawSignal.Pulses[x+1] < LACROSSE43_MIDLO) || (RawSignal.Pulses[x+1] > LACROSSE43_MIDHI)) {
if (x < 2) { // Make sure the first bit is correct..
RawSignal.Pulses[1]=1200/RAWSIGNAL_SAMPLE_RATE;
} else {
if (x+1 < RawSignal.Number) return false; // in between pulse check
}
}
if (RawSignal.Pulses[x] > LACROSSE43_PULSEMID) {
if (RawSignal.Pulses[x] > LACROSSE43_PULSEMAX) return false;
if (bitcounter < 16) {
bitstream1 = (bitstream1 << 1);
bitcounter++; // only need to count the first 16 bits
} else {
bitstream2 = (bitstream2 << 1);
}
} else {
if (RawSignal.Pulses[x] > LACROSSE43_PULSEMINMAX) return false;
if (bitcounter < 16) {
bitstream1 = (bitstream1 << 1) | 0x1;
bitcounter++; // only need to count the first 16 bits
} else {
bitstream2 = (bitstream2 << 1) | 0x1;
}
}
}
//==================================================================================
// all bytes received, make sure checksum is okay
//==================================================================================
if ((bitstream1 == 0) && (bitstream2 == 0)) return false;
data[0] = (bitstream1 >> 12) & 0x0f; // prepare nibbles from bit stream
if (data[0] != 0x00) return false;
data[1] = (bitstream1 >> 8) & 0x0f;
if (data[1] != 0x0a) return false;
data[2] = (bitstream1 >> 4) & 0x0f;
data[3] = (bitstream1 >> 0) & 0x0f;
data[4] = (bitstream2 >> 24) & 0x0f;
data[5] = (bitstream2 >> 20) & 0x0f;
data[6] = (bitstream2 >> 16) & 0x0f;
data[7] = (bitstream2 >> 12) & 0x0f;
data[8] = (bitstream2 >> 8) & 0x0f;
data[9] = (bitstream2 >> 4) & 0x0f;
//==================================================================================
// first perform a checksum check to make sure the packet is a valid LaCrosse packet
for (byte i=0;i<10;i++){
checksum=checksum + data[i];
}
checksum=checksum & 0x0f;
if (checksum != (bitstream2 &0x0f )) return false;
//==================================================================================
// Prevent repeating signals from showing up, skips every second packet!
//==================================================================================
unsigned long tempval=(data[4])>>1;
tempval=((tempval)<<16)+((data[3])<<8)+data[2];
if( (SignalHash!=SignalHashPrevious) || (RepeatingTimer<millis()) || (SignalCRC != tempval) ){
// not seen this RF packet recently
SignalCRC=tempval;
} else {
return true; // already seen the RF packet recently, but still want the humidity
}
//==================================================================================
// now process the various sensor types
//==================================================================================
// Output
// ----------------------------------
if (data[2] == 0x00) {
temperature = data[5]*100;
temperature = temperature + data[6]*10;
temperature = temperature + data[7];
temperature = temperature-500;
data[4]=(data[4])>>1;
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
Serial.print( pbuffer );
Serial.print(F("LaCrosse;ID=")); // Label
PrintHex8( data+3,2);
sprintf(pbuffer, ";TEMP=%04x;", temperature);
Serial.println( pbuffer );
RawSignal.Repeats=false;
RawSignal.Number=0;
success=true;
} else
if (data[2] == 0x0e) {
humidity=(data[5]*16)+data[6];
if (humidity==0) return false; // humidity should not be 0
data[4]=(data[4])>>1;
sprintf(pbuffer, "20;%02X;", PKSequenceNumber++); // Node and packet number
Serial.print( pbuffer );
Serial.print(F("LaCrosse;ID=")); // Label
PrintHex8( data+3,2);
sprintf(pbuffer, ";HUM=%02x;", (humidity)&0xff);
Serial.println( pbuffer );
RawSignal.Repeats=true;
RawSignal.Number=0;
success=true;
}
//==================================================================================
return success;
}
#endif // PLUGIN_043