Add LaCrosse TX141W support
This commit is contained in:
parent
37051a8005
commit
b5f9fb2688
4 changed files with 170 additions and 94 deletions
|
@ -148,7 +148,7 @@ Read the Test Data section at the bottom.
|
|||
[70] Honeywell Door/Window Sensor
|
||||
[71] Maverick ET-732/733 BBQ Sensor
|
||||
[72]* RF-tech
|
||||
[73] LaCrosse TX141-Bv2, TX141TH-Bv2, TX141-Bv3 sensor
|
||||
[73] LaCrosse TX141-Bv2, TX141TH-Bv2, TX141-Bv3, TX141W sensor
|
||||
[74] Acurite 00275rm,00276rm Temp/Humidity with optional probe
|
||||
[75] LaCrosse TX35DTH-IT, TFA Dostmann 30.3155 Temperature/Humidity sensor
|
||||
[76] LaCrosse TX29IT Temperature sensor
|
||||
|
|
|
@ -259,7 +259,7 @@ stop_after_successful_events false
|
|||
protocol 70 # Honeywell Door/Window Sensor
|
||||
protocol 71 # Maverick ET-732/733 BBQ Sensor
|
||||
# protocol 72 # RF-tech
|
||||
protocol 73 # LaCrosse TX141-Bv2, TX141TH-Bv2, TX141-Bv3 sensor
|
||||
protocol 73 # LaCrosse TX141-Bv2, TX141TH-Bv2, TX141-Bv3, TX141W sensor
|
||||
protocol 74 # Acurite 00275rm,00276rm Temp/Humidity with optional probe
|
||||
protocol 75 # LaCrosse TX35DTH-IT, TFA Dostmann 30.3155 Temperature/Humidity sensor
|
||||
protocol 76 # LaCrosse TX29IT Temperature sensor
|
||||
|
|
|
@ -345,7 +345,7 @@ Maverick ET\-732/733 BBQ Sensor
|
|||
* RF\-tech
|
||||
.TP
|
||||
[ \fB73\fI\fP ]
|
||||
LaCrosse TX141\-Bv2, TX141TH\-Bv2, TX141\-Bv3 sensor
|
||||
LaCrosse TX141\-Bv2, TX141TH\-Bv2, TX141\-Bv3, TX141W sensor
|
||||
.TP
|
||||
[ \fB74\fI\fP ]
|
||||
Acurite 00275rm,00276rm Temp/Humidity with optional probe
|
||||
|
|
|
@ -12,91 +12,100 @@
|
|||
(at your option) any later version.
|
||||
*/
|
||||
/**
|
||||
* LaCrosse Color Forecast Station (model C85845), or other LaCrosse product
|
||||
* utilizing the remote temperature/humidity sensor TX141TH-Bv2 transmitting
|
||||
* in the 433.92 MHz band. Product pages:
|
||||
* http://www.lacrossetechnology.com/c85845-color-weather-station/
|
||||
* http://www.lacrossetechnology.com/tx141th-bv2-temperature-humidity-sensor
|
||||
*
|
||||
* The TX141TH-Bv2 protocol is OOK modulated PWM with fixed period of 625 us
|
||||
* for data bits, preambled by four long startbit pulses of fixed period equal
|
||||
* to ~1666 us. Hence, it is similar to Bresser Thermo-/Hygro-Sensor 3CH.
|
||||
*
|
||||
* A single data packet looks as follows:
|
||||
* 1) preamble - 833 us high followed by 833 us low, repeated 4 times:
|
||||
* ---- ---- ---- ----
|
||||
* | | | | | | | |
|
||||
* ---- ---- ---- ----
|
||||
* 2) a train of 40 data pulses with fixed 625 us period follows immediately:
|
||||
* --- -- -- --- --- -- ---
|
||||
* | | | | | | | | | | | | | |
|
||||
* -- --- --- -- -- --- -- ....
|
||||
* A logical 1 is 417 us of high followed by 208 us of low.
|
||||
* A logical 0 is 208 us of high followed by 417 us of low.
|
||||
* Thus, in the example pictured above the bits are 1 0 0 1 1 0 1 ....
|
||||
*
|
||||
* The TX141TH-Bv2 sensor sends 12 of identical packets, one immediately following
|
||||
* the other, in a single burst. These 12-packet bursts repeat every 50 seconds. At
|
||||
* the end of the last packet there are two 833 us pulses ("post-amble"?).
|
||||
*
|
||||
* The data is grouped in 5 bytes / 10 nybbles
|
||||
* [id] [id] [flags] [temp] [temp] [temp] [humi] [humi] [chk] [chk]
|
||||
*
|
||||
* The "id" is an 8 bit random integer generated when the sensor powers up for the
|
||||
* first time; "flags" are 4 bits for battery low indicator, test button press,
|
||||
* and channel; "temp" is 12 bit unsigned integer which encodes temperature in degrees
|
||||
* Celsius as follows:
|
||||
* temp_c = temp/10 - 50
|
||||
* to account for the -40 C -- 60 C range; "humi" is 8 bit integer indicating
|
||||
* relative humidity in %. The method of calculating "chk", the presumed 8-bit checksum
|
||||
* remains a complete mystery at the moment of this writing, and I am not totally sure
|
||||
* if the last is any kind of CRC. I've run reveng 1.4.4 on exemplary data with all
|
||||
* available CRC algorithms and found no match. Be my guest if you want to
|
||||
* solve it - for example, if you figure out why the following two pairs have identical
|
||||
* checksums you'll become a hero:
|
||||
*
|
||||
* 0x87 0x02 0x3c 0x3b 0xe1
|
||||
* 0x87 0x02 0x7d 0x37 0xe1
|
||||
*
|
||||
* 0x87 0x01 0xc3 0x31 0xd8
|
||||
* 0x87 0x02 0x28 0x37 0xd8
|
||||
*
|
||||
* Developer's comment: with unknown CRC (see above) the obvious way of checking the data
|
||||
* integrity is making use of the 12 packet repetition. In principle, transmission errors are
|
||||
* be relatively rare, thus the most frequent packet should represent the true data.
|
||||
* A count enables us to determine the quality of radio transmission.
|
||||
*
|
||||
* *** Addition of TX141 temperature only device, Jan 2018 by Andrew Rivett <veggiefrog@gmail.com> ***
|
||||
*
|
||||
* The TX141-BV2 is the temperature only version of the TX141TH-BV2 sensor.
|
||||
*
|
||||
* Changes:
|
||||
* - LACROSSE_TX141_BITLEN is 37 instead of 40.
|
||||
* - The humidity variable has been removed for TX141.
|
||||
* - Battery check bit is inverse of TX141TH.
|
||||
* - temp_f removed, temp_c (celsius) is what's provided by the device.
|
||||
*
|
||||
* The CRC Checksum is not checked. In trying to reverse engineer the
|
||||
* CRC, the first nibble can be checked by:
|
||||
*
|
||||
* a1 = (bytes[0]&0xF0) >> 4);
|
||||
* b1 = (bytes[1]&0x40) >> 4) - 1;
|
||||
* c1 = (bytes[2]&0xF0) >> 4);
|
||||
* n1 = (a1+a2+c3)&0x0F;
|
||||
*
|
||||
* The second nibble I could not figure out.
|
||||
*/
|
||||
LaCrosse Color Forecast Station (model C85845), or other LaCrosse product
|
||||
utilizing the remote temperature/humidity sensor TX141TH-Bv2 transmitting
|
||||
in the 433.92 MHz band. Product pages:
|
||||
http://www.lacrossetechnology.com/c85845-color-weather-station/
|
||||
http://www.lacrossetechnology.com/tx141th-bv2-temperature-humidity-sensor
|
||||
|
||||
The TX141TH-Bv2 protocol is OOK modulated PWM with fixed period of 625 us
|
||||
for data bits, preambled by four long startbit pulses of fixed period equal
|
||||
to ~1666 us. Hence, it is similar to Bresser Thermo-/Hygro-Sensor 3CH.
|
||||
|
||||
A single data packet looks as follows:
|
||||
1) preamble - 833 us high followed by 833 us low, repeated 4 times:
|
||||
|
||||
---- ---- ---- ----
|
||||
| | | | | | | |
|
||||
---- ---- ---- ----
|
||||
|
||||
2) a train of 40 data pulses with fixed 625 us period follows immediately:
|
||||
|
||||
--- -- -- --- --- -- ---
|
||||
| | | | | | | | | | | | | |
|
||||
-- --- --- -- -- --- -- ....
|
||||
|
||||
A logical 1 is 417 us of high followed by 208 us of low.
|
||||
A logical 0 is 208 us of high followed by 417 us of low.
|
||||
Thus, in the example pictured above the bits are 1 0 0 1 1 0 1 ....
|
||||
|
||||
The TX141TH-Bv2 sensor sends 12 of identical packets, one immediately following
|
||||
the other, in a single burst. These 12-packet bursts repeat every 50 seconds. At
|
||||
the end of the last packet there are two 833 us pulses ("post-amble"?).
|
||||
|
||||
The data is grouped in 5 bytes / 10 nybbles
|
||||
|
||||
[id] [id] [flags] [temp] [temp] [temp] [humi] [humi] [chk] [chk]
|
||||
|
||||
The "id" is an 8 bit random integer generated when the sensor powers up for the
|
||||
first time; "flags" are 4 bits for battery low indicator, test button press,
|
||||
and channel; "temp" is 12 bit unsigned integer which encodes temperature in degrees
|
||||
Celsius as follows:
|
||||
temp_c = temp/10 - 50
|
||||
to account for the -40 C -- 60 C range; "humi" is 8 bit integer indicating
|
||||
relative humidity in %. The method of calculating "chk", the presumed 8-bit checksum
|
||||
remains a complete mystery at the moment of this writing, and I am not totally sure
|
||||
if the last is any kind of CRC. I've run reveng 1.4.4 on exemplary data with all
|
||||
available CRC algorithms and found no match. Be my guest if you want to
|
||||
solve it - for example, if you figure out why the following two pairs have identical
|
||||
checksums you'll become a hero:
|
||||
|
||||
0x87 0x02 0x3c 0x3b 0xe1
|
||||
0x87 0x02 0x7d 0x37 0xe1
|
||||
0x87 0x01 0xc3 0x31 0xd8
|
||||
0x87 0x02 0x28 0x37 0xd8
|
||||
|
||||
Developer's comment: with unknown CRC (see above) the obvious way of checking the data
|
||||
integrity is making use of the 12 packet repetition. In principle, transmission errors are
|
||||
be relatively rare, thus the most frequent packet should represent the true data.
|
||||
A count enables us to determine the quality of radio transmission.
|
||||
|
||||
*** Addition of TX141 temperature only device, Jan 2018 by Andrew Rivett <veggiefrog@gmail.com>**
|
||||
|
||||
The TX141-BV2 is the temperature only version of the TX141TH-BV2 sensor.
|
||||
|
||||
Changes:
|
||||
- LACROSSE_TX141_BITLEN is 37 instead of 40.
|
||||
- The humidity variable has been removed for TX141.
|
||||
- Battery check bit is inverse of TX141TH.
|
||||
- temp_f removed, temp_c (celsius) is what's provided by the device.
|
||||
|
||||
The CRC Checksum is not checked. In trying to reverse engineer the
|
||||
CRC, the first nibble can be checked by:
|
||||
|
||||
a1 = (bytes[0]&0xF0) >> 4);
|
||||
b1 = (bytes[1]&0x40) >> 4) - 1;
|
||||
c1 = (bytes[2]&0xF0) >> 4);
|
||||
n1 = (a1+a2+c3)&0x0F;
|
||||
|
||||
The second nibble I could not figure out.
|
||||
|
||||
Addition of TX141W:
|
||||
|
||||
PRE5b ID19h BAT1b TEST?1b CH?2h TYPE4h TEMP_WIND12d 4h HUM8d CHK8h 1x
|
||||
|
||||
- type 1 has temp+hum (temp is offset 500 and scale 10)
|
||||
- type 2 has the wind (km/h scale 10)
|
||||
- checksum is CRC-8 poly 0x31 init 0x00 over preceeding 7 bytes
|
||||
*/
|
||||
|
||||
#include "decoder.h"
|
||||
|
||||
// Define the types of devices this file supports
|
||||
#define LACROSSE_TX141 1
|
||||
#define LACROSSE_TX141TH 2
|
||||
#define LACROSSE_TX141BV3 3
|
||||
|
||||
//#define LACROSSE_TX141_BITLEN 37
|
||||
//#define LACROSSE_TX141TH_BITLEN 40
|
||||
//#define LACROSSE_TX141BV3_BITLEN 33
|
||||
// Define the types of devices this file supports (uses expected bitlen)
|
||||
#define LACROSSE_TX141 37
|
||||
#define LACROSSE_TX141TH 40
|
||||
#define LACROSSE_TX141BV3 33
|
||||
#define LACROSSE_TX141W 65
|
||||
|
||||
static int lacrosse_tx141x_decode(r_device *decoder, bitbuffer_t *bitbuffer)
|
||||
{
|
||||
|
@ -104,18 +113,23 @@ static int lacrosse_tx141x_decode(r_device *decoder, bitbuffer_t *bitbuffer)
|
|||
int r;
|
||||
int device;
|
||||
uint8_t *b;
|
||||
int id, battery_low, test, channel, temp_raw, humidity = 0;
|
||||
float temp_c;
|
||||
int type, id, battery_low, test, channel, temp_raw, humidity = 0;
|
||||
float temp_c, speed_kmh;
|
||||
|
||||
// Find the most frequent data packet
|
||||
// reduce false positives, require at least 5 out of 12 repeats.
|
||||
r = bitbuffer_find_repeated_row(bitbuffer, 5, 33); // 33
|
||||
if (r < 0 || bitbuffer->bits_per_row[r] > 40) {
|
||||
if (r < 0) {
|
||||
return DECODE_ABORT_LENGTH;
|
||||
}
|
||||
bitbuffer_invert(bitbuffer);
|
||||
|
||||
if (bitbuffer->bits_per_row[r] >= 40) {
|
||||
if (bitbuffer->bits_per_row[r] >= 64) {
|
||||
device = LACROSSE_TX141W;
|
||||
}
|
||||
else if (bitbuffer->bits_per_row[r] > 40) {
|
||||
return DECODE_ABORT_LENGTH;
|
||||
}
|
||||
else if (bitbuffer->bits_per_row[r] >= 40) {
|
||||
device = LACROSSE_TX141TH;
|
||||
}
|
||||
else if (bitbuffer->bits_per_row[r] >= 37) {
|
||||
|
@ -125,8 +139,70 @@ static int lacrosse_tx141x_decode(r_device *decoder, bitbuffer_t *bitbuffer)
|
|||
device = LACROSSE_TX141BV3;
|
||||
}
|
||||
|
||||
bitbuffer_invert(bitbuffer);
|
||||
b = bitbuffer->bb[r];
|
||||
|
||||
if (device == LACROSSE_TX141W) {
|
||||
int pre = (b[0] >> 3);
|
||||
if (pre != 0x01) {
|
||||
return DECODE_ABORT_EARLY;
|
||||
}
|
||||
|
||||
int chk = crc8(b, 8, 0x31, 0x00);
|
||||
if (chk) {
|
||||
return DECODE_FAIL_MIC;
|
||||
}
|
||||
|
||||
id = ((b[0] & 0x07) << 16) | (b[1] << 8) | b[2];
|
||||
battery_low = (b[3] >> 7);
|
||||
test = (b[3] & 0x40) >> 6;
|
||||
channel = (b[3] & 0x30) >> 4;
|
||||
type = (b[3] & 0x0f);
|
||||
temp_raw = (b[4] << 4) | (b[5] >> 4);
|
||||
humidity = b[6];
|
||||
|
||||
if (type == 1) {
|
||||
// Temp/Hum
|
||||
temp_c = (float)temp_raw * 0.1 - 50.0;
|
||||
|
||||
/* clang-format off */
|
||||
data = data_make(
|
||||
"model", "", DATA_STRING, "LaCrosse-TX141W",
|
||||
"id", "Sensor ID", DATA_FORMAT, "%05x", DATA_INT, id,
|
||||
"channel", "Channel", DATA_FORMAT, "%01x", DATA_INT, channel,
|
||||
"battery_ok", "Battery level", DATA_INT, !battery_low,
|
||||
"temperature_C", "Temperature", DATA_FORMAT, "%.2f C", DATA_DOUBLE, temp_c,
|
||||
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
|
||||
"test", "Test?", DATA_INT, test,
|
||||
NULL);
|
||||
/* clang-format on */
|
||||
}
|
||||
else if (type == 2) {
|
||||
// Wind
|
||||
speed_kmh = temp_raw * 0.1;
|
||||
|
||||
/* clang-format off */
|
||||
data = data_make(
|
||||
"model", "", DATA_STRING, "LaCrosse-TX141W",
|
||||
"id", "Sensor ID", DATA_FORMAT, "%05x", DATA_INT, id,
|
||||
"channel", "Channel", DATA_FORMAT, "%01x", DATA_INT, channel,
|
||||
"battery_ok", "Battery level", DATA_INT, !battery_low,
|
||||
"wind_avg_km_h", "Wind speed", DATA_FORMAT, "%.1f km/h", DATA_DOUBLE, speed_kmh,
|
||||
"test", "Test?", DATA_INT, test,
|
||||
NULL);
|
||||
/* clang-format on */
|
||||
}
|
||||
else {
|
||||
if (decoder->verbose) {
|
||||
fprintf(stderr, "%s: unknown subtype: %d\n", __func__, type);
|
||||
}
|
||||
return DECODE_FAIL_OTHER;
|
||||
}
|
||||
|
||||
decoder_output_data(decoder, data);
|
||||
return 1;
|
||||
}
|
||||
|
||||
id = b[0];
|
||||
if (device == LACROSSE_TX141TH) {
|
||||
battery_low = (b[1] >> 7);
|
||||
|
@ -145,10 +221,9 @@ static int lacrosse_tx141x_decode(r_device *decoder, bitbuffer_t *bitbuffer)
|
|||
|
||||
if (0 == id || (device == LACROSSE_TX141TH && (0 == humidity || humidity > 100)) || temp_c < -40.0 || temp_c > 140.0) {
|
||||
if (decoder->verbose) {
|
||||
fprintf(stderr, "LaCrosse TX141-Bv2/TX141TH-Bv2 data error\n");
|
||||
fprintf(stderr, "id: %i, humidity:%i, temp:%f\n", id, humidity, temp_c);
|
||||
fprintf(stderr, "%s: data error, id: %i, humidity:%i, temp:%f\n", __func__, id, humidity, temp_c);
|
||||
}
|
||||
return 0;
|
||||
return DECODE_FAIL_SANITY;
|
||||
}
|
||||
|
||||
if (device == LACROSSE_TX141) {
|
||||
|
@ -204,8 +279,9 @@ static char *output_fields[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
// note TX141W: m=OOK_PWM, s=256, l=500, r=1888, y=748
|
||||
r_device lacrosse_tx141x = {
|
||||
.name = "LaCrosse TX141-Bv2, TX141TH-Bv2, TX141-Bv3 sensor",
|
||||
.name = "LaCrosse TX141-Bv2, TX141TH-Bv2, TX141-Bv3, TX141W sensor",
|
||||
.modulation = OOK_PULSE_PWM,
|
||||
.short_width = 208, // short pulse is 208 us + 417 us gap
|
||||
.long_width = 417, // long pulse is 417 us + 208 us gap
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue