3-phase PV router
Loading...
Searching...
No Matches
utils_relay.h
Go to the documentation of this file.
1
11
12#ifndef UTILS_RELAY_H
13#define UTILS_RELAY_H
14
15#include "types.h"
16#include "type_traits.hpp"
17#include "debug.h"
18
19#include "config_system.h"
20#include "ewma_avg.hpp"
21#include "utils_pins.h"
22
41{
42public:
43 constexpr relayOutput() = delete;
44
50 explicit constexpr relayOutput(const uint8_t _relay_pin)
51 : relay_pin{ _relay_pin }
52 {
53 }
54
65 constexpr relayOutput(uint8_t _relay_pin, int16_t _surplusThreshold, int16_t _importThreshold)
66 : relay_pin{ _relay_pin }, surplusThreshold{ -abs(_surplusThreshold) }, importThreshold{ _importThreshold }
67 {
68 }
69
82 constexpr relayOutput(uint8_t _relay_pin, int16_t _surplusThreshold, int16_t _importThreshold, uint16_t _minON, uint16_t _minOFF)
83 : relay_pin{ _relay_pin }, surplusThreshold{ -abs(_surplusThreshold) }, importThreshold{ _importThreshold }, minON{ _minON * 60 }, minOFF{ _minOFF * 60 }
84 {
85 }
86
92 constexpr auto get_pin() const
93 {
94 return relay_pin;
95 }
96
102 constexpr auto get_surplusThreshold() const
103 {
104 return -surplusThreshold;
105 }
106
112 constexpr auto get_importThreshold() const
113 {
114 return importThreshold;
115 }
116
122 constexpr auto get_minON() const
123 {
124 return minON;
125 }
126
132 constexpr auto get_minOFF() const
133 {
134 return minOFF;
135 }
136
142 auto isRelayON() const
143 {
144 return relayIsON;
145 }
146
152 void inc_duration() const
153 {
154 if (duration < UINT16_MAX)
155 {
156 ++duration;
157 }
158 }
159
165 bool proceed_relay(const int32_t currentAvgPower) const
166 {
167 // To avoid changing sign, surplus is a negative value
168 if (currentAvgPower < surplusThreshold)
169 {
170 return try_turnON();
171 }
172
173 // Handle both positive and negative import thresholds
174 if (importThreshold >= 0)
175 {
176 // Positive threshold: turn OFF when importing > threshold (normal mode)
177 if (currentAvgPower > importThreshold)
178 {
179 return try_turnOFF();
180 }
181 }
182 else
183 {
184 // Negative threshold: turn OFF when surplus < abs(threshold) (battery mode)
185 if (currentAvgPower > importThreshold) // importThreshold is negative, so this checks surplus < abs(threshold)
186 {
187 return try_turnOFF();
188 }
189 }
190
191 return false;
192 }
193
198 void printRelayConfiguration(uint8_t idx) const
199 {
200 Serial.print(F("\tRelay configuration: #"));
201 Serial.println(idx + 1);
202
203 Serial.print(F("\t\tPin is "));
204 Serial.println(get_pin());
205
206 Serial.print(F("\t\tSurplus threshold: "));
207 Serial.println(get_surplusThreshold());
208
209 Serial.print(F("\t\tImport threshold: "));
210 Serial.print(get_importThreshold());
211 if (get_importThreshold() >= 0)
212 {
213 Serial.println(F(" (import mode)"));
214 }
215 else
216 {
217 Serial.print(F(" (surplus mode: turn OFF when surplus < "));
218 Serial.print(-get_importThreshold());
219 Serial.println(F("W)"));
220 }
221
222 Serial.print(F("\t\tMinimum working time in minutes: "));
223 Serial.println(get_minON() / 60);
224
225 Serial.print(F("\t\tMinimum stop time in minutes: "));
226 Serial.println(get_minOFF() / 60);
227 }
228
229private:
235 bool try_turnON() const
236 {
237 if (relayIsON || duration < minOFF)
238 {
239 return false;
240 }
241
243
244 DBUGLN(F("Relay turned ON!"));
245
246 relayIsON = true;
247 duration = 0;
248
249 return true;
250 }
251
257 bool try_turnOFF() const
258 {
259 if (!relayIsON || duration < minON)
260 {
261 return false;
262 }
263
265
266 DBUGLN(F("Relay turned OFF!"));
267
268 relayIsON = false;
269 duration = 0;
270
271 return true;
272 }
273
274private:
275 const uint8_t relay_pin{ unused_pin };
276 const int16_t surplusThreshold{ -1000 };
277 const int16_t importThreshold{ 200 };
278 const uint16_t minON{ 5 * 60 };
279 const uint16_t minOFF{ 5 * 60 };
280
281 mutable uint16_t duration{ 0 };
282 mutable bool relayIsON{ false };
283};
284
307template< uint8_t N, uint8_t D = 10 >
309{
310public:
315 explicit constexpr RelayEngine(const relayOutput (&ref)[N])
316 : relay(ref)
317 {
318 }
319
327 : relay(ref)
328 {
329 }
330
336 constexpr auto get_size() const
337 {
338 return N;
339 }
340
347 constexpr const auto& get_relay(uint8_t idx) const
348 {
349 return relay[idx];
350 }
351
357 inline static auto get_average()
358 {
359 return ewma_average.getAverageT(); // Use TEMA for better cloud immunity
360 }
361
367 inline static void update_average(int16_t currentPower)
368 {
369 ewma_average.addValue(currentPower);
370 }
371
378#if defined(__DOXYGEN__)
379 void inc_duration() const;
380#else
381 void inc_duration() const __attribute__((optimize("-O3")));
382#endif
383
391 void proceed_relays() const
392 {
393 if (settle_change != 0)
394 {
395 // A relay has been toggle less than a minute ago, wait until changes take effect
396 return;
397 }
398
399 if (ewma_average.getAverageT() > 0)
400 {
401 // Currently importing, try to turn OFF some relays
402 uint8_t idx{ N };
403 do
404 {
405 if (relay[--idx].proceed_relay(ewma_average.getAverageT()))
406 {
407 settle_change = 60;
408 return;
409 }
410 } while (idx);
411 }
412 else
413 {
414 // Remaining surplus, try to turn ON more relays
415 uint8_t idx{ 0 };
416 do
417 {
418 if (relay[idx].proceed_relay(ewma_average.getAverageT()))
419 {
420 settle_change = 60;
421 return;
422 }
423 } while (++idx < N);
424 }
425 }
426
434 {
435 Serial.println(F("\t*** Relay(s) configuration ***"));
436 Serial.print(F("\t\tSliding average: "));
437 Serial.println(D);
438
439 for (uint8_t i = 0; i < N; ++i)
440 {
441 relay[i].printRelayConfiguration(i);
442 }
443 }
444
445private:
447
448 mutable uint8_t settle_change{ 60 };
449
451};
452
453template< uint8_t N, uint8_t D > void RelayEngine< N, D >::inc_duration() const
454{
455 uint8_t idx{ N };
456 do
457 {
458 relay[--idx].inc_duration();
459 } while (idx);
460
461 if (settle_change)
462 {
464 }
465}
466
467// Deduction guides for automatic template parameter deduction
468template< uint8_t N >
470
471template< uint8_t N, uint8_t D >
473
474#endif /* UTILS_RELAY_H */
Implements an Exponentially Weighted Moving Average (EWMA).
Definition ewma_avg.hpp:108
Manages a collection of relays and their behavior based on surplus and import thresholds.
static EWMA_average< D *60/DATALOG_PERIOD_IN_SECONDS > ewma_average
constexpr auto get_size() const
Get the number of relays.
void proceed_relays() const
Proceed all relays in increasing order (surplus) or decreasing order (import).
static auto get_average()
Get the current average.
static void update_average(int16_t currentPower)
Update the sliding average.
const relayOutput relay[N]
void inc_duration() const
Increment the duration's state of each relay.
uint8_t settle_change
constexpr RelayEngine(integral_constant< uint8_t, D > ic, const relayOutput(&ref)[N])
Construct a list of relays with a custom sliding average.
constexpr const auto & get_relay(uint8_t idx) const
Get the relay object.
constexpr RelayEngine(const relayOutput(&ref)[N])
Construct a list of relays.
void printConfiguration() const
Print the configuration of each relay.
Represents a single relay configuration and its behavior.
Definition utils_relay.h:41
constexpr relayOutput()=delete
constexpr auto get_minOFF() const
Get the minimum OFF-time in seconds.
const int16_t importThreshold
const int16_t surplusThreshold
const uint8_t relay_pin
constexpr auto get_surplusThreshold() const
Get the surplus threshold which will turns ON the relay.
bool proceed_relay(const int32_t currentAvgPower) const
Proceed with the relay.
constexpr relayOutput(uint8_t _relay_pin, int16_t _surplusThreshold, int16_t _importThreshold, uint16_t _minON, uint16_t _minOFF)
Construct a new relay Config object with custom parameters.
Definition utils_relay.h:82
bool try_turnOFF() const
Turn OFF the relay if the 'time' condition is met.
constexpr relayOutput(const uint8_t _relay_pin)
Construct a new relay Config object with default parameters.
Definition utils_relay.h:50
uint16_t duration
const uint16_t minON
constexpr auto get_importThreshold() const
Get the import threshold which will turns OFF the relay.
void printRelayConfiguration(uint8_t idx) const
Print the configuration of the current relay-diversion.
constexpr relayOutput(uint8_t _relay_pin, int16_t _surplusThreshold, int16_t _importThreshold)
Construct a new relay Config object with default/custom parameters.
Definition utils_relay.h:65
auto isRelayON() const
Return the state.
constexpr auto get_pin() const
Get the control pin of the relay.
Definition utils_relay.h:92
const uint16_t minOFF
void inc_duration() const
Increment the duration of the current state.
bool try_turnON() const
Turn ON the relay if the 'time' condition is met.
constexpr auto get_minON() const
Get the minimum ON-time in seconds.
Basic configuration values to be set by the end-user.
constexpr uint8_t DATALOG_PERIOD_IN_SECONDS
Some macro for the Serial Output and Debugging.
#define DBUGLN(...)
Definition debug.h:97
uint8_t i
This file implements an Exponentially Weighted Moving Average template class.
Some useful but missing stl functions templates.
Some basics classes/types.
Some utility functions for pins manipulation.
constexpr void setPinON(uint8_t pin)
Set the Pin state to ON for the specified pin.
Definition utils_pins.h:128
constexpr void setPinOFF(uint8_t pin)
Set the Pin state to OFF for the specified pin.
Definition utils_pins.h:160
constexpr uint8_t unused_pin
Definition utils_pins.h:17
RelayEngine(const relayOutput(&)[N]) -> RelayEngine< N, 10 >