BresserWeatherSensorReceiver
Bresser 5-in-1/6-in-1/7-in-1 868 MHz Weather Sensor Radio Receiver for Arduino based on CC1101 or SX1276/RFM95W
Loading...
Searching...
No Matches
RainGauge.h
1
2// RainGauge.h
3//
4// Calculation of hourly (past 60 minutes), daily, weekly and monthly rainfall
5// from raw rain gauge data.
6//
7// Non-volatile data is stored in the ESP32's RTC RAM to allow retention during deep sleep mode.
8//
9// https://github.com/matthias-bs/BresserWeatherSensorReceiver
10//
11//
12// created: 08/2022
13//
14//
15// MIT License
16//
17// Copyright (c) 2025 Matthias Prinke
18//
19// Permission is hereby granted, free of charge, to any person obtaining a copy
20// of this software and associated documentation files (the "Software"), to deal
21// in the Software without restriction, including without limitation the rights
22// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23// copies of the Software, and to permit persons to whom the Software is
24// furnished to do so, subject to the following conditions:
25//
26// The above copyright notice and this permission notice shall be included in all
27// copies or substantial portions of the Software.
28//
29// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
35// SOFTWARE.
36//
37// History:
38//
39// 20220830 Created
40// 20230330 Added changes for Adafruit Feather 32u4 LoRa Radio
41// 20230716 Implemented sensor startup handling
42// 20230817 Implemented partial reset
43// 20231227 Added prerequisites for storing rain data in preferences
44// 20231218 Implemented storing of rain data in preferences,
45// new algorithm for past 60 minutes rainfall
46// 20240118 Changed raingaugeMax to class member set by constructor
47// 20240119 Changed preferences to class member
48// Modified update at the same index as before
49// Modified pastHour() algorithm and added features
50// Changed hist[] width
51// 20240120 Added set_max()
52// Removed old implementation
53// 20240122 Changed scope of nvData -
54// Using RTC RAM: global
55// Using Preferences, Unit Tests: class member
56// 20250323 Added configuration of expected update rate at run-time
57// pastHour(): modified parameters
58// 20260211 Added past24Hours()
59// Refactored to use RollingCounter base class
60// 20260221 Improved RollingCounter generalization, documentation, and code deduplication
61//
62// ToDo:
63// -
64//
66
67#ifndef _RAINGAUGE_H
68#define _RAINGAUGE_H
69
70#include "time.h"
71#if defined(ESP32) || defined(ESP8266)
72 #include <sys/time.h>
73#endif
74#include "RollingCounter.h"
75#if defined(RAINGAUGE_USE_PREFS) && !defined(INSIDE_UNITTEST)
76 #include <Preferences.h>
77#endif
78
84#define RAINGAUGE_MAX_VALUE 1000
85//#define RAINGAUGE_MAX_VALUE 20000
86
92#define RAINGAUGE_UPD_RATE 6
93
99#define RAIN_HIST_SIZE 10
100
106#define RAIN_HIST_SIZE_24H 24
107
108
112 #define RESET_RAIN_H 1
113 #define RESET_RAIN_D 2
114 #define RESET_RAIN_W 4
115 #define RESET_RAIN_M 8
116 #define RESET_RAIN_24H 16
117
118
124typedef struct {
125 /* Timestamp of last update */
126 time_t lastUpdate;
127
128 /* Data of past 60 minutes */
129 int16_t hist[RAIN_HIST_SIZE];
130
131 /* Data of past 24 hours */
132 int16_t hist24h[RAIN_HIST_SIZE_24H];
133
134 /* Sensor startup handling */
135 bool startupPrev; // previous state of startup
136 float rainPreStartup; // previous rain gauge reading (before startup)
137
138 /* Rainfall of current day (can start anytime, but will reset on begin of new day) */
139 uint8_t tsDayBegin; // day of week
140 float rainDayBegin; // rain gauge @ begin of day
141
142 /* Rainfall of current week (can start anytime, but will reset on Monday */
143 uint8_t tsWeekBegin; // day of week
144 float rainWeekBegin; // rain gauge @ begin of week
145 uint8_t wdayPrev; // day of week at previous run - to detect new week
146
147 /* Rainfall of current calendar month (can start anytime, but will reset at begin of month */
148 uint8_t tsMonthBegin; // month
149 float rainMonthBegin; // rain gauge @ begin of month
150
151 float rainPrev; // rain gauge at previous run - to detect overflow
152 float rainAcc; // accumulated rain (overflows and startups)
153
154 uint8_t updateRate; // update rate for pastHour() calculation
155} nvData_t;
156
164class RainGauge : public RollingCounter {
165private:
166 float rainCurr;
167 float raingaugeMax;
168
169 #if defined(RAINGAUGE_USE_PREFS) || defined(INSIDE_UNITTEST)
170 nvData_t nvData = {
171 .lastUpdate = 0,
172 .hist = {-1},
173 .hist24h = {-1},
174 .startupPrev = false,
175 .rainPreStartup = 0,
176 .tsDayBegin = 0xFF,
177 .rainDayBegin = 0,
178 .tsWeekBegin = 0xFF,
179 .rainWeekBegin = 0,
180 .wdayPrev = 0xFF,
181 .tsMonthBegin = 0xFF,
182 .rainMonthBegin = 0,
183 .rainPrev = 0,
184 .rainAcc = 0,
185 .updateRate = RAINGAUGE_UPD_RATE
186 };
187 #endif
188 #if defined(RAINGAUGE_USE_PREFS) && !defined(INSIDE_UNITTEST)
189 Preferences preferences;
190 #endif
191
192public:
199 RainGauge(const float raingauge_max = RAINGAUGE_MAX_VALUE, const float quality_threshold = DEFAULT_QUALITY_THRESHOLD) :
200 RollingCounter(quality_threshold),
201 raingaugeMax(raingauge_max)
202 {};
203
209 void set_max(float raingauge_max)
210 {
211 raingaugeMax = raingauge_max;
212 }
213
242 bool setUpdateRate(uint8_t rate = RAINGAUGE_UPD_RATE) {
243 // Validate rate: must be > 0, must evenly divide 60, and result must fit in buffer
244 if (rate == 0) {
245 log_w("setUpdateRate: rate cannot be 0");
246 return false;
247 }
248 if (60 % rate != 0) {
249 log_w("setUpdateRate: rate=%u must evenly divide 60 minutes", rate);
250 return false;
251 }
252 if (60 / rate > RAIN_HIST_SIZE) {
253 log_w("setUpdateRate: rate=%u would require %u bins, but only %u available",
254 rate, 60 / rate, RAIN_HIST_SIZE);
255 return false;
256 }
257
258 #if !defined(INSIDE_UNITTEST)
259 preferences.begin("BWS-RAIN", false);
260 uint8_t updateRatePrev = preferences.getUChar("updateRate", RAINGAUGE_UPD_RATE);
261 preferences.putUChar("updateRate", rate);
262 preferences.end();
263 #else
264 static uint8_t updateRatePrev = RAINGAUGE_UPD_RATE;
265 updateRatePrev = nvData.updateRate;
266 #endif
267 nvData.updateRate = rate;
268 if (nvData.updateRate != updateRatePrev) {
269 hist_init();
270 }
271 return true;
272 }
273
279 void reset(uint8_t flags=0x1F);
280
286 void hist_init(int16_t rain = -1) override;
287
293 void hist24h_init(int16_t rain = -1);
294
295 #if defined(RAINGAUGE_USE_PREFS) && !defined(INSIDE_UNITTEST)
296 void prefs_load(void);
297 void prefs_save(void);
298 #endif
299
311 void update(time_t ts, float rain, bool startup = false);
312
322 float pastHour(bool *valid = nullptr, int *nbins = nullptr, float *quality = nullptr);
323
333 float past24Hours(bool *valid = nullptr, int *nbins = nullptr, float *quality = nullptr);
334
340 float currentDay(void);
341
347 float currentWeek(void);
348
354 float currentMonth(void);
355};
356#endif // _RAINGAUGE_H
Calculation of hourly (past 60 minutes), daily, weekly and monthly rainfall.
Definition RainGauge.h:164
float pastHour(bool *valid=nullptr, int *nbins=nullptr, float *quality=nullptr)
Definition RainGauge.cpp:455
float currentWeek(void)
Definition RainGauge.cpp:486
float currentMonth(void)
Definition RainGauge.cpp:495
bool setUpdateRate(uint8_t rate=RAINGAUGE_UPD_RATE)
Set expected update rate for pastHour() calculation.
Definition RainGauge.h:242
void set_max(float raingauge_max)
Definition RainGauge.h:209
float currentDay(void)
Definition RainGauge.cpp:477
RainGauge(const float raingauge_max=RAINGAUGE_MAX_VALUE, const float quality_threshold=DEFAULT_QUALITY_THRESHOLD)
Definition RainGauge.h:199
void hist24h_init(int16_t rain=-1)
Definition RainGauge.cpp:188
void reset(uint8_t flags=0x1F)
Definition RainGauge.cpp:98
float past24Hours(bool *valid=nullptr, int *nbins=nullptr, float *quality=nullptr)
Definition RainGauge.cpp:466
void hist_init(int16_t rain=-1) override
Definition RainGauge.cpp:180
void update(time_t ts, float rain, bool startup=false)
Update rain gauge statistics.
Definition RainGauge.cpp:275
Base class for rolling counter implementations.
Definition RollingCounter.h:78
Definition RainGauge.h:124