3-phase PV router
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
1
11
12#ifndef UTILS_H
13#define UTILS_H
14
15#include <Arduino.h>
16#include <ArduinoJson.h>
17
18#include "FastDivision.h"
19
20#include "calibration.h"
21#include "constants.h"
22#include "dualtariff.h"
23#include "processing.h"
24#include "teleinfo.h"
25
26#include "utils_rf.h"
27#include "utils_temp.h"
28
29#include "version.h"
30
46inline void printConfiguration()
47{
48#ifndef PROJECT_PATH
49#define PROJECT_PATH (__FILE__)
50#endif
51
52#ifndef BRANCH_NAME
53#define BRANCH_NAME ("N/A")
54#endif
55#ifndef COMMIT_HASH
56#define COMMIT_HASH ("N/A")
57#endif
58
59 DBUGLN();
60 DBUGLN();
61 DBUGLN(F("----------------------------------"));
62 DBUG(F("Sketch ID: "));
64
65 DBUG(F("From branch '"));
66 DBUG(F(BRANCH_NAME));
67 DBUG(F("', commit "));
69
70 DBUG(F("Build on "));
71#ifdef CURRENT_TIME
73#else
74 DBUG(F(__DATE__));
75 DBUG(F(" "));
76 DBUGLN(F(__TIME__));
77#endif
78 DBUGLN(F("ADC mode: free-running"));
79
80 DBUGLN(F("Electrical settings"));
81 for (uint8_t phase = 0; phase < NO_OF_PHASES; ++phase)
82 {
83 DBUG(F("\tf_powerCal for L"));
84 DBUG(phase + 1);
85 DBUG(F(" = "));
86 DBUGLN(f_powerCal[phase], 6);
87
88 DBUG(F("\tf_voltageCal, for Vrms_L"));
89 DBUG(phase + 1);
90 DBUG(F(" = "));
91 DBUGLN(f_voltageCal[phase], 5);
92 }
93
94 DBUG(F("\tf_phaseCal for all phases = "));
95 DBUGLN(f_phaseCal);
96
97 DBUG(F("\tExport rate (Watts) = "));
99
100 DBUG(F("\tzero-crossing persistence (sample sets) = "));
102
104
105 DBUG(F("Temperature capability "));
106 if constexpr (TEMP_SENSOR_PRESENT)
107 {
108 DBUGLN(F("is present"));
109 }
110 else
111 {
112 DBUGLN(F("is NOT present"));
113 }
114
115 DBUG(F("Dual-tariff capability "));
116 if constexpr (DUAL_TARIFF)
117 {
118 DBUGLN(F("is present"));
120 }
121 else
122 {
123 DBUGLN(F("is NOT present"));
124 }
125
126 DBUG(F("Load rotation feature "));
127 if constexpr (PRIORITY_ROTATION != RotationModes::OFF)
128 {
129 DBUGLN(F("is present"));
130 }
131 else
132 {
133 DBUGLN(F("is NOT present"));
134 }
135
136 DBUG(F("Relay diversion feature "));
137 if constexpr (RELAY_DIVERSION)
138 {
139 DBUGLN(F("is present"));
140
141 relays.printConfiguration();
142 }
143 else
144 {
145 DBUGLN(F("is NOT present"));
146 }
147
148 DBUG(F("RF capability "));
149#ifdef RF_PRESENT
150 DBUG(F("IS present, Freq = "));
151 if (FREQ == RF12_433MHZ)
152 DBUGLN(F("433 MHz"));
153 else if (FREQ == RF12_868MHZ)
154 DBUGLN(F("868 MHz"));
155 rf12_initialize(nodeID, FREQ, networkGroup); // initialize RF
156#else
157 DBUGLN(F("is NOT present"));
158#endif
159
160 DBUG(F("Datalogging capability "));
162 {
163 DBUGLN(F("in Human-readable format"));
164 }
165 else if constexpr (SERIAL_OUTPUT_TYPE == SerialOutputType::IoT)
166 {
167 DBUGLN(F("in IoT format"));
168 }
169 else if constexpr (SERIAL_OUTPUT_TYPE == SerialOutputType::EmonCMS)
170 {
171 DBUGLN(F("in EmonCMS format"));
172 }
173 else
174 {
175 DBUGLN(F("is NOT present"));
176 }
177}
178
195inline void printForEmonCMS(const bool bOffPeak)
196{
197 uint8_t idx{ 0 };
198
199 // Total mean power over a data logging period
200 Serial.print(F("P:"));
201 Serial.print(tx_data.power);
202
203 // Mean power for each phase over a data logging period
204 for (idx = 0; idx < NO_OF_PHASES; ++idx)
205 {
206 Serial.print(F(",P"));
207 Serial.print(idx + 1);
208 Serial.print(F(":"));
209 Serial.print(tx_data.power_L[idx]);
210 }
211 // Mean power for each load over a data logging period (in %)
212 for (idx = 0; idx < NO_OF_DUMPLOADS; ++idx)
213 {
214 Serial.print(F(",L"));
215 Serial.print(idx + 1);
216 Serial.print(F(":"));
217 Serial.print(copyOf_countLoadON[idx] * 100 * invDATALOG_PERIOD_IN_MAINS_CYCLES);
218 }
219
220 if constexpr (TEMP_SENSOR_PRESENT)
221 { // Current temperature
222 for (idx = 0; idx < temperatureSensing.get_size(); ++idx)
223 {
224 if ((OUTOFRANGE_TEMPERATURE == tx_data.temperature_x100[idx])
225 || (DEVICE_DISCONNECTED_RAW == tx_data.temperature_x100[idx]))
226 {
227 continue;
228 }
229
230 Serial.print(F(",T"));
231 Serial.print(idx + 1);
232 Serial.print(F(":"));
233 Serial.print(tx_data.temperature_x100[idx] * 0.01F);
234 }
235 }
236
237 if constexpr (DUAL_TARIFF)
238 {
239 // Current tariff
240 Serial.print(F(",T:"));
241 Serial.print(bOffPeak ? "low" : "high");
242 }
243 Serial.println(F(""));
244}
245
260{
261 uint8_t phase{ 0 };
262
264 Serial.print(F(", P:"));
265 Serial.print(tx_data.power);
266
267 if constexpr (RELAY_DIVERSION)
268 {
269 Serial.print(F("/"));
270 Serial.print(relays.get_average());
271 }
272
273 for (phase = 0; phase < NO_OF_PHASES; ++phase)
274 {
275 Serial.print(F(", P"));
276 Serial.print(phase + 1);
277 Serial.print(F(":"));
278 Serial.print(tx_data.power_L[phase]);
279 }
280 for (phase = 0; phase < NO_OF_PHASES; ++phase)
281 {
282 Serial.print(F(", V"));
283 Serial.print(phase + 1);
284 Serial.print(F(":"));
285 Serial.print((float)tx_data.Vrms_L_x100[phase] * 0.01F);
286 }
287
288 if constexpr (TEMP_SENSOR_PRESENT)
289 {
290 for (uint8_t idx = 0; idx < temperatureSensing.get_size(); ++idx)
291 {
292 if ((OUTOFRANGE_TEMPERATURE == tx_data.temperature_x100[idx])
293 || (DEVICE_DISCONNECTED_RAW == tx_data.temperature_x100[idx]))
294 {
295 continue;
296 }
297
298 Serial.print(F(", T"));
299 Serial.print(idx + 1);
300 Serial.print(F(":"));
301 Serial.print((float)tx_data.temperature_x100[idx] * 0.01F);
302 }
303 }
304
305 Serial.print(F(", (minSampleSets/MC "));
307 Serial.print(F(", #ofSampleSets "));
309#ifndef DUAL_TARIFF
310 if constexpr (PRIORITY_ROTATION != RotationModes::OFF)
311 {
312 Serial.print(F(", NoED "));
313 Serial.print(absenceOfDivertedEnergyCount);
314 }
315#endif // DUAL_TARIFF
316 Serial.println(F(")"));
317}
318
343{
344 static TeleInfo teleInfo;
345 uint8_t idx = 0;
346
347 teleInfo.startFrame(); // Start a new telemetry frame
348
349 teleInfo.send("P", tx_data.power); // Send power grid data
350
351 if constexpr (RELAY_DIVERSION)
352 {
353 teleInfo.send("R", static_cast< int16_t >(relays.get_average())); // Send relay average if diversion is enabled
354
355 idx = 0;
356 do
357 {
358 teleInfo.send("R", relays.get_relay(idx).isRelayON()); // Send diverted energy count for each relay
359 } while (++idx < relays.get_size());
360 }
361
362 idx = 0;
363 do
364 {
365 teleInfo.send("V", tx_data.Vrms_L_x100[idx], idx + 1); // Send voltage for each phase
366 } while (++idx < NO_OF_PHASES);
367
368 idx = 0;
369 do
370 {
371 teleInfo.send("L", copyOf_countLoadON[idx] * 100 * invDATALOG_PERIOD_IN_MAINS_CYCLES, idx + 1); // Send load ON count for each load
372 } while (++idx < NO_OF_DUMPLOADS);
373
374 if constexpr (TEMP_SENSOR_PRESENT)
375 {
376 for (uint8_t idx = 0; idx < temperatureSensing.get_size(); ++idx)
377 {
378 if ((OUTOFRANGE_TEMPERATURE == tx_data.temperature_x100[idx])
379 || (DEVICE_DISCONNECTED_RAW == tx_data.temperature_x100[idx]))
380 {
381 continue; // Skip invalid temperature readings
382 }
383 teleInfo.send("T", tx_data.temperature_x100[idx], idx + 1); // Send temperature
384 }
385 }
386
387 teleInfo.send("N", static_cast< int16_t >(absenceOfDivertedEnergyCount)); // Send absence of diverted energy count for 50Hz
388
391
392 teleInfo.endFrame(); // Finalize and send the telemetry frame
393}
394
412inline void sendResults(bool bOffPeak)
413{
414 static bool startup{ true };
415
416 if (startup)
417 {
418 startup = false;
419 return; // reject the first datalogging which is incomplete !
420 }
421
422#ifdef RF_PRESENT
423 send_rf_data(); // *SEND RF DATA*
424#endif
425
427 {
429 }
430 else if constexpr (SERIAL_OUTPUT_TYPE == SerialOutputType::IoT)
431 {
433 }
434 else if constexpr (SERIAL_OUTPUT_TYPE == SerialOutputType::EmonCMS)
435 {
436 printForEmonCMS(bOffPeak);
437 }
438}
439
453inline void logLoadPriorities()
454{
455#ifdef ENABLE_DEBUG
456
457 DBUGLN(F("Load Priorities: "));
458 for (const auto& loadPrioAndState : loadPrioritiesAndState)
459 {
460 DBUG(F("\tload "));
461 DBUGLN(loadPrioAndState);
462 }
463
464#endif
465}
466
478inline int freeRam()
479{
480 extern int __heap_start, *__brkval;
481 int v;
482 return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
483}
484
485#endif // UTILS_H
Calibration values definition.
A class for managing and sending telemetry information in a structured frame format.
Definition teleinfo.h:143
void endFrame()
Finalizes the frame by adding the end character and sending the buffer over Serial.
Definition teleinfo.h:227
void send(const char *tag, int16_t value, uint8_t index=0)
Sends a telemetry value as an integer.
Definition teleinfo.h:207
void startFrame()
Initializes a new frame by resetting the buffer and adding the start character.
Definition teleinfo.h:196
#define FREQ
Definition config.h:102
constexpr bool RELAY_DIVERSION
Definition config.h:40
constexpr int networkGroup
Definition config.h:105
constexpr TemperatureSensing temperatureSensing
Definition config.h:84
constexpr RelayEngine relays
Definition config.h:77
constexpr int nodeID
Definition config.h:104
constexpr bool DUAL_TARIFF
Definition config.h:41
constexpr SerialOutputType SERIAL_OUTPUT_TYPE
Definition config.h:27
constexpr uint8_t NO_OF_DUMPLOADS
Definition config.h:32
constexpr bool TEMP_SENSOR_PRESENT
Definition config.h:42
constexpr int16_t REQUIRED_EXPORT_IN_WATTS
constexpr float invDATALOG_PERIOD_IN_MAINS_CYCLES
constexpr float invSUPPLY_FREQUENCY
constexpr uint8_t NO_OF_PHASES
Some constants.
constexpr int16_t DEVICE_DISCONNECTED_RAW
Definition constants.h:27
constexpr int16_t OUTOFRANGE_TEMPERATURE
Definition constants.h:22
#define DBUGLN(...)
Definition debug.h:97
#define DBUG(...)
Definition debug.h:96
Classes/types needed for dual-tariff support.
void printDualTariffConfiguration()
Print the settings for off-peak period.
Definition dualtariff.h:71
void sendResults(bool bOffPeak)
Prints or sends telemetry data logs based on the selected output format.
Definition utils.h:412
void logLoadPriorities()
Prints the load priorities to the Serial output.
Definition utils.h:453
void printConfiguration()
Print the configuration during startup.
Definition utils.h:46
void printForEmonCMS(const bool bOffPeak)
Write telemetry data to Serial in EmonCMS format.
Definition utils.h:195
void printForSerialText()
Prints data logs to the Serial output in text format.
Definition utils.h:259
void printParamsForSelectedOutputMode()
Print the settings used for the selected output mode.
Public functions/variables of processing engine.
volatile uint8_t copyOf_lowestNoOfSampleSetsPerMainsCycle
Definition processing.h:44
constexpr uint8_t PERSISTENCE_FOR_POLARITY_CHANGE
Definition processing.h:24
uint8_t loadPrioritiesAndState[NO_OF_DUMPLOADS]
Definition processing.h:22
volatile float copyOf_energyInBucket_main
Definition processing.h:43
volatile uint16_t copyOf_sampleSetsDuringThisDatalogPeriod
Definition processing.h:45
PayloadTx_struct< NO_OF_PHASES > tx_data
Definition processing.h:51
volatile uint16_t absenceOfDivertedEnergyCount
Definition processing.h:30
volatile uint16_t copyOf_countLoadON[NO_OF_DUMPLOADS]
Definition processing.h:46
Manages telemetry data and frame formatting.
void sendTelemetryData()
Sends telemetry data using the TeleInfo class.
Definition utils.h:342
int freeRam()
Get the available RAM during setup.
Definition utils.h:478
Some utility functions for the RF chip.
void send_rf_data()
Send the logging data through RF.
Definition utils_rf.h:26
Provides utilities for managing temperature sensors.
#define BRANCH_NAME
Definition version.h:6
#define COMMIT_HASH
Definition version.h:7
#define CURRENT_TIME
Definition version.h:5
#define PROJECT_PATH
Definition version.h:4