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
Lightning.h
1
2// Lightning.h
3//
4// Post-processing of lightning sensor data
5//
6// Input:
7// * Timestamp
8// * Sensor startup flag
9// * Accumulated lightning event counter
10// * Estimated distance of last strike
11//
12// Output:
13// * Number of events during last update cycle
14// * Timestamp, number of strikes and estimated distance of last event
15// * Number of strikes during past 60 minutes
16//
17// Non-volatile data is stored in the ESP32's RTC RAM or in Preferences (Flash FS)
18// to allow retention during deep sleep mode.
19//
20// https://github.com/matthias-bs/BresserWeatherSensorReceiver
21//
22//
23// created: 07/2023
24//
25//
26// MIT License
27//
28// Copyright (c) 2023 Matthias Prinke
29//
30// Permission is hereby granted, free of charge, to any person obtaining a copy
31// of this software and associated documentation files (the "Software"), to deal
32// in the Software without restriction, including without limitation the rights
33// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
34// copies of the Software, and to permit persons to whom the Software is
35// furnished to do so, subject to the following conditions:
36//
37// The above copyright notice and this permission notice shall be included in all
38// copies or substantial portions of the Software.
39//
40// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
41// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
42// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
43// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
44// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
45// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
46// SOFTWARE.
47//
48// History:
49//
50// 20230721 Created
51// 20231105 Added data storage via Preferences, modified history implementation
52// 20240116 Corrected LIGHTNINGCOUNT_MAX_VALUE
53// 20240119 Changed preferences to class member
54// 20240123 Changed scope of nvLightning -
55// Using RTC RAM: global
56// Using Preferences, Unit Tests: class member
57// Modified for unit testing
58// Modified pastHour()
59// Added qualityThreshold
60// 20240124 Fixed handling of overflow, startup and missing update cycles
61// 20240125 Added lastCycle()
62// 20250324 Added configuration of expected update rate at run-time
63// pastHour(): modified parameters
64// 20260211 Refactored to use RollingCounter base class
65// 20260221 Improved RollingCounter generalization, documentation, and code deduplication
66//
67// ToDo:
68// -
69//
71
72#ifndef _LIGHTNING_H
73#define _LIGHTNING_H
74
75#include "time.h"
76#if defined(ESP32) || defined(ESP8266)
77 #include <sys/time.h>
78#endif
79#include "WeatherSensorCfg.h"
80#include "RollingCounter.h"
81
82#if defined(LIGHTNING_USE_PREFS)
83#include <Preferences.h>
84#endif
85
86
87
93#define LIGHTNINGCOUNT_MAX_VALUE 1600
94
100#define LIGHTNING_UPD_RATE 6
101
107#define LIGHTNING_HIST_SIZE 10
108
116typedef struct {
117 /* Timestamp of last update */
118 time_t lastUpdate;
119
120 /* Startup handling */
122 int16_t preStCount;
123 uint32_t accCount;
124
125 /* Data of last lightning event */
126 int16_t prevCount;
127 int16_t events;
128 uint8_t distance;
129 time_t timestamp;
130
131 /* Data of past 60 minutes */
132 int16_t hist[LIGHTNING_HIST_SIZE];
133
134 uint8_t updateRate;
136
137
144class Lightning : public RollingCounter {
145
146private:
147 int currCount;
148 int deltaEvents = -1;
149
150 #if defined(LIGHTNING_USE_PREFS) || defined(INSIDE_UNITTEST)
151 nvLightning_t nvLightning = {
152 .lastUpdate = 0,
153 .startupPrev = false,
154 .preStCount = 0,
155 .accCount = 0,
156 .prevCount = -1,
157 .events = 0,
158 .distance = 0,
159 .timestamp = 0,
160 .hist = {0},
161 .updateRate = LIGHTNING_UPD_RATE
162 };
163 #endif
164
165 #if defined(LIGHTNING_USE_PREFS) && !defined(INSIDE_UNITTEST)
166 Preferences preferences;
167 #endif
168
169public:
175 Lightning(const float quality_threshold = DEFAULT_QUALITY_THRESHOLD) :
176 RollingCounter(quality_threshold)
177 {};
178
179
208 bool setUpdateRate(uint8_t rate = LIGHTNING_UPD_RATE) {
209 // Validate rate: must be > 0, must evenly divide 60, and result must fit in buffer
210 if (rate == 0) {
211 log_w("setUpdateRate: rate cannot be 0");
212 return false;
213 }
214 if (60 % rate != 0) {
215 log_w("setUpdateRate: rate=%u must evenly divide 60 minutes", rate);
216 return false;
217 }
218 if (60 / rate > LIGHTNING_HIST_SIZE) {
219 log_w("setUpdateRate: rate=%u would require %u bins, but only %u available",
220 rate, 60 / rate, LIGHTNING_HIST_SIZE);
221 return false;
222 }
223
224 #if !defined(INSIDE_UNITTEST)
225 preferences.begin("BWS-LGT", false);
226 uint8_t updateRatePrev = preferences.getUChar("updateRate", LIGHTNING_UPD_RATE);
227 preferences.putUChar("updateRate", rate);
228 preferences.end();
229 #else
230 static uint8_t updateRatePrev = LIGHTNING_UPD_RATE;
231 updateRatePrev = nvLightning.updateRate;
232 #endif
233 nvLightning.updateRate = rate;
234 if (nvLightning.updateRate != updateRatePrev) {
235 hist_init();
236 }
237 return true;
238 }
239
240
244 void reset(void);
245
246
252 void hist_init(int16_t count = -1) override;
253
254 #if defined(LIGHTNING_USE_PREFS) && !defined(INSIDE_UNITTEST)
255 void prefs_load(void);
256 void prefs_save(void);
257 #endif
258
272 void update(time_t timestamp, int16_t count, uint8_t distance, bool startup = false /*, uint16_t lightningCountMax = LIGHTNINGCOUNT_MAX */);
273
274
286 int pastHour(bool *valid = nullptr, int *nbins = nullptr, float *quality = nullptr);
287
288 /*
289 * \fn lastCycle
290 *
291 * \brief Get number of events during last update cycle
292 *
293 * \return number of lightning events
294 */
295 int lastCycle(void);
296
297 /*
298 * \fn lastEvent
299 *
300 * \brief Get data of last lightning event
301 *
302 * \param timestamp timestamp of last event
303 * \param events number of lightning strikes
304 * \param distance estimated distance
305 *
306 * \return true if valid
307 */
308 bool lastEvent(time_t &timestamp, int &events, uint8_t &distance);
309};
310#endif // _LIGHTNING_H
Calculation number of lightning events during last sensor update cycle and during last hour (past 60 ...
Definition Lightning.h:144
int pastHour(bool *valid=nullptr, int *nbins=nullptr, float *quality=nullptr)
Get number of lightning events during past 60 minutes.
Definition Lightning.cpp:316
Lightning(const float quality_threshold=DEFAULT_QUALITY_THRESHOLD)
Definition Lightning.h:175
bool setUpdateRate(uint8_t rate=LIGHTNING_UPD_RATE)
Set expected update rate for pastHour() calculation.
Definition Lightning.h:208
void update(time_t timestamp, int16_t count, uint8_t distance, bool startup=false)
Update lightning data.
Definition Lightning.cpp:173
void hist_init(int16_t count=-1) override
Definition Lightning.cpp:112
void reset(void)
Definition Lightning.cpp:98
Base class for rolling counter implementations.
Definition RollingCounter.h:78
Definition Lightning.h:116
uint8_t updateRate
expected update rate for pastHour() calculation
Definition Lightning.h:134
time_t timestamp
Timestamp of last event.
Definition Lightning.h:129
bool startupPrev
Previous startup flag value.
Definition Lightning.h:121
uint32_t accCount
Accumulated counts (overflows and startups)
Definition Lightning.h:123
time_t lastUpdate
Timestamp of last update.
Definition Lightning.h:118
int16_t events
Number of events reported at last event.
Definition Lightning.h:127
int16_t prevCount
Previous counter value.
Definition Lightning.h:126
uint8_t distance
Distance at last event.
Definition Lightning.h:128
int16_t preStCount
Previous raw sensor counter (before startup)
Definition Lightning.h:122