@ -81,7 +81,7 @@ class DisplayMono { 
			
		
	
		
			
				
					            mDispWidth  =  mDisplay - > getDisplayWidth ( ) ;  
			
		
	
		
			
				
					            mDispHeight  =  mDisplay - > getDisplayHeight ( ) ;  
			
		
	
		
			
				
					            mDispSwitchTime . stopTimeMonitor ( ) ;  
			
		
	
		
			
				
					            if  ( mCfg - > graph_ratio  = =  100  )            // if graph ratio is 100% start in graph mode
  
			
		
	
		
			
				
					            if  ( 100  = =  mCfg - > graph_ratio )            // if graph ratio is 100% start in graph mode
  
			
		
	
		
			
				
					                mDispSwitchState  =  DispSwitchState : : GRAPH ;  
			
		
	
		
			
				
					            else  if  ( mCfg - > graph_ratio  ! =  0 )  
			
		
	
		
			
				
					                mDispSwitchTime . startTimeMonitor ( 150  *  ( 100  -  mCfg - > graph_ratio ) ) ;   // start display mode change only if ratio is neither 0 nor 100
  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -90,39 +90,70 @@ class DisplayMono { 
			
		
	
		
			
				
					        // pixelshift screensaver with wipe effect
  
			
		
	
		
			
				
					        void  calcPixelShift ( int  range )  {  
			
		
	
		
			
				
					            int8_t  mod  =  ( millis ( )  /  10000 )  %  ( ( range  > >  1 )  < <  2 ) ;  
			
		
	
		
			
				
					            mPixelshift  =  mCfg - > screenSaver  = =  1 ?  ( ( mod  <  range )  ?  mod  -  ( range  > >  1 )  :  - ( mod  -  range  -  ( range  > >  1 )  +  1 ) )  :  0 ;  
			
		
	
		
			
				
					            mPixelshift  =  ( 1  = =  mCfg - > screenSaver ) ?  ( ( mod  <  range )  ?  mod  -  ( range  > >  1 )  :  - ( mod  -  range  -  ( range  > >  1 )  +  1 ) )  :  0 ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    protected :  
			
		
	
		
			
				
					        enum  class  PowerGraphState  {  
			
		
	
		
			
				
					            NO_TIME_SYNC ,  
			
		
	
		
			
				
					            IN_PERIOD ,  
			
		
	
		
			
				
					            WAIT_4_NEW_PERIOD ,  
			
		
	
		
			
				
					            WAIT_4_RESTART  
			
		
	
		
			
				
					        } ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // initialize power graph and allocate data buffer based on pixel width
  
			
		
	
		
			
				
					        void  initPowerGraph ( uint8_t  width ,  uint8_t  height )  {  
			
		
	
		
			
				
					            DBGPRINTLN ( F ( " ---- Init Power Graph ---- " ) ) ;  
			
		
	
		
			
				
					            mPgWidth  =  width ;  
			
		
	
		
			
				
					            mPgHeight  =  height ;  
			
		
	
		
			
				
					            mPgData  =  new  float [ mPgWidth ] ;  
			
		
	
		
			
				
					            mPgState  =  PowerGraphState : : NO_TIME_SYNC ;  
			
		
	
		
			
				
					            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 ) ) ; */  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // add new value to power graph and maintain state engine for period times
  
			
		
	
		
			
				
					        void  addPowerGraphEntry ( float  val )  {  
			
		
	
		
			
				
					            if  ( ( nullptr  ! =  mPgData )  & &  ( mDisplayData - > utcTs  >  0 ) )  {   // precondition: power graph initialized and 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
  
			
		
	
		
			
				
					            if  ( nullptr  = =  mPgData )   // power graph not initialized
  
			
		
	
		
			
				
					                return ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            bool  store_entry  =  false ;  
			
		
	
		
			
				
					            switch ( mPgState )  {  
			
		
	
		
			
				
					                case  PowerGraphState : : NO_TIME_SYNC :    
			
		
	
		
			
				
					                    if  ( ( mDisplayData - > pGraphStartTime  >  0 )  & &  ( mDisplayData - > pGraphEndTime  >  0 )  & &                                          // wait until period data is available ...
  
			
		
	
		
			
				
					                        ( mDisplayData - > utcTs  > =  mDisplayData - > pGraphStartTime )  & &  ( mDisplayData - > utcTs  <  mDisplayData - > pGraphEndTime ) )  {     // and current time is in period
  
			
		
	
		
			
				
					                        storeStartEndTimes ( ) ;   // period was received -> store
  
			
		
	
		
			
				
					                        store_entry  =  true ;  
			
		
	
		
			
				
					                        mPgState  =  PowerGraphState : : IN_PERIOD ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    break ;  
			
		
	
		
			
				
					                case  PowerGraphState : : IN_PERIOD :  
			
		
	
		
			
				
					                    if  ( mDisplayData - > utcTs  >  mPgEndTime )                    // check if end of day is reached ...
  
			
		
	
		
			
				
					                        mPgState  =  PowerGraphState : : WAIT_4_NEW_PERIOD ;       // then wait for new period setting
  
			
		
	
		
			
				
					                    else  
			
		
	
		
			
				
					                        store_entry  =  true ;                                  
			
		
	
		
			
				
					                    break ;  
			
		
	
		
			
				
					                case  PowerGraphState : : WAIT_4_NEW_PERIOD :  
			
		
	
		
			
				
					                    if  ( ( mPgStartTime  ! =  mDisplayData - > pGraphStartTime )  | |  ( mPgEndTime  ! =  mDisplayData - > pGraphEndTime ) )  {  // wait until new time period was received ...
  
			
		
	
		
			
				
					                        storeStartEndTimes ( ) ;                                                                              // and store it for next period
  
			
		
	
		
			
				
					                        mPgState  =  PowerGraphState : : WAIT_4_RESTART ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    break ;  
			
		
	
		
			
				
					                case  PowerGraphState : : WAIT_4_RESTART :  
			
		
	
		
			
				
					                    if  ( ( mDisplayData - > utcTs  > =  mPgStartTime )  & &  ( mDisplayData - > utcTs  <  mPgEndTime ) )  {  // wait until current time is in period again ...
  
			
		
	
		
			
				
					                        resetPowerGraph ( ) ;                                                              // then reset power graph data
  
			
		
	
		
			
				
					                        store_entry  =  true ;  
			
		
	
		
			
				
					                        mPgState  =  PowerGraphState : : IN_PERIOD ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                    break ;  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					            if  ( store_entry )  {  
			
		
	
		
			
				
					                mPgLastPos  =  std : : min ( ( uint8_t )  sss2PgPos ( mDisplayData - > utcTs  -  mPgStartTime ) ,  ( uint8_t )  ( mPgWidth  -  1 ) ) ;   // current datapoint based on seconds since start
  
			
		
	
		
			
				
					                mPgData [ mPgLastPos ]  =  std : : max ( mPgData [ mPgLastPos ] ,  val ) ;  // update current datapoint to maximum of all seen values
  
			
		
	
		
			
				
					                mPgMaxPwr  =  std : : max ( mPgMaxPwr ,  val ) ;   // update max value of stored data for scaling of y-axis
  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // plot power graph to given display offset
  
			
		
	
		
			
				
					        void  plotPowerGraph ( uint8_t  xoff ,  uint8_t  yoff )  {  
			
		
	
		
			
				
					            if  ( nullptr  = =  mPgData )   // power graph not initialized
  
			
		
	
		
			
				
					                return ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -146,7 +177,7 @@ class DisplayMono { 
			
		
	
		
			
				
					            tm . Minute  =  0 ;  
			
		
	
		
			
				
					            tm . Second  =  0 ;  
			
		
	
		
			
				
					            for  ( ;  tm . Hour  < =  endHour ;  tm . Hour + + )  {  
			
		
	
		
			
				
					                uint8_t  x_pos_screen  =  getPowerGraphXpos ( sss2pgp os ( ( uint32_t )  makeTime ( tm )  -  mDisplayData - > pGraphStartTime ) ) ;  // scale horizontal axis
  
			
		
	
		
			
				
					                uint8_t  x_pos_screen  =  getPowerGraphXpos ( sss2PgP os ( ( uint32_t )  makeTime ( tm )  -  mDisplayData - > pGraphStartTime ) ) ;  // scale horizontal axis
  
			
		
	
		
			
				
					                mDisplay - > drawPixel ( xoff  +  x_pos_screen ,  yoff  -  1 ) ;  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					
 
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -163,8 +194,8 @@ class DisplayMono { 
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            // 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 ) ) ;  
			
		
	
		
			
				
					                mDisplay - > drawLine ( xoff  +  getPowerGraphXpos ( i  -  1 ) ,  yoff  -  getPowerGraphValue Ypos ( i  -  1 ) ,  
			
		
	
		
			
				
					                                   xoff  +  getPowerGraphXpos ( i ) ,      yoff  -  getPowerGraphValue Ypos ( i ) ) ;  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            // print max power value
  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -195,6 +226,7 @@ class DisplayMono { 
			
		
	
		
			
				
					            return  change ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // reset power graph 
  
			
		
	
		
			
				
					        void  resetPowerGraph ( )  {  
			
		
	
		
			
				
					            if  ( mPgData  ! =  nullptr )  {  
			
		
	
		
			
				
					                mPgMaxPwr  =  0.0 ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -205,34 +237,35 @@ class DisplayMono { 
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        uint8_t  sss2pgpos ( uint  seconds_since_start )  {  
			
		
	
		
			
				
					            uint32_t  diff  =  ( mDisplayData - > pGraphEndTime  -  mDisplayData - > pGraphStartTime ) ;   
			
		
	
		
			
				
					            if ( diff )  
			
		
	
		
			
				
					                return  ( seconds_since_start  *  ( mPgWidth  -  1 )  /  diff )  ;  
			
		
	
		
			
				
					            return  0 ;  
			
		
	
		
			
				
					        // store start and end times of current time period and calculate period length
  
			
		
	
		
			
				
					        void  storeStartEndTimes ( )  {  
			
		
	
		
			
				
					            mPgStartTime  =  mDisplayData - > pGraphStartTime ;  
			
		
	
		
			
				
					            mPgEndTime  =  mDisplayData - > pGraphEndTime ;  
			
		
	
		
			
				
					            mPgPeriod  =  mDisplayData - > pGraphEndTime  -  mDisplayData - > pGraphStartTime ;   // time period of power graph in sec for scaling of x-axis
  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        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 ( ) ;  
			
		
	
		
			
				
					            if ( 0  = =  mPgPeriod )  
			
		
	
		
			
				
					                mPgPeriod  =  1 ;  
			
		
	
		
			
				
					            mPgLastPos  =  std : : min ( ( uint8_t )  ( mPgTimeOfDay  *  ( mPgWidth  -  1 )  /  mPgPeriod ) ,  ( uint8_t )  ( mPgWidth  -  1 ) ) ;   // current datapoint based on currenct time of day
  
			
		
	
		
			
				
					        // get power graph datapoint index, scaled to current time period, by seconds since start
  
			
		
	
		
			
				
					        uint8_t  sss2PgPos ( uint  seconds_since_start )  {   
			
		
	
		
			
				
					            if ( mPgPeriod )                         
			
		
	
		
			
				
					                return  ( seconds_since_start  *  ( mPgWidth  -  1 )  /  mPgPeriod ) ;  
			
		
	
		
			
				
					            else  
			
		
	
		
			
				
					                return  0 ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        // get X-position of power graph, scaled to lastpos, by according data point index
  
			
		
	
		
			
				
					        uint8_t  getPowerGraphXpos ( uint8_t  p )  {       
			
		
	
		
			
				
					            if  ( ( p  < =  mPgLastPos )  & &  ( mPgLastPos  >  0 ) )  
			
		
	
		
			
				
					                return ( ( p  *  ( mPgWidth  -  1 ) )  /  mPgLastPos ) ;   // scaling of x-axis
  
			
		
	
		
			
				
					            return  0 ;  
			
		
	
		
			
				
					            else  
			
		
	
		
			
				
					                return  0 ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        uint8_t  getPowerGraphYpos ( uint8_t  p )  {  
			
		
	
		
			
				
					        // get Y-position of power graph, scaled to maximum value, by according datapoint index
  
			
		
	
		
			
				
					        uint8_t  getPowerGraphValueYpos ( uint8_t  p )  {   
			
		
	
		
			
				
					            if  ( ( p  <  mPgWidth )  & &  ( mPgMaxPwr  >  0 ) )  
			
		
	
		
			
				
					                return ( ( mPgData [ p ]  *  ( uint32_t )  mPgHeight  /  mPgMaxPwr ) ) ;  // scaling of data to graph height
  
			
		
	
		
			
				
					            return  0 ;  
			
		
	
		
			
				
					            else  
			
		
	
		
			
				
					                return  0 ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					    protected :  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -254,9 +287,11 @@ class DisplayMono { 
			
		
	
		
			
				
					        float   * mPgData  =  nullptr ;  
			
		
	
		
			
				
					        uint8_t  mPgHeight  =  0 ;  
			
		
	
		
			
				
					        float    mPgMaxPwr  =  0.0 ;  
			
		
	
		
			
				
					        uint32_t  mPgPeriod  =  0 ;  // seconds
  
			
		
	
		
			
				
					        uint32_t  mPgTimeOfDay  =  0 ;  
			
		
	
		
			
				
					        uint32_t  mPgStartTime  =  0 ;  
			
		
	
		
			
				
					        uint32_t  mPgEndTime  =  0 ;  
			
		
	
		
			
				
					        uint32_t  mPgPeriod  =  0 ;   // seconds
  
			
		
	
		
			
				
					        uint8_t   mPgLastPos  =  0 ;  
			
		
	
		
			
				
					        PowerGraphState  mPgState  =  PowerGraphState : : NO_TIME_SYNC ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        uint16_t  mDispHeight ;  
			
		
	
		
			
				
					        uint8_t  mLuminance ;