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 "shared_var.h"
25#include "teleinfo.h"
26
27#include "utils_rf.h"
28#include "utils_temp.h"
29
30#include "version.h"
31
47inline void printConfiguration()
48{
49#ifndef PROJECT_PATH
50#define PROJECT_PATH (__FILE__)
51#endif
52
53#ifndef BRANCH_NAME
54#define BRANCH_NAME ("N/A")
55#endif
56#ifndef COMMIT_HASH
57#define COMMIT_HASH ("N/A")
58#endif
59
60 DBUGLN();
61 DBUGLN();
62 DBUGLN(F("----------------------------------"));
63 DBUG(F("Sketch ID: "));
65
66 DBUG(F("From branch '"));
67 DBUG(F(BRANCH_NAME));
68 DBUG(F("', commit "));
70
71 DBUG(F("Build on "));
72#ifdef CURRENT_TIME
74#else
75 DBUG(F(__DATE__));
76 DBUG(F(" "));
77 DBUGLN(F(__TIME__));
78#endif
79 DBUGLN(F("ADC mode: free-running"));
80
81 DBUGLN(F("Electrical settings"));
82 for (uint8_t phase = 0; phase < NO_OF_PHASES; ++phase)
83 {
84 DBUG(F("\tf_powerCal for L"));
85 DBUG(phase + 1);
86 DBUG(F(" = "));
87 DBUGLN(f_powerCal[phase], 6);
88
89 DBUG(F("\tf_voltageCal, for Vrms_L"));
90 DBUG(phase + 1);
91 DBUG(F(" = "));
92 DBUGLN(f_voltageCal[phase], 5);
93 }
94
95 DBUG(F("\tf_phaseCal for all phases = "));
97
98 DBUG(F("\tExport rate (Watts) = "));
100
101 DBUG(F("\tzero-crossing persistence (sample sets) = "));
103
105
106 DBUG(F("Temperature capability "));
107 if constexpr (TEMP_SENSOR_PRESENT)
108 {
109 DBUGLN(F("is present"));
110 }
111 else
112 {
113 DBUGLN(F("is NOT present"));
114 }
115
116 DBUG(F("Dual-tariff capability "));
117 if constexpr (DUAL_TARIFF)
118 {
119 DBUGLN(F("is present"));
121 }
122 else
123 {
124 DBUGLN(F("is NOT present"));
125 }
126
127 DBUG(F("Load rotation feature "));
128 if constexpr (PRIORITY_ROTATION != RotationModes::OFF)
129 {
130 DBUGLN(F("is present"));
131 }
132 else
133 {
134 DBUGLN(F("is NOT present"));
135 }
136
137 DBUG(F("Relay diversion feature "));
138 if constexpr (RELAY_DIVERSION)
139 {
140 DBUGLN(F("is present"));
141
142 relays.printRelayEngineConfiguration();
143 }
144 else
145 {
146 DBUGLN(F("is NOT present"));
147 }
148
149 DBUG(F("Override feature "));
150 if constexpr (OVERRIDE_PIN_PRESENT)
151 {
152 DBUGLN(F("is present"));
153
154 overridePins.printOverrideConfig();
155 }
156 else
157 {
158 DBUGLN(F("is NOT present"));
159 }
160
161 DBUG(F("RF capability "));
162#ifdef RF_PRESENT
163 DBUG(F("IS present, Freq = "));
164 if (FREQ == RF12_433MHZ)
165 DBUGLN(F("433 MHz"));
166 else if (FREQ == RF12_868MHZ)
167 DBUGLN(F("868 MHz"));
168 rf12_initialize(nodeID, FREQ, networkGroup); // initialize RF
169#else
170 DBUGLN(F("is NOT present"));
171#endif
172
173 DBUG(F("Datalogging capability "));
175 {
176 DBUGLN(F("in Human-readable format"));
177 }
178 else if constexpr (SERIAL_OUTPUT_TYPE == SerialOutputType::IoT)
179 {
180 DBUGLN(F("in IoT format"));
181 }
182 else if constexpr (SERIAL_OUTPUT_TYPE == SerialOutputType::JSON)
183 {
184 DBUGLN(F("in JSON format"));
185 }
186 else
187 {
188 DBUGLN(F("is NOT present"));
189 }
190}
191
208inline void printForJSON(const bool bOffPeak)
209{
210 ArduinoJson::StaticJsonDocument< 256 > doc;
211
212 // Total mean power over a data logging period
213 doc["P"] = tx_data.power;
214
215 if constexpr (RELAY_DIVERSION)
216 {
217 doc["R"] = relays.get_average();
218 }
219
220 if constexpr (NO_OF_PHASES == 3)
221 {
222 // Mean power for each phase over a data logging period
223 doc["P1"] = tx_data.power_L[0];
224 doc["P2"] = tx_data.power_L[1];
225 doc["P3"] = tx_data.power_L[2];
226 }
227 else if constexpr (NO_OF_PHASES == 2)
228 {
229 // Mean power for each phase over a data logging period
230 doc["P1"] = tx_data.power_L[0];
231 doc["P2"] = tx_data.power_L[1];
232 }
233 else
234 static_assert(NO_OF_PHASES != 1, "Unsupported number of phases");
235
236 // Mean power for each load over a data logging period (in %)
237 //for (idx = 0; idx < NO_OF_DUMPLOADS; ++idx)
238 //{
239 // Serial.print(F(",L"));
240 // Serial.print(idx + 1);
241 // Serial.print(F(":"));
242 // Serial.print(copyOf_countLoadON[idx] * 100 * invDATALOG_PERIOD_IN_MAINS_CYCLES);
243 //}
244
245 if constexpr (TEMP_SENSOR_PRESENT)
246 { // Current temperature
247 for (uint8_t idx = 0; idx < temperatureSensing.size(); ++idx)
248 {
249 if ((OUTOFRANGE_TEMPERATURE == tx_data.temperature_x100[idx])
250 || (DEVICE_DISCONNECTED_RAW == tx_data.temperature_x100[idx]))
251 {
252 continue;
253 }
254
255 doc[String("T") + (idx + 1)] = (float)tx_data.temperature_x100[idx] * 0.01F;
256 }
257 }
258
259 if constexpr (DUAL_TARIFF)
260 {
261 // Current tariff
262 doc["TA"] = bOffPeak ? "low" : "high";
263 }
264
265 serializeJson(doc, Serial);
266 Serial.println();
267}
268
283{
284 uint8_t phase{ 0 };
285
287 Serial.print(F(", P:"));
288 Serial.print(tx_data.power);
289
290 if constexpr (RELAY_DIVERSION)
291 {
292 Serial.print(F("/"));
293 Serial.print(relays.get_average());
294 }
295
296 for (phase = 0; phase < NO_OF_PHASES; ++phase)
297 {
298 Serial.print(F(", P"));
299 Serial.print(phase + 1);
300 Serial.print(F(":"));
301 Serial.print(tx_data.power_L[phase]);
302 }
303 for (phase = 0; phase < NO_OF_PHASES; ++phase)
304 {
305 Serial.print(F(", V"));
306 Serial.print(phase + 1);
307 Serial.print(F(":"));
308 Serial.print((float)tx_data.Vrms_L_x100[phase] * 0.01F);
309 }
310
311 if constexpr (TEMP_SENSOR_PRESENT)
312 {
313 for (uint8_t idx = 0; idx < temperatureSensing.size(); ++idx)
314 {
315 if ((OUTOFRANGE_TEMPERATURE == tx_data.temperature_x100[idx])
316 || (DEVICE_DISCONNECTED_RAW == tx_data.temperature_x100[idx]))
317 {
318 continue;
319 }
320
321 Serial.print(F(", T"));
322 Serial.print(idx + 1);
323 Serial.print(F(":"));
324 Serial.print((float)tx_data.temperature_x100[idx] * 0.01F);
325 }
326 }
327
328 Serial.print(F(", (minSampleSets/MC "));
330 Serial.print(F(", #ofSampleSets "));
332#ifndef DUAL_TARIFF
333 if constexpr (PRIORITY_ROTATION != RotationModes::OFF)
334 {
335 Serial.print(F(", NoED "));
337 }
338#endif // DUAL_TARIFF
339 Serial.println(F(")"));
340}
341
368void sendTelemetryData(const bool bOffPeak)
369{
370 static TeleInfo teleInfo;
371 uint8_t idx{ 0 };
372
373 teleInfo.startFrame(); // Start a new telemetry frame
374
375 teleInfo.send("P", tx_data.power); // Send power grid data
376
377 if constexpr (NO_OF_PHASES > 1)
378 {
379 idx = NO_OF_PHASES;
380 do
381 {
382 --idx;
383 teleInfo.send("P", tx_data.power_L[idx], idx + 1); // Send power for each phase
384 teleInfo.send("V", tx_data.Vrms_L_x100[idx], idx + 1); // Send voltage for each phase
385 } while (idx);
386 }
387
388 if constexpr (RELAY_DIVERSION)
389 {
390 teleInfo.send("R", static_cast< int16_t >(relays.get_average())); // Send relay average if diversion is enabled
391
392 idx = relays.size();
393 do
394 {
395 --idx;
396 teleInfo.send("R", relays.get_relay(idx).isRelayON()); // Send state of each relay
397 } while (idx);
398 }
399
400 idx = NO_OF_DUMPLOADS;
401 do
402 {
403 --idx;
404 teleInfo.send("D", Shared::copyOf_countLoadON[idx] * 100 * invDATALOG_PERIOD_IN_MAINS_CYCLES, idx + 1); // Send load ON count for each load
405 } while (idx);
406
407 if constexpr (TEMP_SENSOR_PRESENT)
408 {
409 for (uint8_t idx = 0; idx < temperatureSensing.size(); ++idx)
410 {
411 if ((OUTOFRANGE_TEMPERATURE == tx_data.temperature_x100[idx])
412 || (DEVICE_DISCONNECTED_RAW == tx_data.temperature_x100[idx]))
413 {
414 continue; // Skip invalid temperature readings
415 }
416 teleInfo.send("T", tx_data.temperature_x100[idx], idx + 1); // Send temperature
417 }
418 }
419
420 teleInfo.send("N", static_cast< int16_t >(Shared::absenceOfDivertedEnergyCountInSeconds)); // Send absence of diverted energy count for 50Hz
421
422 if constexpr (DUAL_TARIFF)
423 {
424 teleInfo.send("TA", static_cast< int16_t >(bOffPeak ? 1 : 0)); // Send current tariff state (0=high/on-peak, 1=low/off-peak)
425 }
426
429
430 teleInfo.endFrame(); // Finalize and send the telemetry frame
431}
432
450inline void sendResults(bool bOffPeak)
451{
452 static bool startup{ true };
453
454 if (startup)
455 {
456 startup = false;
457 return; // reject the first datalogging which is incomplete !
458 }
459
460#ifdef RF_PRESENT
461 send_rf_data(); // *SEND RF DATA*
462#endif
463
465 {
467 }
468 else if constexpr (SERIAL_OUTPUT_TYPE == SerialOutputType::IoT)
469 {
470 sendTelemetryData(bOffPeak);
471 }
472 else if constexpr (SERIAL_OUTPUT_TYPE == SerialOutputType::JSON)
473 {
474 printForJSON(bOffPeak);
475 }
476}
477
491inline void logLoadPriorities()
492{
493#ifdef ENABLE_DEBUG
494
495 DBUGLN(F("Load Priorities: "));
496 for (const auto& loadPrioAndState : loadPrioritiesAndState)
497 {
498 DBUG(F("\tload "));
499 DBUGLN(loadPrioAndState);
500 }
501
502#endif
503}
504
516inline int freeRam()
517{
518 extern int __heap_start, *__brkval;
519 int v;
520 return (int)&v - (__brkval == 0 ? (int)&__heap_start : (int)__brkval);
521}
522
523#endif // UTILS_H
Calibration values definition.
constexpr float f_phaseCal
Definition calibration.h:46
constexpr float f_voltageCal[NO_OF_PHASES]
Definition calibration.h:51
constexpr float f_powerCal[NO_OF_PHASES]
Definition calibration.h:34
A class for managing and sending telemetry information in a structured frame format.
Definition teleinfo.h:166
void send(const char *tag, int16_t value, uint8_t index=0)
Sends a telemetry value as an integer.
Definition teleinfo.h:240
#define FREQ
Definition config.h:165
constexpr bool RELAY_DIVERSION
Definition config.h:51
constexpr int networkGroup
Definition config.h:168
constexpr bool OVERRIDE_PIN_PRESENT
Definition config.h:48
constexpr TemperatureSensing temperatureSensing
Definition config.h:150
constexpr RelayEngine relays
Definition config.h:126
constexpr int nodeID
Definition config.h:167
constexpr bool DUAL_TARIFF
Definition config.h:52
constexpr OverridePins overridePins
Definition config.h:143
constexpr SerialOutputType SERIAL_OUTPUT_TYPE
Definition config.h:37
constexpr uint8_t NO_OF_DUMPLOADS
Definition config.h:42
constexpr bool TEMP_SENSOR_PRESENT
Definition config.h:53
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:450
void logLoadPriorities()
Prints the load priorities to the Serial output.
Definition utils.h:491
void printConfiguration()
Print the configuration during startup.
Definition utils.h:47
void printForJSON(const bool bOffPeak)
Write telemetry data to Serial in JSON format.
Definition utils.h:208
void printForSerialText()
Prints data logs to the Serial output in text format.
Definition utils.h:282
volatile float copyOf_energyInBucket_main
Definition shared_var.h:23
volatile uint16_t copyOf_sampleSetsDuringThisDatalogPeriod
Definition shared_var.h:25
volatile uint8_t copyOf_lowestNoOfSampleSetsPerMainsCycle
Definition shared_var.h:24
volatile uint16_t copyOf_countLoadON[NO_OF_DUMPLOADS]
Definition shared_var.h:26
volatile uint16_t absenceOfDivertedEnergyCountInSeconds
Definition shared_var.h:16
void printParamsForSelectedOutputMode()
Print the settings used for the selected output mode.
Public functions/variables of processing engine.
constexpr uint8_t PERSISTENCE_FOR_POLARITY_CHANGE
Definition processing.h:24
uint8_t loadPrioritiesAndState[NO_OF_DUMPLOADS]
Definition processing.h:22
PayloadTx_struct< NO_OF_PHASES > tx_data
Definition processing.h:32
Manages telemetry data and frame formatting.
void sendTelemetryData(const bool bOffPeak)
Sends telemetry data using the TeleInfo class.
Definition utils.h:368
int freeRam()
Get the available RAM during setup.
Definition utils.h:516
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