Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions src/devices/lacrosse_th3.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
(at your option) any later version.
*/
/**
LaCrosse Technology View LTV-TH3 & LTV-TH2 Thermo/Hygro Sensor.
LaCrosse Technology View LTV-TH3, LTV-TH2 and LTV-TH2i Thermo/Hygro Sensor.

LaCrosse Color Forecast Station (model S84060) utilizes the remote
Thermo/Hygro LTV-TH3 and LTV-WR1 multi sensor (wind spd/dir and rain).
Expand All @@ -21,6 +21,7 @@ Product pages:
https://www.lacrossetechnology.com/products/ltv-th3
https://www.lacrossetechnology.com/products/C84343
https://www.lacrossetechnology.com/products/ltv-th2
https://www.lacrossetechnology.com/products/ltv-th2i

Specifications:
- Outdoor Temperature Range: -40 C to 60 C
Expand All @@ -43,7 +44,7 @@ CMT2119A and CMT2219A.
Protocol Specification:

Data bits are NRZ encoded. Logical 1 and 0 bits are 104us in
length for the LTV-TH3 and 107us for the LTV-TH2.
length for the LTV-TH3 and 107us for the LTV-TH2/2i.

LTV-TH3
SYNC:32h ID:24h ?:4b SEQ:3b ?:1b TEMP:12d HUM:12d CHK:8h END:
Expand All @@ -58,6 +59,18 @@ Sequence# 2 & 6
Sequence# 0,1,3,4,5 & 7
CHK is CRC-8 poly 0x31 init 0xac over 7 bytes following SYN

LTV-TH2i
SYNC:32h ID:24h BATTLOW:1b RETRANS:1b ?:2b SEQ:3b ?:1b TEMP:12d HUM:12d CHK:8h TRAILER:96h

CHK is CRC-8 poly 0x31 init (0x00 or 0xb2) over 7 bytes following SYN
The CRC init value for a given packet is seemingly arbitrary, though it
appears that the same init value is used for at most three packets in a row
before switching.

Pressing the TX button under the battery cover causes the sensor to
immediately retransmit the most recent packet with the RETRANS flag set.

TRAILER is 0xd2d2d2d2d200000000000000...

*/

Expand All @@ -70,8 +83,8 @@ static int lacrosse_th_decode(r_device *decoder, bitbuffer_t *bitbuffer)
data_t *data;
uint8_t b[11];
uint32_t id;
int flags, seq, offset, chk3, chk2, model_num;
int raw_temp, humidity;
int flags, seq, offset, chk3, chk2, chk2i, model_num;
int raw_temp, humidity, batt_low, retrans;
float temp_c;

// bit length is specified as 104us for the TH3 (~256 bits per packet)
Expand Down Expand Up @@ -101,16 +114,19 @@ static int lacrosse_th_decode(r_device *decoder, bitbuffer_t *bitbuffer)
bitbuffer_extract_bytes(bitbuffer, 0, offset, b, 8 * 8);

// failing the CRC checks indicates the packet is corrupt <OR>
// this is not a LTV-TH3 or LTV-TH2 sensor
// this is not a LTV-TH sensor
chk3 = crc8(b, 8, 0x31, 0x00);
chk2 = crc8(b, 8, 0x31, 0xac);
if (chk3 != 0 && chk2 != 0) {
chk2i = crc8(b, 8, 0x31, 0xb2);
if (chk3 != 0 && chk2 != 0 && chk2i != 0) {
decoder_log(decoder, 1, __func__, "CRC failed!");
return DECODE_FAIL_MIC;
}

id = (b[0] << 16) | (b[1] << 8) | b[2];
flags = (b[3] & 0xf1); // masks off seq bits
flags = (b[3] & 0x31); // masks off seq bits and known flag bits
batt_low = (b[3] & 0x80) >> 7;
retrans = (b[3] & 0x40) >> 6;
seq = (b[3] & 0x0e) >> 1;
raw_temp = b[4] << 4 | ((b[5] & 0xf0) >> 4);
humidity = ((b[5] & 0x0f) << 8) | b[6];
Expand All @@ -124,11 +140,13 @@ static int lacrosse_th_decode(r_device *decoder, bitbuffer_t *bitbuffer)
/* clang-format off */
data = data_make(
"model", "", DATA_STRING, model_num == 3 ? "LaCrosse-TH3" : "LaCrosse-TH2",
"id", "Sensor ID", DATA_FORMAT, "%06x", DATA_INT, id,
"seq", "Sequence", DATA_INT, seq,
"flags", "unknown", DATA_INT, flags,
"id", "Sensor ID", DATA_FORMAT, "%06x", DATA_INT, id,
"battery_ok", "Battery", DATA_INT, !batt_low,
"retransmit", "Retransmit", DATA_COND, retrans, DATA_INT, retrans,
"seq", "Sequence", DATA_INT, seq,
"flags", "unknown", DATA_COND, flags, DATA_INT, flags,
"temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temp_c,
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
"mic", "Integrity", DATA_STRING, "CRC",
NULL);
/* clang-format on */
Expand All @@ -140,6 +158,8 @@ static int lacrosse_th_decode(r_device *decoder, bitbuffer_t *bitbuffer)
static char const *const output_fields[] = {
"model",
"id",
"battery_ok",
"retransmit",
"seq",
"flags",
"temperature_C",
Expand Down