diff --git a/AUTHORS b/AUTHORS index d8100f60..4229341f 100644 --- a/AUTHORS +++ b/AUTHORS @@ -21,3 +21,4 @@ Helge Weissig <helgew@grajagan.org> Robert Fraczkiewicz <aromring@gmail.com> Nicola Quiriti <nik@wifi4all.it> Petr Konecny <pekon@google.com> +Tom Felker <tomfelker@gmail.com> diff --git a/include/rtl_433_devices.h b/include/rtl_433_devices.h index a5c0b23a..764583ce 100755 --- a/include/rtl_433_devices.h +++ b/include/rtl_433_devices.h @@ -94,7 +94,8 @@ DECL(tpms_toyota) \ DECL(tpms_ford) \ DECL(tpms_renault) \ - DECL(infactory) + DECL(infactory) \ + DECL(thermopro_tp12) typedef struct { char name[256]; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0a87c55..ed6cc544 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -103,6 +103,7 @@ add_executable(rtl_433 devices/tpms_ford.c devices/tpms_renault.c devices/infactory.c + devices/thermopro_tp12.c ) diff --git a/src/devices/thermopro_tp12.c b/src/devices/thermopro_tp12.c new file mode 100644 index 00000000..c06dc714 --- /dev/null +++ b/src/devices/thermopro_tp12.c @@ -0,0 +1,143 @@ +/* Thermopro TP-12 Thermometer. + * + * Copyright (C) 2017 Google Inc. + * 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. + * + */ +#include "data.h" +#include "rtl_433.h" +#include "util.h" + +#define MODEL "Thermopro TP12 Thermometer" + +/* +A normal sequence for the TP12: + +[00] {0} : +[01] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[02] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[03] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[04] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[05] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[06] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[07] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[08] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[09] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[10] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[11] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[12] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[13] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[14] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[15] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[16] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 +[17] {40} 38 73 21 bb 81 : 00111000 01110011 00100001 10111011 10000001 + +Layout appears to be: + +[01] {41} 38 73 21 bb 81 80 : 00111000 01110011 00100001 10111011 10000001 1 + device temp 1 temp temp 2 checksum + low bits 1 2 low bits + hi bits + +*/ + +#define BITS_IN_VALID_ROW 40 + +static int thermopro_tp12_sensor_callback(bitbuffer_t *bitbuffer) { + int iTemp1, iTemp2, good = -1; + float fTemp1, fTemp2; + bitrow_t *bb = bitbuffer->bb; + unsigned int device, value; + char time_str[LOCAL_TIME_BUFLEN]; + data_t *data; + + // The device transmits 16 rows, let's check for 3 matching. + // (Really 17 rows, but the last one doesn't match because it's missing a trailing 1.) + good = bitbuffer_find_repeated_row(bitbuffer, 3, 40); + + if (good < 0) { + return 0; + } + + // Note: the device ID changes randomly each time you replace the battery, so we can't early out based on it. + // This is probably to allow multiple devices to be used at once. When you replace the receiver batteries + // or long-press its power button, it pairs with the first device ID it hears. + device = bb[good][0]; + + if(debug_output) { + // There is a mysterious checksum in bb[good][4]. It may be the same as the checksum used by the TP-11, + // which consisted of a lookup table containing, for each bit in the message, a byte to be xor-ed into + // the checksum if the message bit was 1. It should be possible to solve for that table using Gaussian + // elimnation, so dump some data so we can try this. + + // This format is easily usable by bruteforce-crc, after piping through | grep raw_data | cut -d':' -f2 + // bruteforce-crc didn't find anything, though - this may not be a CRC algorithm specifically. + fprintf(stderr,"thermopro_tp12_raw_data:"); + for(int bit_index = 0; bit_index < 40; ++bit_index){ + fputc(bitrow_get_bit(bb[good], bit_index) + '0', stderr); + } + fputc('\n', stderr); + } + + iTemp1 = ((bb[good][2] & 0xf0) << 4) | bb[good][1]; + iTemp2 = ((bb[good][2] & 0x0f) << 8) | bb[good][3]; + + fTemp1 = (iTemp1 - 200) / 10.; + fTemp2 = (iTemp2 - 200) / 10.; + + local_time_str(0, time_str); + data = data_make("time", "", DATA_STRING, time_str, + "model", "", DATA_STRING, MODEL, + "id", "Id", DATA_FORMAT, "\t %d", DATA_INT, device, + "temperature_1_C", "Temperature 1 (Food)", DATA_FORMAT, "%.01f C", DATA_DOUBLE, fTemp1, + "temperature_2_C", "Temperature 2 (Barbecue)", DATA_FORMAT, "%.01f C", DATA_DOUBLE, fTemp2, + NULL); + data_acquired_handler(data); + return 1; +} + +static char *output_fields[] = { + "time", + "model", + "id", + "temperature_1_C", + "temperature_2_C", + NULL +}; + +/* +Analyzing pulses... +Total count: 714, width: 273019 (1092.1 ms) +Pulse width distribution: + [ 0] count: 1, width: 26 [26;26] ( 104 us) + [ 1] count: 713, width: 119 [116;140] ( 476 us) +Gap width distribution: + [ 0] count: 17, width: 895 [841;945] (3580 us) + [ 1] count: 340, width: 125 [123;128] ( 500 us) + [ 2] count: 340, width: 369 [366;372] (1476 us) + [ 3] count: 16, width: 273 [272;274] (1092 us) +Pulse period distribution: + [ 0] count: 17, width: 1027 [867;1084] (4108 us) + [ 1] count: 340, width: 244 [242;262] ( 976 us) + [ 2] count: 356, width: 483 [390;490] (1932 us) +Level estimates [high, low]: 15891, 83 +Frequency offsets [F1, F2]: 18586, 0 (+70.9 kHz, +0.0 kHz) + +Those gaps are suspiciously close to 500 us and 1500 us. +*/ + +r_device thermopro_tp12 = { + .name = MODEL, + .modulation = OOK_PULSE_PPM_RAW, + // note that these are in microseconds, not samples. + .short_limit = 1000, + .long_limit = 2000, + .reset_limit = 4000, + .json_callback = &thermopro_tp12_sensor_callback, + .disabled = 0, + .demod_arg = 0, + .fields = output_fields, +};