diff --git a/src/AmsConfiguration.cpp b/src/AmsConfiguration.cpp index 5e18ae13..028e8d4e 100644 --- a/src/AmsConfiguration.cpp +++ b/src/AmsConfiguration.cpp @@ -563,6 +563,14 @@ bool AmsConfiguration::hasConfig() { configVersion = 0; return false; } + case 89: + configVersion = -1; // Prevent loop + if(relocateConfig89()) { + configVersion = 90; + } else { + configVersion = 0; + return false; + } case EEPROM_CHECK_SUM: return true; default: @@ -799,6 +807,30 @@ bool AmsConfiguration::relocateConfig88() { return ret; } +bool AmsConfiguration::relocateConfig89() { + EntsoeConfig89 entose89; + EEPROM.begin(EEPROM_SIZE); + EEPROM.get(CONFIG_ENTSOE_START_89, entose89); + + uint32_t multiplier = entose89.multiplier; + + EntsoeConfig entsoe = { + 0x0, + 0x0, + 0x0, + multiplier + }; + strcpy(entsoe.token, entose89.token); + strcpy(entsoe.area, entose89.area); + strcpy(entsoe.currency, entose89.currency); + + EEPROM.put(CONFIG_ENTSOE_START, entsoe); + EEPROM.put(EEPROM_CONFIG_ADDRESS, 90); + bool ret = EEPROM.commit(); + EEPROM.end(); + return ret; +} + bool AmsConfiguration::save() { EEPROM.begin(EEPROM_SIZE); EEPROM.put(EEPROM_CONFIG_ADDRESS, EEPROM_CHECK_SUM); diff --git a/src/AmsConfiguration.h b/src/AmsConfiguration.h index fb105473..0730e142 100644 --- a/src/AmsConfiguration.h +++ b/src/AmsConfiguration.h @@ -4,7 +4,7 @@ #include "Arduino.h" #define EEPROM_SIZE 1024*3 -#define EEPROM_CHECK_SUM 89 // Used to check if config is stored. Change if structure changes +#define EEPROM_CHECK_SUM 90 // Used to check if config is stored. Change if structure changes #define EEPROM_CONFIG_ADDRESS 0 #define EEPROM_TEMP_CONFIG_ADDRESS 2048 @@ -12,16 +12,17 @@ #define CONFIG_WIFI_START 16 #define CONFIG_METER_START 224 #define CONFIG_GPIO_START 266 +#define CONFIG_ENTSOE_START 286 #define CONFIG_WEB_START 648 #define CONFIG_DEBUG_START 824 #define CONFIG_DOMOTICZ_START 856 #define CONFIG_NTP_START 872 -#define CONFIG_ENTSOE_START 944 #define CONFIG_MQTT_START 1004 #define CONFIG_MQTT_START_86 224 #define CONFIG_METER_START_87 784 #define CONFIG_GPIO_START_88 832 +#define CONFIG_ENTSOE_START_89 944 struct SystemConfig { @@ -149,13 +150,20 @@ struct NtpConfig { char server[64]; }; // 70 -struct EntsoeConfig { +struct EntsoeConfig89 { char token[37]; char area[17]; char currency[4]; uint16_t multiplier; }; // 60 +struct EntsoeConfig { + char token[37]; + char area[17]; + char currency[4]; + uint32_t multiplier; +}; // 62 + struct ConfigObject83 { uint8_t boardType; char wifiSsid[32]; @@ -316,6 +324,7 @@ private: bool relocateConfig86(); bool relocateConfig87(); bool relocateConfig88(); // dev 1.6 + bool relocateConfig89(); // dev 1.6 int readString(int pAddress, char* pString[]); int readInt(int pAddress, int *pValue); diff --git a/src/AmsDataStorage.cpp b/src/AmsDataStorage.cpp index 30c9f1f8..4bd8a55f 100644 --- a/src/AmsDataStorage.cpp +++ b/src/AmsDataStorage.cpp @@ -40,11 +40,14 @@ bool AmsDataStorage::update(AmsData* data) { } tmElements_t tm, last; + breakTime(now, tm); if(now > EPOCH_2021_01_01) { tmElements_t last; - breakTime(now, tm); if(day.lastMeterReadTime > EPOCH_2021_01_01) { + if(debugger->isActive(RemoteDebug::DEBUG)) { + debugger->printf("(AmsDataStorage) Last day update: %d\n", day.lastMeterReadTime); + } breakTime(day.lastMeterReadTime, last); for(int i = last.Hour; i < tm.Hour; i++) { if(debugger->isActive(RemoteDebug::DEBUG)) { @@ -55,6 +58,9 @@ bool AmsDataStorage::update(AmsData* data) { } if(month.lastMeterReadTime > EPOCH_2021_01_01) { + if(debugger->isActive(RemoteDebug::DEBUG)) { + debugger->printf("(AmsDataStorage) Last month update: %d\n", month.lastMeterReadTime); + } if(tz != NULL) { breakTime(tz->toLocal(now), tm); breakTime(tz->toLocal(month.lastMeterReadTime), last); @@ -64,15 +70,16 @@ bool AmsDataStorage::update(AmsData* data) { } for(int i = last.Day; i < tm.Day; i++) { - if(debugger->isActive(RemoteDebug::DEBUG)) { + //if(debugger->isActive(RemoteDebug::DEBUG)) { debugger->printf("(AmsDataStorage) Clearing day: %d\n", i); - } + //} setDay(i, 0); } } } if(data->getListType() != 3) return false; + else if(tm.Minute > 5) return false; // Update day plot if(day.activeImport == 0 || now - day.lastMeterReadTime > 86400) { @@ -87,9 +94,9 @@ bool AmsDataStorage::update(AmsData* data) { int16_t val = (((data->getActiveImportCounter() * 1000) - day.activeImport) - ((data->getActiveExportCounter() * 1000) - day.activeExport)); setHour(tm.Hour, val); - if(debugger->isActive(RemoteDebug::INFO)) { + //if(debugger->isActive(RemoteDebug::INFO)) { debugger->printf("(AmsDataStorage) Usage for hour %d: %d\n", tm.Hour, val); - } + //} day.activeImport = data->getActiveImportCounter() * 1000; day.activeExport = data->getActiveExportCounter() * 1000; @@ -101,28 +108,36 @@ bool AmsDataStorage::update(AmsData* data) { float ipm = im / mins; float epm = ex / mins; - while(now - day.lastMeterReadTime > 3590) { - time_t cur = day.lastMeterReadTime + 3600; - tmElements_t tm; - breakTime(cur, tm); - uint8_t minutes = 60 - tm.Minute; - float val = ((ipm * minutes) - (epm * minutes)); - setHour(tm.Hour-1, val); + //if(debugger->isActive(RemoteDebug::DEBUG)) { + debugger->printf("(AmsDataStorage) Since last day update, minutes: %.1f, import: %d (%.2f/min), export: %d (%.2f/min)\n", mins, im, ipm, ex, epm); + //} - if(debugger->isActive(RemoteDebug::INFO)) { - debugger->printf("(AmsDataStorage) Estimated usage for hour %d: %d\n", tm.Hour, val); - } + breakTime(day.lastMeterReadTime, tm); + day.lastMeterReadTime = day.lastMeterReadTime - (tm.Minute * 60) - tm.Second; + breakTime(now, tm); + time_t stopAt = now - (tm.Minute * 60) - tm.Second; + while(day.lastMeterReadTime < stopAt) { + time_t cur = min(day.lastMeterReadTime + 3600, stopAt); + uint8_t minutes = round((cur - day.lastMeterReadTime) / 60.0); + if(minutes < 1) break; + + breakTime(day.lastMeterReadTime, last); + float val = ((ipm * minutes) - (epm * minutes)); + setHour(last.Hour, val); + + //if(debugger->isActive(RemoteDebug::INFO)) { + debugger->printf("(AmsDataStorage) Estimated usage for hour %u: %.1f (%lu)\n", last.Hour, val, cur); + //} day.activeImport += ipm * minutes; day.activeExport += epm * minutes; - day.lastMeterReadTime += 60 * minutes; + day.lastMeterReadTime = cur; } } // Update month plot if(tz != NULL) { - time_t local = tz->toLocal(now); - breakTime(local, tm); + breakTime(tz->toLocal(now), tm); } else { breakTime(now, tm); } @@ -159,21 +174,43 @@ bool AmsDataStorage::update(AmsData* data) { float iph = im / hrs; float eph = ex / hrs; - while(now - month.lastMeterReadTime > 86000) { - time_t cur = month.lastMeterReadTime + 86400; - tmElements_t tm; - breakTime(cur, tm); - uint8_t hours = 24 - tm.Hour; + //if(debugger->isActive(RemoteDebug::DEBUG)) { + debugger->printf("(AmsDataStorage) Since last month update, hours: %.1f, import: %d (%.2f/hr), export: %d (%.2f/hr)\n", hrs, im, iph, ex, eph); + //} + + if(tz != NULL) { + breakTime(tz->toLocal(month.lastMeterReadTime), tm); + } else { + breakTime(month.lastMeterReadTime, tm); + } + month.lastMeterReadTime = month.lastMeterReadTime - (tm.Hour * 3600) - (tm.Minute * 60) - tm.Second; + + if(tz != NULL) { + breakTime(tz->toLocal(now), tm); + } else { + breakTime(now, tm); + } + time_t stopAt = now - (tm.Hour * 3600) - (tm.Minute * 60) - tm.Second; + while(month.lastMeterReadTime < stopAt) { + time_t cur = min(month.lastMeterReadTime + 86400, stopAt); + uint8_t hours = round((cur - month.lastMeterReadTime) / 3600.0); + + if(tz != NULL) { + breakTime(tz->toLocal(month.lastMeterReadTime), last); + } else { + breakTime(month.lastMeterReadTime, last); + } + float val = ((iph * hours) - (eph * hours)); - setDay(tm.Day-1, val); + setDay(last.Day, val); //if(debugger->isActive(RemoteDebug::INFO)) { - debugger->printf("(AmsDataStorage) Estimated usage for day %d: %d\n", tm.Day, val); + debugger->printf("(AmsDataStorage) Estimated usage for day %u: %.1f (%lu)\n", last.Day, val, cur); //} month.activeImport += iph * hours; month.activeExport += eph * hours; - month.lastMeterReadTime += 24 * hours; + month.lastMeterReadTime += cur; } } } @@ -200,7 +237,7 @@ int32_t AmsDataStorage::getDay(uint8_t day) { return (month.points[day-1] * 10); } -bool AmsDataStorage::load(AmsData* meterState) { +bool AmsDataStorage::load() { if(!LittleFS.begin()) { if(debugger->isActive(RemoteDebug::ERROR)) { debugger->printf("(AmsDataStorage) Unable to load LittleFS\n"); diff --git a/src/AmsDataStorage.h b/src/AmsDataStorage.h index 8524d97a..e0426ff0 100644 --- a/src/AmsDataStorage.h +++ b/src/AmsDataStorage.h @@ -30,7 +30,7 @@ public: bool update(AmsData*); int16_t getHour(uint8_t); int32_t getDay(uint8_t); - bool load(AmsData*); + bool load(); bool save(); private: diff --git a/src/AmsToMqttBridge.ino b/src/AmsToMqttBridge.ino index d252e61c..df551434 100644 --- a/src/AmsToMqttBridge.ino +++ b/src/AmsToMqttBridge.ino @@ -299,7 +299,7 @@ void setup() { ds.setTimezone(tz); } - ds.load(&meterState); + ds.load(); } else { if(Debug.isActive(RemoteDebug::INFO)) { debugI("No configuration, booting AP"); @@ -752,20 +752,6 @@ void readHanPort() { if(data.getListType() >= 2) { mqttHandler->publishSystem(&hw); } - time_t now = time(nullptr); - if(now < EPOCH_2021_01_01 && data.getListType() == 3 && !ntpEnabled) { - if(data.getMeterTimestamp() > EPOCH_2021_01_01) { - debugI("Using timestamp from meter"); - now = data.getMeterTimestamp(); - } else if(data.getPackageTimestamp() > EPOCH_2021_01_01) { - debugI("Using timestamp from meter (DLMS)"); - now = data.getPackageTimestamp(); - } - if(now > EPOCH_2021_01_01) { - timeval tv { now, 0}; - settimeofday(&tv, nullptr); - } - } } if(mqtt != NULL) { mqtt->loop(); @@ -773,6 +759,24 @@ void readHanPort() { } } + time_t now = time(nullptr); + if(now < EPOCH_2021_01_01 && data.getListType() == 3 && !ntpEnabled) { + if(data.getMeterTimestamp() > EPOCH_2021_01_01) { + debugI("Using timestamp from meter"); + now = data.getMeterTimestamp(); + } else if(data.getPackageTimestamp() > EPOCH_2021_01_01) { + debugI("Using timestamp from meter (DLMS)"); + now = data.getPackageTimestamp(); + } + if(now > EPOCH_2021_01_01) { + timeval tv { now, 0}; + settimeofday(&tv, nullptr); + } + } + if(meterState.getListType() < 3 && now > EPOCH_2021_01_01) { + // TODO: Load an estimated value from dayplot + } + meterState.apply(data); if(ds.update(&data)) { diff --git a/src/entsoe/EntsoeApi.cpp b/src/entsoe/EntsoeApi.cpp index 475351e9..3f32d223 100644 --- a/src/entsoe/EntsoeApi.cpp +++ b/src/entsoe/EntsoeApi.cpp @@ -77,7 +77,7 @@ float EntsoeApi::getValueForHour(time_t cur, uint8_t hour) { } bool EntsoeApi::loop() { - if(strlen(config->token) == 0) + if(strlen(getToken()) == 0) return false; bool ret = false; @@ -116,7 +116,7 @@ bool EntsoeApi::loop() { char url[256]; snprintf(url, sizeof(url), "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s", - "https://transparency.entsoe.eu/api", config->token, + "https://transparency.entsoe.eu/api", getToken(), d1.Year+1970, d1.Month, d1.Day, 23, 00, d2.Year+1970, d2.Month, d2.Day, 23, 00, config->area, config->area); @@ -146,7 +146,7 @@ bool EntsoeApi::loop() { char url[256]; snprintf(url, sizeof(url), "%s?securityToken=%s&documentType=A44&periodStart=%04d%02d%02d%02d%02d&periodEnd=%04d%02d%02d%02d%02d&in_Domain=%s&out_Domain=%s", - "https://transparency.entsoe.eu/api", config->token, + "https://transparency.entsoe.eu/api", getToken(), d1.Year+1970, d1.Month, d1.Day, 23, 00, d2.Year+1970, d2.Month, d2.Day, 23, 00, config->area, config->area);