From 7571584bfc97f43f288bfdc2ffa35b5d16cb8775 Mon Sep 17 00:00:00 2001 From: Ethan Halsall Date: Sun, 3 Dec 2023 19:20:12 -0600 Subject: [PATCH 1/6] Add support for Grill Thermometer (RF-T0912) --- conf/rtl_433.example.conf | 1 + include/rtl_433_devices.h | 1 + src/CMakeLists.txt | 1 + src/devices/grill_thermometer.c | 106 ++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+) create mode 100644 src/devices/grill_thermometer.c diff --git a/conf/rtl_433.example.conf b/conf/rtl_433.example.conf index 098caa35b..8d9b1f0e6 100644 --- a/conf/rtl_433.example.conf +++ b/conf/rtl_433.example.conf @@ -477,6 +477,7 @@ convert si # protocol 248 # Nissan TPMS protocol 249 # Bresser lightning protocol 250 # Schou 72543 Day Rain Gauge, Motonet MTX Rain, MarQuant Rain Gauge + protocol 251 # Grill Thermometer (RF-T0912) ## Flex devices (command line option "-X") diff --git a/include/rtl_433_devices.h b/include/rtl_433_devices.h index 0fd12552a..8d4630ee7 100644 --- a/include/rtl_433_devices.h +++ b/include/rtl_433_devices.h @@ -258,6 +258,7 @@ DECL(tpms_nissan) \ DECL(bresser_lightning) \ DECL(schou_72543_rain) \ + DECL(grill_thermometer) \ /* Add new decoders here. */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dde1f9031..9c2258fa4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -126,6 +126,7 @@ add_library(r_433 STATIC devices/generic_temperature_sensor.c devices/geo_minim.c devices/govee.c + devices/grill_thermometer.c devices/gt_tmbbq05.c devices/gt_wt_02.c devices/gt_wt_03.c diff --git a/src/devices/grill_thermometer.c b/src/devices/grill_thermometer.c new file mode 100644 index 000000000..7362a788c --- /dev/null +++ b/src/devices/grill_thermometer.c @@ -0,0 +1,106 @@ +/** @file + Remote Grill Thermometer temperature sensor. + + Copyright (C) 2023 Ethan Halsall + + 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. +*/ +/** @fn int grill_thermometer_callback(r_device *decoder, bitbuffer_t *bitbuffer) +Remote Grill Thermometer -- Generic wireless thermometer with probe. + +This is a meat thermometer with no brand / model identification except the FCC ID. + +Manufacturer: +- Yangzhou Fupond Electronic Technology Corp., Ltd + +Supported Models: +- RF-T0912 (FCC ID TXRFPT0912) + +0 - 255 F, frequency 434.052 MHz + +Data structure: + +10 repetitions of the same 24 bit payload. + + 11111111 AAAAAAAA BBBBBBBB + +- 1: 8 bit preamble. Always set to 0xff +- A: 8 bit temperature in Fahrenheit. Calculated as (Temp = 255 - A) +- B: Copy of 'A' presumably for message integrity + +*/ + +#include "decoder.h" + +static int validate_decode_result(int row, bitbuffer_t *bitbuffer) +{ + if (bitbuffer->bits_per_row[row] != 24) + return DECODE_ABORT_LENGTH; + + if (bitbuffer->bb[row][0] != 0xff) + return DECODE_ABORT_EARLY; // preamble + + if (bitbuffer->bb[row][1] != bitbuffer->bb[row][2]) + return DECODE_ABORT_EARLY; // temp values must match + + return 1; +} + +static int grill_thermometer_callback(r_device *decoder, bitbuffer_t *bitbuffer) +{ + int raw_value = -1, repeats = 0; + + // use the most recent "valid" data that repeats more than once + for (int row = 0; row < bitbuffer->num_rows; row++) { + if (validate_decode_result(row, bitbuffer) == 1) { + int current_value = bitbuffer->bb[row][1]; + + if (raw_value != current_value) { + raw_value = current_value; + repeats = 0; + } + else { + repeats++; + } + } + } + + if (raw_value == -1 || repeats < 1) + return DECODE_ABORT_EARLY; + + data_t *data; + int id = 0, temp_f = 0xFF - raw_value; + + /* clang-format off */ + data = data_make( + "model", "", DATA_STRING, "Grill Thermometer", + "id", "Id", DATA_INT, id, + "temperature_F", "Temperature", DATA_FORMAT, "%i F", DATA_INT, temp_f, + NULL); + /* clang-format on */ + + decoder_output_data(decoder, data); + return 1; +} + +static char const *const output_fields[] = { + "model", + "id", + "temperature_F", + NULL, +}; + +r_device const grill_thermometer = { + .name = "Grill Thermometer", + .modulation = OOK_PULSE_PWM, + .short_width = 252, + .long_width = 736, + .gap_limit = 5000, + .reset_limit = 8068, + .sync_width = 980, + .decode_fn = &grill_thermometer_callback, + .fields = output_fields, +}; \ No newline at end of file From f2f962072c64931910e3bc8deed32cf5dec41619 Mon Sep 17 00:00:00 2001 From: Ethan Halsall Date: Mon, 4 Dec 2023 09:29:50 -0600 Subject: [PATCH 2/6] refactor: code review comments --- conf/rtl_433.example.conf | 2 +- src/devices/grill_thermometer.c | 58 +++++++++++++++------------------ 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/conf/rtl_433.example.conf b/conf/rtl_433.example.conf index 8d9b1f0e6..368515249 100644 --- a/conf/rtl_433.example.conf +++ b/conf/rtl_433.example.conf @@ -477,7 +477,7 @@ convert si # protocol 248 # Nissan TPMS protocol 249 # Bresser lightning protocol 250 # Schou 72543 Day Rain Gauge, Motonet MTX Rain, MarQuant Rain Gauge - protocol 251 # Grill Thermometer (RF-T0912) + protocol 251 # RF-T0912 Grill Thermometer ## Flex devices (command line option "-X") diff --git a/src/devices/grill_thermometer.c b/src/devices/grill_thermometer.c index 7362a788c..8f4b2e03d 100644 --- a/src/devices/grill_thermometer.c +++ b/src/devices/grill_thermometer.c @@ -35,48 +35,41 @@ Data structure: #include "decoder.h" -static int validate_decode_result(int row, bitbuffer_t *bitbuffer) -{ - if (bitbuffer->bits_per_row[row] != 24) - return DECODE_ABORT_LENGTH; - - if (bitbuffer->bb[row][0] != 0xff) - return DECODE_ABORT_EARLY; // preamble - - if (bitbuffer->bb[row][1] != bitbuffer->bb[row][2]) - return DECODE_ABORT_EARLY; // temp values must match - - return 1; -} - -static int grill_thermometer_callback(r_device *decoder, bitbuffer_t *bitbuffer) +static int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) { int raw_value = -1, repeats = 0; // use the most recent "valid" data that repeats more than once for (int row = 0; row < bitbuffer->num_rows; row++) { - if (validate_decode_result(row, bitbuffer) == 1) { - int current_value = bitbuffer->bb[row][1]; - - if (raw_value != current_value) { - raw_value = current_value; - repeats = 0; - } - else { - repeats++; - } + uint8_t *row_data = bitbuffer->bb[row]; + + // validate decode result + if (bitbuffer->bits_per_row[row] != 24 || + row_data[0] != 0xff || + row_data[1] != row_data[2]) { + continue; + } + + int current_value = row_data[1]; + + if (raw_value != current_value) { + raw_value = current_value; + repeats = 0; + } + else { + repeats++; } } - if (raw_value == -1 || repeats < 1) + if (raw_value == -1 || repeats < 1) { return DECODE_ABORT_EARLY; + } - data_t *data; int id = 0, temp_f = 0xFF - raw_value; /* clang-format off */ - data = data_make( - "model", "", DATA_STRING, "Grill Thermometer", + data_t *data = data_make( + "model", "", DATA_STRING, "RF-T0912 Grill Thermometer", "id", "Id", DATA_INT, id, "temperature_F", "Temperature", DATA_FORMAT, "%i F", DATA_INT, temp_f, NULL); @@ -94,13 +87,14 @@ static char const *const output_fields[] = { }; r_device const grill_thermometer = { - .name = "Grill Thermometer", + .name = "RF-T0912 Grill Thermometer", .modulation = OOK_PULSE_PWM, .short_width = 252, .long_width = 736, .gap_limit = 5000, .reset_limit = 8068, .sync_width = 980, - .decode_fn = &grill_thermometer_callback, + .priority = 10, // lower decode priority due to potential false positives + .decode_fn = &grill_thermometer_decode, .fields = output_fields, -}; \ No newline at end of file +}; From b4e1c4ec9f168c2a5fdea75d431e3d300e5e3065 Mon Sep 17 00:00:00 2001 From: Ethan Halsall Date: Mon, 4 Dec 2023 10:12:25 -0600 Subject: [PATCH 3/6] fix: function document --- src/devices/grill_thermometer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/devices/grill_thermometer.c b/src/devices/grill_thermometer.c index 8f4b2e03d..582117fa4 100644 --- a/src/devices/grill_thermometer.c +++ b/src/devices/grill_thermometer.c @@ -8,7 +8,7 @@ the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ -/** @fn int grill_thermometer_callback(r_device *decoder, bitbuffer_t *bitbuffer) +/** @fn int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) Remote Grill Thermometer -- Generic wireless thermometer with probe. This is a meat thermometer with no brand / model identification except the FCC ID. From 356570fb047b9bd52b6d38f1312734113dd465ec Mon Sep 17 00:00:00 2001 From: Ethan Halsall Date: Mon, 4 Dec 2023 21:05:11 -0600 Subject: [PATCH 4/6] feat: RF-T0912 use full temp range --- src/devices/grill_thermometer.c | 45 ++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 18 deletions(-) diff --git a/src/devices/grill_thermometer.c b/src/devices/grill_thermometer.c index 582117fa4..197f0155c 100644 --- a/src/devices/grill_thermometer.c +++ b/src/devices/grill_thermometer.c @@ -19,17 +19,16 @@ This is a meat thermometer with no brand / model identification except the FCC I Supported Models: - RF-T0912 (FCC ID TXRFPT0912) -0 - 255 F, frequency 434.052 MHz +9 - 415 F, frequency 434.052 MHz Data structure: 10 repetitions of the same 24 bit payload. - 11111111 AAAAAAAA BBBBBBBB + AAAAAAAA AAAAAAAA BBBBBBBB -- 1: 8 bit preamble. Always set to 0xff -- A: 8 bit temperature in Fahrenheit. Calculated as (Temp = 255 - A) -- B: Copy of 'A' presumably for message integrity +- A: 16 bit temperature in Fahrenheit. Big Endian. +- B: Checksum of A */ @@ -37,41 +36,50 @@ Data structure: static int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) { - int raw_value = -1, repeats = 0; + short temp_f = -1; + int overload = 0; + int repeats = 0; + uint8_t checksum = 0; + + bitbuffer_invert(bitbuffer); // use the most recent "valid" data that repeats more than once for (int row = 0; row < bitbuffer->num_rows; row++) { uint8_t *row_data = bitbuffer->bb[row]; + checksum = row_data[0] + row_data[1]; - // validate decode result if (bitbuffer->bits_per_row[row] != 24 || - row_data[0] != 0xff || - row_data[1] != row_data[2]) { + checksum != row_data[2] || + checksum == 0) { continue; } - int current_value = row_data[1]; + short current_value = (row_data[0] << 8) + row_data[1]; - if (raw_value != current_value) { - raw_value = current_value; - repeats = 0; + if (temp_f != current_value) { + temp_f = current_value; + repeats = 0; } else { repeats++; } } - if (raw_value == -1 || repeats < 1) { + if (temp_f == -1 || repeats < 1) { return DECODE_ABORT_EARLY; } - int id = 0, temp_f = 0xFF - raw_value; + if (temp_f == -1029) { + temp_f = 0; + overload = 1; + } /* clang-format off */ data_t *data = data_make( - "model", "", DATA_STRING, "RF-T0912 Grill Thermometer", - "id", "Id", DATA_INT, id, + "model", "", DATA_STRING, "RF-T0912", "temperature_F", "Temperature", DATA_FORMAT, "%i F", DATA_INT, temp_f, + "overload", "Overload", DATA_STRING, overload ? "true" : "false", + "mic", "Integrity", DATA_STRING, "CHECKSUM", NULL); /* clang-format on */ @@ -81,8 +89,9 @@ static int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) static char const *const output_fields[] = { "model", - "id", "temperature_F", + "overload", + "mic", NULL, }; From 7eaa7cd395a718353de966e9715ea66d5373d11a Mon Sep 17 00:00:00 2001 From: Ethan Halsall Date: Mon, 4 Dec 2023 21:11:16 -0600 Subject: [PATCH 5/6] refactor: remove unneeded conditional --- src/devices/grill_thermometer.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/grill_thermometer.c b/src/devices/grill_thermometer.c index 197f0155c..f514562a6 100644 --- a/src/devices/grill_thermometer.c +++ b/src/devices/grill_thermometer.c @@ -36,7 +36,7 @@ Data structure: static int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) { - short temp_f = -1; + short temp_f = 0; int overload = 0; int repeats = 0; uint8_t checksum = 0; @@ -65,7 +65,7 @@ static int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) } } - if (temp_f == -1 || repeats < 1) { + if (repeats < 1) { return DECODE_ABORT_EARLY; } From 2c46db213145c0b9aa33a66580799e7b56fca486 Mon Sep 17 00:00:00 2001 From: Ethan Halsall Date: Tue, 5 Dec 2023 09:29:12 -0600 Subject: [PATCH 6/6] refactor: address comments --- src/devices/grill_thermometer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/devices/grill_thermometer.c b/src/devices/grill_thermometer.c index f514562a6..334c5b4b9 100644 --- a/src/devices/grill_thermometer.c +++ b/src/devices/grill_thermometer.c @@ -36,7 +36,7 @@ Data structure: static int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) { - short temp_f = 0; + int temp_f = 0; int overload = 0; int repeats = 0; uint8_t checksum = 0; @@ -54,7 +54,7 @@ static int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) continue; } - short current_value = (row_data[0] << 8) + row_data[1]; + int current_value = (int16_t)(row_data[0] << 8) | row_data[1]; // uses sign-extend if (temp_f != current_value) { temp_f = current_value; @@ -70,15 +70,14 @@ static int grill_thermometer_decode(r_device *decoder, bitbuffer_t *bitbuffer) } if (temp_f == -1029) { - temp_f = 0; overload = 1; } /* clang-format off */ data_t *data = data_make( "model", "", DATA_STRING, "RF-T0912", - "temperature_F", "Temperature", DATA_FORMAT, "%i F", DATA_INT, temp_f, - "overload", "Overload", DATA_STRING, overload ? "true" : "false", + "temperature_F", "Temperature", DATA_COND, !overload, DATA_FORMAT, "%i F", DATA_INT, temp_f, + "overload", "Overload", DATA_INT, overload, "mic", "Integrity", DATA_STRING, "CHECKSUM", NULL); /* clang-format on */