From 8960fa6650d9e4893cb90fc3a8018948d94d718d Mon Sep 17 00:00:00 2001 From: Thomas Pohl Date: Mon, 1 May 2023 12:15:33 +0200 Subject: [PATCH] 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]; +};