From 954b4ff7064abd02dd10cc19de648f491fcbebb8 Mon Sep 17 00:00:00 2001 From: you69man Date: Tue, 2 Jan 2024 11:36:14 +0100 Subject: [PATCH 1/3] implementation of power graph --- src/plugins/Display/Display.h | 3 + src/plugins/Display/Display_Mono.h | 145 ++++++++++++++++++++++ src/plugins/Display/Display_Mono_128X64.h | 74 ++++++----- src/plugins/Display/Display_Mono_84X48.h | 78 +++++++----- src/plugins/Display/Display_data.h | 2 + 5 files changed, 240 insertions(+), 62 deletions(-) diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 0cfbd710..387a6a0d 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -165,6 +165,9 @@ class Display { else mDisplayData.utcTs = 0; + mDisplayData.pGraphStartTime = mApp->getSunrise(); + mDisplayData.pGraphEndTime = mApp->getSunset(); + if (mMono ) { mMono->disp(); } diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 322e991e..1d925849 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -60,12 +60,23 @@ class DisplayMono { mLuminance = lum; mDisplay->setContrast(mLuminance); } + + monoMaintainDispSwitchState(); } protected: U8G2* mDisplay; DisplayData *mDisplayData; + float *mPgData=nullptr; + uint8_t mPgWidth=0; + uint8_t mPgHeight=0; + float mPgMaxPwr=0.0; +// float mPgMaxAvailPower = 0.0; + uint32_t mPgPeriod=0; // seconds + uint32_t mPgTimeOfDay=0; + uint8_t mPgLastPos=0; + uint8_t mType; uint16_t mDispWidth; uint16_t mDispHeight; @@ -81,9 +92,16 @@ class DisplayMono { uint8_t mExtra; int8_t mPixelshift=0; TimeMonitor mDisplayTime = TimeMonitor(1000 * DISP_DEFAULT_TIMEOUT, true); + TimeMonitor mDispSwitchTime = TimeMonitor(10000, true); + uint8_t mDispSwitchState = 0; bool mDisplayActive = true; // always start with display on char mFmtText[DISP_FMT_TEXT_LEN]; + enum _dispSwitchState { + d_POWER_TEXT = 0, + d_POWER_GRAPH = 1, + }; + // Common initialization function to be called by subclasses void monoInit(U8G2* display, uint8_t type, DisplayData *displayData) { mDisplay = display; @@ -97,6 +115,133 @@ class DisplayMono { mDispHeight = mDisplay->getDisplayHeight(); } + void monoMaintainDispSwitchState(void) { + switch(mDispSwitchState) { + case d_POWER_TEXT: + if (mDispSwitchTime.isTimeout()) { + mDispSwitchState = d_POWER_GRAPH; + mDispSwitchTime.startTimeMonitor(5000); + } + break; + case d_POWER_GRAPH: + if (mDispSwitchTime.isTimeout()) { + mDispSwitchState = d_POWER_TEXT; + mDispSwitchTime.startTimeMonitor(10000); + } + break; + } + } + + void initPowerGraph(uint8_t width, uint8_t height) { + mPgWidth = width; + mPgHeight = height; + mPgData = new float[mPgWidth]; + //memset(mPgData, 0, mPgWidth); + resetPowerGraph(); +/* + Inverter<> *iv; + mPgMaxAvailPower = 0; + uint8_t nInv = mSys->getNumInverters(); + for (uint8_t i = 0; i < nInv; i++) { + iv = mSys->getInverterByPos(i); + if (iv == NULL) + continue; + for (uint8_t ch = 0; ch < 6; ch++) { + mPgMaxAvailPower += iv->config->chMaxPwr[ch]; + } + } + DBGPRINTLN("max. Power = " + String(mPgMaxAvailPower));*/ + } + + void resetPowerGraph() { + if (mPgData != nullptr) { + mPgMaxPwr = 0.0; + mPgLastPos = 0; + for (uint8_t i = 0; i < mPgWidth; i++) + mPgData[i] = 0.0; + } + } + + uint8_t sss2pgpos(uint seconds_since_start) { + return(seconds_since_start * (mPgWidth - 1) / (mDisplayData->pGraphEndTime - mDisplayData->pGraphStartTime)); + } + + void calcPowerGraphValues() { + mPgPeriod = mDisplayData->pGraphEndTime - mDisplayData->pGraphStartTime; // length of power graph for scaling of x-axis + uint32_t oldTimeOfDay = mPgTimeOfDay; + mPgTimeOfDay = (mDisplayData->utcTs > mDisplayData->pGraphStartTime) ? mDisplayData->utcTs - mDisplayData->pGraphStartTime : 0; // current time of day with respect to current sunrise time + if (oldTimeOfDay > mPgTimeOfDay) // new day -> reset old data + resetPowerGraph(); + mPgLastPos = std::min((uint8_t) (mPgTimeOfDay * (mPgWidth - 1) / mPgPeriod), (uint8_t) (mPgWidth - 1)); // current datapoint based on currenct time of day + } + + void addPowerGraphEntry(float val) { + if (mDisplayData->utcTs > 0) { // precondition: utc time available + calcPowerGraphValues(); + //mPgData[mPgLastPos] = std::max(mPgData[mPgLastPos], (uint8_t) (val * 255.0 / mPgMaxAvailPower)); // normalizing of data to 0-255 + mPgData[mPgLastPos] = std::max(mPgData[mPgLastPos], val); + mPgMaxPwr = std::max(mPgMaxPwr, val); // max value of stored data for scaling of y-axis + } + } + + uint8_t getPowerGraphXpos(uint8_t p) { // + if ((p <= mPgLastPos) && (mPgLastPos > 0)) + return((p * (mPgWidth - 1)) / mPgLastPos); // scaling of x-axis + else + return(0); + } + + uint8_t getPowerGraphYpos(uint8_t p) { + if (p < mPgWidth) + //return(((uint32_t) mPgData[p] * (uint32_t) mPgMaxAvailPower) * (uint32_t) mPgHeight / mPgMaxPwr / 255); // scaling of normalized data (0-255) to graph height + return((mPgData[p] * (uint32_t) mPgHeight / mPgMaxPwr)); // scaling of data to graph height + else + return(0); + } + + void plotPowerGraph(uint8_t xoff, uint8_t yoff) { + // draw axes + mDisplay->drawLine(xoff, yoff, xoff, yoff - mPgHeight); // vertical axis + mDisplay->drawLine(xoff, yoff, xoff + mPgWidth, yoff); // horizontal axis + + // draw X scale + tmElements_t tm; + breakTime(mDisplayData->pGraphEndTime, tm); + uint8_t endHourPg = tm.Hour; + breakTime(mDisplayData->utcTs, tm); + uint8_t endHour = std::min(endHourPg, tm.Hour); + breakTime(mDisplayData->pGraphStartTime, tm); + tm.Hour += 1; + tm.Minute = 0; + tm.Second = 0; + for (; tm.Hour <= endHour; tm.Hour++) { + uint8_t x_pos_screen = getPowerGraphXpos(sss2pgpos((uint32_t) makeTime(tm) - mDisplayData->pGraphStartTime)); // scale horizontal axis + mDisplay->drawPixel(xoff + x_pos_screen, yoff - 1); + } + + // draw Y scale + uint16_t scale_y = 10; + uint32_t maxpwr_int = static_cast(std::round(mPgMaxPwr)); + if (maxpwr_int > 100) + scale_y = 100; + for (uint32_t i = scale_y; i <= maxpwr_int; i += scale_y) { + uint8_t ypos = yoff - static_cast(std::round(i * (float) mPgHeight / mPgMaxPwr)); // scale vertical axis + mDisplay->drawPixel(xoff + 1, ypos); + } + + // draw curve + for (uint8_t i = 1; i <= mPgLastPos; i++) { + mDisplay->drawLine(xoff + getPowerGraphXpos(i - 1), yoff - getPowerGraphYpos(i - 1), + xoff + getPowerGraphXpos(i), yoff - getPowerGraphYpos(i)); + } + + // print max power value + mDisplay->setFont(u8g2_font_4x6_tr); + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%dW", static_cast(std::round(mPgMaxPwr))); + mDisplay->drawStr(xoff + 3, yoff - mPgHeight + 5, mFmtText); + } + + // pixelshift screensaver with wipe effect void calcPixelShift(int range) { int8_t mod = (millis() / 10000) % ((range >> 1) << 2); mPixelshift = mScreenSaver == 1 ? ((mod < range) ? mod - (range >> 1) : -(mod - range - (range >> 1) + 1)) : 0; diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index afb581dd..8f762dde 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -34,6 +34,8 @@ class DisplayMono128X64 : public DisplayMono { } calcLinePositions(); + initPowerGraph(mDispWidth - 20, mLineYOffsets[4] - mLineYOffsets[1]); + printText("Ahoy!", l_Ahoy, 0xff); printText("ahoydtu.de", l_Website, 0xff); printText(mDisplayData->version, l_Version, 0xff); @@ -61,23 +63,16 @@ class DisplayMono128X64 : public DisplayMono { // calculate current pixelshift for pixelshift screensaver calcPixelShift(pixelShiftRange); - // print total power + // add new power data to power graph if (mDisplayData->nrProducing > 0) { - if (mDisplayData->totalPower > 9999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0)); - else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); - - printText(mFmtText, l_TotalPower, 0xff); - } else { - printText("offline", l_TotalPower, 0xff); + addPowerGraphEntry(mDisplayData->totalPower); } // print Date and time if (0 != mDisplayData->utcTs) printText(ah::getDateTimeStrShort(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), l_Time, 0xff); - // dynamic status bar, alternatively: + // alternatively: // print ip address if (!(mExtra % 5) && (mDisplayData->ipAddress)) { snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%s", (mDisplayData->ipAddress).toString().c_str()); @@ -115,22 +110,41 @@ class DisplayMono128X64 : public DisplayMono { mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon symbol } - // print yields - mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); - mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol - mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol + if (mDispSwitchState == d_POWER_TEXT) { - if (mDisplayData->totalYieldDay > 9999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0); - else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); - printText(mFmtText, l_YieldDay, 0xff); + // print total power + if (mDisplayData->nrProducing > 0) { + if (mDisplayData->totalPower > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0)); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); - if (mDisplayData->totalYieldTotal > 9999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); - else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); - printText(mFmtText, l_YieldTotal, 0xff); + printText(mFmtText, l_TotalPower, 0xff); + } else { + printText("offline", l_TotalPower, 0xff); + } + + // print yields + mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); + mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol + mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol + + if (mDisplayData->totalYieldDay > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); + printText(mFmtText, l_YieldDay, 0xff); + + if (mDisplayData->totalYieldTotal > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); + printText(mFmtText, l_YieldTotal, 0xff); + + } else { + // plot power graph + plotPowerGraph(10 + mPixelshift, mLineYOffsets[4] - 1); + } // draw dynamic RSSI bars int xoffs; @@ -142,10 +156,11 @@ class DisplayMono128X64 : public DisplayMono { for (int i = 0; i < 4; i++) { int radio_rssi_threshold = -60 - i * 10; int wifi_rssi_threshold = -60 - i * 10; + uint8_t barwidth = std::min(4 - i, 3); if (mDisplayData->RadioRSSI > radio_rssi_threshold) - mDisplay->drawBox(xoffs + mPixelshift, 8 + (rssi_bar_height + 1) * i, 4 - i, rssi_bar_height); + mDisplay->drawBox(xoffs + mPixelshift, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); if (mDisplayData->WifiRSSI > wifi_rssi_threshold) - mDisplay->drawBox(mDispWidth - 4 - xoffs + mPixelshift + i, 8 + (rssi_bar_height + 1) * i, 4 - i, rssi_bar_height); + mDisplay->drawBox(mDispWidth - barwidth - xoffs + mPixelshift, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); } // draw dynamic antenna and WiFi symbols mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); @@ -160,9 +175,6 @@ class DisplayMono128X64 : public DisplayMono { mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym) - xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym); mDisplay->sendBuffer(); - - mDisplay->sendBuffer(); - mExtra++; } @@ -198,8 +210,8 @@ class DisplayMono128X64 : public DisplayMono { mLineYOffsets[i] = yOff; dsc = mDisplay->getDescent(); yOff -= dsc; - if (l_Time==i) // prevent time and status line to touch - yOff+=1; // -> one pixels space + if (l_Time == i) // prevent time and status line to touch + yOff++; // -> one pixels space i++; } while(l_MAX_LINES>i); } diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index 7e5c157f..7f0281ed 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -5,7 +5,6 @@ #pragma once #include "Display_Mono.h" -#include "../../utils/dbg.h" class DisplayMono84X48 : public DisplayMono { public: @@ -23,6 +22,9 @@ class DisplayMono84X48 : public DisplayMono { u8g2_cb_t *rot = (u8g2_cb_t *)((rotation != 0x00) ? U8G2_R2 : U8G2_R0); monoInit(new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset), type, displayData); calcLinePositions(); + + initPowerGraph(mDispWidth - 16, mLineYOffsets[4] - mLineYOffsets[1] - 2); + printText("Ahoy!", l_Ahoy, 0xff); printText("ahoydtu.de", l_Website, 0xff); printText(mDisplayData->version, l_Version, 0xff); @@ -45,16 +47,9 @@ class DisplayMono84X48 : public DisplayMono { mDisplay->drawPixel(mDispWidth-1, mDispHeight-1); */ - // print total power + // add new power data to power graph if (mDisplayData->nrProducing > 0) { - if (mDisplayData->totalPower > 9999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0)); - else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); - - printText(mFmtText, l_TotalPower, 0xff); - } else { - printText("offline", l_TotalPower, 0xff); + addPowerGraphEntry(mDisplayData->totalPower); } // print Date and time @@ -80,31 +75,51 @@ class DisplayMono84X48 : public DisplayMono { printText(mFmtText, l_Status, 0xff); } - // print yields - printText("\x88", l_YieldDay, 10); // day symbol - printText("\x83", l_YieldTotal, 10); // total symbol + if (mDispSwitchState == d_POWER_TEXT) { - if (mDisplayData->totalYieldDay > 9999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0); - else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); - printText(mFmtText, l_YieldDay, 0xff); + // print total power + if (mDisplayData->nrProducing > 0) { + if (mDisplayData->totalPower > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000.0)); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower); - if (mDisplayData->totalYieldTotal > 9999.0) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); - else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); - printText(mFmtText, l_YieldTotal, 0xff); + printText(mFmtText, l_TotalPower, 0xff); + } else { + printText("offline", l_TotalPower, 0xff); + } + + // print day yield + printText("\x88", l_YieldDay, 10); // day symbol + if (mDisplayData->totalYieldDay > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kWh", mDisplayData->totalYieldDay / 1000.0); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); + printText(mFmtText, l_YieldDay, 0xff); + + // print total yield + printText("\x83", l_YieldTotal, 10); // total symbol + if (mDisplayData->totalYieldTotal > 9999.0) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); + printText(mFmtText, l_YieldTotal, 0xff); + + } else { + // plot power graph + plotPowerGraph(8, mLineYOffsets[4] - 1); + } - // draw dynamic Nokia RSSI bars + // draw dynamic RSSI bars int rssi_bar_height = 7; - for (int i=0; i<4;i++) { - int radio_rssi_threshold = -60 - i*10; // radio rssi not yet tested in reality! - int wifi_rssi_threshold = -60 - i*10; + for (int i = 0; i < 4; i++) { + int radio_rssi_threshold = -60 - i * 10; + int wifi_rssi_threshold = -60 - i * 10; + uint8_t barwidth = std::min(4 - i, 3); if (mDisplayData->RadioRSSI > radio_rssi_threshold) - mDisplay->drawBox(0, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); + mDisplay->drawBox(0, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); if (mDisplayData->WifiRSSI > wifi_rssi_threshold) - mDisplay->drawBox(mDispWidth-4+i, 8+(rssi_bar_height+1)*i, 4-i,rssi_bar_height); + mDisplay->drawBox(mDispWidth - barwidth, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); } // draw dynamic antenna and WiFi symbols @@ -150,7 +165,7 @@ class DisplayMono84X48 : public DisplayMono { yOff += asc; mLineYOffsets[i] = yOff; dsc = mDisplay->getDescent(); - if (l_TotalPower!=i) // power line needs no descent spacing + if (l_TotalPower != i) // power line needs no descent spacing yOff -= dsc; yOff++; // instead lets spend one pixel space between all lines i++; @@ -158,7 +173,8 @@ class DisplayMono84X48 : public DisplayMono { } inline void setLineFont(uint8_t line) { - if ((line == l_TotalPower) || (line == l_Ahoy)) + if ((line == l_TotalPower) || + (line == l_Ahoy)) mDisplay->setFont(u8g2_font_logisoso16_tr); else mDisplay->setFont(u8g2_font_5x8_symbols_ahoy); diff --git a/src/plugins/Display/Display_data.h b/src/plugins/Display/Display_data.h index a7a7ecee..2017403a 100644 --- a/src/plugins/Display/Display_data.h +++ b/src/plugins/Display/Display_data.h @@ -9,6 +9,8 @@ struct DisplayData { float totalYieldDay=0.0f; // indicate day yield (Wh) float totalYieldTotal=0.0f; // indicate total yield (kWh) uint32_t utcTs=0; // indicate absolute timestamp (utc unix time). 0 = time is not synchonized + uint32_t pGraphStartTime=0; // starttime for power graph (e.g. sunRise) + uint32_t pGraphEndTime=0; // starttime for power graph (e.g. sunSet) uint8_t nrProducing=0; // indicate number of producing inverters uint8_t nrSleeping=0; // indicate number of sleeping inverters bool WifiSymbol = false; // indicate if WiFi is connected From 4496981b3b9eba17231eb0c83052f745f6e21d89 Mon Sep 17 00:00:00 2001 From: you69man Date: Sat, 6 Jan 2024 20:39:17 +0100 Subject: [PATCH 2/3] add option for show ratio --- src/config/settings.h | 4 ++++ src/plugins/Display/Display.h | 8 ++++--- src/plugins/Display/Display_Mono.h | 27 ++++++++++++++++------- src/plugins/Display/Display_Mono_128X32.h | 3 ++- src/plugins/Display/Display_Mono_128X64.h | 3 ++- src/plugins/Display/Display_Mono_64X48.h | 3 ++- src/plugins/Display/Display_Mono_84X48.h | 3 ++- src/web/RestApi.h | 25 +++++++++++---------- src/web/html/setup.html | 11 +++++++++ src/web/web.h | 1 + 10 files changed, 61 insertions(+), 27 deletions(-) diff --git a/src/config/settings.h b/src/config/settings.h index 8ce71167..83e2eaa3 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -165,6 +165,7 @@ typedef struct { uint8_t type; bool pwrSaveAtIvOffline; uint8_t screenSaver; + uint8_t graph_ratio; uint8_t rot; //uint16_t wakeUp; //uint16_t sleepAt; @@ -461,6 +462,7 @@ class settings { mCfg.plugin.display.pwrSaveAtIvOffline = false; mCfg.plugin.display.contrast = 60; mCfg.plugin.display.screenSaver = 1; // default: 1 .. pixelshift for OLED for downward compatibility + mCfg.plugin.display.graph_ratio = 50; mCfg.plugin.display.rot = 0; mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL @@ -697,6 +699,7 @@ class settings { disp[F("type")] = mCfg.plugin.display.type; disp[F("pwrSafe")] = (bool)mCfg.plugin.display.pwrSaveAtIvOffline; disp[F("screenSaver")] = mCfg.plugin.display.screenSaver; + disp[F("graph_ratio")] = mCfg.plugin.display.graph_ratio; disp[F("rotation")] = mCfg.plugin.display.rot; //disp[F("wake")] = mCfg.plugin.display.wakeUp; //disp[F("sleep")] = mCfg.plugin.display.sleepAt; @@ -713,6 +716,7 @@ class settings { getVal(disp, F("type"), &mCfg.plugin.display.type); getVal(disp, F("pwrSafe"), &mCfg.plugin.display.pwrSaveAtIvOffline); getVal(disp, F("screenSaver"), &mCfg.plugin.display.screenSaver); + getVal(disp, F("graph_ratio"), &mCfg.plugin.display.graph_ratio); getVal(disp, F("rotation"), &mCfg.plugin.display.rot); //mCfg.plugin.display.wakeUp = disp[F("wake")]; //mCfg.plugin.display.sleepAt = disp[F("sleep")]; diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 387a6a0d..0b06cc58 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -54,7 +54,7 @@ class Display { default: mMono = NULL; break; } if(mMono) { - mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->screenSaver, mCfg->contrast); + mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->screenSaver, mCfg->contrast, mCfg->graph_ratio); mMono->init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, &mDisplayData); } @@ -75,10 +75,12 @@ class Display { } void tickerSecond() { + bool request_refresh = false; + if (mMono != NULL) - mMono->loop(mCfg->contrast, motionSensorActive()); + request_refresh = mMono->loop(mCfg->contrast, motionSensorActive()); - if (mNewPayload || (((++mLoopCnt) % 5) == 0)) { + if (mNewPayload || (((++mLoopCnt) % 5) == 0) || request_refresh) { DataScreen(); mNewPayload = false; mLoopCnt = 0; diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 1d925849..76447ce3 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -26,12 +26,12 @@ class 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, DisplayData *displayData) = 0; - virtual void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) = 0; + virtual void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) = 0; virtual void disp(void) = 0; // Common loop function, manages display on/off functions for powersave and screensaver with motionsensor // can be overridden by subclasses - virtual void loop(uint8_t lum, bool motion) { + virtual bool loop(uint8_t lum, bool motion) { bool dispConditions = (!mEnPowerSave || (mDisplayData->nrProducing > 0)) && ((mScreenSaver != 2) || motion); // screensaver 2 .. motionsensor @@ -61,7 +61,7 @@ class DisplayMono { mDisplay->setContrast(mLuminance); } - monoMaintainDispSwitchState(); + return(monoMaintainDispSwitchState()); } protected: @@ -84,6 +84,7 @@ class DisplayMono { bool mEnPowerSave; uint8_t mScreenSaver = 1; // 0 .. off; 1 .. pixelShift; 2 .. motionsensor uint8_t mLuminance; + uint8_t mGraphRatio; uint8_t mLoopCnt; uint8_t mLineXOffsets[5] = {}; @@ -92,8 +93,8 @@ class DisplayMono { uint8_t mExtra; int8_t mPixelshift=0; TimeMonitor mDisplayTime = TimeMonitor(1000 * DISP_DEFAULT_TIMEOUT, true); - TimeMonitor mDispSwitchTime = TimeMonitor(10000, true); - uint8_t mDispSwitchState = 0; + TimeMonitor mDispSwitchTime = TimeMonitor(); + uint8_t mDispSwitchState; bool mDisplayActive = true; // always start with display on char mFmtText[DISP_FMT_TEXT_LEN]; @@ -113,23 +114,33 @@ class DisplayMono { mDisplay->clearBuffer(); mDispWidth = mDisplay->getDisplayWidth(); mDispHeight = mDisplay->getDisplayHeight(); + mDispSwitchTime.stopTimeMonitor(); + mDispSwitchState = d_POWER_TEXT; + if (mGraphRatio == 100) // if graph ratio is 100% start in graph mode + mDispSwitchState = d_POWER_GRAPH; + else if (mGraphRatio != 0) + mDispSwitchTime.startTimeMonitor(150 * (100 - mGraphRatio)); // start time monitor only if ratio is neither 0 nor 100 } - void monoMaintainDispSwitchState(void) { + bool monoMaintainDispSwitchState(void) { + bool change = false; switch(mDispSwitchState) { case d_POWER_TEXT: if (mDispSwitchTime.isTimeout()) { mDispSwitchState = d_POWER_GRAPH; - mDispSwitchTime.startTimeMonitor(5000); + mDispSwitchTime.startTimeMonitor(150 * mGraphRatio); // mGraphRatio: 0-100 Gesamtperiode 15000 ms + change = true; } break; case d_POWER_GRAPH: if (mDispSwitchTime.isTimeout()) { mDispSwitchState = d_POWER_TEXT; - mDispSwitchTime.startTimeMonitor(10000); + mDispSwitchTime.startTimeMonitor(150 * (100 - mGraphRatio)); + change = true; } break; } + return change; } void initPowerGraph(uint8_t width, uint8_t height) { diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index fa0cacdf..edc79b75 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -12,10 +12,11 @@ class DisplayMono128X32 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; + mGraphRatio = graph_ratio; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index 8f762dde..c578f9a4 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -12,10 +12,11 @@ class DisplayMono128X64 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; + mGraphRatio = graph_ratio; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 68cac96f..5d1bf6ac 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -12,10 +12,11 @@ class DisplayMono64X48 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; + mGraphRatio = graph_ratio; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index 7f0281ed..a996f52d 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -12,10 +12,11 @@ class DisplayMono84X48 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; + mGraphRatio = graph_ratio; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { diff --git a/src/web/RestApi.h b/src/web/RestApi.h index de4fe8e3..7ef4349b 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -671,18 +671,19 @@ class RestApi { } void getDisplay(JsonObject obj) { - obj[F("disp_typ")] = (uint8_t)mConfig->plugin.display.type; - obj[F("disp_pwr")] = (bool)mConfig->plugin.display.pwrSaveAtIvOffline; - obj[F("disp_screensaver")] = (uint8_t)mConfig->plugin.display.screenSaver; - obj[F("disp_rot")] = (uint8_t)mConfig->plugin.display.rot; - obj[F("disp_cont")] = (uint8_t)mConfig->plugin.display.contrast; - obj[F("disp_clk")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_clk; - obj[F("disp_data")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_data; - obj[F("disp_cs")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_cs; - obj[F("disp_dc")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_dc; - obj[F("disp_rst")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_reset; - obj[F("disp_bsy")] = (mConfig->plugin.display.type < 10) ? DEF_PIN_OFF : mConfig->plugin.display.disp_busy; - obj[F("pir_pin")] = mConfig->plugin.display.pirPin; + obj[F("disp_typ")] = (uint8_t)mConfig->plugin.display.type; + obj[F("disp_pwr")] = (bool)mConfig->plugin.display.pwrSaveAtIvOffline; + obj[F("disp_screensaver")] = (uint8_t)mConfig->plugin.display.screenSaver; + obj[F("disp_rot")] = (uint8_t)mConfig->plugin.display.rot; + obj[F("disp_cont")] = (uint8_t)mConfig->plugin.display.contrast; + obj[F("disp_graph_ratio")] = (uint8_t)mConfig->plugin.display.graph_ratio; + obj[F("disp_clk")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_clk; + obj[F("disp_data")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_data; + obj[F("disp_cs")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_cs; + obj[F("disp_dc")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_dc; + obj[F("disp_rst")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_reset; + obj[F("disp_bsy")] = (mConfig->plugin.display.type < 10) ? DEF_PIN_OFF : mConfig->plugin.display.disp_busy; + obj[F("pir_pin")] = mConfig->plugin.display.pirPin; } void getMqttInfo(JsonObject obj) { diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 4903db16..4759f893 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -294,6 +294,15 @@

