diff --git a/lib/PriceService/src/PriceService.cpp b/lib/PriceService/src/PriceService.cpp index bf3275cf..a97128c4 100644 --- a/lib/PriceService/src/PriceService.cpp +++ b/lib/PriceService/src/PriceService.cpp @@ -336,17 +336,17 @@ bool PriceService::retrieve(const char* url, Stream* doc) { nextFetchDelayMinutes = 2; } #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -debugger->printf_P(PSTR("(PriceService) Communication error, returned status: %d\n"), status); + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("(PriceService) Communication error, returned status: %d\n"), status); #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -debugger->printf(http->errorToString(status).c_str()); + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf(http->errorToString(status).c_str()); #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::DEBUG)) -#endif -debugger->printf(http->getString().c_str()); + if (debugger->isActive(RemoteDebug::DEBUG)) + #endif + debugger->printf(http->getString().c_str()); http->end(); return false; @@ -393,18 +393,18 @@ float PriceService::getCurrencyMultiplier(const char* from, const char* to, time } if(currencyMultiplier != 0) { #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::DEBUG)) -#endif -debugger->printf_P(PSTR("(PriceService) Resulting currency multiplier: %.4f\n"), currencyMultiplier); + if (debugger->isActive(RemoteDebug::DEBUG)) + #endif + debugger->printf_P(PSTR("(PriceService) Resulting currency multiplier: %.4f\n"), currencyMultiplier); tmElements_t tm; breakTime(t, tm); lastCurrencyFetch = now + (SECS_PER_DAY * 1000) - (((((tm.Hour * 60) + tm.Minute) * 60) + tm.Second) * 1000) + (3600000 * 6) + (tomorrowFetchMinute * 60); this->currencyMultiplier = currencyMultiplier; } else { #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::WARNING)) -#endif -debugger->printf_P(PSTR("(PriceService) Multiplier ended in success, but without value\n")); + if (debugger->isActive(RemoteDebug::WARNING)) + #endif + debugger->printf_P(PSTR("(PriceService) Multiplier ended in success, but without value\n")); lastCurrencyFetch = now + (SECS_PER_HOUR * 1000); if(this->currencyMultiplier == 1) return 0; } @@ -435,13 +435,13 @@ PricesContainer* PriceService::fetchPrices(time_t t) { #endif #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::INFO)) -#endif -debugger->printf_P(PSTR("(PriceService) Fetching prices for %02d.%02d.%04d\n"), tm.Day, tm.Month, tm.Year+1970); + if (debugger->isActive(RemoteDebug::INFO)) + #endif + debugger->printf_P(PSTR("(PriceService) Fetching prices for %02d.%02d.%04d\n"), tm.Day, tm.Month, tm.Year+1970); #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::DEBUG)) -#endif -debugger->printf_P(PSTR("(PriceService) url: %s\n"), buf); + if (debugger->isActive(RemoteDebug::DEBUG)) + #endif + debugger->printf_P(PSTR("(PriceService) url: %s\n"), buf); EntsoeA44Parser a44; if(retrieve(buf, &a44) && a44.getPoint(0) != PRICE_NO_VALUE) { PricesContainer* ret = new PricesContainer(); @@ -463,13 +463,13 @@ debugger->printf_P(PSTR("(PriceService) url: %s\n"), buf); config->currency ); #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::INFO)) -#endif -debugger->printf_P(PSTR("(PriceService) Fetching prices for %02d.%02d.%04d\n"), tm.Day, tm.Month, tm.Year+1970); + if (debugger->isActive(RemoteDebug::INFO)) + #endif + debugger->printf_P(PSTR("(PriceService) Fetching prices for %02d.%02d.%04d\n"), tm.Day, tm.Month, tm.Year+1970); #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::DEBUG)) -#endif -debugger->printf_P(PSTR("(PriceService) url: %s\n"), buf); + if (debugger->isActive(RemoteDebug::DEBUG)) + #endif + debugger->printf_P(PSTR("(PriceService) url: %s\n"), buf); #if defined(ESP8266) WiFiClient client; client.setTimeout(5000); @@ -511,9 +511,9 @@ debugger->printf_P(PSTR("(PriceService) url: %s\n"), buf); lastError = gcmRet; nextFetchDelayMinutes = 60; #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -debugger->printf_P(PSTR("(PriceService) Error code while decrypting prices: %d\n"), gcmRet); + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("(PriceService) Error code while decrypting prices: %d\n"), gcmRet); } } else { lastError = status; @@ -525,20 +525,20 @@ debugger->printf_P(PSTR("(PriceService) Error code while decrypting prices: %d\n nextFetchDelayMinutes = 5; } #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -debugger->printf_P(PSTR("(PriceService) Communication error, returned status: %d\n"), status); + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("(PriceService) Communication error, returned status: %d\n"), status); #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -{ + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + { debugger->printf(http->errorToString(status).c_str()); debugger->println(); } #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::DEBUG)) -#endif -debugger->printf(http->getString().c_str()); + if (debugger->isActive(RemoteDebug::DEBUG)) + #endif + debugger->printf(http->getString().c_str()); http->end(); } @@ -575,16 +575,16 @@ void PriceService::cropPriceConfig(uint8_t size) { bool PriceService::save() { if(!LittleFS.begin()) { #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -debugger->printf_P(PSTR("(PriceService) Unable to load LittleFS\n")); + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("(PriceService) Unable to load LittleFS\n")); return false; } #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::INFO)) -#endif -debugger->printf_P(PSTR("(PriceService) Saving price config\n")); + if (debugger->isActive(RemoteDebug::INFO)) + #endif + debugger->printf_P(PSTR("(PriceService) Saving price config\n")); PriceConfig pc; File file = LittleFS.open(FILE_PRICE_CONF, "w"); @@ -607,18 +607,18 @@ debugger->printf_P(PSTR("(PriceService) Saving price config\n")); bool PriceService::load() { if(!LittleFS.begin()) { #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::ERROR)) -#endif -debugger->printf_P(PSTR("(PriceService) Unable to load LittleFS\n")); + if (debugger->isActive(RemoteDebug::ERROR)) + #endif + debugger->printf_P(PSTR("(PriceService) Unable to load LittleFS\n")); return false; } if(!LittleFS.exists(FILE_PRICE_CONF)) { return false; } #if defined(AMS_REMOTE_DEBUG) -if (debugger->isActive(RemoteDebug::INFO)) -#endif -debugger->printf_P(PSTR("(PriceService) Loading price config\n")); + if (debugger->isActive(RemoteDebug::INFO)) + #endif + debugger->printf_P(PSTR("(PriceService) Loading price config\n")); this->priceConfig.clear(); diff --git a/lib/SvelteUi/src/AmsWebServer.cpp b/lib/SvelteUi/src/AmsWebServer.cpp index fbd9a3e1..12cd551c 100644 --- a/lib/SvelteUi/src/AmsWebServer.cpp +++ b/lib/SvelteUi/src/AmsWebServer.cpp @@ -2342,6 +2342,8 @@ void AmsWebServer::configFileDownload() { case PRICE_DIRECTION_BOTH: strcpy_P(direction, PSTR("both")); break; + default: + strcpy_P(direction, PSTR("--")); } char type[9] = ""; switch(p.type) { @@ -2357,11 +2359,38 @@ void AmsWebServer::configFileDownload() { case PRICE_TYPE_SUBTRACT: strcpy_P(type, PSTR("subtract")); break; + default: + strcpy_P(direction, PSTR("--")); + } + char days[3*7] = ""; + if(p.days == 0x7F) { + strcpy_P(days, PSTR("all")); + } else { + if((p.days >> 0) & 0x01) strcat_P(days, PSTR("mo,")); + if((p.days >> 1) & 0x01) strcat_P(days, PSTR("tu,")); + if((p.days >> 2) & 0x01) strcat_P(days, PSTR("we,")); + if((p.days >> 3) & 0x01) strcat_P(days, PSTR("th,")); + if((p.days >> 4) & 0x01) strcat_P(days, PSTR("fr,")); + if((p.days >> 5) & 0x01) strcat_P(days, PSTR("sa,")); + if((p.days >> 6) & 0x01) strcat_P(days, PSTR("su,")); + if(strlen(days) > 0) days[strlen(days)-1] = '\0'; } - char days[12] = ""; - char hours[12] = ""; - server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("priceModifier %i %s %s %s %.4f %s %s %02d-%02d %02d-%02d\n"), + char hours[3*24] = ""; + if(p.hours == 0xFFFFFF) { + strcpy_P(hours, PSTR("all")); + } else { + for(uint8_t i = 0; i < 24; i++) { + if((p.hours >> i) & 0x01) { + char h[4]; + snprintf_P(h, 4, PSTR("%02d,"), i); + strcat(hours, h); + } + } + if(strlen(hours) > 0) hours[strlen(hours)-1] = '\0'; + } + + server.sendContent(buf, snprintf_P(buf, BufferSize, PSTR("priceModifier %i \"%s\" %s %s %.4f %s %s %02d-%02d %02d-%02d\n"), i, p.name, direction, diff --git a/src/AmsToMqttBridge.cpp b/src/AmsToMqttBridge.cpp index 5eb1078b..cd306b37 100644 --- a/src/AmsToMqttBridge.cpp +++ b/src/AmsToMqttBridge.cpp @@ -1550,6 +1550,22 @@ void MQTT_connect() { } } +String getSplit(String input, int index) { + char separator = ' '; + String ret = input; + ret.trim(); + for(int i = 0; i < index; i++) { + int pos = ret.indexOf(separator); + if(pos == -1) { + return ""; + } + ret = ret.substring(pos+1); + } + ret = ret.substring(0, ret.indexOf(separator)); + ret.trim(); + return ret; +} + void configFileParse() { debugD_P(PSTR("Parsing config file")); @@ -1587,6 +1603,7 @@ void configFileParse() { NtpConfig ntp; PriceServiceConfig price; EnergyAccountingConfig eac; + uint8_t priceModifierCount = 0; size_t size; char* buf = (char*) commonBuffer; @@ -1821,6 +1838,92 @@ void configFileParse() { } else if(strncmp_P(buf, PSTR("priceFixedPrice "), 16) == 0) { if(!lPrice) { config.getPriceServiceConfig(price); lPrice = true; }; price.unused2 = String(buf+16).toFloat() * 1000; + } else if(strncmp_P(buf, PSTR("priceModifier "), 14) == 0) { + PriceConfig pc; + memset(&pc, 0, sizeof(PriceConfig)); + + String line = String(buf+14); + + uint8_t priceIndex = line.substring(0, line.indexOf(" ")).toInt(); + + int nameStart = line.indexOf("\""); + if(nameStart < 0) { + debugW_P(PSTR("Price modifier without name start")); + continue; + } + int nameEnd = line.indexOf("\"", nameStart+1); + if(nameEnd < nameStart) { + debugW_P(PSTR("Price modifier without name end")); + continue; + } + String name = line.substring(nameStart+1, nameEnd); + strcpy(pc.name, name.c_str()); + String rest = line.substring(nameEnd+1); + + String direction = getSplit(rest, 0); + if(direction.equals("import")) { + pc.direction = PRICE_DIRECTION_IMPORT; + } else if(direction.equals("export")) { + pc.direction = PRICE_DIRECTION_EXPORT; + } else if(direction.equals("both")) { + pc.direction = PRICE_DIRECTION_BOTH; + } else { + debugW_P(PSTR("Price modifier with unknown direction \"%s\""), direction.c_str()); + continue; + } + + String type = getSplit(rest, 1); + if(type.equals("fixed")) { + pc.type = PRICE_TYPE_FIXED; + } else if(type.equals("add")) { + pc.type = PRICE_TYPE_ADD; + } else if(type.equals("percent")) { + pc.type = PRICE_TYPE_PCT; + } else if(type.equals("subtract")) { + pc.type = PRICE_TYPE_SUBTRACT; + } else { + debugW_P(PSTR("Price modifier unknown type")); + continue; + } + + pc.value = getSplit(rest, 2).toFloat() * 10000; + + String days = getSplit(rest, 3); + if(days.equals("all")) { + pc.days = 0x7F; + } else { + pc.days = 0; + if(days.indexOf("mo") >= 0) pc.days |= 1 << 0; + if(days.indexOf("tu") >= 0) pc.days |= 1 << 1; + if(days.indexOf("we") >= 0) pc.days |= 1 << 2; + if(days.indexOf("th") >= 0) pc.days |= 1 << 3; + if(days.indexOf("fr") >= 0) pc.days |= 1 << 4; + if(days.indexOf("sa") >= 0) pc.days |= 1 << 5; + if(days.indexOf("su") >= 0) pc.days |= 1 << 6; + } + + String hours = getSplit(rest, 4); + if(hours.equals("all")) { + pc.hours = 0xFFFFFF; + } else { + pc.hours = 0; + for(uint8_t i = 0; i < 24; i++) { + char h[4]; + snprintf_P(h, 4, PSTR("%02d"), i); + if(hours.indexOf(String(h)) >= 0) pc.hours |= 1 << i; + } + } + + String start = getSplit(rest, 5); + pc.start_dayofmonth = start.substring(0, start.indexOf("-")).toInt(); + pc.start_month = start.substring(start.indexOf("-")+1).toInt(); + + String end = getSplit(rest, 6); + pc.end_dayofmonth = end.substring(0, end.indexOf("-")).toInt(); + pc.end_month = end.substring(end.indexOf("-")+1).toInt(); + + ps->setPriceConfig(priceIndex, pc); + priceModifierCount = priceIndex+1; } else if(strncmp_P(buf, PSTR("thresholds "), 11) == 0) { if(!lEac) { config.getEnergyAccountingConfig(eac); lEac = true; }; int i = 0; @@ -2057,6 +2160,7 @@ void configFileParse() { if(lEac) config.setEnergyAccountingConfig(eac); if(sDs) ds.save(); if(sEa) ea.save(); + if(priceModifierCount > 0) ps->save(); config.save(); LittleFS.end(); }