From df40286c04db2c775fc6d3196e40b7348e2f5aa2 Mon Sep 17 00:00:00 2001 From: Thomas Pohl Date: Sun, 23 Apr 2023 11:14:13 +0200 Subject: [PATCH 01/10] Add support for 128x32 display --- src/plugins/Display/Display_Mono.cpp | 104 +++++++++++++++++++++------ src/plugins/Display/Display_Mono.h | 13 ++-- src/web/html/setup.html | 4 +- 3 files changed, 92 insertions(+), 29 deletions(-) diff --git a/src/plugins/Display/Display_Mono.cpp b/src/plugins/Display/Display_Mono.cpp index d55b6061..26da4142 100644 --- a/src/plugins/Display/Display_Mono.cpp +++ b/src/plugins/Display/Display_Mono.cpp @@ -28,7 +28,7 @@ DisplayMono::DisplayMono() { void DisplayMono::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char* version) { - if ((0 < type) && (type < 4)) { + if ((0 < type) && (type < 5)) { u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); mType = type; switch(type) { @@ -42,21 +42,25 @@ void DisplayMono::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, u case 3: mDisplay = new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset); break; + case 4: + mDisplay = new U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C(rot, reset, clock, data); + break; } mUtcTs = utcTs; mDisplay->begin(); - mIsLarge = (mDisplay->getWidth() > 120); - calcLineHeights(); + mIsWide = (mDisplay->getWidth() > 120); + mIsTall = (mDisplay->getHeight() > 60); + calcLinePositions(); mDisplay->clearBuffer(); if (3 != mType) mDisplay->setContrast(mLuminance); - printText("AHOY!", 0, 35); - printText("ahoydtu.de", 2, 20); - printText(version, 3, 46); + printText("AHOY!", 0); + printText("ahoydtu.de", 2); + printText(version, 3); mDisplay->sendBuffer(); } } @@ -92,7 +96,7 @@ void DisplayMono::disp(float totalPower, float totalYieldDay, float totalYieldTo } printText(_fmtText, 0); } else { - printText("offline", 0, 25); + printText("offline", 0); // check if it's time to enter power saving mode if (mTimeout == 0) mDisplay->setPowerSave(mEnPowerSafe); @@ -111,10 +115,12 @@ void DisplayMono::disp(float totalPower, float totalYieldDay, float totalYieldTo snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); printText(_fmtText, 3); } else { - if(mIsLarge && (NULL != mUtcTs)) - printText(ah::getDateTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); - else - printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); + if (NULL != mUtcTs){ + if(mIsWide && mIsTall) + printText(ah::getDateTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); + else + printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); + } } mDisplay->sendBuffer(); @@ -123,35 +129,87 @@ void DisplayMono::disp(float totalPower, float totalYieldDay, float totalYieldTo _mExtra++; } -void DisplayMono::calcLineHeights() { - uint8_t yOff = 0; +void DisplayMono::calcLinePositions() { + uint8_t yOff[] = {0,0}; for (uint8_t i = 0; i < 4; i++) { setFont(i); - yOff += (mDisplay->getMaxCharHeight()); - mLineOffsets[i] = yOff; + yOff[getColumn(i)] += (mDisplay->getMaxCharHeight()); + mLineYOffsets[i] = yOff[getColumn(i)]; + if (isTwoRowLine(i)){ + yOff[getColumn(i)] += mDisplay->getMaxCharHeight(); + } + yOff[getColumn(i)]+= BOTTOM_MARGIN; + if (mIsTall && mIsWide){ + mLineXOffsets[i] = (i == 0) ? 10 : 5 + (getColumn(i)==1? 80 : 0); + } else { + mLineXOffsets[i] = (getColumn(i)==1? 80 : 0); + } } } inline void DisplayMono::setFont(uint8_t line) { switch (line) { case 0: - mDisplay->setFont((mIsLarge) ? u8g2_font_ncenB14_tr : u8g2_font_logisoso16_tr); + if (mIsWide && mIsTall){ + mDisplay->setFont(u8g2_font_ncenB14_tr); + } else if (mIsWide && ! mIsTall){ + mDisplay->setFont(u8g2_font_9x15_tf); + } else { + mDisplay->setFont(u8g2_font_logisoso16_tr); + } break; case 3: - mDisplay->setFont(u8g2_font_5x8_tr); + if (mIsWide && ! mIsTall){ + mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); + } else { + mDisplay->setFont(u8g2_font_5x8_tr); + } break; default: - mDisplay->setFont((mIsLarge) ? u8g2_font_ncenB10_tr : u8g2_font_5x8_tr); + if (mIsTall){ + mDisplay->setFont(u8g2_font_ncenB10_tr); + } else if (mIsWide){ + mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); + } else { + mDisplay->setFont(u8g2_font_5x8_tr); + } break; } } -void DisplayMono::printText(const char* text, uint8_t line, uint8_t dispX) { - if (!mIsLarge) { - dispX = (line == 0) ? 10 : 5; +inline uint8_t DisplayMono::getColumn(uint8_t line) { + if (mIsTall){ + return 0; + } else if (line>=1 && line<=2){ + return 1; + } else { + return 0; + } +} + +inline bool DisplayMono::isTwoRowLine(uint8_t line) { + if (mIsTall){ + return false; + } else if (line>=1 && line<=2){ + return true; + } else { + return false; } +} +void DisplayMono::printText(const char* text, uint8_t line) { setFont(line); - dispX += (mEnScreenSaver) ? (_mExtra % 7) : 0; - mDisplay->drawStr(dispX, mLineOffsets[line], text); + uint8_t dispX = mLineXOffsets[line] + ((mEnScreenSaver) ? (_mExtra % 7) : 0); + + if (isTwoRowLine(line)){ + String stringText = String(text); + int space = stringText.indexOf(" "); + mDisplay->drawStr(dispX, mLineYOffsets[line], stringText.substring(0,space).c_str()); + if (space>0) + mDisplay->drawStr(dispX, mLineYOffsets[line] + mDisplay->getMaxCharHeight(), stringText.substring(space+1).c_str()); + } else { + mDisplay->drawStr(dispX, mLineYOffsets[line], text); + } } + + diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index ad04c9f4..a2b03212 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -4,6 +4,7 @@ #include #define DISP_DEFAULT_TIMEOUT 60 // in seconds #define DISP_FMT_TEXT_LEN 32 +#define BOTTOM_MARGIN 5 class DisplayMono { public: @@ -15,9 +16,11 @@ class DisplayMono { void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); private: - void calcLineHeights(); + void calcLinePositions(); void setFont(uint8_t line); - void printText(const char* text, uint8_t line, uint8_t dispX = 5); + uint8_t getColumn(uint8_t line); + bool isTwoRowLine(uint8_t line); + void printText(const char* text, uint8_t line); U8G2* mDisplay; @@ -25,10 +28,12 @@ class DisplayMono { bool mEnPowerSafe, mEnScreenSaver; uint8_t mLuminance; - bool mIsLarge = false; + bool mIsTall = false; + bool mIsWide = false; uint8_t mLoopCnt; uint32_t* mUtcTs; - uint8_t mLineOffsets[5]; + uint8_t mLineXOffsets[5]; + uint8_t mLineYOffsets[5]; uint16_t _dispY; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index c86ee980..427152e3 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -733,7 +733,7 @@ ); } - var opts = [[0, "None"], [1, "SSD1306 0.96\""], [2, "SH1106 1.3\""], [3, "Nokia5110"]]; + var opts = [[0, "None"], [1, "SSD1306 0.96\" 128X64"], [2, "SH1106 1.3\""], [3, "Nokia5110"], [4, "SSD1306 0.96\" 128X32"]]; if("ESP32" == type) opts.push([10, "ePaper"]); var dispType = sel("disp_typ", opts, obj["disp_typ"]); @@ -769,7 +769,7 @@ if(0 == dispType) cl.add("hide"); - else if(dispType <= 2) { // OLED + else if(dispType <= 2 || dispType == 4) { // OLED if(i < 2) cl.remove("hide"); else From 8960fa6650d9e4893cb90fc3a8018948d94d718d Mon Sep 17 00:00:00 2001 From: Thomas Pohl Date: Mon, 1 May 2023 12:15:33 +0200 Subject: [PATCH 02/10] Refactored DisplayMono class to improve maintainability --- src/plugins/Display/Display.h | 192 +++++++++-------- src/plugins/Display/Display_Mono.cpp | 215 -------------------- src/plugins/Display/Display_Mono.h | 38 +--- src/plugins/Display/Display_Mono_128X32.cpp | 169 +++++++++++++++ src/plugins/Display/Display_Mono_128X32.h | 37 ++++ src/plugins/Display/Display_Mono_128X64.cpp | 146 +++++++++++++ src/plugins/Display/Display_Mono_128X64.h | 36 ++++ src/plugins/Display/Display_Mono_84X48.cpp | 140 +++++++++++++ src/plugins/Display/Display_Mono_84X48.h | 34 ++++ 9 files changed, 673 insertions(+), 334 deletions(-) delete mode 100644 src/plugins/Display/Display_Mono.cpp create mode 100644 src/plugins/Display/Display_Mono_128X32.cpp create mode 100644 src/plugins/Display/Display_Mono_128X32.h create mode 100644 src/plugins/Display/Display_Mono_128X64.cpp create mode 100644 src/plugins/Display/Display_Mono_128X64.h create mode 100644 src/plugins/Display/Display_Mono_84X48.cpp create mode 100644 src/plugins/Display/Display_Mono_84X48.h diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 1a0222b2..a16b3bb4 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -7,108 +7,124 @@ #include "../../hm/hmSystem.h" #include "../../utils/helper.h" #include "Display_Mono.h" +#include "Display_Mono_128X32.h" +#include "Display_Mono_128X64.h" +#include "Display_Mono_84X48.h" #include "Display_ePaper.h" template class Display { public: - Display() {} + Display() {} + + void setup(display_t *cfg, HMSYSTEM *sys, uint32_t *utcTs, const char *version) { + mCfg = cfg; + mSys = sys; + mUtcTs = utcTs; + mNewPayload = false; + mLoopCnt = 0; + mVersion = version; + + if (mCfg->type == 0) + return; + + if ((0 < mCfg->type) && (mCfg->type < 10)) { + switch (mCfg->type) { + case 2: + case 1: + default: + mMono = new DisplayMono128X64(); + break; + case 3: + mMono = new DisplayMono84X48(); + break; + case 4: + mMono = new DisplayMono128X32(); + break; + } + mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->pxShift, mCfg->contrast); + mMono->init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); + } else if (mCfg->type >= 10) { +#if defined(ESP32) + mRefreshCycle = 0; + mEpaper.config(mCfg->rot); + mEpaper.init(mCfg->type, mCfg->disp_cs, mCfg->disp_dc, mCfg->disp_reset, mCfg->disp_busy, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); +#endif + } + } + + void payloadEventListener(uint8_t cmd) { + mNewPayload = true; + } - void setup(display_t *cfg, HMSYSTEM *sys, uint32_t *utcTs, const char *version) { - mCfg = cfg; - mSys = sys; - mUtcTs = utcTs; + void tickerSecond() { + mMono->loop(); + if (mNewPayload || ((++mLoopCnt % 10) == 0)) { mNewPayload = false; mLoopCnt = 0; - mVersion = version; - - if (mCfg->type == 0) - return; - - if ((0 < mCfg->type) && (mCfg->type < 10)) { - mMono.config(mCfg->pwrSaveAtIvOffline, mCfg->pxShift, mCfg->contrast); - mMono.init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); - } else if (mCfg->type >= 10) { - #if defined(ESP32) - mRefreshCycle = 0; - mEpaper.config(mCfg->rot); - mEpaper.init(mCfg->type, mCfg->disp_cs, mCfg->disp_dc, mCfg->disp_reset, mCfg->disp_busy, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); - #endif - } + DataScreen(); } - - void payloadEventListener(uint8_t cmd) { - mNewPayload = true; + } + + private: + void DataScreen() { + if (mCfg->type == 0) + return; + if (*mUtcTs == 0) + return; + + float totalPower = 0; + float totalYieldDay = 0; + float totalYieldTotal = 0; + + uint8_t isprod = 0; + + Inverter<> *iv; + record_t<> *rec; + for (uint8_t i = 0; i < mSys->getNumInverters(); i++) { + iv = mSys->getInverterByPos(i); + rec = iv->getRecordStruct(RealTimeRunData_Debug); + if (iv == NULL) + continue; + + if (iv->isProducing(*mUtcTs)) + isprod++; + + totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec); + totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec); + totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec); } - void tickerSecond() { - mMono.loop(); - if (mNewPayload || ((++mLoopCnt % 10) == 0)) { - mNewPayload = false; - mLoopCnt = 0; - DataScreen(); - } + if ((0 < mCfg->type) && (mCfg->type < 10)) { + mMono->disp(totalPower, totalYieldDay, totalYieldTotal, isprod); + } else if (mCfg->type >= 10) { +#if defined(ESP32) + mEpaper.loop(totalPower, totalYieldDay, totalYieldTotal, isprod); + mRefreshCycle++; +#endif } - private: - void DataScreen() { - if (mCfg->type == 0) - return; - if (*mUtcTs == 0) - return; - - float totalPower = 0; - float totalYieldDay = 0; - float totalYieldTotal = 0; - - uint8_t isprod = 0; - - Inverter<> *iv; - record_t<> *rec; - for (uint8_t i = 0; i < mSys->getNumInverters(); i++) { - iv = mSys->getInverterByPos(i); - rec = iv->getRecordStruct(RealTimeRunData_Debug); - if (iv == NULL) - continue; - - if (iv->isProducing(*mUtcTs)) - isprod++; - - totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec); - totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec); - totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec); - } - - if ((0 < mCfg->type) && (mCfg->type < 10)) { - mMono.disp(totalPower, totalYieldDay, totalYieldTotal, isprod); - } else if (mCfg->type >= 10) { - #if defined(ESP32) - mEpaper.loop(totalPower, totalYieldDay, totalYieldTotal, isprod); - mRefreshCycle++; - #endif - } - - #if defined(ESP32) - if (mRefreshCycle > 480) { - mEpaper.fullRefresh(); - mRefreshCycle = 0; - } - #endif +#if defined(ESP32) + if (mRefreshCycle > 480) { + mEpaper.fullRefresh(); + mRefreshCycle = 0; } - - // private member variables - bool mNewPayload; - uint8_t mLoopCnt; - uint32_t *mUtcTs; - const char *mVersion; - display_t *mCfg; - HMSYSTEM *mSys; - uint16_t mRefreshCycle; - - #if defined(ESP32) - DisplayEPaper mEpaper; - #endif - DisplayMono mMono; +#endif + } + + // private member variables + bool mNewPayload; + uint8_t mLoopCnt; + uint32_t *mUtcTs; + const char *mVersion; + display_t *mCfg; + HMSYSTEM *mSys; + uint16_t mRefreshCycle; + +#if defined(ESP32) + DisplayEPaper mEpaper; +#endif + DisplayMono *mMono; }; #endif /*__DISPLAY__*/ diff --git a/src/plugins/Display/Display_Mono.cpp b/src/plugins/Display/Display_Mono.cpp deleted file mode 100644 index 26da4142..00000000 --- a/src/plugins/Display/Display_Mono.cpp +++ /dev/null @@ -1,215 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#include "Display_Mono.h" - -#ifdef ESP8266 - #include -#elif defined(ESP32) - #include -#endif -#include "../../utils/helper.h" - -//#ifdef U8X8_HAVE_HW_SPI -//#include -//#endif -//#ifdef U8X8_HAVE_HW_I2C -//#include -//#endif - -DisplayMono::DisplayMono() { - mEnPowerSafe = true; - mEnScreenSaver = true; - mLuminance = 60; - _dispY = 0; - mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) - mUtcTs = NULL; - mType = 0; -} - - - -void DisplayMono::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char* version) { - if ((0 < type) && (type < 5)) { - u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); - mType = type; - switch(type) { - case 1: - mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); - break; - default: - case 2: - mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); - break; - case 3: - mDisplay = new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset); - break; - case 4: - mDisplay = new U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C(rot, reset, clock, data); - break; - } - - mUtcTs = utcTs; - - mDisplay->begin(); - - mIsWide = (mDisplay->getWidth() > 120); - mIsTall = (mDisplay->getHeight() > 60); - calcLinePositions(); - - mDisplay->clearBuffer(); - if (3 != mType) - mDisplay->setContrast(mLuminance); - printText("AHOY!", 0); - printText("ahoydtu.de", 2); - printText(version, 3); - mDisplay->sendBuffer(); - } -} - -void DisplayMono::config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { - mEnPowerSafe = enPowerSafe; - mEnScreenSaver = enScreenSaver; - mLuminance = lum; -} - -void DisplayMono::loop(void) { - if (mEnPowerSafe) - if(mTimeout != 0) - mTimeout--; -} - -void DisplayMono::disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { - - - mDisplay->clearBuffer(); - - // set Contrast of the Display to raise the lifetime - if (3 != mType) - mDisplay->setContrast(mLuminance); - - if ((totalPower > 0) && (isprod > 0)) { - mTimeout = DISP_DEFAULT_TIMEOUT; - mDisplay->setPowerSave(false); - if (totalPower > 999) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); - } else { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); - } - printText(_fmtText, 0); - } else { - printText("offline", 0); - // check if it's time to enter power saving mode - if (mTimeout == 0) - mDisplay->setPowerSave(mEnPowerSafe); - } - - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); - printText(_fmtText, 1); - - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); - printText(_fmtText, 2); - - IPAddress ip = WiFi.localIP(); - if (!(_mExtra % 10) && (ip)) { - printText(ip.toString().c_str(), 3); - } else if (!(_mExtra % 5)) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); - printText(_fmtText, 3); - } else { - if (NULL != mUtcTs){ - if(mIsWide && mIsTall) - printText(ah::getDateTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); - else - printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); - } - } - - mDisplay->sendBuffer(); - - _dispY = 0; - _mExtra++; -} - -void DisplayMono::calcLinePositions() { - uint8_t yOff[] = {0,0}; - for (uint8_t i = 0; i < 4; i++) { - setFont(i); - yOff[getColumn(i)] += (mDisplay->getMaxCharHeight()); - mLineYOffsets[i] = yOff[getColumn(i)]; - if (isTwoRowLine(i)){ - yOff[getColumn(i)] += mDisplay->getMaxCharHeight(); - } - yOff[getColumn(i)]+= BOTTOM_MARGIN; - if (mIsTall && mIsWide){ - mLineXOffsets[i] = (i == 0) ? 10 : 5 + (getColumn(i)==1? 80 : 0); - } else { - mLineXOffsets[i] = (getColumn(i)==1? 80 : 0); - } - } -} - -inline void DisplayMono::setFont(uint8_t line) { - switch (line) { - case 0: - if (mIsWide && mIsTall){ - mDisplay->setFont(u8g2_font_ncenB14_tr); - } else if (mIsWide && ! mIsTall){ - mDisplay->setFont(u8g2_font_9x15_tf); - } else { - mDisplay->setFont(u8g2_font_logisoso16_tr); - } - break; - case 3: - if (mIsWide && ! mIsTall){ - mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); - } else { - mDisplay->setFont(u8g2_font_5x8_tr); - } - break; - default: - if (mIsTall){ - mDisplay->setFont(u8g2_font_ncenB10_tr); - } else if (mIsWide){ - mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); - } else { - mDisplay->setFont(u8g2_font_5x8_tr); - } - break; - } -} - -inline uint8_t DisplayMono::getColumn(uint8_t line) { - if (mIsTall){ - return 0; - } else if (line>=1 && line<=2){ - return 1; - } else { - return 0; - } -} - -inline bool DisplayMono::isTwoRowLine(uint8_t line) { - if (mIsTall){ - return false; - } else if (line>=1 && line<=2){ - return true; - } else { - return false; - } -} -void DisplayMono::printText(const char* text, uint8_t line) { - setFont(line); - - uint8_t dispX = mLineXOffsets[line] + ((mEnScreenSaver) ? (_mExtra % 7) : 0); - - if (isTwoRowLine(line)){ - String stringText = String(text); - int space = stringText.indexOf(" "); - mDisplay->drawStr(dispX, mLineYOffsets[line], stringText.substring(0,space).c_str()); - if (space>0) - mDisplay->drawStr(dispX, mLineYOffsets[line] + mDisplay->getMaxCharHeight(), stringText.substring(space+1).c_str()); - } else { - mDisplay->drawStr(dispX, mLineYOffsets[line], text); - } -} - - diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index a2b03212..5a825d55 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -3,41 +3,17 @@ #include #define DISP_DEFAULT_TIMEOUT 60 // in seconds -#define DISP_FMT_TEXT_LEN 32 -#define BOTTOM_MARGIN 5 +#define DISP_FMT_TEXT_LEN 32 +#define BOTTOM_MARGIN 5 class DisplayMono { public: - DisplayMono(); + DisplayMono(){}; - void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char* version); - void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum); - void loop(void); - void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + virtual void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version) = 0; + virtual void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) = 0; + virtual void loop(void) = 0; + virtual void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) = 0; private: - void calcLinePositions(); - void setFont(uint8_t line); - uint8_t getColumn(uint8_t line); - bool isTwoRowLine(uint8_t line); - void printText(const char* text, uint8_t line); - - U8G2* mDisplay; - - uint8_t mType; - bool mEnPowerSafe, mEnScreenSaver; - uint8_t mLuminance; - - bool mIsTall = false; - bool mIsWide = false; - uint8_t mLoopCnt; - uint32_t* mUtcTs; - uint8_t mLineXOffsets[5]; - uint8_t mLineYOffsets[5]; - - uint16_t _dispY; - - uint8_t _mExtra; - uint16_t mTimeout; - char _fmtText[DISP_FMT_TEXT_LEN]; }; diff --git a/src/plugins/Display/Display_Mono_128X32.cpp b/src/plugins/Display/Display_Mono_128X32.cpp new file mode 100644 index 00000000..46a012ec --- /dev/null +++ b/src/plugins/Display/Display_Mono_128X32.cpp @@ -0,0 +1,169 @@ + +// SPDX-License-Identifier: GPL-2.0-or-later +#include "Display_Mono_128X32.h" + +#include "Display_Mono.h" + +#ifdef ESP8266 +#include +#elif defined(ESP32) +#include +#endif +#include "../../utils/helper.h" + +// #ifdef U8X8_HAVE_HW_SPI +// #include +// #endif +// #ifdef U8X8_HAVE_HW_I2C +// #include +// #endif + +DisplayMono128X32::DisplayMono128X32() : DisplayMono::DisplayMono() { + mEnPowerSafe = true; + mEnScreenSaver = true; + mLuminance = 60; + _dispY = 0; + mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) + mUtcTs = NULL; + mType = 0; +} + +void DisplayMono128X32::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { + if ((0 < type) && (type < 5)) { + u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); + mType = type; + mDisplay = new U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C(rot, reset, clock, data); + + mUtcTs = utcTs; + + mDisplay->begin(); + + calcLinePositions(); + + mDisplay->clearBuffer(); + mDisplay->setContrast(mLuminance); + printText("AHOY!", 0); + printText("ahoydtu.de", 2); + printText(version, 3); + mDisplay->sendBuffer(); + } +} + +void DisplayMono128X32::config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { + mEnPowerSafe = enPowerSafe; + mEnScreenSaver = enScreenSaver; + mLuminance = lum; +} + +void DisplayMono128X32::loop(void) { + if (mEnPowerSafe) + if (mTimeout != 0) + mTimeout--; +} + +void DisplayMono128X32::disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { + mDisplay->clearBuffer(); + + // set Contrast of the Display to raise the lifetime + if (3 != mType) + mDisplay->setContrast(mLuminance); + + if ((totalPower > 0) && (isprod > 0)) { + mTimeout = DISP_DEFAULT_TIMEOUT; + mDisplay->setPowerSave(false); + if (totalPower > 999) { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); + } else { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); + } + printText(_fmtText, 0); + } else { + printText("offline", 0); + // check if it's time to enter power saving mode + if (mTimeout == 0) + mDisplay->setPowerSave(mEnPowerSafe); + } + + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); + printText(_fmtText, 1); + + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); + printText(_fmtText, 2); + + IPAddress ip = WiFi.localIP(); + if (!(_mExtra % 10) && (ip)) { + printText(ip.toString().c_str(), 3); + } else if (!(_mExtra % 5)) { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); + printText(_fmtText, 3); + } else { + if (NULL != mUtcTs) { + printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); + } + } + + mDisplay->sendBuffer(); + + _dispY = 0; + _mExtra++; +} + +void DisplayMono128X32::calcLinePositions() { + uint8_t yOff[] = {0, 0}; + for (uint8_t i = 0; i < 4; i++) { + setFont(i); + yOff[getColumn(i)] += (mDisplay->getMaxCharHeight()); + mLineYOffsets[i] = yOff[getColumn(i)]; + if (isTwoRowLine(i)) { + yOff[getColumn(i)] += mDisplay->getMaxCharHeight(); + } + yOff[getColumn(i)] += BOTTOM_MARGIN; + mLineXOffsets[i] = (getColumn(i) == 1 ? 80 : 0); + } +} + +inline void DisplayMono128X32::setFont(uint8_t line) { + switch (line) { + case 0: + + mDisplay->setFont(u8g2_font_9x15_tf); + break; + case 3: + mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); + break; + default: + mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); + break; + } +} + +inline uint8_t DisplayMono128X32::getColumn(uint8_t line) { + if (line >= 1 && line <= 2) { + return 1; + } else { + return 0; + } +} + +inline bool DisplayMono128X32::isTwoRowLine(uint8_t line) { + if (line >= 1 && line <= 2) { + return true; + } else { + return false; + } +} +void DisplayMono128X32::printText(const char *text, uint8_t line) { + setFont(line); + + uint8_t dispX = mLineXOffsets[line] + ((mEnScreenSaver) ? (_mExtra % 7) : 0); + + if (isTwoRowLine(line)) { + String stringText = String(text); + int space = stringText.indexOf(" "); + mDisplay->drawStr(dispX, mLineYOffsets[line], stringText.substring(0, space).c_str()); + if (space > 0) + mDisplay->drawStr(dispX, mLineYOffsets[line] + mDisplay->getMaxCharHeight(), stringText.substring(space + 1).c_str()); + } else { + mDisplay->drawStr(dispX, mLineYOffsets[line], text); + } +} diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h new file mode 100644 index 00000000..00dbf904 --- /dev/null +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -0,0 +1,37 @@ +#pragma once +// SPDX-License-Identifier: GPL-2.0-or-later +#include "Display_Mono.h" + +class DisplayMono128X32 : public DisplayMono { + public: + DisplayMono128X32(); + + void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version); + void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum); + void loop(void); + void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + + private: + void calcLinePositions(); + void setFont(uint8_t line); + uint8_t getColumn(uint8_t line); + bool isTwoRowLine(uint8_t line); + void printText(const char* text, uint8_t line); + + U8G2* mDisplay; + + uint8_t mType; + bool mEnPowerSafe, mEnScreenSaver; + uint8_t mLuminance; + + uint8_t mLoopCnt; + uint32_t* mUtcTs; + uint8_t mLineXOffsets[5]; + uint8_t mLineYOffsets[5]; + + uint16_t _dispY; + + uint8_t _mExtra; + uint16_t mTimeout; + char _fmtText[DISP_FMT_TEXT_LEN]; +}; diff --git a/src/plugins/Display/Display_Mono_128X64.cpp b/src/plugins/Display/Display_Mono_128X64.cpp new file mode 100644 index 00000000..0224f50a --- /dev/null +++ b/src/plugins/Display/Display_Mono_128X64.cpp @@ -0,0 +1,146 @@ + +// SPDX-License-Identifier: GPL-2.0-or-later +#include "Display_Mono_128X64.h" + +#include "Display_Mono.h" + +#ifdef ESP8266 +#include +#elif defined(ESP32) +#include +#endif +#include "../../utils/helper.h" + +// #ifdef U8X8_HAVE_HW_SPI +// #include +// #endif +// #ifdef U8X8_HAVE_HW_I2C +// #include +// #endif + +DisplayMono128X64::DisplayMono128X64() : DisplayMono::DisplayMono() { + mEnPowerSafe = true; + mEnScreenSaver = true; + mLuminance = 60; + _dispY = 0; + mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) + mUtcTs = NULL; + mType = 0; +} + +void DisplayMono128X64::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { + if ((0 < type) && (type < 5)) { + u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); + mType = type; + switch (type) { + case 1: + mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); + break; + default: + case 2: + mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); + break; + } + + mUtcTs = utcTs; + + mDisplay->begin(); + + calcLineHeights(); + + mDisplay->clearBuffer(); + mDisplay->setContrast(mLuminance); + printText("AHOY!", 0, 35); + printText("ahoydtu.de", 2, 20); + printText(version, 3, 46); + mDisplay->sendBuffer(); + } +} + +void DisplayMono128X64::config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { + mEnPowerSafe = enPowerSafe; + mEnScreenSaver = enScreenSaver; + mLuminance = lum; +} + +void DisplayMono128X64::loop(void) { + if (mEnPowerSafe) + if (mTimeout != 0) + mTimeout--; +} + +void DisplayMono128X64::disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { + mDisplay->clearBuffer(); + + // set Contrast of the Display to raise the lifetime + if (3 != mType) + mDisplay->setContrast(mLuminance); + + if ((totalPower > 0) && (isprod > 0)) { + mTimeout = DISP_DEFAULT_TIMEOUT; + mDisplay->setPowerSave(false); + if (totalPower > 999) { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); + } else { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); + } + printText(_fmtText, 0); + } else { + printText("offline", 0, 25); + // check if it's time to enter power saving mode + if (mTimeout == 0) + mDisplay->setPowerSave(mEnPowerSafe); + } + + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); + printText(_fmtText, 1); + + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); + printText(_fmtText, 2); + + IPAddress ip = WiFi.localIP(); + if (!(_mExtra % 10) && (ip)) { + printText(ip.toString().c_str(), 3); + } else if (!(_mExtra % 5)) { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); + printText(_fmtText, 3); + } else { + if (NULL != mUtcTs) { + printText(ah::getDateTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); + } + } + + mDisplay->sendBuffer(); + + _dispY = 0; + _mExtra++; +} + +void DisplayMono128X64::calcLineHeights() { + uint8_t yOff = 0; + for (uint8_t i = 0; i < 4; i++) { + setFont(i); + yOff += (mDisplay->getMaxCharHeight()); + mLineOffsets[i] = yOff; + } +} + +inline void DisplayMono128X64::setFont(uint8_t line) { + switch (line) { + case 0: + mDisplay->setFont(u8g2_font_ncenB14_tr); + break; + case 3: + mDisplay->setFont(u8g2_font_5x8_tr); + break; + default: + mDisplay->setFont(u8g2_font_ncenB10_tr); + break; + } +} +void DisplayMono128X64::printText(const char *text, uint8_t line, uint8_t dispX) { + setFont(line); + + dispX += (mEnScreenSaver) ? (_mExtra % 7) : 0; + mDisplay->drawStr(dispX, mLineOffsets[line], text); +} diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h new file mode 100644 index 00000000..4902d14b --- /dev/null +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -0,0 +1,36 @@ +#pragma once +// SPDX-License-Identifier: GPL-2.0-or-later +#include "Display_Mono.h" + +class DisplayMono128X64 : public DisplayMono { + public: + DisplayMono128X64(); + + void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version); + void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum); + void loop(void); + void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + + private: + void calcLineHeights(); + void setFont(uint8_t line); + uint8_t getColumn(uint8_t line); + bool isTwoRowLine(uint8_t line); + void printText(const char* text, uint8_t line, uint8_t dispX = 5); + + U8G2* mDisplay; + + uint8_t mType; + bool mEnPowerSafe, mEnScreenSaver; + uint8_t mLuminance; + + uint8_t mLoopCnt; + uint32_t* mUtcTs; + uint8_t mLineOffsets[5]; + + uint16_t _dispY; + + uint8_t _mExtra; + uint16_t mTimeout; + char _fmtText[DISP_FMT_TEXT_LEN]; +}; diff --git a/src/plugins/Display/Display_Mono_84X48.cpp b/src/plugins/Display/Display_Mono_84X48.cpp new file mode 100644 index 00000000..a84f6037 --- /dev/null +++ b/src/plugins/Display/Display_Mono_84X48.cpp @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include "Display_Mono_84X48.h" + +#include "Display_Mono.h" + +#ifdef ESP8266 +#include +#elif defined(ESP32) +#include +#endif +#include "../../utils/helper.h" + +// #ifdef U8X8_HAVE_HW_SPI +// #include +// #endif +// #ifdef U8X8_HAVE_HW_I2C +// #include +// #endif + +DisplayMono84X48::DisplayMono84X48() : DisplayMono::DisplayMono() { + mEnPowerSafe = true; + mEnScreenSaver = true; + mLuminance = 60; + _dispY = 0; + mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) + mUtcTs = NULL; + mType = 0; +} + +void DisplayMono84X48::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { + if ((0 < type) && (type < 5)) { + u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); + mType = type; + mDisplay = new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset); + + mUtcTs = utcTs; + + mDisplay->begin(); + + calcLineHeights(); + + mDisplay->clearBuffer(); + if (3 != mType) + mDisplay->setContrast(mLuminance); + printText("AHOY!", 0); + printText("ahoydtu.de", 2); + printText(version, 3); + mDisplay->sendBuffer(); + } +} + +void DisplayMono84X48::config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { + mEnPowerSafe = enPowerSafe; + mEnScreenSaver = enScreenSaver; + mLuminance = lum; +} + +void DisplayMono84X48::loop(void) { + if (mEnPowerSafe) + if (mTimeout != 0) + mTimeout--; +} + +void DisplayMono84X48::disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { + mDisplay->clearBuffer(); + + // set Contrast of the Display to raise the lifetime + if (3 != mType) + mDisplay->setContrast(mLuminance); + + if ((totalPower > 0) && (isprod > 0)) { + mTimeout = DISP_DEFAULT_TIMEOUT; + mDisplay->setPowerSave(false); + if (totalPower > 999) { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); + } else { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); + } + printText(_fmtText, 0); + } else { + printText("offline", 0); + // check if it's time to enter power saving mode + if (mTimeout == 0) + mDisplay->setPowerSave(mEnPowerSafe); + } + + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); + printText(_fmtText, 1); + + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); + printText(_fmtText, 2); + + IPAddress ip = WiFi.localIP(); + if (!(_mExtra % 10) && (ip)) { + printText(ip.toString().c_str(), 3); + } else if (!(_mExtra % 5)) { + snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); + printText(_fmtText, 3); + } else { + if (NULL != mUtcTs) { + printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); + } + } + + mDisplay->sendBuffer(); + + _dispY = 0; + _mExtra++; +} + +void DisplayMono84X48::calcLineHeights() { + uint8_t yOff = 0; + for (uint8_t i = 0; i < 4; i++) { + setFont(i); + yOff += (mDisplay->getMaxCharHeight()); + mLineOffsets[i] = yOff; + } +} + +inline void DisplayMono84X48::setFont(uint8_t line) { + switch (line) { + case 0: + mDisplay->setFont(u8g2_font_logisoso16_tr); + break; + case 3: + mDisplay->setFont(u8g2_font_5x8_tr); + break; + default: + mDisplay->setFont(u8g2_font_5x8_tr); + break; + } +} + +void DisplayMono84X48::printText(const char *text, uint8_t line) { + uint8_t dispX = (line == 0) ? 10 : 5; + setFont(line); + + dispX += (mEnScreenSaver) ? (_mExtra % 7) : 0; + mDisplay->drawStr(dispX, mLineOffsets[line], text); +} diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h new file mode 100644 index 00000000..1ad140e9 --- /dev/null +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -0,0 +1,34 @@ +#pragma once +// SPDX-License-Identifier: GPL-2.0-or-later +#include "Display_Mono.h" + +class DisplayMono84X48 : public DisplayMono { + public: + DisplayMono84X48(); + + void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version); + void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum); + void loop(void); + void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + + private: + void calcLineHeights(); + void setFont(uint8_t line); + void printText(const char* text, uint8_t line); + + U8G2* mDisplay; + + uint8_t mType; + bool mEnPowerSafe, mEnScreenSaver; + uint8_t mLuminance; + + uint8_t mLoopCnt; + uint32_t* mUtcTs; + uint8_t mLineOffsets[5]; + + uint16_t _dispY; + + uint8_t _mExtra; + uint16_t mTimeout; + char _fmtText[DISP_FMT_TEXT_LEN]; +}; From da4a347c49d7de97cd7f7209a4c34a55c85fb59f Mon Sep 17 00:00:00 2001 From: Thomas Pohl Date: Mon, 1 May 2023 12:50:19 +0200 Subject: [PATCH 03/10] not NULL chheck --- src/plugins/Display/Display.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index a16b3bb4..e2c0a040 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -58,7 +58,9 @@ class Display { } void tickerSecond() { - mMono->loop(); + if (mMono!=NULL){ + mMono->loop(); + } if (mNewPayload || ((++mLoopCnt % 10) == 0)) { mNewPayload = false; mLoopCnt = 0; @@ -95,7 +97,7 @@ class Display { totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec); } - if ((0 < mCfg->type) && (mCfg->type < 10)) { + if ((0 < mCfg->type) && (mCfg->type < 10) && mMono!=NULL) { mMono->disp(totalPower, totalYieldDay, totalYieldTotal, isprod); } else if (mCfg->type >= 10) { #if defined(ESP32) From ded680bc80a2bca2a811f38dde63a01e3fcf91c4 Mon Sep 17 00:00:00 2001 From: Thomas Pohl Date: Mon, 1 May 2023 19:18:34 +0200 Subject: [PATCH 04/10] For ePaper display, show ahoy logo on offline screen Solves #897 --- src/plugins/Display/Display_ePaper.cpp | 94 +++++++++++++++++--------- src/plugins/Display/Display_ePaper.h | 1 + 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index 99d35ed8..7a000c2d 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -120,6 +120,28 @@ void DisplayEPaper::lastUpdatePaged() { } while (_display->nextPage()); } //*************************************************************************** +void DisplayEPaper::offlineFooter() { + int16_t tbx, tby; + uint16_t tbw, tbh; + + _display->setFont(&FreeSans9pt7b); + _display->setTextColor(GxEPD_WHITE); + + _display->setPartialWindow(0, _display->height() - mHeadFootPadding, _display->width(), mHeadFootPadding); + _display->fillScreen(GxEPD_BLACK); + do { + if (NULL != mUtcTs) { + snprintf(_fmtText, sizeof(_fmtText), "offline"); + + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((_display->width() - tbw) / 2) - tbx; + + _display->setCursor(x, (_display->height() - 3)); + _display->println(_fmtText); + } + } while (_display->nextPage()); +} +//*************************************************************************** void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod) { int16_t tbx, tby; uint16_t tbw, tbh, x, y; @@ -139,38 +161,44 @@ void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, fl } else { snprintf(_fmtText, sizeof(_fmtText), "offline"); } - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; - _display->setCursor(x, mHeadFootPadding + tbh + 10); - _display->print(_fmtText); - - _display->setFont(&FreeSans12pt7b); - y = _display->height() / 2; - _display->setCursor(5, y); - _display->print("today:"); - snprintf(_fmtText, _display->width(), "%.0f", _totalYieldDay); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 38, y); - _display->println("Wh"); - - y = y + tbh + 7; - _display->setCursor(5, y); - _display->print("total:"); - snprintf(_fmtText, _display->width(), "%.1f", _totalYieldTotal); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 50, y); - _display->println("kWh"); - - _display->setCursor(10, _display->height() - (mHeadFootPadding + 10)); - snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", _isprod); - _display->println(_fmtText); + if (_totalPower == 0){ + _display->fillRect(0, mHeadFootPadding, 200,200, GxEPD_BLACK); + _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); + } else { + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + x = ((_display->width() - tbw) / 2) - tbx; + _display->setCursor(x, mHeadFootPadding + tbh + 10); + _display->print(_fmtText); + + _display->setFont(&FreeSans12pt7b); + y = _display->height() / 2; + _display->setCursor(5, y); + _display->print("today:"); + snprintf(_fmtText, _display->width(), "%.0f", _totalYieldDay); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + x = ((_display->width() - tbw) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 38, y); + _display->println("Wh"); + + y = y + tbh + 7; + _display->setCursor(5, y); + _display->print("total:"); + snprintf(_fmtText, _display->width(), "%.1f", _totalYieldTotal); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + x = ((_display->width() - tbw) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - 50, y); + _display->println("kWh"); + + _display->setCursor(10, _display->height() - (mHeadFootPadding + 10)); + snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", _isprod); + _display->println(_fmtText); + + } } while (_display->nextPage()); } //*************************************************************************** @@ -185,10 +213,12 @@ void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYield // call the PowerPage to change the PV Power Values actualPowerPaged(totalPower, totalYieldDay, totalYieldTotal, isprod); - // if there was an change and the Inverter is producing set a new Timestam in the footline + // if there was an change and the Inverter is producing set a new Timestamp in the footline if ((isprod > 0) && (_changed)) { _changed = false; lastUpdatePaged(); + } else if(totalPower==0) { + offlineFooter(); } _display->powerOff(); diff --git a/src/plugins/Display/Display_ePaper.h b/src/plugins/Display/Display_ePaper.h index b2729f25..1e8d34b8 100644 --- a/src/plugins/Display/Display_ePaper.h +++ b/src/plugins/Display/Display_ePaper.h @@ -39,6 +39,7 @@ class DisplayEPaper { void headlineIP(); void actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod); void lastUpdatePaged(); + void offlineFooter(); uint8_t mDisplayRotation; bool _changed = false; From 2e71401d093e815ece1a64189998ddf2dcd5ce00 Mon Sep 17 00:00:00 2001 From: lumapu Date: Wed, 17 May 2023 22:58:59 +0200 Subject: [PATCH 05/10] another try to compile successfully --- src/platformio.ini | 18 +++++++++--------- src/publisher/pubMqtt.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/platformio.ini b/src/platformio.ini index a8fa0d03..904f6120 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -30,7 +30,7 @@ lib_deps = bblanchon/ArduinoJson @ ^6.21.2 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.34.17 - zinggjm/GxEPD2 @ ^1.5.0 + zinggjm/GxEPD2 @ ^1.5.2 [env:esp8266-release] @@ -98,9 +98,9 @@ monitor_filters = log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory [env:esp32-wroom32-release] -platform = espressif32@>=6.1.0 +platform = espressif32@6.1.0 board = lolin_d32 -build_flags = -D RELEASE -std=gnu++14 +build_flags = -D RELEASE -std=gnu++17 build_unflags = -std=gnu++11 monitor_filters = ;default ; Remove typical terminal control codes from input @@ -109,10 +109,10 @@ monitor_filters = esp32_exception_decoder [env:esp32-wroom32-release-prometheus] -platform = espressif32@>=6.1.0 +platform = espressif32@6.1.0 board = lolin_d32 build_flags = -D RELEASE - -std=gnu++14 + -std=gnu++17 -DENABLE_PROMETHEUS_EP build_unflags = -std=gnu++11 monitor_filters = @@ -122,7 +122,7 @@ monitor_filters = esp32_exception_decoder [env:esp32-wroom32-debug] -platform = espressif32@>=6.1.0 +platform = espressif32@6.1.0 board = lolin_d32 build_flags = -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_CORE @@ -131,7 +131,7 @@ build_flags = -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_OOM -DDEBUG_ESP_PORT=Serial - -std=gnu++14 + -std=gnu++17 build_unflags = -std=gnu++11 build_type = debug monitor_filters = @@ -140,13 +140,13 @@ monitor_filters = log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory [env:opendtufusionv1-release] -platform = espressif32@>=6.1.0 +platform = espressif32@6.1.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin upload_speed = 115200 debug_tool = esp-builtin debug_speed = 12000 -build_flags = -D RELEASE -std=gnu++14 +build_flags = -D RELEASE -std=gnu++17 build_unflags = -std=gnu++11 monitor_filters = ;default ; Remove typical terminal control codes from input diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index 049554d7..1f8519f5 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -564,7 +564,7 @@ class PubMqtt { void sendIvData() { bool anyAvail = processIvStatus(); if (mLastAnyAvail != anyAvail) - mSendList.push(RealTimeRunData_Debug); // makes shure that total values are calculated + mSendList.push(RealTimeRunData_Debug); // makes sure that total values are calculated if(mSendList.empty()) return; From 78b421dcb56e225e0f6b4559aaac1b5479844541 Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 21 May 2023 14:50:19 +0200 Subject: [PATCH 06/10] 0.6.14 Update Mono Display #902 --- src/defines.h | 2 +- src/plugins/Display/Display.h | 6 +- src/plugins/Display/Display_Mono.h | 44 +++-- src/plugins/Display/Display_Mono_128X32.cpp | 169 -------------------- src/plugins/Display/Display_Mono_128X32.h | 168 ++++++++++++++++--- src/plugins/Display/Display_Mono_128X64.cpp | 146 ----------------- src/plugins/Display/Display_Mono_128X64.h | 150 ++++++++++++++--- src/plugins/Display/Display_Mono_84X48.cpp | 140 ---------------- src/plugins/Display/Display_Mono_84X48.h | 142 +++++++++++++--- 9 files changed, 428 insertions(+), 539 deletions(-) delete mode 100644 src/plugins/Display/Display_Mono_128X32.cpp delete mode 100644 src/plugins/Display/Display_Mono_128X64.cpp delete mode 100644 src/plugins/Display/Display_Mono_84X48.cpp diff --git a/src/defines.h b/src/defines.h index 93722b6c..5e282f46 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 6 -#define VERSION_PATCH 9 +#define VERSION_PATCH 14 //------------------------------------- typedef struct { diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index e2c0a040..8ce4ed7a 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -58,9 +58,9 @@ class Display { } void tickerSecond() { - if (mMono!=NULL){ + if (mMono != NULL) mMono->loop(); - } + if (mNewPayload || ((++mLoopCnt % 10) == 0)) { mNewPayload = false; mLoopCnt = 0; @@ -97,7 +97,7 @@ class Display { totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec); } - if ((0 < mCfg->type) && (mCfg->type < 10) && mMono!=NULL) { + if ((0 < mCfg->type) && (mCfg->type < 10) && (mMono != NULL)) { mMono->disp(totalPower, totalYieldDay, totalYieldTotal, isprod); } else if (mCfg->type >= 10) { #if defined(ESP32) diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 5a825d55..ed9154af 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -1,19 +1,45 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#pragma once +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- +#pragma once #include #define DISP_DEFAULT_TIMEOUT 60 // in seconds #define DISP_FMT_TEXT_LEN 32 #define BOTTOM_MARGIN 5 + +#ifdef ESP8266 +#include +#elif defined(ESP32) +#include +#endif +#include "../../utils/helper.h" + class DisplayMono { public: - DisplayMono(){}; + DisplayMono() {}; + + virtual void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version) = 0; + virtual void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) = 0; + virtual void loop(void) = 0; + virtual void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) = 0; + + protected: + U8G2* mDisplay; + + uint8_t mType; + bool mEnPowerSafe, mEnScreenSaver; + uint8_t mLuminance; + + uint8_t mLoopCnt; + uint32_t* mUtcTs; + uint8_t mLineXOffsets[5]; + uint8_t mLineYOffsets[5]; - virtual void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version) = 0; - virtual void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) = 0; - virtual void loop(void) = 0; - virtual void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) = 0; + uint16_t mDispY; - private: -}; + uint8_t mExtra; + uint16_t mTimeout; + char mFmtText[DISP_FMT_TEXT_LEN];}; diff --git a/src/plugins/Display/Display_Mono_128X32.cpp b/src/plugins/Display/Display_Mono_128X32.cpp deleted file mode 100644 index 46a012ec..00000000 --- a/src/plugins/Display/Display_Mono_128X32.cpp +++ /dev/null @@ -1,169 +0,0 @@ - -// SPDX-License-Identifier: GPL-2.0-or-later -#include "Display_Mono_128X32.h" - -#include "Display_Mono.h" - -#ifdef ESP8266 -#include -#elif defined(ESP32) -#include -#endif -#include "../../utils/helper.h" - -// #ifdef U8X8_HAVE_HW_SPI -// #include -// #endif -// #ifdef U8X8_HAVE_HW_I2C -// #include -// #endif - -DisplayMono128X32::DisplayMono128X32() : DisplayMono::DisplayMono() { - mEnPowerSafe = true; - mEnScreenSaver = true; - mLuminance = 60; - _dispY = 0; - mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) - mUtcTs = NULL; - mType = 0; -} - -void DisplayMono128X32::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { - if ((0 < type) && (type < 5)) { - u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); - mType = type; - mDisplay = new U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C(rot, reset, clock, data); - - mUtcTs = utcTs; - - mDisplay->begin(); - - calcLinePositions(); - - mDisplay->clearBuffer(); - mDisplay->setContrast(mLuminance); - printText("AHOY!", 0); - printText("ahoydtu.de", 2); - printText(version, 3); - mDisplay->sendBuffer(); - } -} - -void DisplayMono128X32::config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { - mEnPowerSafe = enPowerSafe; - mEnScreenSaver = enScreenSaver; - mLuminance = lum; -} - -void DisplayMono128X32::loop(void) { - if (mEnPowerSafe) - if (mTimeout != 0) - mTimeout--; -} - -void DisplayMono128X32::disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { - mDisplay->clearBuffer(); - - // set Contrast of the Display to raise the lifetime - if (3 != mType) - mDisplay->setContrast(mLuminance); - - if ((totalPower > 0) && (isprod > 0)) { - mTimeout = DISP_DEFAULT_TIMEOUT; - mDisplay->setPowerSave(false); - if (totalPower > 999) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); - } else { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); - } - printText(_fmtText, 0); - } else { - printText("offline", 0); - // check if it's time to enter power saving mode - if (mTimeout == 0) - mDisplay->setPowerSave(mEnPowerSafe); - } - - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); - printText(_fmtText, 1); - - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); - printText(_fmtText, 2); - - IPAddress ip = WiFi.localIP(); - if (!(_mExtra % 10) && (ip)) { - printText(ip.toString().c_str(), 3); - } else if (!(_mExtra % 5)) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); - printText(_fmtText, 3); - } else { - if (NULL != mUtcTs) { - printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); - } - } - - mDisplay->sendBuffer(); - - _dispY = 0; - _mExtra++; -} - -void DisplayMono128X32::calcLinePositions() { - uint8_t yOff[] = {0, 0}; - for (uint8_t i = 0; i < 4; i++) { - setFont(i); - yOff[getColumn(i)] += (mDisplay->getMaxCharHeight()); - mLineYOffsets[i] = yOff[getColumn(i)]; - if (isTwoRowLine(i)) { - yOff[getColumn(i)] += mDisplay->getMaxCharHeight(); - } - yOff[getColumn(i)] += BOTTOM_MARGIN; - mLineXOffsets[i] = (getColumn(i) == 1 ? 80 : 0); - } -} - -inline void DisplayMono128X32::setFont(uint8_t line) { - switch (line) { - case 0: - - mDisplay->setFont(u8g2_font_9x15_tf); - break; - case 3: - mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); - break; - default: - mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); - break; - } -} - -inline uint8_t DisplayMono128X32::getColumn(uint8_t line) { - if (line >= 1 && line <= 2) { - return 1; - } else { - return 0; - } -} - -inline bool DisplayMono128X32::isTwoRowLine(uint8_t line) { - if (line >= 1 && line <= 2) { - return true; - } else { - return false; - } -} -void DisplayMono128X32::printText(const char *text, uint8_t line) { - setFont(line); - - uint8_t dispX = mLineXOffsets[line] + ((mEnScreenSaver) ? (_mExtra % 7) : 0); - - if (isTwoRowLine(line)) { - String stringText = String(text); - int space = stringText.indexOf(" "); - mDisplay->drawStr(dispX, mLineYOffsets[line], stringText.substring(0, space).c_str()); - if (space > 0) - mDisplay->drawStr(dispX, mLineYOffsets[line] + mDisplay->getMaxCharHeight(), stringText.substring(space + 1).c_str()); - } else { - mDisplay->drawStr(dispX, mLineYOffsets[line], text); - } -} diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index 00dbf904..9d5ade7e 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -1,37 +1,155 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + #pragma once -// SPDX-License-Identifier: GPL-2.0-or-later #include "Display_Mono.h" class DisplayMono128X32 : public DisplayMono { - public: - DisplayMono128X32(); + public: + DisplayMono128X32() : DisplayMono() { + mEnPowerSafe = true; + mEnScreenSaver = true; + mLuminance = 60; + mExtra = 0; + mDispY = 0; + mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) + mUtcTs = NULL; + mType = 0; + } + + + void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { + if((0 == type) || (type > 4)) + return; + + u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); + mType = type; + mDisplay = new U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C(rot, reset, clock, data); + + mUtcTs = utcTs; + + mDisplay->begin(); + + calcLinePositions(); + + mDisplay->clearBuffer(); + mDisplay->setContrast(mLuminance); + printText("AHOY!", 0); + printText("ahoydtu.de", 2); + printText(version, 3); + mDisplay->sendBuffer(); + } + + void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { + mEnPowerSafe = enPowerSafe; + mEnScreenSaver = enScreenSaver; + mLuminance = lum; + } + + void loop(void) { + if (mEnPowerSafe) { + if (mTimeout != 0) + mTimeout--; + } + } + + void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { + mDisplay->clearBuffer(); + + // set Contrast of the Display to raise the lifetime + if (3 != mType) + mDisplay->setContrast(mLuminance); + + if ((totalPower > 0) && (isprod > 0)) { + mTimeout = DISP_DEFAULT_TIMEOUT; + mDisplay->setPowerSave(false); + if (totalPower > 999) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); + + printText(mFmtText, 0); + } else { + printText("offline", 0); + // check if it's time to enter power saving mode + if (mTimeout == 0) + mDisplay->setPowerSave(mEnPowerSafe); + } + + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); + printText(mFmtText, 1); + + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); + printText(mFmtText, 2); + + IPAddress ip = WiFi.localIP(); + if (!(mExtra % 10) && (ip)) + printText(ip.toString().c_str(), 3); + else if (!(mExtra % 5)) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); + printText(mFmtText, 3); + } else if (NULL != mUtcTs) + printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); + + mDisplay->sendBuffer(); + + mDispY = 0; + mExtra++; + } - void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version); - void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum); - void loop(void); - void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + private: + void calcLinePositions() { + uint8_t yOff[] = {0, 0}; + for (uint8_t i = 0; i < 4; i++) { + setFont(i); + yOff[getColumn(i)] += (mDisplay->getMaxCharHeight()); + mLineYOffsets[i] = yOff[getColumn(i)]; + if (isTwoRowLine(i)) + yOff[getColumn(i)] += mDisplay->getMaxCharHeight(); + yOff[getColumn(i)] += BOTTOM_MARGIN; + mLineXOffsets[i] = (getColumn(i) == 1 ? 80 : 0); + } + } - private: - void calcLinePositions(); - void setFont(uint8_t line); - uint8_t getColumn(uint8_t line); - bool isTwoRowLine(uint8_t line); - void printText(const char* text, uint8_t line); + inline void setFont(uint8_t line) { + switch (line) { + case 0: + mDisplay->setFont(u8g2_font_9x15_tf); + break; + case 3: + mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); + break; + default: + mDisplay->setFont(u8g2_font_tom_thumb_4x6_tf); + break; + } + } - U8G2* mDisplay; + inline uint8_t getColumn(uint8_t line) { + if (line >= 1 && line <= 2) + return 1; + else + return 0; + } - uint8_t mType; - bool mEnPowerSafe, mEnScreenSaver; - uint8_t mLuminance; + inline bool isTwoRowLine(uint8_t line) { + return ((line >= 1) && (line <= 2)); + } - uint8_t mLoopCnt; - uint32_t* mUtcTs; - uint8_t mLineXOffsets[5]; - uint8_t mLineYOffsets[5]; + void printText(const char *text, uint8_t line) { + setFont(line); - uint16_t _dispY; + uint8_t dispX = mLineXOffsets[line] + ((mEnScreenSaver) ? (mExtra % 7) : 0); - uint8_t _mExtra; - uint16_t mTimeout; - char _fmtText[DISP_FMT_TEXT_LEN]; + if (isTwoRowLine(line)) { + String stringText = String(text); + int space = stringText.indexOf(" "); + mDisplay->drawStr(dispX, mLineYOffsets[line], stringText.substring(0, space).c_str()); + if (space > 0) + mDisplay->drawStr(dispX, mLineYOffsets[line] + mDisplay->getMaxCharHeight(), stringText.substring(space + 1).c_str()); + } else + mDisplay->drawStr(dispX, mLineYOffsets[line], text); + } }; diff --git a/src/plugins/Display/Display_Mono_128X64.cpp b/src/plugins/Display/Display_Mono_128X64.cpp deleted file mode 100644 index 0224f50a..00000000 --- a/src/plugins/Display/Display_Mono_128X64.cpp +++ /dev/null @@ -1,146 +0,0 @@ - -// SPDX-License-Identifier: GPL-2.0-or-later -#include "Display_Mono_128X64.h" - -#include "Display_Mono.h" - -#ifdef ESP8266 -#include -#elif defined(ESP32) -#include -#endif -#include "../../utils/helper.h" - -// #ifdef U8X8_HAVE_HW_SPI -// #include -// #endif -// #ifdef U8X8_HAVE_HW_I2C -// #include -// #endif - -DisplayMono128X64::DisplayMono128X64() : DisplayMono::DisplayMono() { - mEnPowerSafe = true; - mEnScreenSaver = true; - mLuminance = 60; - _dispY = 0; - mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) - mUtcTs = NULL; - mType = 0; -} - -void DisplayMono128X64::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { - if ((0 < type) && (type < 5)) { - u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); - mType = type; - switch (type) { - case 1: - mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); - break; - default: - case 2: - mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); - break; - } - - mUtcTs = utcTs; - - mDisplay->begin(); - - calcLineHeights(); - - mDisplay->clearBuffer(); - mDisplay->setContrast(mLuminance); - printText("AHOY!", 0, 35); - printText("ahoydtu.de", 2, 20); - printText(version, 3, 46); - mDisplay->sendBuffer(); - } -} - -void DisplayMono128X64::config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { - mEnPowerSafe = enPowerSafe; - mEnScreenSaver = enScreenSaver; - mLuminance = lum; -} - -void DisplayMono128X64::loop(void) { - if (mEnPowerSafe) - if (mTimeout != 0) - mTimeout--; -} - -void DisplayMono128X64::disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { - mDisplay->clearBuffer(); - - // set Contrast of the Display to raise the lifetime - if (3 != mType) - mDisplay->setContrast(mLuminance); - - if ((totalPower > 0) && (isprod > 0)) { - mTimeout = DISP_DEFAULT_TIMEOUT; - mDisplay->setPowerSave(false); - if (totalPower > 999) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); - } else { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); - } - printText(_fmtText, 0); - } else { - printText("offline", 0, 25); - // check if it's time to enter power saving mode - if (mTimeout == 0) - mDisplay->setPowerSave(mEnPowerSafe); - } - - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); - printText(_fmtText, 1); - - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); - printText(_fmtText, 2); - - IPAddress ip = WiFi.localIP(); - if (!(_mExtra % 10) && (ip)) { - printText(ip.toString().c_str(), 3); - } else if (!(_mExtra % 5)) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); - printText(_fmtText, 3); - } else { - if (NULL != mUtcTs) { - printText(ah::getDateTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); - } - } - - mDisplay->sendBuffer(); - - _dispY = 0; - _mExtra++; -} - -void DisplayMono128X64::calcLineHeights() { - uint8_t yOff = 0; - for (uint8_t i = 0; i < 4; i++) { - setFont(i); - yOff += (mDisplay->getMaxCharHeight()); - mLineOffsets[i] = yOff; - } -} - -inline void DisplayMono128X64::setFont(uint8_t line) { - switch (line) { - case 0: - mDisplay->setFont(u8g2_font_ncenB14_tr); - break; - case 3: - mDisplay->setFont(u8g2_font_5x8_tr); - break; - default: - mDisplay->setFont(u8g2_font_ncenB10_tr); - break; - } -} -void DisplayMono128X64::printText(const char *text, uint8_t line, uint8_t dispX) { - setFont(line); - - dispX += (mEnScreenSaver) ? (_mExtra % 7) : 0; - mDisplay->drawStr(dispX, mLineOffsets[line], text); -} diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index 4902d14b..3d4f91ee 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -1,36 +1,138 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + #pragma once -// SPDX-License-Identifier: GPL-2.0-or-later #include "Display_Mono.h" class DisplayMono128X64 : public DisplayMono { - public: - DisplayMono128X64(); + public: + DisplayMono128X64() : DisplayMono() { + mEnPowerSafe = true; + mEnScreenSaver = true; + mLuminance = 60; + mDispY = 0; + mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) + mUtcTs = NULL; + mType = 0; + } + + void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { + if((0 == type) || (type > 4)) + return; + + u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); + mType = type; + + switch (type) { + case 1: + mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); + break; + default: + case 2: + mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); + break; + } + + mUtcTs = utcTs; + + mDisplay->begin(); + calcLinePositions(); + + mDisplay->clearBuffer(); + mDisplay->setContrast(mLuminance); + printText("AHOY!", 0, 35); + printText("ahoydtu.de", 2, 20); + printText(version, 3, 46); + mDisplay->sendBuffer(); + } + + void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { + mEnPowerSafe = enPowerSafe; + mEnScreenSaver = enScreenSaver; + mLuminance = lum; + } + + void loop(void) { + if (mEnPowerSafe) { + if (mTimeout != 0) + mTimeout--; + } + } + + void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { + mDisplay->clearBuffer(); + + // set Contrast of the Display to raise the lifetime + if (3 != mType) + mDisplay->setContrast(mLuminance); + + if ((totalPower > 0) && (isprod > 0)) { + mTimeout = DISP_DEFAULT_TIMEOUT; + mDisplay->setPowerSave(false); + + if (totalPower > 999) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); + + printText(mFmtText, 0); + } else { + printText("offline", 0, 25); + // check if it's time to enter power saving mode + if (mTimeout == 0) + mDisplay->setPowerSave(mEnPowerSafe); + } + + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); + printText(mFmtText, 1); - void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version); - void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum); - void loop(void); - void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); + printText(mFmtText, 2); - private: - void calcLineHeights(); - void setFont(uint8_t line); - uint8_t getColumn(uint8_t line); - bool isTwoRowLine(uint8_t line); - void printText(const char* text, uint8_t line, uint8_t dispX = 5); + IPAddress ip = WiFi.localIP(); + if (!(mExtra % 10) && (ip)) + printText(ip.toString().c_str(), 3); + else if (!(mExtra % 5)) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); + printText(mFmtText, 3); + } else if (NULL != mUtcTs) + printText(ah::getDateTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); - U8G2* mDisplay; + mDisplay->sendBuffer(); - uint8_t mType; - bool mEnPowerSafe, mEnScreenSaver; - uint8_t mLuminance; + mDispY = 0; + mExtra++; + } - uint8_t mLoopCnt; - uint32_t* mUtcTs; - uint8_t mLineOffsets[5]; + private: + void calcLinePositions() { + uint8_t yOff = 0; + for (uint8_t i = 0; i < 4; i++) { + setFont(i); + yOff += (mDisplay->getMaxCharHeight()); + mLineYOffsets[i] = yOff; + } + } - uint16_t _dispY; + inline void setFont(uint8_t line) { + switch (line) { + case 0: + mDisplay->setFont(u8g2_font_ncenB14_tr); + break; + case 3: + mDisplay->setFont(u8g2_font_5x8_tr); + break; + default: + mDisplay->setFont(u8g2_font_ncenB10_tr); + break; + } + } + void printText(const char *text, uint8_t line, uint8_t dispX = 5) { + setFont(line); - uint8_t _mExtra; - uint16_t mTimeout; - char _fmtText[DISP_FMT_TEXT_LEN]; + dispX += (mEnScreenSaver) ? (mExtra % 7) : 0; + mDisplay->drawStr(dispX, mLineYOffsets[line], text); + } }; diff --git a/src/plugins/Display/Display_Mono_84X48.cpp b/src/plugins/Display/Display_Mono_84X48.cpp deleted file mode 100644 index a84f6037..00000000 --- a/src/plugins/Display/Display_Mono_84X48.cpp +++ /dev/null @@ -1,140 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#include "Display_Mono_84X48.h" - -#include "Display_Mono.h" - -#ifdef ESP8266 -#include -#elif defined(ESP32) -#include -#endif -#include "../../utils/helper.h" - -// #ifdef U8X8_HAVE_HW_SPI -// #include -// #endif -// #ifdef U8X8_HAVE_HW_I2C -// #include -// #endif - -DisplayMono84X48::DisplayMono84X48() : DisplayMono::DisplayMono() { - mEnPowerSafe = true; - mEnScreenSaver = true; - mLuminance = 60; - _dispY = 0; - mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) - mUtcTs = NULL; - mType = 0; -} - -void DisplayMono84X48::init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { - if ((0 < type) && (type < 5)) { - u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); - mType = type; - mDisplay = new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset); - - mUtcTs = utcTs; - - mDisplay->begin(); - - calcLineHeights(); - - mDisplay->clearBuffer(); - if (3 != mType) - mDisplay->setContrast(mLuminance); - printText("AHOY!", 0); - printText("ahoydtu.de", 2); - printText(version, 3); - mDisplay->sendBuffer(); - } -} - -void DisplayMono84X48::config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { - mEnPowerSafe = enPowerSafe; - mEnScreenSaver = enScreenSaver; - mLuminance = lum; -} - -void DisplayMono84X48::loop(void) { - if (mEnPowerSafe) - if (mTimeout != 0) - mTimeout--; -} - -void DisplayMono84X48::disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { - mDisplay->clearBuffer(); - - // set Contrast of the Display to raise the lifetime - if (3 != mType) - mDisplay->setContrast(mLuminance); - - if ((totalPower > 0) && (isprod > 0)) { - mTimeout = DISP_DEFAULT_TIMEOUT; - mDisplay->setPowerSave(false); - if (totalPower > 999) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); - } else { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); - } - printText(_fmtText, 0); - } else { - printText("offline", 0); - // check if it's time to enter power saving mode - if (mTimeout == 0) - mDisplay->setPowerSave(mEnPowerSafe); - } - - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); - printText(_fmtText, 1); - - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); - printText(_fmtText, 2); - - IPAddress ip = WiFi.localIP(); - if (!(_mExtra % 10) && (ip)) { - printText(ip.toString().c_str(), 3); - } else if (!(_mExtra % 5)) { - snprintf(_fmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); - printText(_fmtText, 3); - } else { - if (NULL != mUtcTs) { - printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); - } - } - - mDisplay->sendBuffer(); - - _dispY = 0; - _mExtra++; -} - -void DisplayMono84X48::calcLineHeights() { - uint8_t yOff = 0; - for (uint8_t i = 0; i < 4; i++) { - setFont(i); - yOff += (mDisplay->getMaxCharHeight()); - mLineOffsets[i] = yOff; - } -} - -inline void DisplayMono84X48::setFont(uint8_t line) { - switch (line) { - case 0: - mDisplay->setFont(u8g2_font_logisoso16_tr); - break; - case 3: - mDisplay->setFont(u8g2_font_5x8_tr); - break; - default: - mDisplay->setFont(u8g2_font_5x8_tr); - break; - } -} - -void DisplayMono84X48::printText(const char *text, uint8_t line) { - uint8_t dispX = (line == 0) ? 10 : 5; - setFont(line); - - dispX += (mEnScreenSaver) ? (_mExtra % 7) : 0; - mDisplay->drawStr(dispX, mLineOffsets[line], text); -} diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index 1ad140e9..82aa83fa 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -1,34 +1,132 @@ +//----------------------------------------------------------------------------- +// 2023 Ahoy, https://ahoydtu.de +// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed +//----------------------------------------------------------------------------- + #pragma once -// SPDX-License-Identifier: GPL-2.0-or-later #include "Display_Mono.h" class DisplayMono84X48 : public DisplayMono { - public: - DisplayMono84X48(); + public: + DisplayMono84X48() : DisplayMono() { + mEnPowerSafe = true; + mEnScreenSaver = true; + mLuminance = 60; + mExtra = 0; + mDispY = 0; + mTimeout = DISP_DEFAULT_TIMEOUT; // interval at which to power save (milliseconds) + mUtcTs = NULL; + mType = 0; + } + + void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t *utcTs, const char *version) { + if((0 == type) || (type > 4)) + return; + + u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); + mType = type; + mDisplay = new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset); + + mUtcTs = utcTs; + + mDisplay->begin(); + calcLinePositions(); + + mDisplay->clearBuffer(); + if (3 != mType) + mDisplay->setContrast(mLuminance); + printText("AHOY!", 0); + printText("ahoydtu.de", 2); + printText(version, 3); + mDisplay->sendBuffer(); + } + + void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) { + mEnPowerSafe = enPowerSafe; + mEnScreenSaver = enScreenSaver; + mLuminance = lum; + } + + void loop(void) { + if (mEnPowerSafe) { + if (mTimeout != 0) + mTimeout--; + } + } + + void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { + mDisplay->clearBuffer(); + + // set Contrast of the Display to raise the lifetime + if (3 != mType) + mDisplay->setContrast(mLuminance); + + if ((totalPower > 0) && (isprod > 0)) { + mTimeout = DISP_DEFAULT_TIMEOUT; + mDisplay->setPowerSave(false); + + if (totalPower > 999) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2.2f kW", (totalPower / 1000)); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%3.0f W", totalPower); + + printText(mFmtText, 0); + } else { + printText("offline", 0); + // check if it's time to enter power saving mode + if (mTimeout == 0) + mDisplay->setPowerSave(mEnPowerSafe); + } + + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "today: %4.0f Wh", totalYieldDay); + printText(mFmtText, 1); + + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "total: %.1f kWh", totalYieldTotal); + printText(mFmtText, 2); - void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version); - void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum); - void loop(void); - void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + IPAddress ip = WiFi.localIP(); + if (!(mExtra % 10) && (ip)) + printText(ip.toString().c_str(), 3); + else if (!(mExtra % 5)) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d Inverter on", isprod); + printText(mFmtText, 3); + } else if (NULL != mUtcTs) + printText(ah::getTimeStr(gTimezone.toLocal(*mUtcTs)).c_str(), 3); - private: - void calcLineHeights(); - void setFont(uint8_t line); - void printText(const char* text, uint8_t line); + mDisplay->sendBuffer(); - U8G2* mDisplay; + mExtra = 1; + } - uint8_t mType; - bool mEnPowerSafe, mEnScreenSaver; - uint8_t mLuminance; + private: + void calcLinePositions() { + uint8_t yOff = 0; + for (uint8_t i = 0; i < 4; i++) { + setFont(i); + yOff += (mDisplay->getMaxCharHeight()); + mLineYOffsets[i] = yOff; + } + } - uint8_t mLoopCnt; - uint32_t* mUtcTs; - uint8_t mLineOffsets[5]; + inline void setFont(uint8_t line) { + switch (line) { + case 0: + mDisplay->setFont(u8g2_font_logisoso16_tr); + break; + case 3: + mDisplay->setFont(u8g2_font_5x8_tr); + break; + default: + mDisplay->setFont(u8g2_font_5x8_tr); + break; + } + } - uint16_t _dispY; + void printText(const char *text, uint8_t line) { + uint8_t dispX = (line == 0) ? 10 : 5; + setFont(line); - uint8_t _mExtra; - uint16_t mTimeout; - char _fmtText[DISP_FMT_TEXT_LEN]; + dispX += (mEnScreenSaver) ? (mExtra % 7) : 0; + mDisplay->drawStr(dispX, mLineYOffsets[line], text); + } }; From e6d8e2ee978d14736580c9a2cddde0b3bd5268ab Mon Sep 17 00:00:00 2001 From: lumapu Date: Sun, 21 May 2023 14:57:17 +0200 Subject: [PATCH 07/10] 0.6.14 merge PR #920 --- src/plugins/Display/Display_ePaper.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index 7a000c2d..eccf118c 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -197,7 +197,6 @@ void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, fl snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", _isprod); _display->println(_fmtText); - } } while (_display->nextPage()); } @@ -217,9 +216,8 @@ void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYield if ((isprod > 0) && (_changed)) { _changed = false; lastUpdatePaged(); - } else if(totalPower==0) { + } else if(totalPower==0) offlineFooter(); - } _display->powerOff(); } From 5ae1f4b86fcc2e595f1347bbfee8874d9ace3a4e Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 24 May 2023 11:09:33 +0200 Subject: [PATCH 08/10] Declare metric type only once. Add grouping of metrics. Send realtime data for each inverter in a separate chunk. --- src/web/web.h | 222 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 147 insertions(+), 75 deletions(-) diff --git a/src/web/web.h b/src/web/web.h index 056b9e7c..d8804b54 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -627,14 +627,22 @@ class Web { #ifdef ENABLE_PROMETHEUS_EP + // Note + // Prometheus exposition format is defined here: https://github.com/prometheus/docs/blob/main/content/docs/instrumenting/exposition_formats.md + // TODO: Check packetsize for MAX_NUM_INVERTERS. Successfull Tested with 4 Inverters (each with 4 channels) enum { - metricsStateStart, metricsStateInverter, metricStateRealtimeData,metricsStateAlarmData,metricsStateEnd + metricsStateStart, + metricsStateInverter1, metricsStateInverter2, metricsStateInverter3, metricsStateInverter4, + metricStateRealtimeFieldId, metricStateRealtimeInverterId, + metricsStateAlarmData, + metricsStateEnd } metricsStep; - int metricsInverterId,metricsChannelId; + int metricsInverterId; + uint8_t metricsFieldId; + bool metricDeclared; void showMetrics(AsyncWebServerRequest *request) { DPRINTLN(DBG_VERBOSE, F("web::showMetrics")); - metricsStep = metricsStateStart; AsyncWebServerResponse *response = request->beginChunkedResponse(F("text/plain"), [this](uint8_t *buffer, size_t maxLen, size_t filledLength) -> size_t @@ -647,7 +655,11 @@ class Web { char type[60], topic[100], val[25]; size_t len = 0; int alarmChannelId; + int metricsChannelId; + // Perform grouping on metrics according to format specification + // Each step must return at least one character. Otherwise the processing of AsyncWebServerResponse stops. + // So several "Info:" blocks are used to keep the transmission going switch (metricsStep) { case metricsStateStart: // System Info & NRF Statistics : fit to one packet snprintf(type,sizeof(type),"# TYPE ahoy_solar_info gauge\n"); @@ -676,93 +688,138 @@ class Web { metrics += radioStatistic(F("tx_cnt"), mSys->Radio.mSendCnt); len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); - // Start Inverter loop + // Next is Inverter information metricsInverterId = 0; - metricsStep = metricsStateInverter; + metricsStep = metricsStateInverter1; break; - case metricsStateInverter: // Inverter loop - if (metricsInverterId < mSys->getNumInverters()) { - iv = mSys->getInverterByPos(metricsInverterId); - if(NULL != iv) { - // Inverter info : fit to one packet - snprintf(type,sizeof(type),"# TYPE ahoy_solar_inverter_info gauge\n"); - snprintf(topic,sizeof(topic),"ahoy_solar_inverter_info{name=\"%s\",serial=\"%12llx\"} 1\n", - iv->config->name, iv->config->serial.u64); - metrics = String(type) + String(topic); - - snprintf(type,sizeof(type),"# TYPE ahoy_solar_inverter_is_enabled gauge\n"); - snprintf(topic,sizeof(topic),"ahoy_solar_inverter_is_enabled {inverter=\"%s\"} %d\n",iv->config->name,iv->config->enabled); - metrics += String(type) + String(topic); - - snprintf(type,sizeof(type),"# TYPE ahoy_solar_inverter_is_available gauge\n"); - snprintf(topic,sizeof(topic),"ahoy_solar_inverter_is_available {inverter=\"%s\"} %d\n",iv->config->name,iv->isAvailable(mApp->getTimestamp())); - metrics += String(type) + String(topic); - - snprintf(type,sizeof(type),"# TYPE ahoy_solar_inverter_is_producing gauge\n"); - snprintf(topic,sizeof(topic),"ahoy_solar_inverter_is_producing {inverter=\"%s\"} %d\n",iv->config->name,iv->isProducing(mApp->getTimestamp())); - metrics += String(type) + String(topic); - - len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); - - // Start Realtime Data Channel loop for this inverter - metricsChannelId = 0; - metricsStep = metricStateRealtimeData; - } + case metricsStateInverter1: // Information about all inverters configured : fit to one packet + metrics = "# TYPE ahoy_solar_inverter_info gauge\n"; + metrics += inverterMetric(topic, sizeof(topic),"ahoy_solar_inverter_info{name=\"%s\",serial=\"%12llx\"} 1\n", + [](Inverter<> *iv,IApp *mApp)-> uint64_t {return iv->config->serial.u64;}); + len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + metricsStep = metricsStateInverter2; + break; + + case metricsStateInverter2: // Information about all inverters configured : fit to one packet + metrics += "# TYPE ahoy_solar_inverter_is_enabled gauge\n"; + metrics += inverterMetric(topic, sizeof(topic),"ahoy_solar_inverter_is_enabled {inverter=\"%s\"} %d\n", + [](Inverter<> *iv,IApp *mApp)-> uint64_t {return iv->config->enabled;}); + + len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + metricsStep = metricsStateInverter3; + break; + + case metricsStateInverter3: // Information about all inverters configured : fit to one packet + metrics += "# TYPE ahoy_solar_inverter_is_available gauge\n"; + metrics += inverterMetric(topic, sizeof(topic),"ahoy_solar_inverter_is_available {inverter=\"%s\"} %d\n", + [](Inverter<> *iv,IApp *mApp)-> uint64_t {return iv->isAvailable(mApp->getTimestamp());}); + len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + metricsStep = metricsStateInverter4; + break; + + case metricsStateInverter4: // Information about all inverters configured : fit to one packet + metrics += "# TYPE ahoy_solar_inverter_is_producing gauge\n"; + metrics += inverterMetric(topic, sizeof(topic),"ahoy_solar_inverter_is_producing {inverter=\"%s\"} %d\n", + [](Inverter<> *iv,IApp *mApp)-> uint64_t {return iv->isProducing(mApp->getTimestamp());}); + len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); + // Start Realtime Field loop + metricsFieldId = FLD_UDC; + metricsStep = metricStateRealtimeFieldId; + break; + + case metricStateRealtimeFieldId: // Iterate over all defined fields + if (metricsFieldId < FLD_LAST_ALARM_CODE) { + metrics = "# Info: processing realtime field #"+String(metricsFieldId)+"\n"; + metricDeclared = false; + + metricsInverterId = 0; + metricsStep = metricStateRealtimeInverterId; } else { - metricsStep = metricsStateEnd; + metrics = "# Info: all realtime fields processed\n"; + metricsStep = metricsStateAlarmData; } + len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); break; - case metricStateRealtimeData: // Realtime Data Channel loop - iv = mSys->getInverterByPos(metricsInverterId); - rec = iv->getRecordStruct(RealTimeRunData_Debug); - if (metricsChannelId < rec->length) { - uint8_t channel = rec->assign[metricsChannelId].ch; - // Skip entry if maxPwr is 0 and it's not the inverter channel (channel 0) - if (0 == channel || 0 != iv->config->chMaxPwr[channel-1]) { - std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(metricsChannelId, rec)); - snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s %s", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), promType.c_str()); - if (0 == channel) { - snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name); - } else { - snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\",channel=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,iv->config->chName[channel-1]); + case metricStateRealtimeInverterId: // Iterate over all inverters for this field + metrics = ""; + if (metricsInverterId < mSys->getNumInverters()) { + // process all channels of this inverter + + iv = mSys->getInverterByPos(metricsInverterId); + if (NULL != iv) { + rec = iv->getRecordStruct(RealTimeRunData_Debug); + for (metricsChannelId=0; metricsChannelId < rec->length;metricsChannelId++) { + uint8_t channel = rec->assign[metricsChannelId].ch; + + // Try inverter channel (channel 0) or any channel with maxPwr > 0 + if (0 == channel || 0 != iv->config->chMaxPwr[channel-1]) { + + if (metricsFieldId == iv->getByteAssign(metricsChannelId, rec)->fieldId) { + // This is the correct field to report + std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(metricsChannelId, rec)); + // Declare metric only once + if (!metricDeclared) { + snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s %s\n", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), promType.c_str()); + metrics += type; + metricDeclared = true; + } + // report value + if (0 == channel) { + snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name); + } else { + snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\",channel=\"%s\"}", iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), iv->config->name,iv->config->chName[channel-1]); + } + snprintf(val, sizeof(val), " %.3f\n", iv->getValue(metricsChannelId, rec)); + metrics += topic; + metrics += val; + } + } + } + if (metrics.length() < 1) { + metrics = "# Info: Field #"+String(metricsFieldId)+" not available for inverter #"+String(metricsInverterId)+". Skipping remaining inverters\n"; + metricsFieldId++; // Process next field Id + metricsStep = metricStateRealtimeFieldId; } - snprintf(val, sizeof(val), "%.3f", iv->getValue(metricsChannelId, rec)); - len = snprintf((char*)buffer,maxLen,"%s\n%s %s\n",type,topic,val); } else { - len = snprintf((char*)buffer,maxLen,"#\n"); // At least one char to send otherwise the transmission ends. + metrics = "# Info: No data for field #"+String(metricsFieldId)+" of inverter #"+String(metricsInverterId)+". Skipping remaining inverters\n"; + metricsFieldId++; // Process next field Id + metricsStep = metricStateRealtimeFieldId; } - - metricsChannelId++; + // Stay in this state and try next inverter + metricsInverterId++; } else { - len = snprintf((char*)buffer,maxLen,"#\n"); // At least one char to send otherwise the transmission ends. - - // All realtime data channels processed --> try alarm data - metricsStep = metricsStateAlarmData; + metrics = "# Info: All inverters for field #"+String(metricsFieldId)+" processed.\n"; + metricsFieldId++; // Process next field Id + metricsStep = metricStateRealtimeFieldId; } + len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); break; - case metricsStateAlarmData: // Alarm Info loop - iv = mSys->getInverterByPos(metricsInverterId); - rec = iv->getRecordStruct(AlarmData); - // simple hack : there is only one channel with alarm data - // TODO: find the right one channel with the alarm id - alarmChannelId = 0; - // printf("AlarmData Length %d\n",rec->length); - if (alarmChannelId < rec->length) { - //uint8_t channel = rec->assign[alarmChannelId].ch; - std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(alarmChannelId, rec)); - snprintf(type, sizeof(type), "# TYPE ahoy_solar_%s%s %s", iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), promType.c_str()); - snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\"}", iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name); - snprintf(val, sizeof(val), "%.3f", iv->getValue(alarmChannelId, rec)); - len = snprintf((char*)buffer,maxLen,"%s\n%s %s\n",type,topic,val); - } else { - len = snprintf((char*)buffer,maxLen,"#\n"); // At least one char to send otherwise the transmission ends. + case metricsStateAlarmData: // Alarm Info loop : fit to one packet + // Perform grouping on metrics according to Prometheus exposition format specification + snprintf(type, sizeof(type),"# TYPE ahoy_solar_%s gauge\n",fields[FLD_LAST_ALARM_CODE]); + metrics = type; + + for (metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) { + iv = mSys->getInverterByPos(metricsInverterId); + if (NULL != iv) { + rec = iv->getRecordStruct(AlarmData); + // simple hack : there is only one channel with alarm data + // TODO: find the right one channel with the alarm id + alarmChannelId = 0; + if (alarmChannelId < rec->length) { + std::tie(promUnit, promType) = convertToPromUnits(iv->getUnit(alarmChannelId, rec)); + snprintf(topic, sizeof(topic), "ahoy_solar_%s%s{inverter=\"%s\"}", iv->getFieldName(alarmChannelId, rec), promUnit.c_str(), iv->config->name); + snprintf(val, sizeof(val), " %.3f\n", iv->getValue(alarmChannelId, rec)); + metrics += topic; + metrics += val; + } + } } - // alarm channel processed --> try next inverter - metricsInverterId++; - metricsStep = metricsStateInverter; + len = snprintf((char*)buffer,maxLen,"%s",metrics.c_str()); + metricsStep = metricsStateEnd; break; case metricsStateEnd: @@ -775,6 +832,21 @@ class Web { request->send(response); } + + // Traverse all inverters and collect the metric via valueFunc + String inverterMetric(char *buffer, size_t len, const char *format, std::function *iv, IApp *mApp)> valueFunc) { + Inverter<> *iv; + String metric = ""; + for (int metricsInverterId = 0; metricsInverterId < mSys->getNumInverters();metricsInverterId++) { + iv = mSys->getInverterByPos(metricsInverterId); + if (NULL != iv) { + snprintf(buffer,len,format,iv->config->name, valueFunc(iv,mApp)); + metric += String(buffer); + } + } + return metric; + } + String radioStatistic(String statistic, uint32_t value) { char type[60], topic[80], val[25]; snprintf(type, sizeof(type), "# TYPE ahoy_solar_radio_%s counter",statistic.c_str()); From 5b82d1aa8b69a5f140a1b4684cdc08045b908475 Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 25 May 2023 21:41:56 +0200 Subject: [PATCH 09/10] 0.6.15 * improved Prometheus Endpoint PR #958 * fix turn off ePaper only if setting was set #956 --- src/CHANGES.md | 4 ++++ src/defines.h | 2 +- src/plugins/Display/Display.h | 2 +- src/plugins/Display/Display_ePaper.cpp | 23 ++++++++++++----------- src/plugins/Display/Display_ePaper.h | 3 ++- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f3e60193..f789c234 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,9 @@ # Development Changes +## 0.6.15 - 2023-05-25 +* improved Prometheus Endpoint PR #958 +* fix turn off ePaper only if setting was set #956 + ## 0.6.14 - 2023-05-21 * merge PR #902 Mono-Display diff --git a/src/defines.h b/src/defines.h index e82047d0..baaea8b6 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 6 -#define VERSION_PATCH 14 +#define VERSION_PATCH 15 //------------------------------------- typedef struct { diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 8ce4ed7a..ba187c7d 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -47,7 +47,7 @@ class Display { } else if (mCfg->type >= 10) { #if defined(ESP32) mRefreshCycle = 0; - mEpaper.config(mCfg->rot); + mEpaper.config(mCfg->rot, mCfg->pwrSaveAtIvOffline); mEpaper.init(mCfg->type, mCfg->disp_cs, mCfg->disp_dc, mCfg->disp_reset, mCfg->disp_busy, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mVersion); #endif } diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index eccf118c..924961a3 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -57,8 +57,9 @@ void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, u } } -void DisplayEPaper::config(uint8_t rotation) { +void DisplayEPaper::config(uint8_t rotation, bool enPowerSafe) { mDisplayRotation = rotation; + mEnPowerSafe = enPowerSafe; } //*************************************************************************** @@ -142,7 +143,7 @@ void DisplayEPaper::offlineFooter() { } while (_display->nextPage()); } //*************************************************************************** -void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod) { +void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { int16_t tbx, tby; uint16_t tbw, tbh, x, y; @@ -152,16 +153,16 @@ void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, fl _display->setPartialWindow(0, mHeadFootPadding, _display->width(), _display->height() - (mHeadFootPadding * 2)); _display->fillScreen(GxEPD_WHITE); do { - if (_totalPower > 9999) { - snprintf(_fmtText, sizeof(_fmtText), "%.1f kW", (_totalPower / 10000)); + if (totalPower > 9999) { + snprintf(_fmtText, sizeof(_fmtText), "%.1f kW", (totalPower / 10000)); _changed = true; - } else if ((_totalPower > 0) && (_totalPower <= 9999)) { - snprintf(_fmtText, sizeof(_fmtText), "%.0f W", _totalPower); + } else if ((totalPower > 0) && (totalPower <= 9999)) { + snprintf(_fmtText, sizeof(_fmtText), "%.0f W", totalPower); _changed = true; } else { snprintf(_fmtText, sizeof(_fmtText), "offline"); } - if (_totalPower == 0){ + if (totalPower == 0){ _display->fillRect(0, mHeadFootPadding, 200,200, GxEPD_BLACK); _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); } else { @@ -174,7 +175,7 @@ void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, fl y = _display->height() / 2; _display->setCursor(5, y); _display->print("today:"); - snprintf(_fmtText, _display->width(), "%.0f", _totalYieldDay); + snprintf(_fmtText, _display->width(), "%.0f", totalYieldDay); _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); x = ((_display->width() - tbw) / 2) - tbx; _display->setCursor(x, y); @@ -185,7 +186,7 @@ void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, fl y = y + tbh + 7; _display->setCursor(5, y); _display->print("total:"); - snprintf(_fmtText, _display->width(), "%.1f", _totalYieldTotal); + snprintf(_fmtText, _display->width(), "%.1f", totalYieldTotal); _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); x = ((_display->width() - tbw) / 2) - tbx; _display->setCursor(x, y); @@ -194,7 +195,7 @@ void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, fl _display->println("kWh"); _display->setCursor(10, _display->height() - (mHeadFootPadding + 10)); - snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", _isprod); + snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", isprod); _display->println(_fmtText); } @@ -216,7 +217,7 @@ void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYield if ((isprod > 0) && (_changed)) { _changed = false; lastUpdatePaged(); - } else if(totalPower==0) + } else if((0 == totalPower) && (mEnPowerSafe)) offlineFooter(); _display->powerOff(); diff --git a/src/plugins/Display/Display_ePaper.h b/src/plugins/Display/Display_ePaper.h index 1e8d34b8..ad422b26 100644 --- a/src/plugins/Display/Display_ePaper.h +++ b/src/plugins/Display/Display_ePaper.h @@ -31,7 +31,7 @@ class DisplayEPaper { DisplayEPaper(); void fullRefresh(); void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t *utcTs, const char* version); - void config(uint8_t rotation); + void config(uint8_t rotation, bool enPowerSafe); void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); @@ -48,6 +48,7 @@ class DisplayEPaper { uint8_t mHeadFootPadding; GxEPD2_GFX* _display; uint32_t *mUtcTs; + bool mEnPowerSafe; }; #endif // ESP32 From 6dcf5ee9aa9b0fe15fc32a0843656010535d928e Mon Sep 17 00:00:00 2001 From: lumapu Date: Thu, 25 May 2023 22:26:33 +0200 Subject: [PATCH 10/10] 0.6.15 * improved reset values and update MqTT #957 --- src/CHANGES.md | 1 + src/app.cpp | 21 ++++++++++++++++++--- src/hm/hmPayload.h | 19 ++++++------------- 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index f789c234..6b97e319 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -3,6 +3,7 @@ ## 0.6.15 - 2023-05-25 * improved Prometheus Endpoint PR #958 * fix turn off ePaper only if setting was set #956 +* improved reset values and update MqTT #957 ## 0.6.14 - 2023-05-21 * merge PR #902 Mono-Display diff --git a/src/app.cpp b/src/app.cpp index c61c81aa..780e16f4 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -274,6 +274,7 @@ void app::tickComm(void) { //----------------------------------------------------------------------------- void app::tickZeroValues(void) { Inverter<> *iv; + bool changed = false; // set values to zero, except yields for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { iv = mSys.getInverterByPos(id); @@ -281,7 +282,11 @@ void app::tickZeroValues(void) { continue; // skip to next inverter mPayload.zeroInverterValues(iv); + changed = true; } + + if(changed) + payloadEventListener(RealTimeRunData_Debug); } //----------------------------------------------------------------------------- @@ -289,15 +294,21 @@ void app::tickMinute(void) { // only triggered if 'reset values on no avail is enabled' Inverter<> *iv; + bool changed = false; // set values to zero, except yields for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { iv = mSys.getInverterByPos(id); if (NULL == iv) continue; // skip to next inverter - if (!iv->isAvailable(mTimestamp) && !iv->isProducing(mTimestamp) && iv->config->enabled) + if (!iv->isAvailable(mTimestamp) && !iv->isProducing(mTimestamp) && iv->config->enabled) { mPayload.zeroInverterValues(iv); + changed = true; + } } + + if(changed) + payloadEventListener(RealTimeRunData_Debug); } //----------------------------------------------------------------------------- @@ -308,16 +319,20 @@ void app::tickMidnight(void) { onceAt(std::bind(&app::tickMidnight, this), nxtTrig, "mid2"); Inverter<> *iv; + bool changed = false; // set values to zero, except yield total for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { iv = mSys.getInverterByPos(id); if (NULL == iv) continue; // skip to next inverter - mPayload.zeroInverterValues(iv); - mPayload.zeroYieldDay(iv); + mPayload.zeroInverterValues(iv, false); + changed = true; } + if(changed) + payloadEventListener(RealTimeRunData_Debug); + if (mMqttEnabled) mMqtt.tickerMidnight(); } diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index 0ec40d22..5c66f1f8 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -93,17 +93,7 @@ class HmPayload { notify(0x0b); }*/ - void zeroYieldDay(Inverter<> *iv) { - DPRINTLN(DBG_DEBUG, F("zeroYieldDay")); - record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); - uint8_t pos; - for(uint8_t ch = 0; ch <= iv->channels; ch++) { - pos = iv->getPosByChFld(ch, FLD_YD, rec); - iv->setValue(pos, rec, 0.0f); - } - } - - void zeroInverterValues(Inverter<> *iv) { + void zeroInverterValues(Inverter<> *iv, bool skipYieldDay = true) { DPRINTLN(DBG_DEBUG, F("zeroInverterValues")); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); for(uint8_t ch = 0; ch <= iv->channels; ch++) { @@ -111,15 +101,18 @@ class HmPayload { for(uint8_t fld = 0; fld < FLD_EVT; fld++) { switch(fld) { case FLD_YD: + if(skipYieldDay) + continue; + else + break; case FLD_YT: continue; } pos = iv->getPosByChFld(ch, fld, rec); iv->setValue(pos, rec, 0.0f); } + iv->doCalculations(); } - - notify(RealTimeRunData_Debug); } void ivSendHighPrio(Inverter<> *iv) {