powermeter refactor: test HTTP+JSON power meter as a whole
apply all config values from the webfrontend, then perform one polling cycle. display values seperately in the result, and show the resulting value as well.
This commit is contained in:
parent
20ecf2a66b
commit
a08ef4cb43
@ -53,7 +53,6 @@ void PowerMeterHttpJson::loop()
|
||||
return;
|
||||
}
|
||||
|
||||
_powerValues = std::get<power_values_t>(res);
|
||||
gotUpdate();
|
||||
}
|
||||
|
||||
@ -62,6 +61,12 @@ PowerMeterHttpJson::poll_result_t PowerMeterHttpJson::poll()
|
||||
power_values_t cache;
|
||||
JsonDocument jsonResponse;
|
||||
|
||||
auto prefixedError = [](uint8_t idx, char const* err) -> String {
|
||||
String res("Value ");
|
||||
res.reserve(strlen(err) + 16);
|
||||
return res + String(idx + 1) + ": " + err;
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < POWERMETER_HTTP_JSON_MAX_VALUES; i++) {
|
||||
auto const& cfg = Configuration.get().PowerMeter.HttpJson[i];
|
||||
|
||||
@ -75,24 +80,24 @@ PowerMeterHttpJson::poll_result_t PowerMeterHttpJson::poll()
|
||||
if (upGetter) {
|
||||
auto res = upGetter->performGetRequest();
|
||||
if (!res) {
|
||||
return upGetter->getErrorText();
|
||||
return prefixedError(i, upGetter->getErrorText());
|
||||
}
|
||||
|
||||
auto pStream = res.getStream();
|
||||
if (!pStream) {
|
||||
return String("Programmer error: HTTP request yields no stream");
|
||||
return prefixedError(i, "Programmer error: HTTP request yields no stream");
|
||||
}
|
||||
|
||||
const DeserializationError error = deserializeJson(jsonResponse, *pStream);
|
||||
if (error) {
|
||||
String msg("Unable to parse server response as JSON: ");
|
||||
return msg + error.c_str();
|
||||
return prefixedError(i, String(msg + error.c_str()).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
auto pathResolutionResult = Utils::getJsonValueByPath<float>(jsonResponse, cfg.JsonPath);
|
||||
if (!pathResolutionResult.second.isEmpty()) {
|
||||
return pathResolutionResult.second;
|
||||
return prefixedError(i, pathResolutionResult.second.c_str());
|
||||
}
|
||||
|
||||
// this value is supposed to be in Watts and positive if energy is consumed
|
||||
@ -112,6 +117,7 @@ PowerMeterHttpJson::poll_result_t PowerMeterHttpJson::poll()
|
||||
if (cfg.SignInverted) { cache[i] *= -1; }
|
||||
}
|
||||
|
||||
_powerValues = cache;
|
||||
return cache;
|
||||
}
|
||||
|
||||
|
||||
@ -192,26 +192,15 @@ void WebApiPowerMeterClass::onTestHttpJsonRequest(AsyncWebServerRequest* request
|
||||
|
||||
auto& retMsg = asyncJsonResponse->getRoot();
|
||||
|
||||
JsonObject requestConfig = root["http_request"];
|
||||
if (!requestConfig.containsKey("url")
|
||||
|| !requestConfig.containsKey("auth_type")
|
||||
|| !requestConfig.containsKey("username")
|
||||
|| !requestConfig.containsKey("password")
|
||||
|| !requestConfig.containsKey("header_key")
|
||||
|| !requestConfig.containsKey("header_value")
|
||||
|| !requestConfig.containsKey("timeout")
|
||||
|| !root.containsKey("json_path")) {
|
||||
retMsg["message"] = "Missing fields!";
|
||||
asyncJsonResponse->setLength();
|
||||
request->send(asyncJsonResponse);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
char response[256];
|
||||
|
||||
auto powerMeterConfig = std::make_unique<CONFIG_T::PowerMeterConfig>();
|
||||
Configuration.deserializePowerMeterHttpJsonConfig(root.as<JsonObject>(), powerMeterConfig->HttpJson[0]);
|
||||
powerMeterConfig->HttpIndividualRequests = root["http_individual_requests"].as<bool>();
|
||||
JsonArray httpJson = root["http_json"];
|
||||
for (uint8_t i = 0; i < httpJson.size(); i++) {
|
||||
Configuration.deserializePowerMeterHttpJsonConfig(httpJson[i].as<JsonObject>(),
|
||||
powerMeterConfig->HttpJson[i]);
|
||||
}
|
||||
auto backup = std::make_unique<CONFIG_T::PowerMeterConfig>(Configuration.get().PowerMeter);
|
||||
Configuration.get().PowerMeter = *powerMeterConfig;
|
||||
auto upMeter = std::make_unique<PowerMeterHttpJson>();
|
||||
@ -222,9 +211,14 @@ void WebApiPowerMeterClass::onTestHttpJsonRequest(AsyncWebServerRequest* request
|
||||
if (std::holds_alternative<values_t>(res)) {
|
||||
retMsg["type"] = "success";
|
||||
auto vals = std::get<values_t>(res);
|
||||
snprintf_P(response, sizeof(response), "Result: %5.2fW", vals[0]);
|
||||
auto pos = snprintf(response, sizeof(response), "Result: %5.2fW", vals[0]);
|
||||
for (size_t i = 1; i < POWERMETER_HTTP_JSON_MAX_VALUES; ++i) {
|
||||
if (!powerMeterConfig->HttpJson[i].Enabled) { continue; }
|
||||
pos += snprintf(response + pos, sizeof(response) - pos, ", %5.2fW", vals[i]);
|
||||
}
|
||||
snprintf(response + pos, sizeof(response) - pos, ", Total: %5.2f", upMeter->getPowerTotal());
|
||||
} else {
|
||||
snprintf_P(response, sizeof(response), "%s", std::get<String>(res).c_str());
|
||||
snprintf(response, sizeof(response), "%s", std::get<String>(res).c_str());
|
||||
}
|
||||
|
||||
retMsg["message"] = response;
|
||||
|
||||
@ -581,7 +581,8 @@
|
||||
"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.",
|
||||
"testHttpJsonRequest": "Konfiguration testen (HTTP(S)-Anfrage senden)",
|
||||
"testHttpJsonHeader": "Konfiguration testen",
|
||||
"testHttpJsonRequest": "HTTP(S)-Anfrage(n) senden und Antwort(en) verarbeiten",
|
||||
"testHttpSmlRequest": "Konfiguration testen (HTTP(S)-Anfrage senden)",
|
||||
"HTTP_SML": "HTTP(S) + SML - Konfiguration"
|
||||
},
|
||||
|
||||
@ -583,7 +583,8 @@
|
||||
"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.",
|
||||
"testHttpJsonRequest": "Test configuration (send HTTP(S) request)",
|
||||
"testHttpJsonHeader": "Test Configuration",
|
||||
"testHttpJsonRequest": "Send HTTP(S) request(s) and process response(s)",
|
||||
"testHttpSmlRequest": "Test configuration (send HTTP(S) request)",
|
||||
"HTTP_SML": "Configuration"
|
||||
},
|
||||
|
||||
@ -154,17 +154,23 @@
|
||||
v-model="httpJson.sign_inverted"
|
||||
:tooltip="$t('powermeteradmin.httpSignInvertedHint')"
|
||||
type="checkbox" />
|
||||
</div>
|
||||
</CardElement>
|
||||
|
||||
<div class="text-center mb-3">
|
||||
<button type="button" class="btn btn-danger" @click="testHttpJsonRequest(index)">
|
||||
<CardElement
|
||||
:text="$t('powermeteradmin.testHttpJsonHeader')"
|
||||
textVariant="text-bg-primary"
|
||||
add-space>
|
||||
|
||||
<div class="text-center mt-3 mb-3">
|
||||
<button type="button" class="btn btn-primary" @click="testHttpJsonRequest()">
|
||||
{{ $t('powermeteradmin.testHttpJsonRequest') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<BootstrapAlert v-model="testHttpJsonRequestAlert[index].show" dismissible :variant="testHttpJsonRequestAlert[index].type">
|
||||
{{ testHttpJsonRequestAlert[index].message }}
|
||||
<BootstrapAlert v-model="testHttpJsonRequestAlert.show" dismissible :variant="testHttpJsonRequestAlert.type">
|
||||
{{ testHttpJsonRequestAlert.message }}
|
||||
</BootstrapAlert>
|
||||
</div>
|
||||
</CardElement>
|
||||
</div>
|
||||
|
||||
@ -203,7 +209,7 @@ import FormFooter from '@/components/FormFooter.vue';
|
||||
import InputElement from '@/components/InputElement.vue';
|
||||
import HttpRequestSettings from '@/components/HttpRequestSettings.vue';
|
||||
import { handleResponse, authHeader } from '@/utils/authentication';
|
||||
import type { PowerMeterHttpJsonConfig, PowerMeterConfig } from "@/types/PowerMeterConfig";
|
||||
import type { PowerMeterConfig } from "@/types/PowerMeterConfig";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
@ -235,7 +241,7 @@ export default defineComponent({
|
||||
alertMessage: "",
|
||||
alertType: "info",
|
||||
showAlert: false,
|
||||
testHttpJsonRequestAlert: [{message: "", type: "", show: false}] as { message: string; type: string; show: boolean; }[],
|
||||
testHttpJsonRequestAlert: {message: "", type: "", show: false} as { message: string; type: string; show: boolean; },
|
||||
testHttpSmlRequestAlert: {message: "", type: "", show: false} as { message: string; type: string; show: boolean; }
|
||||
};
|
||||
},
|
||||
@ -250,14 +256,6 @@ export default defineComponent({
|
||||
.then((data) => {
|
||||
this.powerMeterConfigList = data;
|
||||
this.dataLoading = false;
|
||||
|
||||
for (let i = 0; i < this.powerMeterConfigList.http_json.length; i++) {
|
||||
this.testHttpJsonRequestAlert.push({
|
||||
message: "",
|
||||
type: "",
|
||||
show: false,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
savePowerMeterConfig(e: Event) {
|
||||
@ -281,25 +279,15 @@ export default defineComponent({
|
||||
}
|
||||
);
|
||||
},
|
||||
testHttpJsonRequest(index: number) {
|
||||
let valueConfig:PowerMeterHttpJsonConfig;
|
||||
|
||||
if (this.powerMeterConfigList.http_individual_requests) {
|
||||
valueConfig = this.powerMeterConfigList.http_json[index];
|
||||
} else {
|
||||
valueConfig = { ...this.powerMeterConfigList.http_json[0] };
|
||||
valueConfig.index = this.powerMeterConfigList.http_json[index].index;
|
||||
valueConfig.json_path = this.powerMeterConfigList.http_json[index].json_path;
|
||||
}
|
||||
|
||||
this.testHttpJsonRequestAlert[index] = {
|
||||
testHttpJsonRequest() {
|
||||
this.testHttpJsonRequestAlert = {
|
||||
message: "Sending HTTP request...",
|
||||
type: "info",
|
||||
show: true,
|
||||
};
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append("data", JSON.stringify(valueConfig));
|
||||
formData.append("data", JSON.stringify(this.powerMeterConfigList));
|
||||
|
||||
fetch("/api/powermeter/testhttpjsonrequest", {
|
||||
method: "POST",
|
||||
@ -309,7 +297,7 @@ export default defineComponent({
|
||||
.then((response) => handleResponse(response, this.$emitter, this.$router))
|
||||
.then(
|
||||
(response) => {
|
||||
this.testHttpJsonRequestAlert[index] = {
|
||||
this.testHttpJsonRequestAlert = {
|
||||
message: response.message,
|
||||
type: response.type,
|
||||
show: true,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user