rtl_433/src/devices/tfa_30_3196.c

127 lines
4.2 KiB
C

/** @file
TFA Dostmann 30.3196 T/H outdoor sensor.
Copyright (c) 2019 Christian W. Zuckschwerdt <zany@triq.net>
Documented by Ekkehart Tessmer.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
*/
/**
TFA Dostmann 30.3196 T/H outdoor sensor at 868.33M.
https://www.tfa-dostmann.de/en/produkt/temperature-humidity-transmitter-11/
https://clientmedia.trade-server.net/1768_tfadost/media/7/86/3786.pdf
The device comes with 'TFA Modus Plus' (indoor) base station.
Up to three outdoor sensors can be operated (ch 1, 2, or 3).
- At the start there is a 6 ms gap (FSK space)
- Data is Manchester coded with a half-bit width of 245 us
- The data row is repeated four times with 7 ms gaps (FSK space)
- A second layer of manchester coding yields 16 bit preamble and 48 bits data
- The 64 bits of preamble 0xcccccccccccccccc, after first MC 0xaaaaaaaa, after second MC 0xffff
- A data row consists of 48 bits (6 Bytes).
Data layout:
FFFFFFFF ??CCTTTT TTTTTTTT BHHHHHHH AAAAAAAA AAAAAAAA
- F: 8 bit Fixed message type 0xA8. d2d2d333 -> 9995 -> 57 (~ A8)
- C: 2 bit Channel number (1,2,3,X)
- T: 12 bit Temperature (Celsius) offset 40 scaled 10
- B: 1 bit Low battery indicator
- H: 7 bit Humidity
- A: 16 bit LFSR hash, gen 0x8810, key 0x22d0
- e.g. TYPE:8h ?2h CH:2d TEMP:12d BATT:1b HUM:7d CHK?16h
Example data:
a8 21 fa 5b 38 54 : 10101000 00100001 11111010 01011011 00111000 01010100
a8 22 22 5e 90 48 : 10101000 00100010 00100010 01011110 10010000 01001000
*/
#include "decoder.h"
static int tfa_303196_callback(r_device *decoder, bitbuffer_t *bitbuffer)
{
uint8_t const preamble_pattern[] = {0x55, 0x56}; // 12 bit preamble + 4 bit data
int row;
data_t *data;
uint8_t *b;
bitbuffer_t databits = {0};
row = bitbuffer_find_repeated_row(bitbuffer, 2, 48 * 2 + 12); // expected are 4 rows, require 2
if (row < 0)
return DECODE_ABORT_EARLY;
unsigned start_pos = bitbuffer_search(bitbuffer, row, 0, preamble_pattern, 16);
start_pos += 12; // skip preamble
if (bitbuffer->bits_per_row[row] - start_pos < 48 * 2)
return DECODE_ABORT_LENGTH; // short buffer or preamble not found
bitbuffer_manchester_decode(bitbuffer, row, start_pos, &databits, 48);
if (databits.bits_per_row[0] < 48)
return DECODE_ABORT_LENGTH; // payload malformed MC
b = databits.bb[0];
if (b[0] != 0xa8)
return DECODE_FAIL_SANITY;
uint16_t digest = (b[4] << 8) | (b[5]);
int chk = lfsr_digest16(b, 4, 0x8810, 0x22d0) ^ digest;
//decoder_logf_bitrow(decoder, 0, __func__, b, 48, "TFA-303196 (%08x %04x %04x)", chk_data, digest, session);
int channel = (b[1] >> 4) + 1;
int temp_raw = ((b[1] & 0x0F) << 8) | b[2];
float temp_c = (temp_raw - 400) * 0.1f;
int battery_low = b[3] >> 7;
int humidity = b[3] & 0x7F;
/* clang-format off */
data = data_make(
"model", "", DATA_STRING, "TFA-303196",
"id", "", DATA_INT, chk,
"channel", "Channel", DATA_INT, channel,
"battery_ok", "Battery", DATA_INT, !battery_low,
"temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temp_c,
"humidity", "Humidity", DATA_FORMAT, "%u %%", DATA_INT, humidity,
"mic", "Integrity", DATA_STRING, "missing",
NULL);
/* clang-format on */
decoder_output_data(decoder, data);
return 1;
}
static char const *const output_fields[] = {
"model",
"id",
"channel",
"battery_ok",
"temperature_C",
"humidity",
"mic",
NULL,
};
r_device const tfa_303196 = {
.name = "TFA Dostmann 30.3196 T/H outdoor sensor",
.modulation = FSK_PULSE_MANCHESTER_ZEROBIT,
.short_width = 245,
.long_width = 0, // unused
.tolerance = 60,
.reset_limit = 22000,
.decode_fn = &tfa_303196_callback,
.fields = output_fields,
};