Skip to content

Commit dcccc2a

Browse files
Jon Klixbuell Langelandmerbanan
authored andcommitted
Add support for Thermor_a6n_132tx
High nibble checksum investigation done by Qwen3.6 Plus. Assisted-by: Qwen 3.6 Plus
1 parent a0247a6 commit dcccc2a

5 files changed

Lines changed: 139 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
386386
[298] TRW TPMS OOK OEM and Clone models
387387
[299] TRW TPMS FSK OEM and Clone models
388388
[300] Govee Water Leak Detector H5059
389+
[301] Thermor A6N 132TX temperature sensor
389390
390391
* Disabled by default, use -R n or a conf file to enable
391392

conf/rtl_433.example.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,7 @@ convert si
539539
protocol 298 # TRW TPMS OOK OEM and Clone models
540540
protocol 299 # TRW TPMS FSK OEM and Clone models
541541
protocol 300 # Govee Water Leak Detector H5059
542+
protocol 301 # Thermor A6N 132TX temperature sensor
542543

543544
## Flex devices (command line option "-X")
544545

include/rtl_433_devices.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@
308308
DECL(tpms_trw_ook) \
309309
DECL(tpms_trw_fsk) \
310310
DECL(govee_h5059) \
311+
DECL(thermor_a6n_132tx) \
311312

312313
/* Add new decoders here. */
313314

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ add_library(r_433 STATIC
264264
devices/thermopro_tx2c.c
265265
devices/thermopro_tx7b.c
266266
devices/thermor.c
267+
devices/thermor_a6n_132tx.c
267268
devices/tpms_abarth124.c
268269
devices/tpms_airpuxem.c
269270
devices/tpms_ave.c

src/devices/thermor_a6n_132tx.c

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/** @file
2+
Thermor A6N 132TX temperature sensor.
3+
4+
Copyright (C) 2020 Jon Klixbuell Langeland
5+
This program is free software; you can redistribute it and/or modify
6+
it under the terms of the GNU General Public License as published by
7+
the Free Software Foundation; either version 2 of the License, or
8+
(at your option) any later version.
9+
*/
10+
11+
#include "decoder.h"
12+
13+
/**
14+
Thermor A6N 132TX temperature sensor.
15+
16+
FCC: https://fccid.io/A6N-132TX
17+
18+
32-bit frame, repeated 11 times (look for 5 identical versions).
19+
20+
Data layout:
21+
22+
IIIICC-- TTTTTTTT TTTTTTTT CCCCCCCC
23+
24+
- I: 4 bit ID
25+
- C: 2 bit channel
26+
- -: 2 bit unknown
27+
- T: 16 bit temperature, stored as int / 10 (e.g. 376 = 37.6C)
28+
- C: 8 bit checksum
29+
30+
Checksum algorithm:
31+
- Low nibble: sum of low nibbles of bytes 0-2, mod 16
32+
- High nibble: ID-specific
33+
- ID=4: single bit = (hi_sum + overflow) & 1, upper 3 bits are 0
34+
where hi_sum = (b0>>4) + (b1>>4) + (b2>>4)
35+
and overflow = low_nibble_sum >> 4
36+
- ID=3,5: MSB (bit 3) = parity(b0_lo) XOR parity(b1_lo) XOR parity(b2)
37+
lower 3 bits = (2 + (hi_sum & 1)) XOR overflow
38+
39+
Sample data:
40+
41+
3c 01 7f 3c : 38.3C
42+
3c 01 88 a5 : 39.2C
43+
3c 01 90 ad : 40.0C
44+
50 01 0c bd : 26.8C
45+
50 02 03 b5 : 51.5C
46+
4c 01 7f 0c : 38.3C (ID=4)
47+
48+
Flex decoder:
49+
50+
rtl_433 -X 'n=thermor_a6n_132tx,m=OOK_PPM,s=1000,l=2000,g=2000,r=4000,repeats>=5'
51+
*/
52+
53+
static int thermor_a6n_132tx_decode(r_device *decoder, bitbuffer_t *bitbuffer)
54+
{
55+
int row;
56+
57+
if (bitbuffer->num_rows == 1 && bitbuffer->bits_per_row[0] == 32) {
58+
row = 0;
59+
} else {
60+
row = bitbuffer_find_repeated_row(bitbuffer, 5, 32);
61+
if (row < 0) {
62+
return DECODE_ABORT_EARLY;
63+
}
64+
}
65+
66+
if (bitbuffer->bits_per_row[row] != 32) {
67+
return DECODE_ABORT_LENGTH;
68+
}
69+
70+
uint8_t *b = bitbuffer->bb[row];
71+
72+
// Checksum low nibble: sum of low nibbles of payload bytes (mod 16)
73+
int lo_sum = (b[0] & 0x0f) + (b[1] & 0x0f) + (b[2] & 0x0f);
74+
int overflow = lo_sum >> 4;
75+
if ((lo_sum & 0x0f) != (b[3] & 0x0f)) {
76+
return DECODE_FAIL_MIC;
77+
}
78+
79+
// Checksum high nibble: ID-specific
80+
int id = (b[0] >> 4) & 0x0f;
81+
int hi_sum = (b[0] >> 4) + (b[1] >> 4) + (b[2] >> 4);
82+
int chk_hi = b[3] >> 4;
83+
84+
if (id == 4) {
85+
// ID=4: high nibble is 1 bit, upper 3 bits are 0
86+
if (chk_hi != ((hi_sum + overflow) & 1)) {
87+
return DECODE_FAIL_MIC;
88+
}
89+
} else {
90+
// ID=3,5: MSB = parity(b0_lo) XOR parity(b1_lo) XOR parity(b2)
91+
// lower 3 bits = (2 + (hi_sum & 1)) XOR overflow
92+
int chk_hi_msb = parity8(b[0] & 0x0f) ^ parity8(b[1] & 0x0f) ^ parity8(b[2]);
93+
int chk_hi_low = (2 + (hi_sum & 1)) ^ overflow;
94+
if (chk_hi != ((chk_hi_msb << 3) | chk_hi_low)) {
95+
return DECODE_FAIL_MIC;
96+
}
97+
}
98+
99+
int channel = (b[0] >> 2) & 0x03;
100+
int temp_raw = (b[1] << 8) | b[2];
101+
float temperature_c = temp_raw * 0.1f;
102+
103+
/* clang-format off */
104+
data_t *data = data_make(
105+
"model", "", DATA_STRING, "Thermor-A6N-132TX",
106+
"id", "ID", DATA_INT, id,
107+
"channel", "Channel", DATA_INT, channel,
108+
"temperature_C", "Temperature", DATA_FORMAT, "%.1f C", DATA_DOUBLE, temperature_c,
109+
"mic", "Integrity", DATA_STRING, "CHECKSUM",
110+
NULL);
111+
/* clang-format on */
112+
113+
decoder_output_data(decoder, data);
114+
return 1;
115+
}
116+
117+
static char const *const output_fields[] = {
118+
"model",
119+
"id",
120+
"channel",
121+
"temperature_C",
122+
"mic",
123+
NULL,
124+
};
125+
126+
r_device const thermor_a6n_132tx = {
127+
.name = "Thermor A6N 132TX temperature sensor",
128+
.modulation = OOK_PULSE_PPM,
129+
.short_width = 1000,
130+
.long_width = 2000,
131+
.gap_limit = 2000,
132+
.reset_limit = 4000,
133+
.decode_fn = &thermor_a6n_132tx_decode,
134+
.fields = output_fields,
135+
};

0 commit comments

Comments
 (0)