diff --git a/include/Configuration.h b/include/Configuration.h index 570b7c3a..cda48265 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -75,6 +75,7 @@ struct POWERMETER_HTTP_PHASE_CONFIG_T { uint16_t Timeout; char JsonPath[POWERMETER_MAX_HTTP_JSON_PATH_STRLEN + 1]; Unit PowerUnit; + bool SignInverted; }; using PowerMeterHttpConfig = struct POWERMETER_HTTP_PHASE_CONFIG_T; diff --git a/include/HttpPowerMeter.h b/include/HttpPowerMeter.h index db79fe09..25e627cd 100644 --- a/include/HttpPowerMeter.h +++ b/include/HttpPowerMeter.h @@ -26,7 +26,7 @@ private: String extractParam(String& authReq, const String& param, const char delimit); String getcNonce(const int len); String getDigestAuth(String& authReq, const String& username, const String& password, const String& method, const String& uri, unsigned int counter); - bool tryGetFloatValueForPhase(int phase, const char* jsonPath, Unit_t unit); + bool tryGetFloatValueForPhase(int phase, const char* jsonPath, Unit_t unit, bool signInverted); void prepareRequest(uint32_t timeout, const char* httpHeader, const char* httpValue); String sha256(const String& data); }; diff --git a/src/Configuration.cpp b/src/Configuration.cpp index f21571cb..b6565715 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -176,6 +176,7 @@ bool ConfigurationClass::write() powermeter_phase["timeout"] = config.PowerMeter.Http_Phase[i].Timeout; powermeter_phase["json_path"] = config.PowerMeter.Http_Phase[i].JsonPath; powermeter_phase["unit"] = config.PowerMeter.Http_Phase[i].PowerUnit; + powermeter_phase["sign_inverted"] = config.PowerMeter.Http_Phase[i].SignInverted; } JsonObject powerlimiter = doc.createNestedObject("powerlimiter"); @@ -429,6 +430,7 @@ bool ConfigurationClass::read() config.PowerMeter.Http_Phase[i].Timeout = powermeter_phase["timeout"] | POWERMETER_HTTP_TIMEOUT; strlcpy(config.PowerMeter.Http_Phase[i].JsonPath, powermeter_phase["json_path"] | "", sizeof(config.PowerMeter.Http_Phase[i].JsonPath)); config.PowerMeter.Http_Phase[i].PowerUnit = powermeter_phase["unit"] | PowerMeterHttpConfig::Unit::Watts; + config.PowerMeter.Http_Phase[i].SignInverted = powermeter_phase["sign_inverted"] | false; } JsonObject powerlimiter = doc["powerlimiter"]; diff --git a/src/HttpPowerMeter.cpp b/src/HttpPowerMeter.cpp index ada18982..cdb1253f 100644 --- a/src/HttpPowerMeter.cpp +++ b/src/HttpPowerMeter.cpp @@ -42,7 +42,7 @@ bool HttpPowerMeterClass::updateValues() continue; } - if(!tryGetFloatValueForPhase(i, phaseConfig.JsonPath, phaseConfig.PowerUnit)) { + if(!tryGetFloatValueForPhase(i, phaseConfig.JsonPath, phaseConfig.PowerUnit, phaseConfig.SignInverted)) { MessageOutput.printf("[HttpPowerMeter] Getting the power of phase %d (from JSON fetched with Phase 1 config) failed.\r\n", i + 1); MessageOutput.printf("%s\r\n", httpPowerMeterError); return false; @@ -161,7 +161,7 @@ bool HttpPowerMeterClass::httpRequest(int phase, WiFiClient &wifiClient, const S // TODO(schlimmchen): postpone calling tryGetFloatValueForPhase, as it // will be called twice for each phase when doing separate requests. - return tryGetFloatValueForPhase(phase, config.JsonPath, config.PowerUnit); + return tryGetFloatValueForPhase(phase, config.JsonPath, config.PowerUnit, config.SignInverted); } String HttpPowerMeterClass::extractParam(String& authReq, const String& param, const char delimit) { @@ -219,7 +219,7 @@ String HttpPowerMeterClass::getDigestAuth(String& authReq, const String& usernam return authorization; } -bool HttpPowerMeterClass::tryGetFloatValueForPhase(int phase, const char* jsonPath, Unit_t unit) +bool HttpPowerMeterClass::tryGetFloatValueForPhase(int phase, const char* jsonPath, Unit_t unit, bool signInverted) { FirebaseJson json; json.setJsonData(httpResponse); @@ -229,7 +229,9 @@ bool HttpPowerMeterClass::tryGetFloatValueForPhase(int phase, const char* jsonPa return false; } - power[phase] = value.to(); // this is supposed to be in Watts + // this value is supposed to be in Watts and positive if energy is consumed. + power[phase] = value.to(); + switch (unit) { case Unit_t::MilliWatts: power[phase] /= 1000; @@ -240,6 +242,9 @@ bool HttpPowerMeterClass::tryGetFloatValueForPhase(int phase, const char* jsonPa default: break; } + + if (signInverted) { power[phase] *= -1; } + return true; } diff --git a/src/WebApi_powermeter.cpp b/src/WebApi_powermeter.cpp index d66bfe43..bd708c4f 100644 --- a/src/WebApi_powermeter.cpp +++ b/src/WebApi_powermeter.cpp @@ -40,6 +40,7 @@ void WebApiPowerMeterClass::decodeJsonPhaseConfig(JsonObject const& json, PowerM config.Timeout = json["timeout"].as(); strlcpy(config.JsonPath, json["json_path"].as().c_str(), sizeof(config.JsonPath)); config.PowerUnit = json["unit"].as(); + config.SignInverted = json["sign_inverted"].as(); } void WebApiPowerMeterClass::onStatus(AsyncWebServerRequest* request) @@ -75,6 +76,7 @@ void WebApiPowerMeterClass::onStatus(AsyncWebServerRequest* request) phaseObject["timeout"] = config.PowerMeter.Http_Phase[i].Timeout; phaseObject["json_path"] = String(config.PowerMeter.Http_Phase[i].JsonPath); phaseObject["unit"] = config.PowerMeter.Http_Phase[i].PowerUnit; + phaseObject["sign_inverted"] = config.PowerMeter.Http_Phase[i].SignInverted; } response->setLength(); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 14bc1048..882bf40c 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -576,6 +576,8 @@ "httpJsonPath": "JSON Pfad", "httpJsonPathDescription": "JSON Pfad um den Leistungswert zu finden. Es verwendet die Selektions-Syntax von mobizt/FirebaseJson. Beispiele gibt es oben.", "httpUnit": "Einheit", + "httpSignInverted": "Vorzeichen umkehren", + "httpSignInvertedHint": "Positive Werte werden als Leistungsabnahme aus dem Netz interpretiert. Diese Option muss aktiviert werden, wenn das Vorzeichen des Wertes die gegenteilige Bedeutung hat.", "httpTimeout": "Timeout", "testHttpRequest": "Testen" }, diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index b841448c..21dfc81f 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -581,6 +581,8 @@ "httpJsonPath": "JSON path", "httpJsonPathDescription": "JSON path to find the power value in the response. This uses the JSON path query syntax from mobizt/FirebaseJson. See above for examples.", "httpUnit": "Unit", + "httpSignInverted": "Change Sign", + "httpSignInvertedHint": "Is is expected that positive values denote power usage from the grid. Check this option if the sign of this value has the opposite meaning.", "httpTimeout": "Timeout", "testHttpRequest": "Run test", "milliSeconds": "ms" diff --git a/webapp/src/types/PowerMeterConfig.ts b/webapp/src/types/PowerMeterConfig.ts index 5b38faeb..a8ceb4f7 100644 --- a/webapp/src/types/PowerMeterConfig.ts +++ b/webapp/src/types/PowerMeterConfig.ts @@ -10,6 +10,7 @@ export interface PowerMeterHttpPhaseConfig { json_path: string; timeout: number; unit: number; + sign_inverted: boolean; } export interface PowerMeterConfig { diff --git a/webapp/src/views/PowerMeterAdminView.vue b/webapp/src/views/PowerMeterAdminView.vue index 51cde9de..4bc9e76c 100644 --- a/webapp/src/views/PowerMeterAdminView.vue +++ b/webapp/src/views/PowerMeterAdminView.vue @@ -202,6 +202,12 @@ + +