From 924066355200b95f3d47443ddd013f4da7906273 Mon Sep 17 00:00:00 2001 From: Bernhard Kirchen Date: Mon, 19 Feb 2024 13:38:57 +0100 Subject: [PATCH] Feature: show power grid usage on display (#658) * make efficient use of available display area fix calculation of the text baselines, using getAscent() in favor of getMaxCharHeight(), which includes ascent and descent. this moves the first text up and allows to insert margin between the lines until the display area is fully utilized. on large displays, if the small diagram is selected, keep the first line rather low to avoid collision with the diagram y-axis label. in this mode, there is still more space between the text lines as before, allowing for improved readability. * Feature: show power grid usage on display if the power meter is enabled, the display will use two of three out of every three-second time slot to show the grid consumption. closes #620. --- src/Display_Graphic.cpp | 42 +++++++++++++++++++++++++++++++++++++++-- src/WebApi_device.cpp | 2 +- src/main.cpp | 2 +- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/Display_Graphic.cpp b/src/Display_Graphic.cpp index 12b2aa56e..ae9973d6c 100644 --- a/src/Display_Graphic.cpp +++ b/src/Display_Graphic.cpp @@ -4,6 +4,8 @@ */ #include "Display_Graphic.h" #include "Datastore.h" +#include "PowerMeter.h" +#include "Configuration.h" #include #include #include @@ -31,6 +33,8 @@ const uint8_t languages[] = { static const char* const i18n_offline[] = { "Offline", "Offline", "Offline" }; static const char* const i18n_current_power_w[] = { "%.0f W", "%.0f W", "%.0f W" }; static const char* const i18n_current_power_kw[] = { "%.1f kW", "%.1f kW", "%.1f kW" }; +static const char* const i18n_meter_power_w[] = { "grid: %.0f W", "Netz: %.0f W", "reseau: %.0f W" }; +static const char* const i18n_meter_power_kw[] = { "grid: %.1f kW", "Netz: %.1f kW", "reseau: %.1f kW" }; static const char* const i18n_yield_today_wh[] = { "today: %4.0f Wh", "Heute: %4.0f Wh", "auj.: %4.0f Wh" }; static const char* const i18n_yield_total_kwh[] = { "total: %.1f kWh", "Ges.: %.1f kWh", "total: %.1f kWh" }; static const char* const i18n_date_format[] = { "%m/%d/%Y %H:%M", "%d.%m.%Y %H:%M", "%d/%m/%Y %H:%M" }; @@ -67,11 +71,19 @@ void DisplayGraphicClass::init(Scheduler& scheduler, const DisplayType_t type, c void DisplayGraphicClass::calcLineHeights() { - uint8_t yOff = 0; + bool diagram = (_isLarge && _diagram_mode == DiagramMode_t::Small); + // the diagram needs space. we need to keep + // away from the y-axis label in particular. + uint8_t yOff = (diagram?7:0); for (uint8_t i = 0; i < 4; i++) { setFont(i); - yOff += (_display->getMaxCharHeight()); + yOff += _display->getAscent(); _lineOffsets[i] = yOff; + yOff += ((!_isLarge || diagram)?2:3); + // the descent is a negative value and moves the *next* line's + // baseline. the first line never uses a letter with descent and + // we need that space when showing the small diagram. + yOff -= ((i == 0 && diagram)?0:_display->getDescent()); } } @@ -252,6 +264,32 @@ void DisplayGraphicClass::loop() } } + // the IP and time info in the third line use three-second slots. the + // timing for the power meter is chosen such that every third of those + // three-second slots is used to NOT overwrite the total inverter energy. + bool timing = (_mExtra % 9) >= 3; + + if (showText && Configuration.get().PowerMeter.Enabled && timing && !displayPowerSave) { + // erase the third line and print the power meter value instead. + // we do it this way to touch as least upstream code as possible + // to make maintenance easier. + setFont(2); + auto lineHeight = _display->getAscent() - _display->getDescent(); + auto y = _lineOffsets[2] - _display->getAscent(); + _display->setDrawColor(0); + _display->drawBox(0, y, _display->getDisplayWidth(), lineHeight); + _display->setDrawColor(1); + + auto acPower = PowerMeter.getPowerTotal(false); + if (acPower > 999) { + snprintf(_fmtText, sizeof(_fmtText), i18n_meter_power_kw[_display_language], (acPower / 1000)); + } else { + snprintf(_fmtText, sizeof(_fmtText), i18n_meter_power_w[_display_language], acPower); + } + + printText(_fmtText, 2); + } + _display->sendBuffer(); _mExtra++; diff --git a/src/WebApi_device.cpp b/src/WebApi_device.cpp index 010a539f9..4f55de8d0 100644 --- a/src/WebApi_device.cpp +++ b/src/WebApi_device.cpp @@ -184,12 +184,12 @@ void WebApiDeviceClass::onDeviceAdminPost(AsyncWebServerRequest* request) config.Led_Single[i].Brightness = min(100, config.Led_Single[i].Brightness); } + Display.setDiagramMode(static_cast(config.Display.Diagram.Mode)); Display.setOrientation(config.Display.Rotation); Display.enablePowerSafe = config.Display.PowerSafe; Display.enableScreensaver = config.Display.ScreenSaver; Display.setContrast(config.Display.Contrast); Display.setLanguage(config.Display.Language); - Display.setDiagramMode(static_cast(config.Display.Diagram.Mode)); Display.Diagram().updatePeriod(); WebApi.writeConfig(retMsg); diff --git a/src/main.cpp b/src/main.cpp index dd080832e..726a4a97d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -135,12 +135,12 @@ void setup() pin.display_clk, pin.display_cs, pin.display_reset); + Display.setDiagramMode(static_cast(config.Display.Diagram.Mode)); Display.setOrientation(config.Display.Rotation); Display.enablePowerSafe = config.Display.PowerSafe; Display.enableScreensaver = config.Display.ScreenSaver; Display.setContrast(config.Display.Contrast); Display.setLanguage(config.Display.Language); - Display.setDiagramMode(static_cast(config.Display.Diagram.Mode)); Display.setStartupDisplay(); MessageOutput.println("done");