{#DISP_PINOUT}

+

Graph options

+
+
Graph Size
+
+
+
+
Show ratio (0-100 %)
+
+
@@ -1087,6 +1096,8 @@ hideDispPins(pins, parseInt(dtype_sel.value)) }); + document.getElementsByName("disp_graph_ratio")[0].value = obj["disp_graph_ratio"]; + hideDispPins(pins, obj.disp_typ); } diff --git a/src/web/web.h b/src/web/web.h index eae106a9..1b4f5702 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -584,6 +584,7 @@ class Web { // display mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on"); mConfig->plugin.display.screenSaver = request->arg("disp_screensaver").toInt(); + mConfig->plugin.display.graph_ratio = request->arg("disp_graph_ratio").toInt(); mConfig->plugin.display.rot = request->arg("disp_rot").toInt(); mConfig->plugin.display.type = request->arg("disp_typ").toInt(); mConfig->plugin.display.contrast = (mConfig->plugin.display.type == 0) ? 60 : request->arg("disp_cont").toInt(); From c82cc1c77ec2b4df3678d8bb7a829d0d03025408 Mon Sep 17 00:00:00 2001 From: you69man Date: Sat, 6 Jan 2024 22:15:29 +0100 Subject: [PATCH 3/3] add option for graph size --- src/config/settings.h | 4 + src/plugins/Display/Display.h | 2 +- src/plugins/Display/Display_Mono.h | 5 +- src/plugins/Display/Display_Mono_128X32.h | 3 +- src/plugins/Display/Display_Mono_128X64.h | 135 ++++++++++++++-------- src/plugins/Display/Display_Mono_64X48.h | 3 +- src/plugins/Display/Display_Mono_84X48.h | 84 ++++++++++---- src/web/RestApi.h | 1 + src/web/html/setup.html | 15 ++- src/web/web.h | 1 + 10 files changed, 172 insertions(+), 81 deletions(-) diff --git a/src/config/settings.h b/src/config/settings.h index 83e2eaa3..28739db3 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -166,6 +166,7 @@ typedef struct { bool pwrSaveAtIvOffline; uint8_t screenSaver; uint8_t graph_ratio; + uint8_t graph_size; uint8_t rot; //uint16_t wakeUp; //uint16_t sleepAt; @@ -463,6 +464,7 @@ class settings { mCfg.plugin.display.contrast = 60; mCfg.plugin.display.screenSaver = 1; // default: 1 .. pixelshift for OLED for downward compatibility mCfg.plugin.display.graph_ratio = 50; + mCfg.plugin.display.graph_size = 2; mCfg.plugin.display.rot = 0; mCfg.plugin.display.disp_data = DEF_PIN_OFF; // SDA mCfg.plugin.display.disp_clk = DEF_PIN_OFF; // SCL @@ -700,6 +702,7 @@ class settings { disp[F("pwrSafe")] = (bool)mCfg.plugin.display.pwrSaveAtIvOffline; disp[F("screenSaver")] = mCfg.plugin.display.screenSaver; disp[F("graph_ratio")] = mCfg.plugin.display.graph_ratio; + disp[F("graph_size")] = mCfg.plugin.display.graph_size; disp[F("rotation")] = mCfg.plugin.display.rot; //disp[F("wake")] = mCfg.plugin.display.wakeUp; //disp[F("sleep")] = mCfg.plugin.display.sleepAt; @@ -717,6 +720,7 @@ class settings { getVal(disp, F("pwrSafe"), &mCfg.plugin.display.pwrSaveAtIvOffline); getVal(disp, F("screenSaver"), &mCfg.plugin.display.screenSaver); getVal(disp, F("graph_ratio"), &mCfg.plugin.display.graph_ratio); + getVal(disp, F("graph_size"), &mCfg.plugin.display.graph_size); getVal(disp, F("rotation"), &mCfg.plugin.display.rot); //mCfg.plugin.display.wakeUp = disp[F("wake")]; //mCfg.plugin.display.sleepAt = disp[F("sleep")]; diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 0b06cc58..6c8bb9cb 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -54,7 +54,7 @@ class Display { default: mMono = NULL; break; } if(mMono) { - mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->screenSaver, mCfg->contrast, mCfg->graph_ratio); + mMono->config(mCfg->pwrSaveAtIvOffline, mCfg->screenSaver, mCfg->contrast, mCfg->graph_ratio, mCfg->graph_size); mMono->init(mCfg->type, mCfg->rot, mCfg->disp_cs, mCfg->disp_dc, 0xff, mCfg->disp_clk, mCfg->disp_data, &mDisplayData); } diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 76447ce3..c5aa2ed3 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -26,7 +26,7 @@ class 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, DisplayData *displayData) = 0; - virtual void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) = 0; + virtual void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio, uint8_t graph_size) = 0; virtual void disp(void) = 0; // Common loop function, manages display on/off functions for powersave and screensaver with motionsensor @@ -85,6 +85,7 @@ class DisplayMono { uint8_t mScreenSaver = 1; // 0 .. off; 1 .. pixelShift; 2 .. motionsensor uint8_t mLuminance; uint8_t mGraphRatio; + uint8_t mGraphSize; uint8_t mLoopCnt; uint8_t mLineXOffsets[5] = {}; @@ -119,7 +120,7 @@ class DisplayMono { if (mGraphRatio == 100) // if graph ratio is 100% start in graph mode mDispSwitchState = d_POWER_GRAPH; else if (mGraphRatio != 0) - mDispSwitchTime.startTimeMonitor(150 * (100 - mGraphRatio)); // start time monitor only if ratio is neither 0 nor 100 + mDispSwitchTime.startTimeMonitor(150 * (100 - mGraphRatio)); // start display mode change only if ratio is neither 0 nor 100 } bool monoMaintainDispSwitchState(void) { diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index edc79b75..1b3927b3 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -12,11 +12,12 @@ class DisplayMono128X32 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio, uint8_t graph_size) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; mGraphRatio = graph_ratio; + mGraphSize = graph_size; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index c578f9a4..32459c89 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -12,11 +12,12 @@ class DisplayMono128X64 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio, uint8_t graph_size) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; mGraphRatio = graph_ratio; + mGraphSize = graph_size; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { @@ -35,7 +36,33 @@ class DisplayMono128X64 : public DisplayMono { } calcLinePositions(); - initPowerGraph(mDispWidth - 20, mLineYOffsets[4] - mLineYOffsets[1]); + switch(mGraphSize) { // var opts2 = [[0, "Line 1 - 2"], [1, "Line 2 - 3"], [2, "Line 1 - 3"], [3, "Line 2 - 4"], [4, "Line 1 - 4"]]; + case 0: + graph_first_line = 1; + graph_last_line = 2; + break; + case 1: + graph_first_line = 2; + graph_last_line = 3; + break; + case 2: + graph_first_line = 1; + graph_last_line = 3; + break; + case 3: + graph_first_line = 2; + graph_last_line = 4; + break; + case 4: + default: + graph_first_line = 1; + graph_last_line = 4; + break; + } + + widthShrink = (mScreenSaver == 1) ? pixelShiftRange : 0; // shrink graphwidth for pixelshift screensaver + + initPowerGraph(mDispWidth - 22 - widthShrink, mLineYOffsets[graph_last_line] - mLineYOffsets[graph_first_line - 1] - 2); printText("Ahoy!", l_Ahoy, 0xff); printText("ahoydtu.de", l_Website, 0xff); @@ -73,46 +100,47 @@ class DisplayMono128X64 : public DisplayMono { if (0 != mDisplayData->utcTs) printText(ah::getDateTimeStrShort(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), l_Time, 0xff); - // alternatively: - // print ip address - if (!(mExtra % 5) && (mDisplayData->ipAddress)) { - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%s", (mDisplayData->ipAddress).toString().c_str()); - printText(mFmtText, l_Status, 0xff); - } - // print status of inverters - else { - sun_pos = -1; - moon_pos = -1; - setLineFont(l_Status); - if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter"); - else if (0 == mDisplayData->nrSleeping) { - snprintf(mFmtText, DISP_FMT_TEXT_LEN, " "); - sun_pos = 0; - } - else if (0 == mDisplayData->nrProducing) { - snprintf(mFmtText, DISP_FMT_TEXT_LEN, " "); - moon_pos = 0; + if (showLine(l_Status)) { + // alternatively: + // print ip address + if (!(mExtra % 5) && (mDisplayData->ipAddress)) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%s", (mDisplayData->ipAddress).toString().c_str()); + printText(mFmtText, l_Status, 0xff); } + // print status of inverters else { - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2d", mDisplayData->nrProducing); - sun_pos = mDisplay->getStrWidth(mFmtText) + 1; - snprintf(mFmtText+2, DISP_FMT_TEXT_LEN, " %2d", mDisplayData->nrSleeping); - moon_pos = mDisplay->getStrWidth(mFmtText) + 1; - snprintf(mFmtText+7, DISP_FMT_TEXT_LEN, " "); + sun_pos = -1; + moon_pos = -1; + setLineFont(l_Status); + if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter"); + else if (0 == mDisplayData->nrSleeping) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, " "); + sun_pos = 0; + } + else if (0 == mDisplayData->nrProducing) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, " "); + moon_pos = 0; + } + else { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%2d", mDisplayData->nrProducing); + sun_pos = mDisplay->getStrWidth(mFmtText) + 1; + snprintf(mFmtText+2, DISP_FMT_TEXT_LEN, " %2d", mDisplayData->nrSleeping); + moon_pos = mDisplay->getStrWidth(mFmtText) + 1; + snprintf(mFmtText+7, DISP_FMT_TEXT_LEN, " "); + } + printText(mFmtText, l_Status, 0xff); + + pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2; + mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy); + if (sun_pos!=-1) + mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun symbol + if (moon_pos!=-1) + mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon symbol } - printText(mFmtText, l_Status, 0xff); - - pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2; - mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy); - if (sun_pos!=-1) - mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun symbol - if (moon_pos!=-1) - mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon symbol } - if (mDispSwitchState == d_POWER_TEXT) { - + if (showLine(l_TotalPower)) { // print total power if (mDisplayData->nrProducing > 0) { if (mDisplayData->totalPower > 9999.0) @@ -124,8 +152,10 @@ class DisplayMono128X64 : public DisplayMono { } else { printText("offline", l_TotalPower, 0xff); } + } - // print yields + if (showLine(l_YieldDay)) { + // print day yield mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol @@ -135,45 +165,44 @@ class DisplayMono128X64 : public DisplayMono { else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); printText(mFmtText, l_YieldDay, 0xff); + } + if (showLine(l_YieldTotal)) { + // print total yield if (mDisplayData->totalYieldTotal > 9999.0) snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f MWh", mDisplayData->totalYieldTotal / 1000.0); else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); printText(mFmtText, l_YieldTotal, 0xff); + } - } else { + if (mDispSwitchState == d_POWER_GRAPH) { // plot power graph - plotPowerGraph(10 + mPixelshift, mLineYOffsets[4] - 1); + plotPowerGraph((mDispWidth - mPgWidth) / 2 + mPixelshift, mLineYOffsets[graph_last_line] - 1); } // draw dynamic RSSI bars - int xoffs; - if (mScreenSaver == 1) // shrink screenwidth for pixelshift screensaver - xoffs = pixelShiftRange/2; - else - xoffs = 0; int rssi_bar_height = 9; for (int i = 0; i < 4; i++) { int radio_rssi_threshold = -60 - i * 10; int wifi_rssi_threshold = -60 - i * 10; uint8_t barwidth = std::min(4 - i, 3); if (mDisplayData->RadioRSSI > radio_rssi_threshold) - mDisplay->drawBox(xoffs + mPixelshift, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); + mDisplay->drawBox(widthShrink / 2 + mPixelshift, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); if (mDisplayData->WifiRSSI > wifi_rssi_threshold) - mDisplay->drawBox(mDispWidth - barwidth - xoffs + mPixelshift, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); + mDisplay->drawBox(mDispWidth - barwidth - widthShrink / 2 + mPixelshift, 8 + (rssi_bar_height + 1) * i, barwidth, rssi_bar_height); } // draw dynamic antenna and WiFi symbols mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy); char sym[]=" "; sym[0] = mDisplayData->RadioSymbol?'A':'E'; // NRF - mDisplay->drawStr(xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym); + mDisplay->drawStr(widthShrink / 2 + mPixelshift, mLineYOffsets[l_RSSI], sym); if (mDisplayData->MQTTSymbol) sym[0] = 'J'; // MQTT else sym[0] = mDisplayData->WifiSymbol?'B':'F'; // Wifi - mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym) - xoffs + mPixelshift, mLineYOffsets[l_RSSI], sym); + mDisplay->drawStr(mDispWidth - mDisplay->getStrWidth(sym) - widthShrink / 2 + mPixelshift, mLineYOffsets[l_RSSI], sym); mDisplay->sendBuffer(); mExtra++; @@ -197,7 +226,11 @@ class DisplayMono128X64 : public DisplayMono { l_MAX_LINES = 5, }; + uint8_t graph_first_line; + uint8_t graph_last_line; + const uint8_t pixelShiftRange = 11; // number of pixels to shift from left to right (centered -> must be odd!) + uint8_t widthShrink; void calcLinePositions() { uint8_t yOff = 0; @@ -239,4 +272,8 @@ class DisplayMono128X64 : public DisplayMono { dispX += mPixelshift; mDisplay->drawStr(dispX, mLineYOffsets[line], text); } + + bool showLine(uint8_t line) { + return ((mDispSwitchState == d_POWER_TEXT) || ((line < graph_first_line) || (line > graph_last_line))); + } }; diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 5d1bf6ac..e55f5ac3 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -12,11 +12,12 @@ class DisplayMono64X48 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio, uint8_t graph_size) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; mGraphRatio = graph_ratio; + mGraphSize = graph_size; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index a996f52d..ee2aebd5 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -12,11 +12,12 @@ class DisplayMono84X48 : public DisplayMono { mExtra = 0; } - void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio) { + void config(bool enPowerSave, uint8_t screenSaver, uint8_t lum, uint8_t graph_ratio, uint8_t graph_size) { mEnPowerSave = enPowerSave; mScreenSaver = screenSaver; mLuminance = lum; mGraphRatio = graph_ratio; + mGraphSize = graph_size; } void init(uint8_t type, uint8_t rotation, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, DisplayData *displayData) { @@ -24,7 +25,31 @@ class DisplayMono84X48 : public DisplayMono { monoInit(new U8G2_PCD8544_84X48_F_4W_SW_SPI(rot, clock, data, cs, dc, reset), type, displayData); calcLinePositions(); - initPowerGraph(mDispWidth - 16, mLineYOffsets[4] - mLineYOffsets[1] - 2); + switch(mGraphSize) { // var opts2 = [[0, "Line 1 - 2"], [1, "Line 2 - 3"], [2, "Line 1 - 3"], [3, "Line 2 - 4"], [4, "Line 1 - 4"]]; + case 0: + graph_first_line = 1; + graph_last_line = 2; + break; + case 1: + graph_first_line = 2; + graph_last_line = 3; + break; + case 2: + graph_first_line = 1; + graph_last_line = 3; + break; + case 3: + graph_first_line = 2; + graph_last_line = 4; + break; + case 4: + default: + graph_first_line = 1; + graph_last_line = 4; + break; + } + + initPowerGraph(mDispWidth - 16, mLineYOffsets[graph_last_line] - mLineYOffsets[graph_first_line - 1] - 2); printText("Ahoy!", l_Ahoy, 0xff); printText("ahoydtu.de", l_Website, 0xff); @@ -57,27 +82,28 @@ class DisplayMono84X48 : public DisplayMono { if (0 != mDisplayData->utcTs) printText(ah::getDateTimeStrShort(gTimezone.toLocal(mDisplayData->utcTs)).c_str(), l_Time, 0xff); - // alternatively: - // print ip address - if (!(mExtra % 5) && (mDisplayData->ipAddress)) { - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%s", (mDisplayData->ipAddress).toString().c_str()); - printText(mFmtText, l_Status, 0xff); - } - // print status of inverters - else { - if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter"); - else if (0 == mDisplayData->nrSleeping) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x86"); // sun symbol - else if (0 == mDisplayData->nrProducing) - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x87"); // moon symbol - else - snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d\x86 %d\x87", mDisplayData->nrProducing, mDisplayData->nrSleeping); - printText(mFmtText, l_Status, 0xff); + if (showLine(l_Status)) { + // alternatively: + // print ip address + if (!(mExtra % 5) && (mDisplayData->ipAddress)) { + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%s", (mDisplayData->ipAddress).toString().c_str()); + printText(mFmtText, l_Status, 0xff); + } + // print status of inverters + else { + if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter"); + else if (0 == mDisplayData->nrSleeping) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x86"); // sun symbol + else if (0 == mDisplayData->nrProducing) + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x87"); // moon symbol + else + snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d\x86 %d\x87", mDisplayData->nrProducing, mDisplayData->nrSleeping); + printText(mFmtText, l_Status, 0xff); + } } - if (mDispSwitchState == d_POWER_TEXT) { - + if (showLine(l_TotalPower)) { // print total power if (mDisplayData->nrProducing > 0) { if (mDisplayData->totalPower > 9999.0) @@ -89,7 +115,9 @@ class DisplayMono84X48 : public DisplayMono { } else { printText("offline", l_TotalPower, 0xff); } + } + if (showLine(l_YieldDay)) { // print day yield printText("\x88", l_YieldDay, 10); // day symbol if (mDisplayData->totalYieldDay > 9999.0) @@ -97,7 +125,9 @@ class DisplayMono84X48 : public DisplayMono { else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay); printText(mFmtText, l_YieldDay, 0xff); + } + if (showLine(l_YieldTotal)) { // print total yield printText("\x83", l_YieldTotal, 10); // total symbol if (mDisplayData->totalYieldTotal > 9999.0) @@ -105,10 +135,11 @@ class DisplayMono84X48 : public DisplayMono { else snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f kWh", mDisplayData->totalYieldTotal); printText(mFmtText, l_YieldTotal, 0xff); + } - } else { + if (mDispSwitchState == d_POWER_GRAPH) { // plot power graph - plotPowerGraph(8, mLineYOffsets[4] - 1); + plotPowerGraph(8, mLineYOffsets[graph_last_line] - 1); } // draw dynamic RSSI bars @@ -155,6 +186,9 @@ class DisplayMono84X48 : public DisplayMono { l_MAX_LINES = 5, }; + uint8_t graph_first_line; + uint8_t graph_last_line; + void calcLinePositions() { uint8_t yOff = 0; uint8_t i = 0; @@ -191,6 +225,10 @@ class DisplayMono84X48 : public DisplayMono { dispX = col; mDisplay->drawStr(dispX, mLineYOffsets[line], text); } + + bool showLine(uint8_t line) { + return ((mDispSwitchState == d_POWER_TEXT) || ((line < graph_first_line) || (line > graph_last_line))); + } }; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 7ef4349b..3d4a6c0d 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -677,6 +677,7 @@ class RestApi { obj[F("disp_rot")] = (uint8_t)mConfig->plugin.display.rot; obj[F("disp_cont")] = (uint8_t)mConfig->plugin.display.contrast; obj[F("disp_graph_ratio")] = (uint8_t)mConfig->plugin.display.graph_ratio; + obj[F("disp_graph_size")] = (uint8_t)mConfig->plugin.display.graph_size; obj[F("disp_clk")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_clk; obj[F("disp_data")] = (mConfig->plugin.display.type == 0) ? DEF_PIN_OFF : mConfig->plugin.display.disp_data; obj[F("disp_cs")] = (mConfig->plugin.display.type < 3) ? DEF_PIN_OFF : mConfig->plugin.display.disp_cs; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 4759f893..6d0b3710 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -295,10 +295,7 @@

Graph options

-
-
Graph Size
-
-
+
Show ratio (0-100 %)
@@ -1098,6 +1095,16 @@ document.getElementsByName("disp_graph_ratio")[0].value = obj["disp_graph_ratio"]; + var opts2 = [[0, "Line 1 - 2"], [1, "Line 2 - 3"], [2, "Line 1 - 3"], [3, "Line 2 - 4"], [4, "Line 1 - 4"]]; + var graph_size_sel = sel("disp_graph_size", opts2, obj["disp_graph_size"]); + graph_size_sel.id = 'disp_graph_size'; + document.getElementById("graphSize").append( + ml("div", {class: "row mb-3"}, [ + ml("div", {class: "col-12 col-sm-3 my-2"}, "Graph size"), + ml("div", {class: "col-12 col-sm-9"}, graph_size_sel) + ]) + ); + hideDispPins(pins, obj.disp_typ); } diff --git a/src/web/web.h b/src/web/web.h index 1b4f5702..38ecf171 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -585,6 +585,7 @@ class Web { mConfig->plugin.display.pwrSaveAtIvOffline = (request->arg("disp_pwr") == "on"); mConfig->plugin.display.screenSaver = request->arg("disp_screensaver").toInt(); mConfig->plugin.display.graph_ratio = request->arg("disp_graph_ratio").toInt(); + mConfig->plugin.display.graph_size = request->arg("disp_graph_size").toInt(); mConfig->plugin.display.rot = request->arg("disp_rot").toInt(); mConfig->plugin.display.type = request->arg("disp_typ").toInt(); mConfig->plugin.display.contrast = (mConfig->plugin.display.type == 0) ? 60 : request->arg("disp_cont").toInt();