@ -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 < uint8_t > ( 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 < uint8_t > ( 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 < uint16_t > ( 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 ;