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
167 bool proceed_relay(const int32_t currentAvgPower, uint16_t& overrideBitmask) const
168 {
169 const bool isOverrideActive = bit_read(overrideBitmask, relay_pin);
170
171 // To avoid changing sign, surplus is a negative value
172 // Turn ON if surplus threshold is met OR if override is active
173 if (currentAvgPower < surplusThreshold || isOverrideActive)
174 {
175 bit_clear(overrideBitmask, relay_pin); // Clear override bit if it was set
176 return try_turnON();
177 }
178
179 // Handle both positive and negative import thresholds
180 if (importThreshold >= 0)
181 {
182 // Positive threshold: turn OFF when importing > threshold (normal mode)
183 if (currentAvgPower > importThreshold)
184 {
185 return try_turnOFF();
186 }
187 }
188 else
189 {
190 // Negative threshold: turn OFF when surplus < abs(threshold) (battery mode)
191 if (currentAvgPower > importThreshold) // importThreshold is negative, so this checks surplus < abs(threshold)
192 {
193 return try_turnOFF();
194 }
195 }
196
197 return false;
198 }
199
204 void printRelayConfiguration(uint8_t idx) const
205 {
206 Serial.print(F("\tRelay configuration: #"));
207 Serial.println(idx + 1);
208
209 Serial.print(F("\t\tPin is "));
210 Serial.println(get_pin());
211
212 Serial.print(F("\t\tSurplus threshold: "));
213 Serial.println(get_surplusThreshold());
214
215 Serial.print(F("\t\tImport threshold: "));
216 Serial.print(get_importThreshold());
217 if (get_importThreshold() >= 0)
218 {
219 Serial.println(F(" (import mode)"));
220 }
221 else
222 {
223 Serial.print(F(" (surplus mode: turn OFF when surplus < "));
224 Serial.print(-get_importThreshold());
225 Serial.println(F("W)"));
226 }
227
228 Serial.print(F("\t\tMinimum working time in minutes: "));
229 Serial.println(get_minON() / 60);
230
231 Serial.print(F("\t\tMinimum stop time in minutes: "));
232 Serial.println(get_minOFF() / 60);
233 }
234
235private:
241 bool try_turnON() const
242 {
243 if (relayIsON || duration < minOFF)
244 {
245 return false;
246 }
247
249
250 DBUGLN(F("Relay turned ON!"));
251
252 relayIsON = true;
253 duration = 0;
254
255 return true;
256 }
257
263 bool try_turnOFF() const
264 {
265 if (!relayIsON || duration < minON)
266 {
267 return false;
268 }
269
271
272 DBUGLN(F("Relay turned OFF!"));
273
274 relayIsON = false;
275 duration = 0;
276
277 return true;
278 }
279
280private:
281 const uint8_t relay_pin{ unused_pin };
282 const int16_t surplusThreshold{ -1000 };
283 const int16_t importThreshold{ 200 };
284 const uint16_t minON{ 5 * 60 };
285 const uint16_t minOFF{ 5 * 60 };
286
287 mutable uint16_t duration{ 0 };
288 mutable bool relayIsON{ false };
289};
290
313template< uint8_t N, uint8_t D = 10 >
315{
316public:
321 explicit constexpr RelayEngine(const relayOutput (&ref)[N])
322 : relay(ref)
323 {
324 }
325
332 constexpr RelayEngine(integral_constant< uint8_t, D > /* ic */, const relayOutput (&ref)[N])
333 : relay(ref)
334 {
335 }
336
342 constexpr auto size() const
343 {
344 return N;
345 }
346
353 constexpr const auto& get_relay(uint8_t idx) const
354 {
355 return relay[idx];
356 }
357
363 inline static auto get_average()
364 {
365 return ewma_average.getAverageT(); // Use TEMA for better cloud immunity
366 }
367
373 inline static void update_average(int16_t currentPower)
374 {
375 ewma_average.addValue(currentPower);
376 }
377
384#if defined(__DOXYGEN__)
385 void inc_duration() const;
386#else
387 void inc_duration() const __attribute__((optimize("-O3")));
388#endif
389
400 void proceed_relays(uint16_t& overrideBitmask) const
401 {
402 if (settle_change != 0)
403 {
404 // A relay has been toggle less than a minute ago, wait until changes take effect
405 return;
406 }
407
408 if (ewma_average.getAverageT() > 0)
409 {
410 // Currently importing, try to turn OFF some relays
411 uint8_t idx{ N };
412 do
413 {
414 if (relay[--idx].proceed_relay(ewma_average.getAverageT(), overrideBitmask))
415 {
416 settle_change = 60;
417 return;
418 }
419 } while (idx);
420 }
421 else
422 {
423 // Remaining surplus, try to turn ON more relays
424 uint8_t idx{ 0 };
425 do
426 {
427 if (relay[idx].proceed_relay(ewma_average.getAverageT(), overrideBitmask))
428 {
429 settle_change = 60;
430 return;
431 }
432 } while (++idx < N);
433 }
434 }
435
443 {
444 Serial.println(F("*** Relay(s) configuration ***"));
445 Serial.print(F("\tSliding average: "));
446 Serial.println(D);
447
448 for (uint8_t i = 0; i < N; ++i)
449 {
450 relay[i].printRelayConfiguration(i);
451 }
452 }
453
454private:
456
457 mutable uint8_t settle_change{ 60 };
458
460};
461
462template< uint8_t N, uint8_t D > void RelayEngine< N, D >::inc_duration() const
463{
464 uint8_t idx{ N };
465 do
466 {
467 relay[--idx].inc_duration();
468 } while (idx);
469
470 if (settle_change)
471 {
473 }
474}
475
476// Deduction guides for automatic template parameter deduction
477template< uint8_t N >
479
480template< uint8_t N, uint8_t D >
482
483#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
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 const auto & get_relay(uint8_t idx) const
Get the relay object.
constexpr RelayEngine(const relayOutput(&ref)[N])
Construct a list of relays.
constexpr auto size() const
Get the number of relays.
void proceed_relays(uint16_t &overrideBitmask) const
Proceed all relays in increasing order (surplus) or decreasing order (import).
void printRelayEngineConfiguration() const
Print the configuration of each relay.
constexpr RelayEngine(integral_constant< uint8_t, D >, const relayOutput(&ref)[N])
Construct a list of relays with a custom sliding average.
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, uint16_t &overrideBitmask) 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 uint8_t bit_read(const T &_src, const uint8_t bit)
Read the specified bit.
Definition utils_pins.h:67
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 bit_clear(T &_dest, const uint8_t bit)
Clear the specified bit.
Definition utils_pins.h:80
constexpr uint8_t unused_pin
Definition utils_pins.h:17
RelayEngine(const relayOutput(&)[N]) -> RelayEngine< N, 10 >