3-phase PV router
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1
12static_assert(__cplusplus >= 201703L, "**** Please define 'gnu++17' in 'platform.txt' ! ****");
13static_assert(__cplusplus >= 201703L, "See also : https://github.com/FredM67/PVRouter-3-phase/blob/main/Mk2_3phase_RFdatalog_temp/Readme.md");
14
15#include <Arduino.h> // may not be needed, but it's probably a good idea to include this
16
17#include "config.h"
18
19// In this sketch, the ADC is free-running with a cycle time of ~104uS.
20
21//--------------------------------------------------------------------------------------------------
22#ifdef EMONESP
23#undef SERIALPRINT // Must not corrupt serial output to emonHub with 'human-friendly' printout
24#undef SERIALOUT
25#endif
26
27#ifdef SERIALOUT
28#undef EMONESP
29#undef SERIALPRINT // Must not corrupt serial output to emonHub with 'human-friendly' printout
30#undef ENABLE_DEBUG
31#endif
32//--------------------------------------------------------------------------------------------------
33
34#include "calibration.h"
35#include "processing.h"
36#include "types.h"
37#include "utils.h"
38#include "utils_relay.h"
39#include "validation.h"
40
41// -------------- general global variables -----------------
42//
43// Some of these variables are used in multiple blocks so cannot be static.
44// For integer maths, some variables need to be 'int32_t'
45//
46
77ISR(ADC_vect)
78{
79 static uint8_t sample_index{ 0 };
80 int16_t rawSample;
81
82 switch (sample_index)
83 {
84 case 0:
85 rawSample = ADC; // store the ADC value (this one is for Voltage L1)
86 ADMUX = bit(REFS0) + sensorV[1]; // the conversion for I1 is already under way
87 ++sample_index; // increment the control flag
88 //
89 processVoltageRawSample(0, rawSample);
90 break;
91 case 1:
92 rawSample = ADC; // store the ADC value (this one is for Current L1)
93 ADMUX = bit(REFS0) + sensorI[1]; // the conversion for V2 is already under way
94 ++sample_index; // increment the control flag
95 //
96 processCurrentRawSample(0, rawSample);
97 break;
98 case 2:
99 rawSample = ADC; // store the ADC value (this one is for Voltage L2)
100 ADMUX = bit(REFS0) + sensorV[2]; // the conversion for I2 is already under way
101 ++sample_index; // increment the control flag
102 //
103 processVoltageRawSample(1, rawSample);
104 break;
105 case 3:
106 rawSample = ADC; // store the ADC value (this one is for Current L2)
107 ADMUX = bit(REFS0) + sensorI[2]; // the conversion for V3 is already under way
108 ++sample_index; // increment the control flag
109 //
110 processCurrentRawSample(1, rawSample);
111 break;
112 case 4:
113 rawSample = ADC; // store the ADC value (this one is for Voltage L3)
114 ADMUX = bit(REFS0) + sensorV[0]; // the conversion for I3 is already under way
115 ++sample_index; // increment the control flag
116 //
117 processVoltageRawSample(2, rawSample);
118 break;
119 case 5:
120 rawSample = ADC; // store the ADC value (this one is for Current L3)
121 ADMUX = bit(REFS0) + sensorI[0]; // the conversion for V1 is already under way
122 sample_index = 0; // reset the control flag
123 //
124 processCurrentRawSample(2, rawSample);
125 break;
126 default:
127 sample_index = 0; // to prevent lockup (should never get here)
128 }
129} // end of ISR
130
138{
139 if constexpr (OVERRIDE_PIN_PRESENT)
140 {
141 const auto pinState{ getPinState(forcePin) };
142
143#ifdef ENABLE_DEBUG
144 static uint8_t previousState{ HIGH };
145 if (previousState != pinState)
146 {
147 DBUGLN(!pinState ? F("Trigger override!") : F("End override!"));
148 }
149
150 previousState = pinState;
151#endif
152
153 for (auto &bOverrideLoad : b_overrideLoadOn)
154 {
155 bOverrideLoad = !pinState;
156 }
157
158 return !pinState;
159 }
160 else
161 {
162 return false;
163 }
164}
165
171{
172 if constexpr (DIVERSION_PIN_PRESENT)
173 {
174 const auto pinState{ getPinState(diversionPin) };
175
176#ifdef ENABLE_DEBUG
177 static auto previousState{ HIGH };
178 if (previousState != pinState)
179 {
180 DBUGLN(!pinState ? F("Trigger diversion OFF!") : F("End diversion OFF!"));
181 }
182
183 previousState = pinState;
184#endif
185
186 b_diversionOff = !pinState;
187 }
188}
189
195{
196 b_reOrderLoads = true;
197
198 // waits till the priorities have been rotated from inside the ISR
199 do
200 {
201 delay(10);
202 } while (b_reOrderLoads);
203
204 // prints the (new) load priorities
206}
207
215bool proceedLoadPrioritiesAndOverridingDualTariff(const int16_t currentTemperature_x100)
216{
217 constexpr int16_t iTemperatureThreshold_x100{ iTemperatureThreshold * 100 };
218 static bool pinOffPeakState{ HIGH };
219 const auto pinNewState{ getPinState(dualTariffPin) };
220
221 if (pinOffPeakState && !pinNewState)
222 {
223 // we start off-peak period
224 DBUGLN(F("Change to off-peak period!"));
225
226 ul_TimeOffPeak = millis();
227
228 if constexpr (PRIORITY_ROTATION == RotationModes::AUTO)
229 {
231 }
232 }
233 else
234 {
235 const auto ulElapsedTime{ static_cast< uint32_t >(millis() - ul_TimeOffPeak) };
236 const auto pinState{ getPinState(forcePin) };
237
238 for (uint8_t i = 0; i < NO_OF_DUMPLOADS; ++i)
239 {
240 // for each load, if we're inside off-peak period and within the 'force period', trigger the ISR to turn the load ON
241 if (!pinOffPeakState && !pinNewState && (ulElapsedTime >= rg_OffsetForce[i][0]) && (ulElapsedTime < rg_OffsetForce[i][1]))
242 {
243 b_overrideLoadOn[i] = !pinState || (currentTemperature_x100 <= iTemperatureThreshold_x100);
244 }
245 else
246 {
247 b_overrideLoadOn[i] = !pinState;
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
271bool proceedLoadPrioritiesAndOverriding(const int16_t currentTemperature_x100)
272{
273 if constexpr (DUAL_TARIFF)
274 {
275 return proceedLoadPrioritiesAndOverridingDualTariff(currentTemperature_x100);
276 }
277
278 if constexpr (EMONESP_CONTROL)
279 {
280 static uint8_t pinRotationState{ HIGH };
281 const auto pinNewState{ getPinState(rotationPin) };
282
283 if (pinRotationState && !pinNewState)
284 {
285 DBUGLN(F("Trigger rotation!"));
286
288 }
289 pinRotationState = pinNewState;
290 }
291 else if constexpr (PRIORITY_ROTATION == RotationModes::AUTO)
292 {
294 {
296
298 }
299 }
300
301 if constexpr (OVERRIDE_PIN_PRESENT)
302 {
303 const auto pinState{ getPinState(forcePin) };
304
305 for (auto &bOverrideLoad : b_overrideLoadOn)
306 {
307 bOverrideLoad = !pinState;
308 }
309 }
310
311 return false;
312}
313
320void setup()
321{
322 delay(initialDelay); // allows time to open the Serial Monitor
323
324 DEBUG_PORT.begin(9600);
325 Serial.begin(9600); // initialize Serial interface, Do NOT set greater than 9600
326
327 // On start, always display config info in the serial monitor
329
330 // initializes all loads to OFF at startup
332
334
336
337 if constexpr (TEMP_SENSOR_PRESENT)
338 {
340 }
341
342 DBUG(F(">>free RAM = "));
343 DBUGLN(freeRam()); // a useful value to keep an eye on
344 DBUGLN(F("----"));
345}
346
353void loop()
354{
355 static uint8_t perSecondTimer{ 0 };
356 static bool bOffPeak{ false };
357 static int16_t iTemperature_x100{ 0 };
358
359 if (b_newMainsCycle) // flag is set after every pair of ADC conversions
360 {
361 b_newMainsCycle = false; // reset the flag
362 ++perSecondTimer;
363
364 if (perSecondTimer >= SUPPLY_FREQUENCY)
365 {
366 perSecondTimer = 0;
367
368 if constexpr (WATCHDOG_PIN_PRESENT)
369 {
371 }
372
374
375 if (!forceFullPower())
376 {
377 bOffPeak = proceedLoadPrioritiesAndOverriding(iTemperature_x100); // called every second
378 }
379
380 if constexpr (RELAY_DIVERSION)
381 {
384 }
385 }
386 }
387
389 {
390 b_datalogEventPending = false;
391
392 tx_data.power = 0;
393 for (uint8_t phase = 0; phase < NO_OF_PHASES; ++phase)
394 {
396 tx_data.power_L[phase] *= -1;
397
398 tx_data.power += tx_data.power_L[phase];
399
400 if constexpr (DATALOG_PERIOD_IN_SECONDS > 10)
401 {
402 tx_data.Vrms_L_x100[phase] = static_cast< int32_t >((100 << 2) * f_voltageCal[phase] * sqrt(copyOf_sum_Vsquared[phase] / copyOf_sampleSetsDuringThisDatalogPeriod));
403 }
404 else
405 {
406 tx_data.Vrms_L_x100[phase] = static_cast< int32_t >(100 * f_voltageCal[phase] * sqrt(copyOf_sum_Vsquared[phase] / copyOf_sampleSetsDuringThisDatalogPeriod));
407 }
408 }
409
410 if constexpr (RELAY_DIVERSION)
411 {
413 }
414
415 if constexpr (TEMP_SENSOR_PRESENT)
416 {
417 uint8_t idx{ temperatureSensing.get_size() };
418 do
419 {
420 auto tmp = temperatureSensing.readTemperature(--idx);
421
422 // if read temperature is 85 and the delta with previous is greater than 5, skip the value
423 if (8500 == tmp && (abs(tmp - tx_data.temperature_x100[idx]) > 500))
424 {
426 }
427
428 tx_data.temperature_x100[idx] = tmp;
429 } while (idx);
430
431 temperatureSensing.requestTemperatures(); // for use next time around
432 }
433
434 sendResults(bOffPeak);
435 }
436} // 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
void proceed_relays() const
Proceed all relays in increasing order (surplus) or decreasing order (import)
Definition: utils_relay.h:328
static void update_average(int16_t currentPower)
Update the sliding average.
Definition: utils_relay.h:309
void inc_duration() const
Increment the duration's state of each relay.
Definition: utils_relay.h:402
constexpr auto get_size() const
Get the number of sensors.
Definition: utils_temp.h:94
int16_t readTemperature(const uint8_t idx)
Read temperature of a specific device.
Definition: utils_temp.h:115
void requestTemperatures()
Request temperature for all sensors.
Definition: utils_temp.h:68
void initTemperatureSensors()
Initialize the Dallas sensors.
Definition: utils_temp.h:81
Configuration values to be set by the end-user.
constexpr bool RELAY_DIVERSION
Definition: config.h:53
constexpr bool OVERRIDE_PIN_PRESENT
Definition: config.h:49
constexpr uint8_t dualTariffPin
Definition: config.h:78
constexpr TemperatureSensing temperatureSensing
Definition: config.h:91
constexpr uint8_t forcePin
Definition: config.h:81
constexpr RelayEngine relays
Definition: config.h:84
constexpr uint32_t ROTATION_AFTER_CYCLES
Definition: config.h:98
constexpr bool DUAL_TARIFF
Definition: config.h:54
constexpr uint8_t diversionPin
Definition: config.h:79
constexpr bool EMONESP_CONTROL
Definition: config.h:46
constexpr uint8_t NO_OF_DUMPLOADS
Definition: config.h:38
constexpr int16_t iTemperatureThreshold
Definition: config.h:89
constexpr bool WATCHDOG_PIN_PRESENT
Definition: config.h:52
constexpr bool DIVERSION_PIN_PRESENT
Definition: config.h:47
constexpr uint8_t rotationPin
Definition: config.h:80
constexpr uint8_t watchDogPin
Definition: config.h:82
constexpr uint8_t DATALOG_PERIOD_IN_SECONDS
Definition: config_system.h:31
constexpr uint8_t NO_OF_PHASES
Definition: config_system.h:19
constexpr uint8_t SUPPLY_FREQUENCY
Definition: config_system.h:27
constexpr int16_t DEVICE_DISCONNECTED_RAW
Definition: constants.h:25
#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
ISR(ADC_vect)
Interrupt Service Routine - Interrupt-Driven Analog Conversion.
Definition: main.cpp:77
void processVoltageRawSample(const uint8_t phase, const int16_t rawSample)
Process the current voltage raw sample for the specific phase.
Definition: processing.cpp:780
void processCurrentRawSample(const uint8_t phase, const int16_t rawSample)
Process the calculation for the actual current raw sample for the specific phase.
Definition: processing.cpp:299
void checkDiversionOnOff()
Check the diversion state.
Definition: main.cpp:170
void setup()
Called once during startup.
Definition: main.cpp:320
bool forceFullPower()
This function set all 3 loads to full power.
Definition: main.cpp:137
bool proceedLoadPrioritiesAndOverridingDualTariff(const int16_t currentTemperature_x100)
Proceed load priority in combination with dual tariff.
Definition: main.cpp:215
void proceedRotation()
Proceed load priority rotation.
Definition: main.cpp:194
bool proceedLoadPrioritiesAndOverriding(const int16_t currentTemperature_x100)
This function changes the value of the load priorities.
Definition: main.cpp:271
void loop()
Main processor.
Definition: main.cpp:353
void initializeOptionalPins()
Initializes the optional pins.
Definition: processing.cpp:143
void initializeProcessing()
Initializes the ports and load states for processing.
Definition: processing.cpp:91
Public functions/variables of processing engine.
volatile bool b_reOrderLoads
Definition: processing.h:34
constexpr uint8_t sensorV[NO_OF_PHASES]
Definition: processing.h:18
constexpr uint8_t sensorI[NO_OF_PHASES]
Definition: processing.h:19
volatile int32_t copyOf_sumP_atSupplyPoint[NO_OF_PHASES]
Definition: processing.h:40
volatile int32_t copyOf_sum_Vsquared[NO_OF_PHASES]
Definition: processing.h:41
volatile uint16_t copyOf_sampleSetsDuringThisDatalogPeriod
Definition: processing.h:44
volatile bool b_overrideLoadOn[NO_OF_DUMPLOADS]
Definition: processing.h:33
volatile bool b_newMainsCycle
Definition: processing.h:32
volatile bool b_datalogEventPending
Definition: processing.h:31
volatile uint32_t absenceOfDivertedEnergyCount
Definition: processing.h:30
volatile bool b_diversionOff
Definition: processing.h:35
constexpr uint16_t initialDelay
Definition: processing.h:26
PayloadTx_struct< NO_OF_PHASES > tx_data
Definition: processing.h:50
uint8_t i
Definition: test_main.cpp:94
Some basics classes/types.
Some utility functions.
void printConfiguration()
Print the configuration during start.
Definition: utils.h:27
int freeRam()
Get the available RAM during setup.
Definition: utils.h:372
void sendResults(bool bOffPeak)
Prints data logs to the Serial output in text or json format.
Definition: utils.h:321
void logLoadPriorities()
Prints the load priorities to the Serial output.
Definition: utils.h:353
constexpr void togglePin(const uint8_t pin)
Toggle the specified pin.
Definition: utils_pins.h:81
bool getPinState(const uint8_t pin)
Get the Pin State.
Definition: utils_pins.h:174
Some utility functions for the relay output feature.
constexpr bool TEMP_SENSOR_PRESENT
Definition: utils_temp.h:23
Compile-time validations.