3-phase PV router
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1
23
24static_assert(__cplusplus >= 201703L, "**** Please define 'gnu++17' in 'platform.txt' ! ****");
25static_assert(__cplusplus >= 201703L, "See also : https://github.com/FredM67/PVRouter-3-phase/blob/main/Mk2_3phase_RFdatalog_temp/Readme.md");
26
27#include <Arduino.h> // may not be needed, but it's probably a good idea to include this
28
29#include "config.h"
30
31// In this sketch, the ADC is free-running with a cycle time of ~104uS.
32
33#include "calibration.h"
34#include "processing.h"
35#include "shared_var.h"
36#include "types.h"
37#include "utils.h"
38#include "utils_relay.h"
39#include "validation.h"
40#include "main.h"
41
42// -------------- general global variables -----------------
43//
44// Some of these variables are used in multiple blocks so cannot be static.
45// For integer maths, some variables need to be 'int32_t'
46//
47
65uint16_t getDualTariffForcingBitmask(const int16_t currentTemperature_x100)
66{
67 if constexpr (!DUAL_TARIFF)
68 {
69 return 0;
70 }
71
72 constexpr int16_t iTemperatureThreshold_x100{ iTemperatureThreshold * 100 };
73 static bool pinOffPeakState{ HIGH };
74 const auto pinNewState{ getPinState(dualTariffPin) };
75
76 // Return early if we're not in off-peak period
77 if (pinOffPeakState || pinNewState)
78 {
79 return 0;
80 }
81
82 // We're in off-peak period - check forcing time windows
83 const auto ulElapsedTime{ static_cast< uint32_t >(millis() - ul_TimeOffPeak) };
84
85 uint16_t forcingBitmask = 0;
86 uint8_t i{ NO_OF_DUMPLOADS };
87 do
88 {
89 --i;
90 // Skip if not within the 'force period'
91 if ((ulElapsedTime < rg_OffsetForce[i][0]) || (ulElapsedTime >= rg_OffsetForce[i][1]))
92 {
93 continue;
94 }
95
96 // Force load ON if temperature condition is met
97 if (currentTemperature_x100 <= iTemperatureThreshold_x100)
98 {
99 bit_set(forcingBitmask, physicalLoadPin[i]);
100 }
101 } while (i);
102
103 return forcingBitmask;
104}
105
125uint16_t getOverrideBitmask(const int16_t currentTemperature_x100)
126{
127 uint16_t overrideBitmask = 0;
128
129 // Add external override pins
130 if constexpr (OVERRIDE_PIN_PRESENT)
131 {
132 // Check each configured override pin and combine their bitmasks
133 uint8_t i{ overridePins.size() };
134 do
135 {
136 --i;
137 const uint8_t pin = overridePins.getPin(i);
138 const auto pinState = getPinState(pin);
139
140 if (!pinState) // Pin is LOW (active)
141 {
142 overrideBitmask |= overridePins.getBitmask(i);
143 }
144 } while (i);
145 }
146
147 // Add dual tariff forcing - OR operation handles precedence automatically
148 // If a bit is already set by external override, OR won't change it
149 // If a bit is not set, OR will apply dual tariff forcing
150 overrideBitmask |= getDualTariffForcingBitmask(currentTemperature_x100);
151
152 return overrideBitmask;
153}
154
170{
171 if constexpr (DIVERSION_PIN_PRESENT)
172 {
173 const auto pinState{ getPinState(diversionPin) };
174
175#ifdef ENABLE_DEBUG
176 static auto previousState{ HIGH };
177 if (previousState != pinState)
178 {
179 DBUGLN(!pinState ? F("Trigger diversion OFF!") : F("End diversion OFF!"));
180 }
181
182 previousState = pinState;
183#endif
184
186 }
187}
188
203{
205
206 // waits till the priorities have been rotated from inside the ISR
207 do
208 {
209 delay(10);
210 } while (Shared::b_reOrderLoads);
211
212 // prints the (new) load priorities
214}
215
234{
235 static bool pinOffPeakState{ HIGH };
236 const auto pinNewState{ getPinState(dualTariffPin) };
237
238 if (pinOffPeakState && !pinNewState)
239 {
240 // we start off-peak period
241 DBUGLN(F("Change to off-peak period!"));
242
243 ul_TimeOffPeak = millis();
244
245 if constexpr (PRIORITY_ROTATION == RotationModes::AUTO)
246 {
248 }
249 }
250
251 // end of off-peak period
252 if (!pinOffPeakState && pinNewState)
253 {
254 DBUGLN(F("Change to peak period!"));
255 }
256
257 pinOffPeakState = pinNewState;
258
259 return (LOW == pinOffPeakState);
260}
261
281bool proceedLoadPriorities(const int16_t &currentTemperature_x100)
282{
283 // Suppress unused parameter warning when DUAL_TARIFF is disabled
284 (void)currentTemperature_x100;
285
286 if constexpr (DUAL_TARIFF)
287 {
288 return proceedDualTariffLogic();
289 }
290
291 if constexpr ((PRIORITY_ROTATION == RotationModes::PIN) || (EMONESP_CONTROL))
292 {
293 static uint8_t pinRotationState{ HIGH };
294 const auto pinNewState{ getPinState(rotationPin) };
295
296 if (pinRotationState && !pinNewState)
297 {
298 DBUGLN(F("Trigger rotation!"));
299
301 }
302 pinRotationState = pinNewState;
303 }
304 else if constexpr (PRIORITY_ROTATION == RotationModes::AUTO)
305 {
307 {
309
311 }
312 }
313
314 return false;
315}
316
334void setup()
335{
336 delay(initialDelay); // allows time to open the Serial Monitor
337
338 DEBUG_PORT.begin(9600);
339 Serial.begin(9600, SERIAL_OUTPUT_TYPE == SerialOutputType::IoT ? SERIAL_7E1 : SERIAL_8N1); // initialize Serial interface, Do NOT set greater than 9600
340
341 // On start, always display config info in the serial monitor
343
344 // initializes all loads to OFF at startup
346
348
349 if constexpr (TEMP_SENSOR_PRESENT)
350 {
351 temperatureSensing.initTemperatureSensors();
352 }
353
354 DBUG(F(">>free RAM = "));
355 DBUGLN(freeRam()); // a useful value to keep an eye on
356 DBUGLN(F("----"));
357}
358
373{
374 tx_data.power = 0;
375 uint8_t phase{ NO_OF_PHASES };
376 do
377 {
378 --phase;
380 tx_data.power_L[phase] *= -1;
381
382 tx_data.power += tx_data.power_L[phase];
383
384 if constexpr (DATALOG_PERIOD_IN_SECONDS > 10)
385 {
386 tx_data.Vrms_L_x100[phase] = static_cast< uint32_t >((100U << 2) * f_voltageCal[phase] * sqrt(Shared::copyOf_sum_Vsquared[phase] / Shared::copyOf_sampleSetsDuringThisDatalogPeriod));
387 }
388 else
389 {
390 tx_data.Vrms_L_x100[phase] = static_cast< uint32_t >(100U * f_voltageCal[phase] * sqrt(Shared::copyOf_sum_Vsquared[phase] / Shared::copyOf_sampleSetsDuringThisDatalogPeriod));
391 }
392 } while (phase);
393}
394
412{
413 uint8_t idx{ temperatureSensing.size() };
414 do
415 {
416 auto tmp = temperatureSensing.readTemperature(--idx);
417
418 // if read temperature is 85 and the delta with previous is greater than 5, skip the value
419 if (8500 == tmp && (abs(tmp - tx_data.temperature_x100[idx]) > 500))
420 {
422 }
423
424 tx_data.temperature_x100[idx] = tmp;
425 } while (idx);
426
427 temperatureSensing.requestTemperatures(); // for use next time around
428}
429
448void handlePerSecondTasks(bool &bOffPeak, int16_t &iTemperature_x100)
449{
450 if constexpr (WATCHDOG_PIN_PRESENT)
451 {
453 }
454
456
457 // Get complete override bitmask atomically (external pins + dual tariff forcing)
458 uint16_t privateOverrideBitmask = getOverrideBitmask(iTemperature_x100);
459
460 if constexpr (RELAY_DIVERSION)
461 {
462 relays.inc_duration();
463 // Pass private bitmask to relay engine, it will filter out relay pins that can be controlled
464 relays.proceed_relays(privateOverrideBitmask);
465 }
466
467 // Copy the filtered bitmask (only triac/load pins) to shared version
468 Shared::overrideBitmask = privateOverrideBitmask;
469
470 // Only process priority logic if no override pins are active
472 {
473 bOffPeak = proceedLoadPriorities(iTemperature_x100);
474 }
475}
476
492void loop()
493{
494 static uint8_t perSecondTimer{ 0 };
495 static bool bOffPeak{ false };
496 static int16_t iTemperature_x100{ 0 };
497
498 if (Shared::b_newMainsCycle) // flag is set after every pair of ADC conversions
499 {
500 Shared::b_newMainsCycle = false; // reset the flag
501 ++perSecondTimer;
502
503 if (perSecondTimer >= SUPPLY_FREQUENCY)
504 {
505 perSecondTimer = 0;
506 handlePerSecondTasks(bOffPeak, iTemperature_x100);
507 }
508 }
509
511 {
513
515
516 if constexpr (RELAY_DIVERSION)
517 {
518 relays.update_average(tx_data.power);
519 }
520
521 if constexpr (TEMP_SENSOR_PRESENT)
522 {
524 }
525
526 sendResults(bOffPeak);
527 }
528} // end of loop()
Calibration values definition.
constexpr float f_voltageCal[NO_OF_PHASES]
Definition calibration.h:51
constexpr float f_powerCal[NO_OF_PHASES]
Definition calibration.h:34
Standard three-phase PVRouter setup with 2 dump loads.
constexpr bool RELAY_DIVERSION
Definition config.h:51
constexpr bool OVERRIDE_PIN_PRESENT
Definition config.h:48
constexpr uint32_t ROTATION_AFTER_SECONDS
Definition config.h:154
constexpr uint8_t dualTariffPin
Definition config.h:96
constexpr TemperatureSensing temperatureSensing
Definition config.h:150
constexpr RelayEngine relays
Definition config.h:126
constexpr uint8_t physicalLoadPin[NO_OF_DUMPLOADS]
Definition config.h:92
constexpr bool DUAL_TARIFF
Definition config.h:52
constexpr uint8_t diversionPin
Definition config.h:97
constexpr OverridePins overridePins
Definition config.h:143
constexpr SerialOutputType SERIAL_OUTPUT_TYPE
Definition config.h:37
constexpr bool EMONESP_CONTROL
Definition config.h:45
constexpr uint8_t NO_OF_DUMPLOADS
Definition config.h:42
constexpr bool TEMP_SENSOR_PRESENT
Definition config.h:53
constexpr int16_t iTemperatureThreshold
Definition config.h:148
constexpr bool WATCHDOG_PIN_PRESENT
Definition config.h:50
constexpr bool DIVERSION_PIN_PRESENT
Definition config.h:46
constexpr uint8_t rotationPin
Definition config.h:98
constexpr uint8_t watchDogPin
Definition config.h:99
constexpr uint8_t DATALOG_PERIOD_IN_SECONDS
constexpr uint8_t NO_OF_PHASES
constexpr uint8_t SUPPLY_FREQUENCY
constexpr int16_t DEVICE_DISCONNECTED_RAW
Definition constants.h:27
#define DBUGLN(...)
Definition debug.h:97
#define DBUG(...)
Definition debug.h:96
uint32_t ul_TimeOffPeak
Definition dualtariff.h:62
constexpr auto rg_OffsetForce
Definition dualtariff.h:64
uint8_t i
uint16_t getDualTariffForcingBitmask(const int16_t currentTemperature_x100)
Calculates the dual tariff forcing bitmask based on current conditions.
Definition main.cpp:65
void updatePowerAndVoltageData()
Updates power and voltage data for all phases.
Definition main.cpp:372
void handlePerSecondTasks(bool &bOffPeak, int16_t &iTemperature_x100)
Handles tasks that need to be executed every second.
Definition main.cpp:448
void checkDiversionOnOff()
Checks and updates the diversion state based on the diversion pin.
Definition main.cpp:169
bool proceedDualTariffLogic()
Handles dual tariff state transitions and priority rotation during off-peak periods.
Definition main.cpp:233
bool proceedLoadPriorities(const int16_t &currentTemperature_x100)
Handles load priority rotation and dual tariff state transitions.
Definition main.cpp:281
uint16_t getOverrideBitmask(const int16_t currentTemperature_x100)
Gets the combined bitmask of all active override pins and dual tariff forcing.
Definition main.cpp:125
void proceedRotation()
Proceeds with load priority rotation.
Definition main.cpp:202
void sendResults(bool bOffPeak)
Prints or sends telemetry data logs based on the selected output format.
Definition utils.h:450
void logLoadPriorities()
Prints the load priorities to the Serial output.
Definition utils.h:491
void loop()
Main processor loop.
Definition main.cpp:492
void setup()
Called once during startup.
Definition main.cpp:334
void printConfiguration()
Print the configuration during startup.
Definition utils.h:47
void initializeProcessing()
Initializes the processing engine, including ports, load states, and ADC setup.
void processTemperatureData()
Processes temperature data from DS18B20 sensors.
Definition main.cpp:411
Header file for the main application.
volatile int32_t copyOf_sum_Vsquared[NO_OF_PHASES]
Definition shared_var.h:22
volatile uint16_t overrideBitmask
Definition shared_var.h:14
volatile bool b_datalogEventPending
Definition shared_var.h:10
volatile bool b_reOrderLoads
Definition shared_var.h:12
volatile uint16_t copyOf_sampleSetsDuringThisDatalogPeriod
Definition shared_var.h:25
volatile int32_t copyOf_sumP_atSupplyPoint[NO_OF_PHASES]
Definition shared_var.h:21
volatile uint16_t absenceOfDivertedEnergyCountInSeconds
Definition shared_var.h:16
volatile bool b_newMainsCycle
Definition shared_var.h:11
volatile bool b_diversionEnabled
Definition shared_var.h:13
#define HIGH
Definition test_main.cpp:6
#define LOW
Definition test_main.cpp:7
Public functions/variables of processing engine.
constexpr uint16_t initialDelay
Definition processing.h:26
PayloadTx_struct< NO_OF_PHASES > tx_data
Definition processing.h:32
Some basics classes/types.
Some utility functions.
int freeRam()
Get the available RAM during setup.
Definition utils.h:516
constexpr void bit_set(T &_dest, const uint8_t bit)
Set the specified bit to 1.
Definition utils_pins.h:54
constexpr bool getPinState(uint8_t pin)
Get the Pin State.
Definition utils_pins.h:194
constexpr void togglePin(uint8_t pin)
Toggle the specified pin.
Definition utils_pins.h:89
Some utility functions for the relay output feature.
Compile-time validations.