Skip to content

Commit 18452ba

Browse files
authored
Add Support for Mueller Hot Rod water meter
Add Support for Mueller Hot Rod water meter
2 parents 9448d42 + e8f419e commit 18452ba

File tree

4 files changed

+124
-0
lines changed

4 files changed

+124
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ See [CONTRIBUTING.md](./docs/CONTRIBUTING.md).
340340
[252] BMW Gen5 TPMS, multi-brand HUF, Continental, Schrader/Sensata
341341
[253] Watts WFHT-RF Thermostat
342342
[254] Thermor DG950 Weather Station
343+
[255] Mueller Hot Rod water meter
343344
344345
* Disabled by default, use -R n or a conf file to enable
345346

include/rtl_433_devices.h

+1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,7 @@
262262
DECL(tpms_bmw) \
263263
DECL(watts_thermostat) \
264264
DECL(thermor) \
265+
DECL(mueller_hotrod) \
265266

266267
/* Add new decoders here. */
267268

src/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ add_library(r_433 STATIC
171171
devices/mebus.c
172172
devices/megacode.c
173173
devices/missil_ml0757.c
174+
devices/mueller_hotrod.c
174175
devices/neptune_r900.c
175176
devices/new_template.c
176177
devices/newkaku.c

src/devices/mueller_hotrod.c

+121
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/** @file
2+
Mueller Hot Rod water meter.
3+
4+
Copyright (C) 2024 Christian W. Zuckschwerdt <[email protected]>
5+
Copyright (C) 2024 Bruno OCTAU (ProfBoc75)
6+
7+
This program is free software; you can redistribute it and/or modify
8+
it under the terms of the GNU General Public License as published by
9+
the Free Software Foundation; either version 2 of the License, or
10+
(at your option) any later version.
11+
*/
12+
13+
#include "decoder.h"
14+
15+
/**
16+
Mueller Hot Rod water meter.
17+
18+
S.a. #2719 Decoder desired for Mueller Systems Hot Rod transmitter (water meter), open by "howardtopher", related to Hod Rod v2 transmitter
19+
S.a. #2752 Decoder for Mueller Hot Rod V1 Water Meter Transmitter, open by "dolai1", related to Hod Rod v1 transmitter
20+
21+
Both version v1 and v2 protocols look same format.
22+
23+
Flex decoder:
24+
25+
rtl_433 -X 'n=hotrod,m=FSK_PCM,s=26,l=26,r=2500,preamble=feb100'
26+
27+
Raw RF Signal:
28+
29+
{136}ffffffffffd62002884cc2c092f1201f80
30+
{135}fff555555fd62002884cc2c092f1201f80
31+
{135}ffeaaaaabfac40051099858125e2403f00
32+
{134}000002aabfac40051099858125e54015c0
33+
{134}00000000000040051099858125e54015c0
34+
35+
The preamble is not stable because of the GFSK encoding not well handle by rtl_433.
36+
37+
Data layout:
38+
PP PP PP YY YY YY 0 1 2 3 4 5 6 7 8 9 10 11 ...
39+
aa aa aa fe b1 00 II II II II GG GG GG GF CC ?? ?? ?? ...
40+
41+
- PP: {xx} Preamble 0xaaaaa but not stable, see RF samples above.
42+
- YY: {24} Sync word 0xfeb100
43+
- II: {32} Device ID
44+
- GG: {28} 7 niblles BCD water cumulative volume, US liquid gallon
45+
- FF: {4} Flag, protocol version, battery_low ??? to be confirmed later.
46+
- CC: {8} CRC-8/UTI, poly 0x07, init 0x00, xorout 0x55
47+
- ??: extra trailing bit not used, related to GFSK/FSK encoding.
48+
49+
*/
50+
51+
static int mueller_hotrod_decode(r_device *decoder, bitbuffer_t *bitbuffer)
52+
{
53+
uint8_t const preamble_pattern[] = {0xfe, 0xb1, 0x00};
54+
55+
if (bitbuffer->num_rows != 1) {
56+
decoder_log(decoder, 2, __func__, "Row check failed");
57+
return DECODE_ABORT_EARLY;
58+
}
59+
60+
// 3 byte for the sync word + 9 byte for data = 96 bits in total, too short if less
61+
if (bitbuffer->bits_per_row[0] < 96) {
62+
decoder_log(decoder, 2, __func__, "Len before preamble check failed");
63+
return DECODE_ABORT_LENGTH;
64+
}
65+
66+
// Find the preamble
67+
unsigned pos = bitbuffer_search(bitbuffer, 0, 0, preamble_pattern, sizeof(preamble_pattern) * 8);
68+
if ((pos + 9 * 8) >= bitbuffer->bits_per_row[0]) {
69+
decoder_log(decoder, 2, __func__, "Len after preamble check failed");
70+
return DECODE_ABORT_EARLY;
71+
}
72+
73+
uint8_t b[9];
74+
bitbuffer_extract_bytes(bitbuffer, 0, pos + 24, b, 72); // 9 x 8 bit
75+
decoder_log_bitrow(decoder, 1, __func__, b, sizeof(b) * 8, "MSG");
76+
77+
// poly 0x07, init 0x00, xorout 0x55
78+
int crc_calc = crc8(b, 8, 0x07, 0x00) ^ 0x55;
79+
if (crc_calc != b[8]) {
80+
decoder_logf(decoder, 2, __func__, "CRC check failed : %0x %0x", b[8], crc_calc);
81+
return 0;
82+
}
83+
84+
char id_str[16];
85+
snprintf(id_str, sizeof(id_str), "%02x%02x%02x%02x", b[0], b[1], b[2], b[3]);
86+
87+
// 7 nibbles BCD (28 bit) = volume_gal
88+
int volume = ((b[4] & 0xf0) >> 4)*1000000+(b[4] & 0x0f)*100000+((b[5] & 0xf0) >> 4)*10000+(b[5] & 0x0f)*1000+((b[6] & 0xf0) >> 4)*100+(b[6] & 0x0f)*10+((b[7] & 0xf0) >> 4);
89+
int flag = b[7] & 0x0f;
90+
91+
/* clang-format off */
92+
data_t *data = data_make(
93+
"model", "", DATA_STRING, "Mueller-HotRod",
94+
"id", "", DATA_STRING, id_str,
95+
"volume_gal", "Volume", DATA_FORMAT, "%u gal", DATA_INT, volume,
96+
"flag", "Flag", DATA_FORMAT, "%x" , DATA_INT, flag,
97+
"mic", "Integrity", DATA_STRING, "CRC",
98+
NULL);
99+
/* clang-format on */
100+
decoder_output_data(decoder, data);
101+
return 1;
102+
}
103+
104+
static char const *const output_fields[] = {
105+
"model",
106+
"id",
107+
"volume_gal",
108+
"flag",
109+
"mic",
110+
NULL,
111+
};
112+
113+
r_device const mueller_hotrod = {
114+
.name = "Mueller Hot Rod water meter",
115+
.modulation = FSK_PULSE_PCM,
116+
.short_width = 26,
117+
.long_width = 26,
118+
.reset_limit = 2500,
119+
.decode_fn = &mueller_hotrod_decode,
120+
.fields = output_fields,
121+
};

0 commit comments

Comments
 (0)