Browse Source

Refactored DisplayMono class to improve maintainability

pull/902/head
Thomas Pohl 1 year ago
parent
commit
8960fa6650
  1. 192
      src/plugins/Display/Display.h
  2. 215
      src/plugins/Display/Display_Mono.cpp
  3. 38
      src/plugins/Display/Display_Mono.h
  4. 169
      src/plugins/Display/Display_Mono_128X32.cpp
  5. 37
      src/plugins/Display/Display_Mono_128X32.h
  6. 146
      src/plugins/Display/Display_Mono_128X64.cpp
  7. 36
      src/plugins/Display/Display_Mono_128X64.h
  8. 140
      src/plugins/Display/Display_Mono_84X48.cpp
  9. 34
      src/plugins/Display/Display_Mono_84X48.h

192
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 HMSYSTEM>
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__*/

215
src/plugins/Display/Display_Mono.cpp

@ -1,215 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Display_Mono.h"
#ifdef ESP8266
#include <ESP8266WiFi.h>
#elif defined(ESP32)
#include <WiFi.h>
#endif
#include "../../utils/helper.h"
//#ifdef U8X8_HAVE_HW_SPI
//#include <SPI.h>
//#endif
//#ifdef U8X8_HAVE_HW_I2C
//#include <Wire.h>
//#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);
}
}

38
src/plugins/Display/Display_Mono.h

@ -3,41 +3,17 @@
#include <U8g2lib.h>
#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];
};

169
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 <ESP8266WiFi.h>
#elif defined(ESP32)
#include <WiFi.h>
#endif
#include "../../utils/helper.h"
// #ifdef U8X8_HAVE_HW_SPI
// #include <SPI.h>
// #endif
// #ifdef U8X8_HAVE_HW_I2C
// #include <Wire.h>
// #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);
}
}

37
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];
};

146
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 <ESP8266WiFi.h>
#elif defined(ESP32)
#include <WiFi.h>
#endif
#include "../../utils/helper.h"
// #ifdef U8X8_HAVE_HW_SPI
// #include <SPI.h>
// #endif
// #ifdef U8X8_HAVE_HW_I2C
// #include <Wire.h>
// #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);
}

36
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];
};

140
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 <ESP8266WiFi.h>
#elif defined(ESP32)
#include <WiFi.h>
#endif
#include "../../utils/helper.h"
// #ifdef U8X8_HAVE_HW_SPI
// #include <SPI.h>
// #endif
// #ifdef U8X8_HAVE_HW_I2C
// #include <Wire.h>
// #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);
}

34
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];
};
Loading…
Cancel
Save