// #Inspired ad:
// * https://www.theelectronics.co.in/2022/03/ntp-client-simulation-using-esp32.html
// * https://github.com/satyamkr80/ESP32-Simulation-Codes
// * https://www.youtube.com/watch?v=bwaIEtLUVKQ
#include <WiFi.h>
#include <TimeLib.h>
#include <Wire.h>
#define NTP_SERVER "pool.ntp.org"
#define UTC_OFFSET 0
#define UTC_OFFSET_DST 0
const int PIN_LEVEL_HIGH = 25;
const int PIN_LEVEL_LOW = 26;
const int PIN_IMPULSE = 27;
const int PIN_LED_HIGH = 23;
const int PIN_LED_LOW = 22;
const int PIN_LED_IMPULSE = 21;
// ========================================================
/*
Popis funcke
- po preruseni nacteme aktualni cas + prdame hodnotu highLevel/lowLevel
a vse zapiseme do Stringu pro odeslani do db
- ve smycce kontrolujeme zda jsou nejaka data k odeslani, a pokud ano odesleme je vsechny naraz na server
pricemz kontrolujeme odpoved - pokud je 200-299 akceptujeme jako ulozene a smazeme pole pro odeslani
a vynulujeme pocitadlo radku zaznamu
Nutno vyresit problem s prerusenim - pokud vezmu data a poslu na server, pote je smazu tak v tento maly okamzik
pokud by prislo preruseni a pridal by se radek tak by nebyl nikdy odelan a byl by hned smazan
- mozny navrh prepracovani:
-- preruseni ulozi pouze millis() do globalni promenne a tim preruseni konci
-- ve smycce se kontroluze jestli je ulozen nejaky cas, pokud ano teprve nyni se
vygeneruje radek pro odeslani dat do DB + inkrementujeme pocitadlo radku/zaznamu
-- nepredpoklada se preruseni vicekrat jak po cca 500ms (to by byl prikon 14kW!)
-- ve smycce se nadale zkontroluje zda jsou nejaka data a pripadne odesle
-- odesilani dat take opodminkujeme na max 1x za minutu
-- pokud odeslani selze mazani dat nerovedeme a zkusime o minutu pozdeji
-- pokud je ulozeno vice jak cca 300 radku ktere se nepodarilo odeslat, je nutne data zahodi
--- pripadne ukladat nejaky souhrnny stav ktery se odesle (ukladat pocet impulzu ktere se neodeslali a kdy bylo posledni uspesne odeslani)
-- NodeMcu ma 96kB RAM - lze ulozit cca 900 radku o delce 100 znaku
*/
// ========================================================
String dataToInfluxDb = "";
String messagesToSerial = "";
bool impulseInteruptProcessing = false;
unsigned long lastImpulseMilis = 0;
// ========================================================
unsigned long ntpTimestamp = 0;
unsigned long ntpTimestampMilis = 0;
unsigned long loadNtpTimestamp() {
Serial.println("Loading NTP time . . .");
struct tm timeinfo;
if (!getLocalTime(&timeinfo)) {
Serial.println("Cannot load NTP time - repeat after 10s");
delay(10);
return loadNtpTimestamp();
}
Serial.print("NTP time: ");
Serial.println(&timeinfo, "%H:%M:%S %d.%m.%Y %Z");
time_t now;
time(&now);
ntpTimestamp = (unsigned long) now;
ntpTimestampMilis = millis();
Serial.print("NTP timestamp: ");
Serial.println(now);
Serial.print("NTP timestamp milis: ");
Serial.println(ntpTimestampMilis);
return now;
}
unsigned long getCurrentTimestamp(unsigned long curMillis = 0)
{
if(curMillis == 0) {
curMillis = millis();
}
return ntpTimestamp + (int) ((curMillis - ntpTimestampMilis) / 1000);
}
// ========================================================
void setup() {
Serial.begin(115200);
Serial.println("");
Serial.println("Serial startup");
// WI-FI
WiFi.begin("Wokwi-GUEST", "", 6);
while (WiFi.status() != WL_CONNECTED) {
delay(250);
}
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// NTP time
configTime(UTC_OFFSET, UTC_OFFSET_DST, NTP_SERVER);
loadNtpTimestamp();
// Setup buttons
pinMode(PIN_LEVEL_HIGH, INPUT);
pinMode(PIN_LEVEL_LOW, INPUT);
pinMode(PIN_IMPULSE, INPUT);
pinMode(PIN_LED_HIGH, OUTPUT);
pinMode(PIN_LED_LOW, OUTPUT);
pinMode(PIN_LED_IMPULSE, OUTPUT);
digitalWrite(PIN_LED_HIGH, LOW);
digitalWrite(PIN_LED_LOW, LOW);
digitalWrite(PIN_LED_IMPULSE, LOW);
attachInterrupt(digitalPinToInterrupt(PIN_IMPULSE), interuptImpulse, FALLING);
Serial.println("Start loop()");
Serial.println("====================");
}
void loop() {
if(messagesToSerial != "") {
Serial.println(messagesToSerial);
messagesToSerial = "";
}
digitalWrite(PIN_LED_HIGH, !digitalRead(PIN_LEVEL_HIGH));
digitalWrite(PIN_LED_LOW, !digitalRead(PIN_LEVEL_LOW));
digitalWrite(PIN_LED_IMPULSE, !digitalRead(PIN_IMPULSE));
if(dataToInfluxDb != ""){
Serial.println("*** Influx DB ***");
Serial.println(dataToInfluxDb);
Serial.println("----------");
dataToInfluxDb = "";
}
/*
delay(1100);
Serial.print(getCurrentTimestamp());
Serial.println(
String(" - Status ")
+ String(" H:") + String(digitalRead(PIN_LEVEL_HIGH) ? 'Y' : 'N')
+ String(" L:") + String(digitalRead(PIN_LEVEL_LOW) ? 'Y' : 'N')
+ String(" I:") + String(digitalRead(PIN_IMPULSE) ? 'Y' : 'N')
);
*/
}
void interuptImpulse() {
if(impulseInteruptProcessing) {
// Already processing
return;
}
impulseInteruptProcessing = true;
unsigned long curMillis = millis();
unsigned long curTime = getCurrentTimestamp(curMillis);
if(lastImpulseMilis == 0) {
// Frst impulse only store
lastImpulseMilis = curMillis;
messagesToSerial += String(curTime) + String(" - First impulse\n");
} else {
messagesToSerial += String(curTime) + String(" - Next impulse\n");
unsigned long impulseDiff = curMillis - lastImpulseMilis;
if(impulseDiff < 100) {
// Lower then 10ms - fake - ignore
impulseInteruptProcessing = false;
return;
} else {
lastImpulseMilis = curMillis;
}
int power = (int) (7200 / (impulseDiff / 1000));
bool levelHigh = !digitalRead(PIN_LEVEL_HIGH);
bool levelLow = !digitalRead(PIN_LEVEL_LOW);
messagesToSerial += String(curTime)
+ String(" - Impulse: ")
+ String("milis: ")
+ String(curMillis)
+ String(" / diff: ")
+ String(impulseDiff)
+ String("ms / power: ")
+ String(power)
+ String("W \n");
/*
dataToInfluxDb += String("wattmetter power=")
+ String(power)
+ String(",levelHigh=")
+ String(levelHigh?"1":0)
+ String(",levelLow=")
+ String(levelLow?"1":0)
+ String(" ")
+ String(curTime)
+ String(".")
+ String(curMillis % 1000)
+ String("\n");)
*/
impulseInteruptProcessing = false;
}
}