2018-08-28 17:13:14 +01:00
/*
xdrv_13_display . ino - Display support for Sonoff - Tasmota
2019-01-01 12:55:01 +00:00
Copyright ( C ) 2019 Theo Arends
2018-08-28 17:13:14 +01:00
This program is free software : you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# if defined(USE_I2C) || defined(USE_SPI)
# ifdef USE_DISPLAY
2018-11-07 09:30:03 +00:00
# define XDRV_13 13
2019-03-31 10:59:04 +01:00
const uint8_t DISPLAY_MAX_DRIVERS = 16 ; // Max number of display drivers/models supported by xdsp_interface.ino
const uint8_t DISPLAY_MAX_COLS = 44 ; // Max number of columns allowed with command DisplayCols
const uint8_t DISPLAY_MAX_ROWS = 32 ; // Max number of lines allowed with command DisplayRows
2018-08-28 17:13:14 +01:00
2019-03-31 10:59:04 +01:00
const uint8_t DISPLAY_LOG_ROWS = 32 ; // Number of lines in display log buffer
2018-08-28 17:13:14 +01:00
# define D_CMND_DISPLAY "Display"
# define D_CMND_DISP_ADDRESS "Address"
# define D_CMND_DISP_COLS "Cols"
# define D_CMND_DISP_DIMMER "Dimmer"
# define D_CMND_DISP_MODE "Mode"
# define D_CMND_DISP_MODEL "Model"
# define D_CMND_DISP_REFRESH "Refresh"
# define D_CMND_DISP_ROWS "Rows"
# define D_CMND_DISP_SIZE "Size"
# define D_CMND_DISP_FONT "Font"
# define D_CMND_DISP_ROTATE "Rotate"
# define D_CMND_DISP_TEXT "Text"
2019-07-23 13:05:42 +01:00
# define D_CMND_DISP_WIDTH "Width"
# define D_CMND_DISP_HEIGHT "Height"
2018-08-28 17:13:14 +01:00
enum XdspFunctions { FUNC_DISPLAY_INIT_DRIVER , FUNC_DISPLAY_INIT , FUNC_DISPLAY_EVERY_50_MSECOND , FUNC_DISPLAY_EVERY_SECOND ,
FUNC_DISPLAY_MODEL , FUNC_DISPLAY_MODE , FUNC_DISPLAY_POWER ,
FUNC_DISPLAY_CLEAR , FUNC_DISPLAY_DRAW_FRAME ,
FUNC_DISPLAY_DRAW_HLINE , FUNC_DISPLAY_DRAW_VLINE , FUNC_DISPLAY_DRAW_LINE ,
FUNC_DISPLAY_DRAW_CIRCLE , FUNC_DISPLAY_FILL_CIRCLE ,
FUNC_DISPLAY_DRAW_RECTANGLE , FUNC_DISPLAY_FILL_RECTANGLE ,
FUNC_DISPLAY_TEXT_SIZE , FUNC_DISPLAY_FONT_SIZE , FUNC_DISPLAY_ROTATION , FUNC_DISPLAY_DRAW_STRING , FUNC_DISPLAY_ONOFF } ;
enum DisplayInitModes { DISPLAY_INIT_MODE , DISPLAY_INIT_PARTIAL , DISPLAY_INIT_FULL } ;
2019-07-23 13:05:42 +01:00
enum DisplayCommands { CMND_DISPLAY , CMND_DISP_MODEL , CMND_DISP_WIDTH , CMND_DISP_HEIGHT , CMND_DISP_MODE , CMND_DISP_REFRESH , CMND_DISP_DIMMER ,
CMND_DISP_COLS , CMND_DISP_ROWS , CMND_DISP_SIZE , CMND_DISP_FONT , CMND_DISP_ROTATE , CMND_DISP_TEXT , CMND_DISP_ADDRESS } ;
2018-08-28 17:13:14 +01:00
const char kDisplayCommands [ ] PROGMEM =
2019-07-23 13:05:42 +01:00
" | " D_CMND_DISP_MODEL " | " D_CMND_DISP_MODE " | " D_CMND_DISP_WIDTH " | " D_CMND_DISP_HEIGHT " | " D_CMND_DISP_REFRESH " | " D_CMND_DISP_DIMMER " | "
D_CMND_DISP_COLS " | " D_CMND_DISP_ROWS " | " D_CMND_DISP_SIZE " | " D_CMND_DISP_FONT " | " D_CMND_DISP_ROTATE " | " D_CMND_DISP_TEXT " | " D_CMND_DISP_ADDRESS ;
2018-08-28 17:13:14 +01:00
const char S_JSON_DISPLAY_COMMAND_VALUE [ ] PROGMEM = " { \" " D_CMND_DISPLAY " %s \" : \" %s \" } " ;
const char S_JSON_DISPLAY_COMMAND_NVALUE [ ] PROGMEM = " { \" " D_CMND_DISPLAY " %s \" :%d} " ;
const char S_JSON_DISPLAY_COMMAND_INDEX_NVALUE [ ] PROGMEM = " { \" " D_CMND_DISPLAY " %s%d \" :%d} " ;
2019-07-01 11:54:26 +01:00
char * dsp_str ;
2018-08-28 17:13:14 +01:00
uint16_t dsp_x ;
uint16_t dsp_y ;
uint16_t dsp_x2 ;
uint16_t dsp_y2 ;
uint16_t dsp_rad ;
uint16_t dsp_color ;
int16_t dsp_len ;
2019-07-01 11:54:26 +01:00
int16_t disp_xpos = 0 ;
int16_t disp_ypos = 0 ;
uint8_t disp_power = 0 ;
uint8_t disp_device = 0 ;
uint8_t disp_refresh = 1 ;
uint8_t disp_autodraw = 1 ;
uint8_t dsp_init ;
uint8_t dsp_font ;
uint8_t dsp_flag ;
uint8_t dsp_on ;
2018-08-28 17:13:14 +01:00
# ifdef USE_DISPLAY_MODES1TO5
2019-07-01 11:54:26 +01:00
char * * disp_log_buffer ;
char * * disp_screen_buffer ;
2018-08-28 17:13:14 +01:00
char disp_temp [ 2 ] ; // C or F
uint8_t disp_log_buffer_cols = 0 ;
uint8_t disp_log_buffer_idx = 0 ;
uint8_t disp_log_buffer_ptr = 0 ;
uint8_t disp_screen_buffer_cols = 0 ;
uint8_t disp_screen_buffer_rows = 0 ;
2019-07-01 11:54:26 +01:00
bool disp_subscribed = false ;
2018-08-28 17:13:14 +01:00
# endif // USE_DISPLAY_MODES1TO5
/*********************************************************************************************/
void DisplayInit ( uint8_t mode )
{
dsp_init = mode ;
XdspCall ( FUNC_DISPLAY_INIT ) ;
}
2018-11-14 13:32:09 +00:00
void DisplayClear ( void )
2018-08-28 17:13:14 +01:00
{
XdspCall ( FUNC_DISPLAY_CLEAR ) ;
}
void DisplayDrawHLine ( uint16_t x , uint16_t y , int16_t len , uint16_t color )
{
dsp_x = x ;
dsp_y = y ;
dsp_len = len ;
dsp_color = color ;
XdspCall ( FUNC_DISPLAY_DRAW_HLINE ) ;
}
void DisplayDrawVLine ( uint16_t x , uint16_t y , int16_t len , uint16_t color )
{
dsp_x = x ;
dsp_y = y ;
dsp_len = len ;
dsp_color = color ;
XdspCall ( FUNC_DISPLAY_DRAW_VLINE ) ;
}
void DisplayDrawLine ( uint16_t x , uint16_t y , uint16_t x2 , uint16_t y2 , uint16_t color )
{
dsp_x = x ;
dsp_y = y ;
dsp_x2 = x2 ;
dsp_y2 = y2 ;
dsp_color = color ;
XdspCall ( FUNC_DISPLAY_DRAW_LINE ) ;
}
void DisplayDrawCircle ( uint16_t x , uint16_t y , uint16_t rad , uint16_t color )
{
dsp_x = x ;
dsp_y = y ;
dsp_rad = rad ;
dsp_color = color ;
XdspCall ( FUNC_DISPLAY_DRAW_CIRCLE ) ;
}
void DisplayDrawFilledCircle ( uint16_t x , uint16_t y , uint16_t rad , uint16_t color )
{
dsp_x = x ;
dsp_y = y ;
dsp_rad = rad ;
dsp_color = color ;
XdspCall ( FUNC_DISPLAY_FILL_CIRCLE ) ;
}
void DisplayDrawRectangle ( uint16_t x , uint16_t y , uint16_t x2 , uint16_t y2 , uint16_t color )
{
dsp_x = x ;
dsp_y = y ;
dsp_x2 = x2 ;
dsp_y2 = y2 ;
dsp_color = color ;
XdspCall ( FUNC_DISPLAY_DRAW_RECTANGLE ) ;
}
void DisplayDrawFilledRectangle ( uint16_t x , uint16_t y , uint16_t x2 , uint16_t y2 , uint16_t color )
{
dsp_x = x ;
dsp_y = y ;
dsp_x2 = x2 ;
dsp_y2 = y2 ;
dsp_color = color ;
XdspCall ( FUNC_DISPLAY_FILL_RECTANGLE ) ;
}
2018-11-14 13:32:09 +00:00
void DisplayDrawFrame ( void )
2018-08-28 17:13:14 +01:00
{
XdspCall ( FUNC_DISPLAY_DRAW_FRAME ) ;
}
void DisplaySetSize ( uint8_t size )
{
Settings . display_size = size & 3 ;
XdspCall ( FUNC_DISPLAY_TEXT_SIZE ) ;
}
void DisplaySetFont ( uint8_t font )
{
Settings . display_font = font & 3 ;
XdspCall ( FUNC_DISPLAY_FONT_SIZE ) ;
}
void DisplaySetRotation ( uint8_t rotation )
{
Settings . display_rotate = rotation & 3 ;
XdspCall ( FUNC_DISPLAY_ROTATION ) ;
}
void DisplayDrawStringAt ( uint16_t x , uint16_t y , char * str , uint16_t color , uint8_t flag )
{
dsp_x = x ;
dsp_y = y ;
dsp_str = str ;
dsp_color = color ;
dsp_flag = flag ;
XdspCall ( FUNC_DISPLAY_DRAW_STRING ) ;
}
void DisplayOnOff ( uint8_t on )
{
dsp_on = on ;
XdspCall ( FUNC_DISPLAY_ONOFF ) ;
}
/*-------------------------------------------------------------------------------------------*/
// get asci number until delimiter and return asci number lenght and value
uint8_t atoiv ( char * cp , int16_t * res )
{
uint8_t index = 0 ;
* res = atoi ( cp ) ;
while ( * cp ) {
if ( ( * cp > = ' 0 ' & & * cp < = ' 9 ' ) | | ( * cp = = ' - ' ) ) {
cp + + ;
index + + ;
} else {
break ;
}
}
return index ;
}
// get asci number until delimiter and return asci number lenght and value
uint8_t atoiV ( char * cp , uint16_t * res )
{
uint8_t index = 0 ;
* res = atoi ( cp ) ;
while ( * cp ) {
if ( * cp > = ' 0 ' & & * cp < = ' 9 ' ) {
cp + + ;
index + + ;
} else {
break ;
}
}
return index ;
}
/*-------------------------------------------------------------------------------------------*/
# define DISPLAY_BUFFER_COLS 128 // Max number of characters in linebuf
2018-11-14 13:32:09 +00:00
void DisplayText ( void )
2018-08-28 17:13:14 +01:00
{
uint8_t lpos ;
uint8_t escape = 0 ;
uint8_t var ;
uint8_t font_x = 6 ;
uint8_t font_y = 8 ;
uint8_t fontnumber = 1 ;
int16_t lin = 0 ;
int16_t col = 0 ;
int16_t fill = 0 ;
int16_t temp ;
int16_t temp1 ;
uint16_t color = 0 ;
char linebuf [ DISPLAY_BUFFER_COLS ] ;
char * dp = linebuf ;
char * cp = XdrvMailbox . data ;
memset ( linebuf , ' ' , sizeof ( linebuf ) ) ;
linebuf [ sizeof ( linebuf ) - 1 ] = 0 ;
* dp = 0 ;
while ( * cp ) {
if ( ! escape ) {
// check for escape
if ( * cp = = ' [ ' ) {
escape = 1 ;
cp + + ;
// if string in buffer print it
if ( ( uint32_t ) dp - ( uint32_t ) linebuf ) {
if ( ! fill ) { * dp = 0 ; }
if ( col > 0 & & lin > 0 ) {
// use col and lin
DisplayDrawStringAt ( col , lin , linebuf , color , 1 ) ;
} else {
// use disp_xpos, disp_ypos
DisplayDrawStringAt ( disp_xpos , disp_ypos , linebuf , color , 0 ) ;
}
memset ( linebuf , ' ' , sizeof ( linebuf ) ) ;
linebuf [ sizeof ( linebuf ) - 1 ] = 0 ;
dp = linebuf ;
}
} else {
// copy chars
if ( dp < ( linebuf + DISPLAY_BUFFER_COLS ) ) { * dp + + = * cp + + ; }
}
} else {
// check escapes
if ( * cp = = ' ] ' ) {
escape = 0 ;
cp + + ;
} else {
// analyze escapes
switch ( * cp + + ) {
case ' z ' :
// clear display
DisplayClear ( ) ;
disp_xpos = 0 ;
disp_ypos = 0 ;
col = 0 ;
lin = 0 ;
break ;
case ' i ' :
// init display with partial update
DisplayInit ( DISPLAY_INIT_PARTIAL ) ;
break ;
case ' I ' :
// init display with full refresh
DisplayInit ( DISPLAY_INIT_FULL ) ;
break ;
case ' o ' :
DisplayOnOff ( 0 ) ;
break ;
case ' O ' :
DisplayOnOff ( 1 ) ;
break ;
case ' x ' :
// set disp_xpos
var = atoiv ( cp , & disp_xpos ) ;
cp + = var ;
break ;
case ' y ' :
// set disp_ypos
var = atoiv ( cp , & disp_ypos ) ;
cp + = var ;
break ;
case ' l ' :
// text line lxx
var = atoiv ( cp , & lin ) ;
cp + = var ;
//display.setCursor(display.getCursorX(),(lin-1)*font_y*txtsize);
break ;
case ' c ' :
// text column cxx
var = atoiv ( cp , & col ) ;
cp + = var ;
//display.setCursor((col-1)*font_x*txtsize,display.getCursorY());
break ;
case ' C ' :
// text color cxx
var = atoiV ( cp , & color ) ;
cp + = var ;
break ;
case ' p ' :
// pad field with spaces fxx
var = atoiv ( cp , & fill ) ;
cp + = var ;
linebuf [ fill ] = 0 ;
break ;
case ' h ' :
// hor line to
var = atoiv ( cp , & temp ) ;
cp + = var ;
if ( temp < 0 ) {
DisplayDrawHLine ( disp_xpos + temp , disp_ypos , - temp , color ) ;
} else {
DisplayDrawHLine ( disp_xpos , disp_ypos , temp , color ) ;
}
disp_xpos + = temp ;
break ;
case ' v ' :
// vert line to
var = atoiv ( cp , & temp ) ;
cp + = var ;
if ( temp < 0 ) {
DisplayDrawVLine ( disp_xpos , disp_ypos + temp , - temp , color ) ;
} else {
DisplayDrawVLine ( disp_xpos , disp_ypos , temp , color ) ;
}
disp_ypos + = temp ;
break ;
case ' L ' :
// any line to
var = atoiv ( cp , & temp ) ;
cp + = var ;
cp + + ;
var = atoiv ( cp , & temp1 ) ;
cp + = var ;
DisplayDrawLine ( disp_xpos , disp_ypos , temp , temp1 , color ) ;
disp_xpos + = temp ;
disp_ypos + = temp1 ;
break ;
case ' k ' :
// circle
var = atoiv ( cp , & temp ) ;
cp + = var ;
DisplayDrawCircle ( disp_xpos , disp_ypos , temp , color ) ;
break ;
case ' K ' :
// filled circle
var = atoiv ( cp , & temp ) ;
cp + = var ;
DisplayDrawFilledCircle ( disp_xpos , disp_ypos , temp , color ) ;
break ;
case ' r ' :
// rectangle
var = atoiv ( cp , & temp ) ;
cp + = var ;
cp + + ;
var = atoiv ( cp , & temp1 ) ;
cp + = var ;
DisplayDrawRectangle ( disp_xpos , disp_ypos , temp , temp1 , color ) ;
break ;
case ' R ' :
// filled rectangle
var = atoiv ( cp , & temp ) ;
cp + = var ;
cp + + ;
var = atoiv ( cp , & temp1 ) ;
cp + = var ;
DisplayDrawFilledRectangle ( disp_xpos , disp_ypos , temp , temp1 , color ) ;
break ;
2019-01-09 13:14:55 +00:00
case ' t ' :
2018-08-28 17:13:14 +01:00
if ( dp < ( linebuf + DISPLAY_BUFFER_COLS ) - 5 ) {
2019-01-09 13:14:55 +00:00
snprintf_P ( dp , 6 , PSTR ( " %02d " D_HOUR_MINUTE_SEPARATOR " %02d " ) , RtcTime . hour , RtcTime . minute ) ;
2018-08-28 17:13:14 +01:00
dp + = 5 ;
}
break ;
2019-01-09 13:14:55 +00:00
case ' T ' :
if ( dp < ( linebuf + DISPLAY_BUFFER_COLS ) - 8 ) {
snprintf_P ( dp , 9 , PSTR ( " %02d " D_MONTH_DAY_SEPARATOR " %02d " D_YEAR_MONTH_SEPARATOR " %02d " ) , RtcTime . day_of_month , RtcTime . month , RtcTime . year % 2000 ) ;
dp + = 8 ;
}
break ;
2018-08-28 17:13:14 +01:00
case ' d ' :
// force draw grafics buffer
DisplayDrawFrame ( ) ;
break ;
case ' D ' :
// set auto draw mode
disp_autodraw = * cp & 1 ;
cp + = 1 ;
break ;
case ' s ' :
// size sx
DisplaySetSize ( * cp & 3 ) ;
cp + = 1 ;
break ;
case ' f ' :
// font sx
DisplaySetFont ( * cp & 3 ) ;
cp + = 1 ;
break ;
case ' a ' :
// rotation angle
DisplaySetRotation ( * cp & 3 ) ;
cp + = 1 ;
break ;
default :
// unknown escape
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " Unknown Escape " ) ) ;
2018-08-28 17:13:14 +01:00
goto exit ;
break ;
}
}
2019-01-09 13:56:16 +00:00
}
2018-08-28 17:13:14 +01:00
}
exit :
// now draw buffer
if ( ( uint32_t ) dp - ( uint32_t ) linebuf ) {
if ( ! fill ) { * dp = 0 ; }
if ( col > 0 & & lin > 0 ) {
// use col and lin
DisplayDrawStringAt ( col , lin , linebuf , color , 1 ) ;
} else {
// use disp_xpos, disp_ypos
DisplayDrawStringAt ( disp_xpos , disp_ypos , linebuf , color , 0 ) ;
}
}
// draw buffer
if ( disp_autodraw ) { DisplayDrawFrame ( ) ; }
}
/*********************************************************************************************/
# ifdef USE_DISPLAY_MODES1TO5
2018-11-14 13:32:09 +00:00
void DisplayClearScreenBuffer ( void )
2018-08-28 17:13:14 +01:00
{
if ( disp_screen_buffer_cols ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < disp_screen_buffer_rows ; i + + ) {
2018-08-28 17:13:14 +01:00
memset ( disp_screen_buffer [ i ] , 0 , disp_screen_buffer_cols ) ;
}
}
}
2018-11-14 13:32:09 +00:00
void DisplayFreeScreenBuffer ( void )
2018-08-28 17:13:14 +01:00
{
2019-03-26 17:26:50 +00:00
if ( disp_screen_buffer ! = nullptr ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < disp_screen_buffer_rows ; i + + ) {
2019-03-26 17:26:50 +00:00
if ( disp_screen_buffer [ i ] ! = nullptr ) { free ( disp_screen_buffer [ i ] ) ; }
2018-08-28 17:13:14 +01:00
}
free ( disp_screen_buffer ) ;
disp_screen_buffer_cols = 0 ;
disp_screen_buffer_rows = 0 ;
}
}
2018-11-14 13:32:09 +00:00
void DisplayAllocScreenBuffer ( void )
2018-08-28 17:13:14 +01:00
{
if ( ! disp_screen_buffer_cols ) {
disp_screen_buffer_rows = Settings . display_rows ;
disp_screen_buffer = ( char * * ) malloc ( sizeof ( * disp_screen_buffer ) * disp_screen_buffer_rows ) ;
2019-03-26 17:26:50 +00:00
if ( disp_screen_buffer ! = nullptr ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < disp_screen_buffer_rows ; i + + ) {
2018-08-28 17:13:14 +01:00
disp_screen_buffer [ i ] = ( char * ) malloc ( sizeof ( * disp_screen_buffer [ i ] ) * ( Settings . display_cols [ 0 ] + 1 ) ) ;
2019-03-26 17:26:50 +00:00
if ( disp_screen_buffer [ i ] = = nullptr ) {
2018-08-28 17:13:14 +01:00
DisplayFreeScreenBuffer ( ) ;
break ;
}
}
}
2019-03-26 17:26:50 +00:00
if ( disp_screen_buffer ! = nullptr ) {
2018-08-28 17:13:14 +01:00
disp_screen_buffer_cols = Settings . display_cols [ 0 ] + 1 ;
DisplayClearScreenBuffer ( ) ;
}
}
}
2018-11-14 13:32:09 +00:00
void DisplayReAllocScreenBuffer ( void )
2018-08-28 17:13:14 +01:00
{
DisplayFreeScreenBuffer ( ) ;
DisplayAllocScreenBuffer ( ) ;
}
2018-08-31 11:17:09 +01:00
void DisplayFillScreen ( uint8_t line )
{
2019-01-28 13:08:33 +00:00
uint8_t len = disp_screen_buffer_cols - strlen ( disp_screen_buffer [ line ] ) ;
2018-08-31 11:17:09 +01:00
if ( len ) {
memset ( disp_screen_buffer [ line ] + strlen ( disp_screen_buffer [ line ] ) , 0x20 , len ) ;
disp_screen_buffer [ line ] [ disp_screen_buffer_cols - 1 ] = 0 ;
}
}
2018-08-28 17:13:14 +01:00
/*-------------------------------------------------------------------------------------------*/
2018-11-14 13:32:09 +00:00
void DisplayClearLogBuffer ( void )
2018-08-28 17:13:14 +01:00
{
if ( disp_log_buffer_cols ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < DISPLAY_LOG_ROWS ; i + + ) {
2018-08-28 17:13:14 +01:00
memset ( disp_log_buffer [ i ] , 0 , disp_log_buffer_cols ) ;
}
}
}
2018-11-14 13:32:09 +00:00
void DisplayFreeLogBuffer ( void )
2018-08-28 17:13:14 +01:00
{
2019-03-26 17:26:50 +00:00
if ( disp_log_buffer ! = nullptr ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < DISPLAY_LOG_ROWS ; i + + ) {
2019-03-26 17:26:50 +00:00
if ( disp_log_buffer [ i ] ! = nullptr ) { free ( disp_log_buffer [ i ] ) ; }
2018-08-28 17:13:14 +01:00
}
free ( disp_log_buffer ) ;
disp_log_buffer_cols = 0 ;
}
}
2018-11-14 13:32:09 +00:00
void DisplayAllocLogBuffer ( void )
2018-08-28 17:13:14 +01:00
{
if ( ! disp_log_buffer_cols ) {
disp_log_buffer = ( char * * ) malloc ( sizeof ( * disp_log_buffer ) * DISPLAY_LOG_ROWS ) ;
2019-03-26 17:26:50 +00:00
if ( disp_log_buffer ! = nullptr ) {
2019-06-30 15:44:36 +01:00
for ( uint32_t i = 0 ; i < DISPLAY_LOG_ROWS ; i + + ) {
2018-08-28 17:13:14 +01:00
disp_log_buffer [ i ] = ( char * ) malloc ( sizeof ( * disp_log_buffer [ i ] ) * ( Settings . display_cols [ 0 ] + 1 ) ) ;
2019-03-26 17:26:50 +00:00
if ( disp_log_buffer [ i ] = = nullptr ) {
2018-08-28 17:13:14 +01:00
DisplayFreeLogBuffer ( ) ;
break ;
}
}
}
2019-03-26 17:26:50 +00:00
if ( disp_log_buffer ! = nullptr ) {
2018-08-28 17:13:14 +01:00
disp_log_buffer_cols = Settings . display_cols [ 0 ] + 1 ;
DisplayClearLogBuffer ( ) ;
}
}
}
2018-11-14 13:32:09 +00:00
void DisplayReAllocLogBuffer ( void )
2018-08-28 17:13:14 +01:00
{
DisplayFreeLogBuffer ( ) ;
DisplayAllocLogBuffer ( ) ;
}
2018-08-31 11:17:09 +01:00
void DisplayLogBufferAdd ( char * txt )
2018-08-28 17:13:14 +01:00
{
2018-08-31 11:17:09 +01:00
if ( disp_log_buffer_cols ) {
strlcpy ( disp_log_buffer [ disp_log_buffer_idx ] , txt , disp_log_buffer_cols ) ; // This preserves the % sign where printf won't
disp_log_buffer_idx + + ;
if ( DISPLAY_LOG_ROWS = = disp_log_buffer_idx ) { disp_log_buffer_idx = 0 ; }
2018-08-28 17:13:14 +01:00
}
}
2018-08-31 11:17:09 +01:00
char * DisplayLogBuffer ( char temp_code )
2018-08-28 17:13:14 +01:00
{
2019-03-26 17:26:50 +00:00
char * result = nullptr ;
2018-08-31 11:17:09 +01:00
if ( disp_log_buffer_cols ) {
if ( disp_log_buffer_idx ! = disp_log_buffer_ptr ) {
result = disp_log_buffer [ disp_log_buffer_ptr ] ;
disp_log_buffer_ptr + + ;
if ( DISPLAY_LOG_ROWS = = disp_log_buffer_ptr ) { disp_log_buffer_ptr = 0 ; }
2018-08-28 17:13:14 +01:00
2018-08-31 11:17:09 +01:00
char * pch = strchr ( result , ' ~ ' ) ; // = 0x7E (~) Replace degrees character (276 octal)
2019-03-26 17:26:50 +00:00
if ( pch ! = nullptr ) { result [ pch - result ] = temp_code ; }
2018-08-28 17:13:14 +01:00
}
}
2018-08-31 11:17:09 +01:00
return result ;
2018-08-28 17:13:14 +01:00
}
2018-11-14 13:32:09 +00:00
void DisplayLogBufferInit ( void )
2018-08-28 17:13:14 +01:00
{
if ( Settings . display_mode ) {
disp_log_buffer_idx = 0 ;
disp_log_buffer_ptr = 0 ;
disp_refresh = Settings . display_refresh ;
snprintf_P ( disp_temp , sizeof ( disp_temp ) , PSTR ( " %c " ) , TempUnit ( ) ) ;
2018-08-31 11:17:09 +01:00
DisplayReAllocLogBuffer ( ) ;
2018-08-28 17:13:14 +01:00
2018-09-05 14:38:48 +01:00
char buffer [ 40 ] ;
2018-11-07 14:03:41 +00:00
snprintf_P ( buffer , sizeof ( buffer ) , PSTR ( D_VERSION " %s%s " ) , my_version , my_image ) ;
2018-08-31 11:17:09 +01:00
DisplayLogBufferAdd ( buffer ) ;
snprintf_P ( buffer , sizeof ( buffer ) , PSTR ( " Display mode %d " ) , Settings . display_mode ) ;
DisplayLogBufferAdd ( buffer ) ;
2018-09-05 14:38:48 +01:00
snprintf_P ( buffer , sizeof ( buffer ) , PSTR ( D_CMND_HOSTNAME " %s " ) , my_hostname ) ;
DisplayLogBufferAdd ( buffer ) ;
snprintf_P ( buffer , sizeof ( buffer ) , PSTR ( D_JSON_SSID " %s " ) , Settings . sta_ssid [ Settings . sta_active ] ) ;
DisplayLogBufferAdd ( buffer ) ;
snprintf_P ( buffer , sizeof ( buffer ) , PSTR ( D_JSON_MAC " %s " ) , WiFi . macAddress ( ) . c_str ( ) ) ;
DisplayLogBufferAdd ( buffer ) ;
2018-11-04 17:00:07 +00:00
if ( ! global_state . wifi_down ) {
2018-09-05 14:38:48 +01:00
snprintf_P ( buffer , sizeof ( buffer ) , PSTR ( " IP %s " ) , WiFi . localIP ( ) . toString ( ) . c_str ( ) ) ;
DisplayLogBufferAdd ( buffer ) ;
snprintf_P ( buffer , sizeof ( buffer ) , PSTR ( D_JSON_RSSI " %d%% " ) , WifiGetRssiAsQuality ( WiFi . RSSI ( ) ) ) ;
DisplayLogBufferAdd ( buffer ) ;
}
2018-08-28 17:13:14 +01:00
}
}
/*********************************************************************************************\
* Sensors
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
enum SensorQuantity {
JSON_TEMPERATURE ,
JSON_HUMIDITY , JSON_LIGHT , JSON_NOISE , JSON_AIRQUALITY ,
JSON_PRESSURE , JSON_PRESSUREATSEALEVEL ,
JSON_ILLUMINANCE ,
JSON_GAS ,
JSON_YESTERDAY , JSON_TOTAL , JSON_TODAY ,
JSON_PERIOD ,
JSON_POWERFACTOR , JSON_COUNTER , JSON_ANALOG_INPUT , JSON_UV_LEVEL ,
JSON_CURRENT ,
JSON_VOLTAGE ,
JSON_POWERUSAGE ,
2018-11-04 17:00:07 +00:00
JSON_CO2 ,
JSON_FREQUENCY } ;
2018-08-28 17:13:14 +01:00
const char kSensorQuantity [ ] PROGMEM =
D_JSON_TEMPERATURE " | " // degrees
D_JSON_HUMIDITY " | " D_JSON_LIGHT " | " D_JSON_NOISE " | " D_JSON_AIRQUALITY " | " // percentage
D_JSON_PRESSURE " | " D_JSON_PRESSUREATSEALEVEL " | " // hPa
D_JSON_ILLUMINANCE " | " // lx
D_JSON_GAS " | " // kOhm
D_JSON_YESTERDAY " | " D_JSON_TOTAL " | " D_JSON_TODAY " | " // kWh
D_JSON_PERIOD " | " // Wh
D_JSON_POWERFACTOR " | " D_JSON_COUNTER " | " D_JSON_ANALOG_INPUT " | " D_JSON_UV_LEVEL " | " // No unit
D_JSON_CURRENT " | " // Ampere
D_JSON_VOLTAGE " | " // Volt
D_JSON_POWERUSAGE " | " // Watt
2018-11-04 17:00:07 +00:00
D_JSON_CO2 " | " // ppm
D_JSON_FREQUENCY ; // Hz
2018-08-28 17:13:14 +01:00
2019-02-24 16:29:28 +00:00
void DisplayJsonValue ( const char * topic , const char * device , const char * mkey , const char * value )
2018-08-28 17:13:14 +01:00
{
char quantity [ TOPSZ ] ;
2018-08-31 11:17:09 +01:00
char buffer [ Settings . display_cols [ 0 ] + 1 ] ;
2018-08-28 17:13:14 +01:00
char spaces [ Settings . display_cols [ 0 ] ] ;
char source [ Settings . display_cols [ 0 ] - Settings . display_cols [ 1 ] ] ;
char svalue [ Settings . display_cols [ 1 ] + 1 ] ;
2019-03-11 09:38:41 +00:00
# ifdef USE_DEBUG_DRIVER
2018-08-28 17:13:14 +01:00
ShowFreeMem ( PSTR ( " DisplayJsonValue " ) ) ;
2019-03-11 09:38:41 +00:00
# endif
2018-08-28 17:13:14 +01:00
memset ( spaces , 0x20 , sizeof ( spaces ) ) ;
spaces [ sizeof ( spaces ) - 1 ] = ' \0 ' ;
2019-02-24 16:29:28 +00:00
snprintf_P ( source , sizeof ( source ) , PSTR ( " %s%s%s%s " ) , topic , ( strlen ( topic ) ) ? " / " : " " , mkey , spaces ) ; // pow1/Voltage or Voltage if topic is empty (local sensor)
2018-08-28 17:13:14 +01:00
int quantity_code = GetCommandCode ( quantity , sizeof ( quantity ) , mkey , kSensorQuantity ) ;
if ( ( - 1 = = quantity_code ) | | ! strcmp_P ( mkey , S_RSLT_POWER ) ) { // Ok: Power, Not ok: POWER
return ;
}
if ( JSON_TEMPERATURE = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s~%s " ) , value , disp_temp ) ;
}
else if ( ( quantity_code > = JSON_HUMIDITY ) & & ( quantity_code < = JSON_AIRQUALITY ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s%% " ) , value ) ;
}
else if ( ( quantity_code > = JSON_PRESSURE ) & & ( quantity_code < = JSON_PRESSUREATSEALEVEL ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_PRESSURE ) , value ) ;
}
else if ( JSON_ILLUMINANCE = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_LUX ) , value ) ;
}
else if ( JSON_GAS = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_KILOOHM ) , value ) ;
}
else if ( ( quantity_code > = JSON_YESTERDAY ) & & ( quantity_code < = JSON_TODAY ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_KILOWATTHOUR ) , value ) ;
}
else if ( JSON_PERIOD = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_WATTHOUR ) , value ) ;
}
else if ( ( quantity_code > = JSON_POWERFACTOR ) & & ( quantity_code < = JSON_UV_LEVEL ) ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " ) , value ) ;
}
else if ( JSON_CURRENT = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_AMPERE ) , value ) ;
}
else if ( JSON_VOLTAGE = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_VOLT ) , value ) ;
}
else if ( JSON_POWERUSAGE = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_WATT ) , value ) ;
}
else if ( JSON_CO2 = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_PARTS_PER_MILLION ) , value ) ;
}
2018-11-04 17:00:07 +00:00
else if ( JSON_FREQUENCY = = quantity_code ) {
snprintf_P ( svalue , sizeof ( svalue ) , PSTR ( " %s " D_UNIT_HERTZ ) , value ) ;
}
2018-08-31 11:17:09 +01:00
snprintf_P ( buffer , sizeof ( buffer ) , PSTR ( " %s %s " ) , source , svalue ) ;
2018-08-28 17:13:14 +01:00
2019-03-08 14:15:42 +00:00
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "mkey [%s], source [%s], value [%s], quantity_code %d, log_buffer [%s]"), mkey, source, value, quantity_code, buffer);
2018-08-28 17:13:14 +01:00
2018-08-31 11:17:09 +01:00
DisplayLogBufferAdd ( buffer ) ;
2018-08-28 17:13:14 +01:00
}
void DisplayAnalyzeJson ( char * topic , char * json )
{
// //tele/pow2/STATE {"Time":"2017-09-20T11:53:03", "Uptime":10, "Vcc":3.123, "POWER":"ON", "Wifi":{"AP":2, "SSId":"indebuurt2", "RSSI":68, "APMac":"00:22:6B:FE:8E:20"}}
// //tele/pow2/ENERGY {"Time":"2017-09-20T11:53:03", "Total":6.522, "Yesterday":0.150, "Today":0.073, "Period":0.5, "Power":12.1, "Factor":0.56, "Voltage":210.1, "Current":0.102}
// tele/pow1/SENSOR = {"Time":"2018-01-02T17:13:17","ENERGY":{"Total":13.091,"Yesterday":0.060,"Today":0.046,"Period":0.2,"Power":9.8,"Factor":0.49,"Voltage":206.8,"Current":0.096}}
// tele/dual/STATE {"Time":"2017-09-20T11:53:03","Uptime":25,"Vcc":3.178,"POWER1":"OFF","POWER2":"OFF","Wifi":{"AP":2,"SSId":"indebuurt2","RSSI":100,"APMac":"00:22:6B:FE:8E:20"}}
// tele/sc/SENSOR {"Time":"2017-09-20T11:53:09","Temperature":24.0,"Humidity":16.0,"Light":30,"Noise":20,"AirQuality":100,"TempUnit":"C"}
// tele/rf1/SENSOR {"Time":"2017-09-20T11:53:23","BH1750":{"Illuminance":57}}
// tele/wemos5/SENSOR {"Time":"2017-09-20T11:53:53","SHT1X":{"Temperature":20.1,"Humidity":58.9},"HTU21":{"Temperature":20.7,"Humidity":58.5},"BMP280":{"Temperature":21.6,"Pressure":1020.3},"TempUnit":"C"}
// tele/th1/SENSOR {"Time":"2017-09-20T11:54:48","DS18B20":{"Temperature":49.7},"TempUnit":"C"}
const char * tempunit ;
// char jsonStr[MESSZ];
// strlcpy(jsonStr, json, sizeof(jsonStr)); // Save original before destruction by JsonObject
String jsonStr = json ; // Move from stack to heap to fix watchdogs (20180626)
StaticJsonBuffer < 1024 > jsonBuf ;
JsonObject & root = jsonBuf . parseObject ( jsonStr ) ;
if ( root . success ( ) ) {
tempunit = root [ D_JSON_TEMPERATURE_UNIT ] ;
if ( tempunit ) {
snprintf_P ( disp_temp , sizeof ( disp_temp ) , PSTR ( " %s " ) , tempunit ) ;
2019-03-08 14:15:42 +00:00
// AddLog_P2(LOG_LEVEL_DEBUG, disp_temp);
2018-08-28 17:13:14 +01:00
}
for ( JsonObject : : iterator it = root . begin ( ) ; it ! = root . end ( ) ; + + it ) {
JsonVariant value = it - > value ;
if ( value . is < JsonObject > ( ) ) {
JsonObject & Object2 = value ;
for ( JsonObject : : iterator it2 = Object2 . begin ( ) ; it2 ! = Object2 . end ( ) ; + + it2 ) {
JsonVariant value2 = it2 - > value ;
if ( value2 . is < JsonObject > ( ) ) {
JsonObject & Object3 = value2 ;
for ( JsonObject : : iterator it3 = Object3 . begin ( ) ; it3 ! = Object3 . end ( ) ; + + it3 ) {
2019-01-09 13:56:16 +00:00
const char * value = it3 - > value ;
if ( value ! = nullptr ) { // "DHT11":{"Temperature":null,"Humidity":null} - ignore null as it will raise exception 28
DisplayJsonValue ( topic , it - > key , it3 - > key , value ) ; // Sensor 56%
2019-01-08 13:22:45 +00:00
}
2018-08-28 17:13:14 +01:00
}
} else {
2019-01-09 13:56:16 +00:00
const char * value = it2 - > value ;
if ( value ! = nullptr ) {
DisplayJsonValue ( topic , it - > key , it2 - > key , value ) ; // Sensor 56%
2019-01-08 13:22:45 +00:00
}
2018-08-28 17:13:14 +01:00
}
}
} else {
2019-01-09 13:56:16 +00:00
const char * value = it - > value ;
if ( value ! = nullptr ) {
DisplayJsonValue ( topic , it - > key , it - > key , value ) ; // Topic 56%
2019-01-08 13:22:45 +00:00
}
2018-08-28 17:13:14 +01:00
}
}
}
}
2018-11-14 13:32:09 +00:00
void DisplayMqttSubscribe ( void )
2018-08-28 17:13:14 +01:00
{
/* Subscribe to tele messages only
* Supports the following FullTopic formats
* - % prefix % / % topic %
* - home / % prefix % / % topic %
* - home / level2 / % prefix % / % topic % etc .
*/
2019-07-01 11:54:26 +01:00
if ( Settings . display_model & & ( Settings . display_mode & 0x04 ) ) {
2018-08-28 17:13:14 +01:00
char stopic [ TOPSZ ] ;
char ntopic [ TOPSZ ] ;
ntopic [ 0 ] = ' \0 ' ;
strlcpy ( stopic , Settings . mqtt_fulltopic , sizeof ( stopic ) ) ;
char * tp = strtok ( stopic , " / " ) ;
2019-03-26 17:26:50 +00:00
while ( tp ! = nullptr ) {
2019-03-30 15:29:27 +00:00
if ( ! strcmp_P ( tp , MQTT_TOKEN_PREFIX ) ) {
2018-08-28 17:13:14 +01:00
break ;
}
2018-11-22 14:41:30 +00:00
strncat_P ( ntopic , PSTR ( " +/ " ) , sizeof ( ntopic ) - strlen ( ntopic ) - 1 ) ; // Add single-level wildcards
2019-03-26 17:26:50 +00:00
tp = strtok ( nullptr , " / " ) ;
2018-08-28 17:13:14 +01:00
}
2018-11-22 14:41:30 +00:00
strncat ( ntopic , Settings . mqtt_prefix [ 2 ] , sizeof ( ntopic ) - strlen ( ntopic ) - 1 ) ; // Subscribe to tele messages
strncat_P ( ntopic , PSTR ( " /# " ) , sizeof ( ntopic ) - strlen ( ntopic ) - 1 ) ; // Add multi-level wildcard
2018-08-28 17:13:14 +01:00
MqttSubscribe ( ntopic ) ;
2019-07-01 11:54:26 +01:00
disp_subscribed = true ;
2018-08-28 17:13:14 +01:00
} else {
2019-07-01 11:54:26 +01:00
disp_subscribed = false ;
2018-08-28 17:13:14 +01:00
}
}
2019-01-28 13:08:33 +00:00
bool DisplayMqttData ( void )
2018-08-28 17:13:14 +01:00
{
if ( disp_subscribed ) {
char stopic [ TOPSZ ] ;
snprintf_P ( stopic , sizeof ( stopic ) , PSTR ( " %s/ " ) , Settings . mqtt_prefix [ 2 ] ) ; // tele/
char * tp = strstr ( XdrvMailbox . topic , stopic ) ;
if ( tp ) { // tele/sonoff/SENSOR
if ( Settings . display_mode & 0x04 ) {
tp = tp + strlen ( stopic ) ; // sonoff/SENSOR
char * topic = strtok ( tp , " / " ) ; // sonoff
DisplayAnalyzeJson ( topic , XdrvMailbox . data ) ;
}
return true ;
}
}
return false ;
}
2018-11-14 13:32:09 +00:00
void DisplayLocalSensor ( void )
2018-08-28 17:13:14 +01:00
{
if ( ( Settings . display_mode & 0x02 ) & & ( 0 = = tele_period ) ) {
2019-02-24 16:29:28 +00:00
char no_topic [ 1 ] = { 0 } ;
// DisplayAnalyzeJson(mqtt_topic, mqtt_data); // Add local topic
DisplayAnalyzeJson ( no_topic , mqtt_data ) ; // Discard any topic
2018-08-28 17:13:14 +01:00
}
}
# endif // USE_DISPLAY_MODES1TO5
/*********************************************************************************************\
* Public
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2018-11-14 13:32:09 +00:00
void DisplayInitDriver ( void )
2018-08-28 17:13:14 +01:00
{
XdspCall ( FUNC_DISPLAY_INIT_DRIVER ) ;
2019-03-08 14:15:42 +00:00
// AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_DEBUG "Display model %d"), Settings.display_model);
2018-08-28 17:13:14 +01:00
if ( Settings . display_model ) {
devices_present + + ;
disp_device = devices_present ;
# ifndef USE_DISPLAY_MODES1TO5
Settings . display_mode = 0 ;
# else
DisplayLogBufferInit ( ) ;
# endif // USE_DISPLAY_MODES1TO5
}
}
2018-11-14 13:32:09 +00:00
void DisplaySetPower ( void )
2018-08-28 17:13:14 +01:00
{
disp_power = bitRead ( XdrvMailbox . index , disp_device - 1 ) ;
if ( Settings . display_model ) {
XdspCall ( FUNC_DISPLAY_POWER ) ;
}
}
/*********************************************************************************************\
* Commands
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-28 13:08:33 +00:00
bool DisplayCommand ( void )
2018-08-28 17:13:14 +01:00
{
char command [ CMDSZ ] ;
2019-01-28 13:08:33 +00:00
bool serviced = true ;
2018-08-28 17:13:14 +01:00
uint8_t disp_len = strlen ( D_CMND_DISPLAY ) ; // Prep for string length change
if ( ! strncasecmp_P ( XdrvMailbox . topic , PSTR ( D_CMND_DISPLAY ) , disp_len ) ) { // Prefix
int command_code = GetCommandCode ( command , sizeof ( command ) , XdrvMailbox . topic + disp_len , kDisplayCommands ) ;
if ( - 1 = = command_code ) {
serviced = false ; // Unknown command
}
2018-09-05 17:01:15 +01:00
else if ( CMND_DISPLAY = = command_code ) {
2019-07-23 13:05:42 +01:00
Response_P ( PSTR ( " { \" " D_CMND_DISPLAY " \" :{ \" " D_CMND_DISP_MODEL " \" :%d, \" " D_CMND_DISP_WIDTH " \" :%d, \" " D_CMND_DISP_HEIGHT " \" :%d, \" " D_CMND_DISP_MODE " \" :%d, \" "
D_CMND_DISP_DIMMER " \" :%d, \" " D_CMND_DISP_SIZE " \" :%d, \" " D_CMND_DISP_FONT " \" :%d, \" " D_CMND_DISP_ROTATE " \" :%d, \" " D_CMND_DISP_REFRESH " \" :%d, \" "
D_CMND_DISP_COLS " \" :[%d,%d], \" " D_CMND_DISP_ROWS " \" :%d}} " ) ,
Settings . display_model , Settings . display_width , Settings . display_height , Settings . display_mode ,
Settings . display_dimmer , Settings . display_size , Settings . display_font , Settings . display_rotate , Settings . display_refresh ,
2018-09-05 17:01:15 +01:00
Settings . display_cols [ 0 ] , Settings . display_cols [ 1 ] , Settings . display_rows ) ;
}
2018-08-28 17:13:14 +01:00
else if ( CMND_DISP_MODEL = = command_code ) {
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < DISPLAY_MAX_DRIVERS ) ) {
uint8_t last_display_model = Settings . display_model ;
Settings . display_model = XdrvMailbox . payload ;
if ( XdspCall ( FUNC_DISPLAY_MODEL ) ) {
restart_flag = 2 ; // Restart to re-init interface and add/Remove MQTT subscribe
} else {
Settings . display_model = last_display_model ;
}
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_model ) ;
2018-08-28 17:13:14 +01:00
}
2019-07-23 13:05:42 +01:00
else if ( CMND_DISP_WIDTH = = command_code ) {
if ( XdrvMailbox . payload > 0 ) {
if ( XdrvMailbox . payload ! = Settings . display_width ) {
Settings . display_width = XdrvMailbox . payload ;
restart_flag = 2 ; // Restart to re-init width
}
}
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_width ) ;
}
else if ( CMND_DISP_HEIGHT = = command_code ) {
if ( XdrvMailbox . payload > 0 ) {
if ( XdrvMailbox . payload ! = Settings . display_height ) {
Settings . display_height = XdrvMailbox . payload ;
restart_flag = 2 ; // Restart to re-init height
}
}
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_height ) ;
}
2018-08-28 17:13:14 +01:00
else if ( CMND_DISP_MODE = = command_code ) {
# ifdef USE_DISPLAY_MODES1TO5
/* Matrix LCD / Oled TFT
* 1 = Text up and time Time
* 2 = Date Local sensors Local sensors
* 3 = Day Local sensors and time Local sensors and time
* 4 = Mqtt left and time Mqtt ( incl local ) sensors Mqtt ( incl local ) sensors
* 5 = Mqtt up and time Mqtt ( incl local ) sensors and time Mqtt ( incl local ) sensors and time
*/
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 5 ) ) {
2019-07-01 11:54:26 +01:00
uint32_t last_display_mode = Settings . display_mode ;
2018-08-28 17:13:14 +01:00
Settings . display_mode = XdrvMailbox . payload ;
2019-07-01 11:54:26 +01:00
if ( disp_subscribed ! = ( Settings . display_mode & 0x04 ) ) {
2018-08-28 17:13:14 +01:00
restart_flag = 2 ; // Restart to Add/Remove MQTT subscribe
} else {
if ( last_display_mode & & ! Settings . display_mode ) { // Switch to mode 0
DisplayInit ( DISPLAY_INIT_MODE ) ;
DisplayClear ( ) ;
2018-09-05 14:38:48 +01:00
} else {
2018-08-28 17:13:14 +01:00
DisplayLogBufferInit ( ) ;
DisplayInit ( DISPLAY_INIT_MODE ) ;
}
}
}
# endif // USE_DISPLAY_MODES1TO5
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_mode ) ;
2018-08-28 17:13:14 +01:00
}
else if ( CMND_DISP_DIMMER = = command_code ) {
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 100 ) ) {
Settings . display_dimmer = ( ( XdrvMailbox . payload + 1 ) * 100 ) / 666 ; // Correction for Domoticz (0 - 15)
if ( Settings . display_dimmer & & ! ( disp_power ) ) {
ExecuteCommandPower ( disp_device , POWER_ON , SRC_DISPLAY ) ;
}
else if ( ! Settings . display_dimmer & & disp_power ) {
ExecuteCommandPower ( disp_device , POWER_OFF , SRC_DISPLAY ) ;
}
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_dimmer ) ;
2018-08-28 17:13:14 +01:00
}
else if ( CMND_DISP_SIZE = = command_code ) {
if ( ( XdrvMailbox . payload > 0 ) & & ( XdrvMailbox . payload < = 4 ) ) {
Settings . display_size = XdrvMailbox . payload ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_size ) ;
2018-08-28 17:13:14 +01:00
}
else if ( CMND_DISP_FONT = = command_code ) {
if ( ( XdrvMailbox . payload > 0 ) & & ( XdrvMailbox . payload < = 4 ) ) {
Settings . display_font = XdrvMailbox . payload ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_font ) ;
2018-08-28 17:13:14 +01:00
}
else if ( CMND_DISP_ROTATE = = command_code ) {
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < 4 ) ) {
if ( Settings . display_rotate ! = XdrvMailbox . payload ) {
/*
// Needs font info regarding height and width
if ( ( Settings . display_rotate & 1 ) ! = ( XdrvMailbox . payload & 1 ) ) {
uint8_t temp_rows = Settings . display_rows ;
Settings . display_rows = Settings . display_cols [ 0 ] ;
Settings . display_cols [ 0 ] = temp_rows ;
# ifdef USE_DISPLAY_MODES1TO5
DisplayReAllocScreenBuffer ( ) ;
# endif // USE_DISPLAY_MODES1TO5
}
*/
Settings . display_rotate = XdrvMailbox . payload ;
DisplayInit ( DISPLAY_INIT_MODE ) ;
# ifdef USE_DISPLAY_MODES1TO5
DisplayLogBufferInit ( ) ;
# endif // USE_DISPLAY_MODES1TO5
}
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_rotate ) ;
2018-08-28 17:13:14 +01:00
}
else if ( CMND_DISP_TEXT = = command_code ) {
mqtt_data [ 0 ] = ' \0 ' ;
if ( disp_device & & XdrvMailbox . data_len > 0 ) {
# ifndef USE_DISPLAY_MODES1TO5
DisplayText ( ) ;
# else
if ( ! Settings . display_mode ) {
DisplayText ( ) ;
} else {
2018-08-31 11:17:09 +01:00
DisplayLogBufferAdd ( XdrvMailbox . data ) ;
2018-08-28 17:13:14 +01:00
}
# endif // USE_DISPLAY_MODES1TO5
} else {
2019-03-23 16:00:59 +00:00
Response_P ( PSTR ( " No Text " ) ) ;
2018-08-28 17:13:14 +01:00
}
if ( mqtt_data [ 0 ] = = ' \0 ' ) {
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_VALUE , command , XdrvMailbox . data ) ;
2018-08-28 17:13:14 +01:00
}
}
else if ( ( CMND_DISP_ADDRESS = = command_code ) & & ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = 8 ) ) {
if ( ( XdrvMailbox . payload > = 0 ) & & ( XdrvMailbox . payload < = 255 ) ) {
Settings . display_address [ XdrvMailbox . index - 1 ] = XdrvMailbox . payload ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_INDEX_NVALUE , command , XdrvMailbox . index , Settings . display_address [ XdrvMailbox . index - 1 ] ) ;
2018-08-28 17:13:14 +01:00
}
else if ( CMND_DISP_REFRESH = = command_code ) {
if ( ( XdrvMailbox . payload > = 1 ) & & ( XdrvMailbox . payload < = 7 ) ) {
Settings . display_refresh = XdrvMailbox . payload ;
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_refresh ) ;
2018-08-28 17:13:14 +01:00
}
else if ( ( CMND_DISP_COLS = = command_code ) & & ( XdrvMailbox . index > 0 ) & & ( XdrvMailbox . index < = 2 ) ) {
if ( ( XdrvMailbox . payload > 0 ) & & ( XdrvMailbox . payload < = DISPLAY_MAX_COLS ) ) {
2018-08-31 11:17:09 +01:00
Settings . display_cols [ XdrvMailbox . index - 1 ] = XdrvMailbox . payload ;
2018-08-28 17:13:14 +01:00
# ifdef USE_DISPLAY_MODES1TO5
2018-08-31 11:17:09 +01:00
if ( 1 = = XdrvMailbox . index ) {
2018-08-28 17:13:14 +01:00
DisplayLogBufferInit ( ) ;
DisplayReAllocScreenBuffer ( ) ;
}
# endif // USE_DISPLAY_MODES1TO5
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_INDEX_NVALUE , command , XdrvMailbox . index , Settings . display_cols [ XdrvMailbox . index - 1 ] ) ;
2018-08-28 17:13:14 +01:00
}
else if ( CMND_DISP_ROWS = = command_code ) {
if ( ( XdrvMailbox . payload > 0 ) & & ( XdrvMailbox . payload < = DISPLAY_MAX_ROWS ) ) {
2018-08-31 11:17:09 +01:00
Settings . display_rows = XdrvMailbox . payload ;
2018-08-28 17:13:14 +01:00
# ifdef USE_DISPLAY_MODES1TO5
2018-08-31 11:17:09 +01:00
DisplayLogBufferInit ( ) ;
DisplayReAllocScreenBuffer ( ) ;
2018-08-28 17:13:14 +01:00
# endif // USE_DISPLAY_MODES1TO5
}
2019-03-23 16:00:59 +00:00
Response_P ( S_JSON_DISPLAY_COMMAND_NVALUE , command , Settings . display_rows ) ;
2018-08-28 17:13:14 +01:00
}
else serviced = false ; // Unknown command
}
else serviced = false ; // Unknown command
return serviced ;
}
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2019-01-28 13:08:33 +00:00
bool Xdrv13 ( uint8_t function )
2018-08-28 17:13:14 +01:00
{
2019-01-28 13:08:33 +00:00
bool result = false ;
2018-08-28 17:13:14 +01:00
2018-11-29 16:50:45 +00:00
if ( ( i2c_flg | | spi_flg | | soft_spi_flg ) & & XdspPresent ( ) ) {
2018-08-28 17:13:14 +01:00
switch ( function ) {
case FUNC_PRE_INIT :
DisplayInitDriver ( ) ;
break ;
case FUNC_EVERY_50_MSECOND :
if ( Settings . display_model ) { XdspCall ( FUNC_DISPLAY_EVERY_50_MSECOND ) ; }
break ;
case FUNC_COMMAND :
result = DisplayCommand ( ) ;
break ;
case FUNC_SET_POWER :
DisplaySetPower ( ) ;
break ;
# ifdef USE_DISPLAY_MODES1TO5
case FUNC_EVERY_SECOND :
if ( Settings . display_model & & Settings . display_mode ) { XdspCall ( FUNC_DISPLAY_EVERY_SECOND ) ; }
break ;
case FUNC_MQTT_SUBSCRIBE :
DisplayMqttSubscribe ( ) ;
break ;
case FUNC_MQTT_DATA :
result = DisplayMqttData ( ) ;
break ;
case FUNC_SHOW_SENSOR :
DisplayLocalSensor ( ) ;
break ;
# endif // USE_DISPLAY_MODES1TO5
}
}
return result ;
}
# endif // USE_DISPLAY
# endif // USE_I2C or USE_SPI