Skip to content

Commit a0156e0

Browse files
committed
Add Support for RainPoint HCS012ARF Rain Gauge sensor
1 parent 9a78a48 commit a0156e0

File tree

3 files changed

+131
-0
lines changed

3 files changed

+131
-0
lines changed

include/rtl_433_devices.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,7 @@
283283
DECL(gridstream384) \
284284
DECL(revolt_zx7717) \
285285
DECL(tpms_gm) \
286+
DECL(rainpoint_hcs012arf) \
286287

287288
/* Add new decoders here. */
288289

src/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ add_library(r_433 STATIC
204204
devices/quinetic.c
205205
devices/radiohead_ask.c
206206
devices/rainpoint.c
207+
devices/rainpoint_hcs012arf.c
207208
devices/regency_fan.c
208209
devices/revolt_nc5462.c
209210
devices/revolt_zx7717.c

src/devices/rainpoint_hcs012arf.c

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/** @file
2+
RainPoint HCS012ARF Rain Gauge sensor.
3+
4+
Copyright (C) 2021 Christian W. Zuckschwerdt <zany@triq.net>
5+
Copyright (C) 2025 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+
RainPoint HCS012ARF Rain Gauge sensor.
17+
18+
Manufacturer:
19+
- Fujian Baldr Technology Co., Ltd
20+
21+
RF Information:
22+
- Seen on 433.92 Mhz.
23+
- FCC ID : 2AWDBHCS008FRF
24+
- RF Module used in other RainPoint / Fujian Baldr Technology Co., Ltd devices : HCS008FRF, HCS012ARF, HTV113FRF, HTV213FRF, TTC819, TCS008B
25+
26+
Description of the HCS012ARF Rain Gauge Sensor:
27+
- Rainfall Range: 0-9999mm , but 2 bytes identified, missing 1 bit MSB somewhere in the data layout flags
28+
- Accuracy: ±0.1mm
29+
- Data Reporting: Every 3 mins
30+
31+
A Transmission contains ten packets with Manchester coded data, reflected
32+
33+
Data layout:
34+
35+
Byte Index 0 1 2 3 4 5 6 7 8 9
36+
Sample a5 08 54 03 04 61 03 00 00 c7 [Batt inserted]
37+
HH[II II II II FB FF RR RR]SS
38+
39+
- HH: {8} Header, fixed 0xa5 (or 0xa4 when MC Zero bit decoded)
40+
- ID: {32} Sensor ID, does not change with new battery, looks unique
41+
- FF: {6} Fixed value, 0x18, may contains 1 bit MSB Rain Gauge
42+
- B:{1} Low Battery flag = 1, Good Battery = 0
43+
- B:{1} Powered on, batteries are inserted = 1, then always = 0
44+
- FF:{8} Fixed value, 0x03, may contains 1 bit MSB Rain Gauge
45+
- RR:{16} little-endian rain gauge value, scale 10 (1 Tip = 0,1 mm), 2 bytes are not enough, max 0xFFFF = 6553.5 mm, 1 bit MSB somewhere in flags ?
46+
- SS:{8} Byte sum of previous bytes except header [value in the hooks, from ID to Rain gauge].
47+
48+
Raw data:
49+
50+
rtl_433 -X 'n=HCS012ARF,m=OOK_PCM,s=320,l=320,r=1000,g=700,repeats>=5,unique'
51+
52+
53+
*/
54+
55+
static int rainpoint_hcs012arf_decode(r_device *decoder, bitbuffer_t *bitbuffer)
56+
{
57+
58+
// Find repeats
59+
int row = bitbuffer_find_repeated_row(bitbuffer, 4, 163);
60+
if (row < 0)
61+
return DECODE_ABORT_EARLY;
62+
63+
if (bitbuffer->bits_per_row[row] > 163)
64+
return DECODE_ABORT_LENGTH;
65+
66+
bitbuffer_t msg = {0};
67+
bitbuffer_manchester_decode(bitbuffer, row, 0, &msg, 10 * 2 * 8); // including header
68+
bitbuffer_invert(&msg);
69+
70+
uint8_t *b = msg.bb[0];
71+
reflect_bytes(b, 10);
72+
73+
if (b[0] != 0xa5) // header = 0xa5, could be 0xa4 when MC Zero bit decoded
74+
return DECODE_ABORT_EARLY;
75+
76+
decoder_log_bitrow(decoder, 2, __func__, b, 10 * 8, "MC and Reflect decoded");
77+
78+
// Checksum
79+
int sum = add_bytes(&b[1], 8); // header not part of the sum
80+
if ((sum & 0xff) != b[9]) {
81+
decoder_logf(decoder, 2, __func__, "Checksum failed %04x vs %04x", b[9], sum);
82+
return DECODE_FAIL_MIC;
83+
}
84+
85+
int id = (b[4] << 24) | (b[3] << 16) | (b[2] << 8) | b[1]; // just a guess, little-endian
86+
int flags1 = b[5]; // may contains 1 bit MSB for Rain Gauge
87+
int bat_low = (flags1 & 0x02) >> 1;
88+
//int bat_in = (flags1 & 0x01); // power up, battery inserted = 1, then always 0
89+
int flags2 = b[6]; // may contains 1 bit MSB for Rain Gauge
90+
int rain_raw = (b[8] << 8) | b[7]; // little-endian
91+
float rain_mm = rain_raw * 0.1f;
92+
93+
/* clang-format off */
94+
data_t *data = data_make(
95+
"model", "", DATA_STRING, "RainPoint-HCS012ARF",
96+
"id", "", DATA_INT, id, // decimal value reported at Rainpoint application
97+
"flags1", "Flags 1", DATA_FORMAT, "%02x", DATA_INT, (flags1 >> 2), // remove battery flags
98+
"flags2", "Flags 2", DATA_FORMAT, "%02x", DATA_INT, flags2,
99+
"battery_ok", "Battery", DATA_INT, !bat_low,
100+
"rain_mm", "Total rainfall", DATA_FORMAT, "%.1f mm", DATA_DOUBLE, rain_mm,
101+
"mic", "Integrity", DATA_STRING, "CHECKSUM",
102+
NULL);
103+
/* clang-format on */
104+
105+
decoder_output_data(decoder, data);
106+
return 1;
107+
}
108+
109+
static char const *const output_fields[] = {
110+
"model",
111+
"id",
112+
"flags1",
113+
"flags2",
114+
"battery_ok",
115+
"rain_mm",
116+
"mic",
117+
NULL,
118+
};
119+
120+
r_device const rainpoint_hcs012arf = {
121+
.name = "RainPoint HCS012ARF Rain Gauge sensor",
122+
.modulation = OOK_PULSE_PCM,
123+
.short_width = 320,
124+
.long_width = 320,
125+
.reset_limit = 1000,
126+
.gap_limit = 700,
127+
.decode_fn = &rainpoint_hcs012arf_decode,
128+
.fields = output_fields,
129+
};

0 commit comments

Comments
 (0)