Normalize power/energy output formatting
This commit is contained in:
@@ -4,6 +4,8 @@
|
|||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <Adafruit_GFX.h>
|
#include <Adafruit_GFX.h>
|
||||||
#include <Adafruit_SSD1306.h>
|
#include <Adafruit_SSD1306.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
static Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, -1);
|
static Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, -1);
|
||||||
@@ -161,6 +163,20 @@ static uint32_t age_seconds(uint32_t ts_utc, uint32_t ts_ms) {
|
|||||||
return (millis() - ts_ms) / 1000;
|
return (millis() - ts_ms) / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t round_power_w(float value) {
|
||||||
|
if (isnan(value)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
long rounded = lroundf(value);
|
||||||
|
if (rounded > INT32_MAX) {
|
||||||
|
return INT32_MAX;
|
||||||
|
}
|
||||||
|
if (rounded < INT32_MIN) {
|
||||||
|
return INT32_MIN;
|
||||||
|
}
|
||||||
|
return static_cast<int32_t>(rounded);
|
||||||
|
}
|
||||||
|
|
||||||
static bool render_last_error_line(uint8_t y) {
|
static bool render_last_error_line(uint8_t y) {
|
||||||
if (g_last_error == FaultType::None) {
|
if (g_last_error == FaultType::None) {
|
||||||
return false;
|
return false;
|
||||||
@@ -238,15 +254,15 @@ static void render_sender_status() {
|
|||||||
static void render_sender_measurement() {
|
static void render_sender_measurement() {
|
||||||
display.clearDisplay();
|
display.clearDisplay();
|
||||||
display.setCursor(0, 0);
|
display.setCursor(0, 0);
|
||||||
display.printf("E %.1f kWh", g_last_meter.energy_total_kwh);
|
display.printf("E %.2f kWh", g_last_meter.energy_total_kwh);
|
||||||
display.setCursor(0, 12);
|
display.setCursor(0, 12);
|
||||||
display.printf("P %.0fW", g_last_meter.total_power_w);
|
display.printf("P %dW", static_cast<int>(round_power_w(g_last_meter.total_power_w)));
|
||||||
display.setCursor(0, 24);
|
display.setCursor(0, 24);
|
||||||
display.printf("L1 %.0fW", g_last_meter.phase_power_w[0]);
|
display.printf("L1 %dW", static_cast<int>(round_power_w(g_last_meter.phase_power_w[0])));
|
||||||
display.setCursor(0, 36);
|
display.setCursor(0, 36);
|
||||||
display.printf("L2 %.0fW", g_last_meter.phase_power_w[1]);
|
display.printf("L2 %dW", static_cast<int>(round_power_w(g_last_meter.phase_power_w[1])));
|
||||||
display.setCursor(0, 48);
|
display.setCursor(0, 48);
|
||||||
display.printf("L3 %.0fW", g_last_meter.phase_power_w[2]);
|
display.printf("L3 %dW", static_cast<int>(round_power_w(g_last_meter.phase_power_w[2])));
|
||||||
display.display();
|
display.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -336,17 +352,17 @@ static void render_receiver_sender(uint8_t index) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
display.setCursor(0, 12);
|
display.setCursor(0, 12);
|
||||||
display.printf("E %.1f kWh", status.last_data.energy_total_kwh);
|
display.printf("E %.2f kWh", status.last_data.energy_total_kwh);
|
||||||
display.setCursor(0, 22);
|
display.setCursor(0, 22);
|
||||||
display.printf("L1 %.0fW", status.last_data.phase_power_w[0]);
|
display.printf("L1 %dW", static_cast<int>(round_power_w(status.last_data.phase_power_w[0])));
|
||||||
display.setCursor(0, 32);
|
display.setCursor(0, 32);
|
||||||
display.printf("L2 %.0fW", status.last_data.phase_power_w[1]);
|
display.printf("L2 %dW", static_cast<int>(round_power_w(status.last_data.phase_power_w[1])));
|
||||||
display.setCursor(0, 42);
|
display.setCursor(0, 42);
|
||||||
display.printf("L3 %.0fW", status.last_data.phase_power_w[2]);
|
display.printf("L3 %dW", static_cast<int>(round_power_w(status.last_data.phase_power_w[2])));
|
||||||
display.setCursor(0, 52);
|
display.setCursor(0, 52);
|
||||||
display.print("P");
|
display.print("P");
|
||||||
char p_buf[16];
|
char p_buf[16];
|
||||||
snprintf(p_buf, sizeof(p_buf), "%.0fW", status.last_data.total_power_w);
|
snprintf(p_buf, sizeof(p_buf), "%dW", static_cast<int>(round_power_w(status.last_data.total_power_w)));
|
||||||
int16_t x1 = 0;
|
int16_t x1 = 0;
|
||||||
int16_t y1 = 0;
|
int16_t y1 = 0;
|
||||||
uint16_t w = 0;
|
uint16_t w = 0;
|
||||||
|
|||||||
@@ -87,6 +87,17 @@ static void format_float_2(char *buf, size_t buf_len, float value) {
|
|||||||
snprintf(buf, buf_len, "%.2f", round2(value));
|
snprintf(buf, buf_len, "%.2f", round2(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void set_int_or_null(JsonDocument &doc, const char *key, float value) {
|
||||||
|
if (!key || key[0] == '\0') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (isnan(value)) {
|
||||||
|
doc[key] = nullptr;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doc[key] = round_to_i32(value);
|
||||||
|
}
|
||||||
|
|
||||||
bool meterDataToJson(const MeterData &data, String &out_json) {
|
bool meterDataToJson(const MeterData &data, String &out_json) {
|
||||||
StaticJsonDocument<256> doc;
|
StaticJsonDocument<256> doc;
|
||||||
doc["id"] = short_id_from_device_id(data.device_id);
|
doc["id"] = short_id_from_device_id(data.device_id);
|
||||||
@@ -94,14 +105,10 @@ bool meterDataToJson(const MeterData &data, String &out_json) {
|
|||||||
char buf[16];
|
char buf[16];
|
||||||
format_float_2(buf, sizeof(buf), data.energy_total_kwh);
|
format_float_2(buf, sizeof(buf), data.energy_total_kwh);
|
||||||
doc["e_kwh"] = serialized(buf);
|
doc["e_kwh"] = serialized(buf);
|
||||||
format_float_2(buf, sizeof(buf), data.total_power_w);
|
set_int_or_null(doc, "p_w", data.total_power_w);
|
||||||
doc["p_w"] = serialized(buf);
|
set_int_or_null(doc, "p1_w", data.phase_power_w[0]);
|
||||||
format_float_2(buf, sizeof(buf), data.phase_power_w[0]);
|
set_int_or_null(doc, "p2_w", data.phase_power_w[1]);
|
||||||
doc["p1_w"] = serialized(buf);
|
set_int_or_null(doc, "p3_w", data.phase_power_w[2]);
|
||||||
format_float_2(buf, sizeof(buf), data.phase_power_w[1]);
|
|
||||||
doc["p2_w"] = serialized(buf);
|
|
||||||
format_float_2(buf, sizeof(buf), data.phase_power_w[2]);
|
|
||||||
doc["p3_w"] = serialized(buf);
|
|
||||||
format_float_2(buf, sizeof(buf), data.battery_voltage_v);
|
format_float_2(buf, sizeof(buf), data.battery_voltage_v);
|
||||||
doc["bat_v"] = serialized(buf);
|
doc["bat_v"] = serialized(buf);
|
||||||
doc["bat_pct"] = data.battery_percent;
|
doc["bat_pct"] = data.battery_percent;
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static WebServer server(80);
|
static WebServer server(80);
|
||||||
@@ -55,6 +57,20 @@ static HistoryJob g_history = {};
|
|||||||
static constexpr size_t SD_LIST_MAX_FILES = 200;
|
static constexpr size_t SD_LIST_MAX_FILES = 200;
|
||||||
static constexpr size_t SD_DOWNLOAD_MAX_PATH = 160;
|
static constexpr size_t SD_DOWNLOAD_MAX_PATH = 160;
|
||||||
|
|
||||||
|
static int32_t round_power_w(float value) {
|
||||||
|
if (isnan(value)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
long rounded = lroundf(value);
|
||||||
|
if (rounded > INT32_MAX) {
|
||||||
|
return INT32_MAX;
|
||||||
|
}
|
||||||
|
if (rounded < INT32_MIN) {
|
||||||
|
return INT32_MIN;
|
||||||
|
}
|
||||||
|
return static_cast<int32_t>(rounded);
|
||||||
|
}
|
||||||
|
|
||||||
static bool auth_required() {
|
static bool auth_required() {
|
||||||
return g_is_ap ? WEB_AUTH_REQUIRE_AP : WEB_AUTH_REQUIRE_STA;
|
return g_is_ap ? WEB_AUTH_REQUIRE_AP : WEB_AUTH_REQUIRE_STA;
|
||||||
}
|
}
|
||||||
@@ -360,10 +376,11 @@ static String render_sender_block(const SenderStatus &status) {
|
|||||||
if (!status.has_data) {
|
if (!status.has_data) {
|
||||||
s += "No data";
|
s += "No data";
|
||||||
} else {
|
} else {
|
||||||
s += "Energy: " + String(status.last_data.energy_total_kwh, 3) + " kWh<br>";
|
s += "Energy: " + String(status.last_data.energy_total_kwh, 2) + " kWh<br>";
|
||||||
s += "Power: " + String(status.last_data.total_power_w, 1) + " W<br>";
|
s += "Power: " + String(round_power_w(status.last_data.total_power_w)) + " W<br>";
|
||||||
s += "P1/P2/P3: " + String(status.last_data.phase_power_w[0], 1) + " / " + String(status.last_data.phase_power_w[1], 1) +
|
s += "P1/P2/P3: " + String(round_power_w(status.last_data.phase_power_w[0])) + " / " +
|
||||||
" / " + String(status.last_data.phase_power_w[2], 1) + " W<br>";
|
String(round_power_w(status.last_data.phase_power_w[1])) + " / " +
|
||||||
|
String(round_power_w(status.last_data.phase_power_w[2])) + " W<br>";
|
||||||
s += "Battery: " + String(status.last_data.battery_percent) + "% (" + String(status.last_data.battery_voltage_v, 2) + " V)";
|
s += "Battery: " + String(status.last_data.battery_percent) + "% (" + String(status.last_data.battery_voltage_v, 2) + " V)";
|
||||||
}
|
}
|
||||||
s += "</div>";
|
s += "</div>";
|
||||||
@@ -597,11 +614,11 @@ static void handle_sender() {
|
|||||||
html += "<tr>";
|
html += "<tr>";
|
||||||
html += "<td>" + String(r) + "</td>";
|
html += "<td>" + String(r) + "</td>";
|
||||||
html += "<td>" + String(d.ts_utc) + "</td>";
|
html += "<td>" + String(d.ts_utc) + "</td>";
|
||||||
html += "<td>" + String(d.energy_total_kwh, 3) + "</td>";
|
html += "<td>" + String(d.energy_total_kwh, 2) + "</td>";
|
||||||
html += "<td>" + String(d.total_power_w, 1) + "</td>";
|
html += "<td>" + String(round_power_w(d.total_power_w)) + "</td>";
|
||||||
html += "<td>" + String(d.phase_power_w[0], 1) + "</td>";
|
html += "<td>" + String(round_power_w(d.phase_power_w[0])) + "</td>";
|
||||||
html += "<td>" + String(d.phase_power_w[1], 1) + "</td>";
|
html += "<td>" + String(round_power_w(d.phase_power_w[1])) + "</td>";
|
||||||
html += "<td>" + String(d.phase_power_w[2], 1) + "</td>";
|
html += "<td>" + String(round_power_w(d.phase_power_w[2])) + "</td>";
|
||||||
html += "<td>" + String(d.battery_voltage_v, 2) + "</td>";
|
html += "<td>" + String(d.battery_voltage_v, 2) + "</td>";
|
||||||
html += "<td>" + String(d.battery_percent) + "</td>";
|
html += "<td>" + String(d.battery_percent) + "</td>";
|
||||||
html += "<td>" + String(d.link_rssi_dbm) + "</td>";
|
html += "<td>" + String(d.link_rssi_dbm) + "</td>";
|
||||||
@@ -754,7 +771,8 @@ static void handle_history_data() {
|
|||||||
if (bin.count == 0) {
|
if (bin.count == 0) {
|
||||||
server.sendContent(String("[") + bin.ts + ",null]");
|
server.sendContent(String("[") + bin.ts + ",null]");
|
||||||
} else {
|
} else {
|
||||||
server.sendContent(String("[") + bin.ts + "," + String(value, 2) + "]");
|
int32_t rounded = round_power_w(value);
|
||||||
|
server.sendContent(String("[") + bin.ts + "," + String(rounded) + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
server.sendContent("]}");
|
server.sendContent("]}");
|
||||||
|
|||||||
Reference in New Issue
Block a user