2021-11-30 15:03:57 +00:00
/*
xlgt_07_lsc_mcsl . ino - GPE Multi color smart light support for Tasmota
Copyright ( C ) 2021 Theo Arends
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/>.
*/
2021-12-15 10:15:30 +00:00
# define USE_LSC_MCSL_GUI
2021-11-30 15:03:57 +00:00
# ifdef USE_LIGHT
# ifdef USE_LSC_MCSL
/*********************************************************************************************\
* Golden Power Electronics Integrated Switching Power Supply with Built - in Controller
* GP - SW084 - 052 uses an ESP8285 ( TYWE2S ) and submicrocontroller controlling two wire RGB leds
* https : //www.gp-electronic.com/product/integrated-switching-power-supply-with-built-in-controller/eugs/european-vertical-6w8-function.html
*
2021-12-01 15:05:03 +00:00
* Template :
* { " NAME " : " LSC MC Lights " , " GPIO " : [ 0 , 0 , 0 , 0 , 544 , 32 , 0 , 0 , 3840 , 0 , 3872 , 0 , 0 , 0 ] , " FLAG " : 0 , " BASE " : 18 }
2021-11-30 15:03:57 +00:00
*
2021-12-15 10:15:30 +00:00
* Webbutton :
* { " WebButton1 " : " On / Off " ,
* " WebButton2 " : " Bright " ,
* " WebButton3 " : " Slow " ,
* " WebButton4 " : " Star " ,
* " WebButton5 " : " Flower " ,
* " WebButton6 " : " Marquee " ,
* " WebButton7 " : " Fireworks " ,
* " WebButton8 " : " Meteor " ,
* " WebButton9 " : " Stream " }
*
2021-11-30 15:03:57 +00:00
* NL : Action LSC Multi color smart lights
*
* Button usage :
* Single press = Power On / Off
* Double press = Cycle Colors
* Triple press = Cycle Effects
*
* HSBColor Color
* - - - - - - - - - - - - - - - - - - - - -
* 1 . . 45 R ( Red )
* 46 . . 90 RG ( Yellow )
* 91 . . 135 G ( Green )
* 136 . . 179 GB ( Light Blue )
* 180 . . 224 B ( Blue )
* 225 . . 269 RB ( Purple )
* 270 . . 314 RGB ( White )
* 315 . . 360 ( Alternating )
*
* Dimmer Effect
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* 0 . . 12 Bright ( Steady On )
* 13 . . 24 Gradually ( Slow Fade )
* 25 . . 37 Star ( Sequential )
* 38 . . 49 Flower ( In Waves )
* 50 . . 62 Marquee ( Chasing / Flash )
* 63 . . 74 Fireworks ( Twinkle / Flash )
* 75 . . 87 Meteor
* 88 . . 100 Stream
*
* GPIO04 = Green led
* GPIO05 = Button
* GPIO12 = Data to submicrocontroller
* GPIO14 = Reset to submicrocontroller ( 26 ms active high )
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define XLGT_07 7
# define LSCMC_GPIO_DATA 12
# define LSCMC_GPIO_RESET 14
# define LSCMC_BIT_TIME 600 // us
const uint16_t kLscMcData [ ] PROGMEM = {
//R RG G GB B RB RGB RGBa
0x0F4D , 0x0745 , 0x08B5 , 0x0340 , 0x0CB0 , 0x04B8 , 0x0B48 , 0x0143 , // Bright (Steady on)
0x8FED , 0x87E5 , 0x8815 , 0x83E0 , 0x8C10 , 0x8418 , 0x8BE8 , 0x81E3 , // Gradually (Slow Fade)
0x70ED , 0x78E5 , 0x7715 , 0x7CE0 , 0x7510 , 0x7B18 , 0x74E8 , 0x7EE3 , // Star (Sequential)
0xCF92 , 0xC79A , 0xC86A , 0xC39F , 0xCC6F , 0xC467 , 0xCB97 , 0xC19C , // Flower (In Waves)
0x3093 , 0x389A , 0x376A , 0x3C9F , 0x336F , 0x3B67 , 0x3497 , 0x3E9C , // Marquee (Chasing / Flash)
0xB02D , 0xB825 , 0xB7D5 , 0xBC20 , 0xB3D0 , 0xBBD8 , 0xB428 , 0xBE23 , // Fireworks (Twinkle / Flash)
0x4F2D , 0x4725 , 0x48D5 , 0x4320 , 0x4CD0 , 0x44D8 , 0x4B28 , 0x4123 , // Meteor
0xEFAD , 0xE7A5 , 0xE855 , 0xE3A1 , 0xEC50 , 0xE458 , 0xEBA8 , 0xE1A3 // Stream
} ;
# include <Ticker.h>
Ticker LscMcStartDelay ;
struct LSCMC {
uint32_t last_send ;
uint8_t function ;
uint8_t color ;
uint8_t dimmer ;
uint8_t power ;
uint8_t scheme_offset ;
uint8_t pin ;
} Lscmc ;
/*********************************************************************************************/
void LscMcSend ( void ) {
Lscmc . function & = 0x7 ;
Lscmc . color & = 0x7 ;
uint16_t fc = pgm_read_word ( kLscMcData + ( 8 * Lscmc . function ) + Lscmc . color ) ;
uint32_t data ;
if ( Lscmc . power ) {
data = 0xC2FF0000 | fc ;
} else {
data = Lscmc . last_send & 0xFF00FFFF ;
data ^ = 0x0000FF00 ;
}
if ( data = = Lscmc . last_send ) { return ; }
AddLog ( LOG_LEVEL_DEBUG_MORE , PSTR ( " LSC: Function %d, Color %d, State %d, Send %08X " ) ,
Lscmc . function , Lscmc . color , Lscmc . power , data ) ;
Lscmc . last_send = data ;
digitalWrite ( Lscmc . pin , LOW ) ;
delayMicroseconds ( LSCMC_BIT_TIME * 15 ) ;
digitalWrite ( Lscmc . pin , HIGH ) ;
delayMicroseconds ( LSCMC_BIT_TIME * 7 + ( LSCMC_BIT_TIME / 2 ) ) ;
digitalWrite ( Lscmc . pin , LOW ) ;
delayMicroseconds ( LSCMC_BIT_TIME ) ;
digitalWrite ( Lscmc . pin , HIGH ) ;
bool last_bit = 0 ;
bool bit = 0 ;
uint32_t bit_mask = 0x80000000 ;
for ( uint32_t i = 0 ; i < 32 ; i + + ) {
bit = ( data & bit_mask ) ;
if ( bit ! = last_bit ) {
delayMicroseconds ( LSCMC_BIT_TIME * 3 ) ; // Switch bit state
} else {
delayMicroseconds ( LSCMC_BIT_TIME ) ;
}
digitalWrite ( Lscmc . pin , LOW ) ;
delayMicroseconds ( LSCMC_BIT_TIME ) ;
digitalWrite ( Lscmc . pin , HIGH ) ;
last_bit = bit ;
bit_mask > > = 1 ;
}
}
/*********************************************************************************************/
bool LscMcSetChannelsFromFunc ( void ) {
// Use power for Off / On
uint8_t power = Light . power ;
bool power_changed = ( Lscmc . power ! = power ) ;
Lscmc . power = power ;
// Use dimmer for function
uint8_t dimmer = light_state . getDimmer ( ) ;
/*
dimmer = changeUIntScale ( dimmer , 0 , 100 , 0 , 3 ) ;
dimmer = changeUIntScale ( dimmer , 0 , 3 , 0 , 255 ) ;
bool dimmer_changed = ( Lscmc . dimmer ! = dimmer ) ;
Lscmc . dimmer = dimmer ;
*/
uint8_t function = changeUIntScale ( dimmer , 0 , 100 , 0 , 7 ) ;
bool function_changed = ( Lscmc . function ! = function ) ;
Lscmc . function = function ;
uint16_t hue ;
uint8_t sat ;
LightGetHSB ( & hue , & sat , nullptr ) ;
/*
// Use saturation for function (won't work as if sat = 0 this function is not called)
uint8_t function = changeUIntScale ( sat , 0 , 255 , 0 , 7 ) ;
bool function_changed = ( Lscmc . function ! = function ) ;
Lscmc . function = function ;
*/
// Use hue for color
uint8_t color = changeUIntScale ( hue , 1 , 359 , 0 , 7 ) ;
bool color_changed = ( Lscmc . color ! = color ) ;
Lscmc . color = color ;
// AddLog(LOG_LEVEL_DEBUG, PSTR("LSC: Power %d, Hue %d = Color %d, Dimmer %d = Function %d"),
// Lscmc.power, hue, Lscmc.color, dimmer, Lscmc.function);
if ( ! power_changed & & ! function_changed & & ! color_changed ) { return true ; }
static bool first_call = true ;
if ( first_call ) {
LscMcStartDelay . once_ms ( 900 , LscMcSend ) ; // Allow startup time for microcontroller
first_call = false ;
} else {
LscMcSend ( ) ;
}
return true ;
}
bool LscMcMultiButtonPressed ( void ) {
if ( XdrvMailbox . index ! = 0 ) { return false ; } // button_index
char command [ 20 ] ;
uint32_t press_counter = XdrvMailbox . payload ;
if ( 2 = = press_counter ) { // Color rotate
uint32_t color = Lscmc . color + 1 ;
if ( color > 7 ) { color = 0 ; }
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_HSBCOLOR " %d " ) , ( color * ( 360 / 8 ) ) + ( ( 360 / 8 ) / 2 ) ) ;
ExecuteCommand ( command , SRC_BUTTON ) ;
} else if ( 3 = = press_counter ) { // Function rotate
uint32_t function = Lscmc . function + 1 ;
if ( function > 7 ) { function = 0 ; }
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_DIMMER " %d " ) , ( function * ( 100 / 8 ) ) + ( ( 100 / 8 ) / 2 ) ) ;
ExecuteCommand ( command , SRC_BUTTON ) ;
}
return true ;
}
void LscMcModuleSelected ( void ) {
if ( ! ValidTemplate ( PSTR ( " LSC MC Lights " ) ) ) { return ; }
if ( ! PinUsed ( GPIO_OUTPUT_HI ) | | ! PinUsed ( GPIO_OUTPUT_LO ) ) { return ; }
Lscmc . pin = Pin ( GPIO_OUTPUT_HI ) ;
uint32_t pin_reset = Pin ( GPIO_OUTPUT_LO ) ;
digitalWrite ( pin_reset , HIGH ) ;
delay ( 26 ) ;
digitalWrite ( pin_reset , LOW ) ;
Settings - > flag . button_single = 0 ; // SetOption13 - We need multi press detection
Settings - > flag3 . slider_dimmer_stay_on = 1 ; // SetOption77 - We need dimmer to keep power on at 0
Lscmc . last_send = 0xC2FFEBA8 ;
TasmotaGlobal . light_type = LT_RGB ;
TasmotaGlobal . light_driver = XLGT_07 ;
// AddLog(LOG_LEVEL_DEBUG, PSTR("LGT: LSC Multi Color Found"));
}
2021-12-15 10:15:30 +00:00
# ifdef USE_WEBSERVER
2024-11-11 14:17:22 +00:00
# ifndef FIRMWARE_MINIMAL
2021-12-15 10:15:30 +00:00
# ifdef USE_LSC_MCSL_GUI
void LscMcAddFuctionButtons ( void ) {
uint32_t rows = 1 ;
uint32_t cols = 8 ;
for ( uint32_t i = 0 ; i < 8 ; i + + ) {
2023-09-29 08:56:52 +01:00
if ( strlen ( GetWebButton ( i + 1 ) ) ) {
2021-12-15 10:15:30 +00:00
rows < < = 1 ;
cols > > = 1 ;
break ;
}
}
WSContentSend_P ( HTTP_TABLE100 ) ;
WSContentSend_P ( PSTR ( " <tr> " ) ) ;
2021-12-15 11:14:52 +00:00
char number [ 4 ] ;
2021-12-15 10:15:30 +00:00
uint32_t idx = 0 ;
for ( uint32_t i = 0 ; i < rows ; i + + ) {
if ( idx > 0 ) { WSContentSend_P ( PSTR ( " </tr><tr> " ) ) ; }
for ( uint32_t j = 0 ; j < cols ; j + + ) {
idx + + ;
WSContentSend_P ( PSTR ( " <td style='width:%d%%'><button onclick='la( \" &lsc=%d \" );'>%s</button></td> " ) , // &lsc is related to WebGetArg("lsc", tmp, sizeof(tmp));
100 / cols ,
idx - 1 ,
2023-12-18 11:31:14 +00:00
( strlen ( GetWebButton ( idx ) ) ) ? HtmlEscape ( GetWebButton ( idx ) ) . c_str ( ) : itoa ( idx , number , 10 ) ) ;
2021-12-15 10:15:30 +00:00
}
}
WSContentSend_P ( PSTR ( " </tr></table> " ) ) ;
}
void LscMcWebGetArg ( void ) {
2021-12-15 11:14:52 +00:00
char tmp [ 8 ] ; // WebGetArg numbers only
2021-12-15 10:15:30 +00:00
WebGetArg ( PSTR ( " lsc " ) , tmp , sizeof ( tmp ) ) ; // 0 - 7 functions
if ( strlen ( tmp ) ) {
uint32_t function = atoi ( tmp ) ;
2021-12-15 11:14:52 +00:00
char command [ 20 ] ;
2021-12-15 10:15:30 +00:00
snprintf_P ( command , sizeof ( command ) , PSTR ( D_CMND_DIMMER " %d " ) , ( function * ( 100 / 8 ) ) + ( ( 100 / 8 ) / 2 ) ) ;
ExecuteWebCommand ( command ) ;
}
}
# endif // USE_LSC_MCSL_GUI
2024-11-11 14:17:22 +00:00
# endif // not FIRMWARE_MINIMAL
2021-12-15 10:15:30 +00:00
# endif // USE_WEBSERVER
2021-11-30 15:03:57 +00:00
/*********************************************************************************************\
* Interface
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-11-11 09:44:56 +00:00
bool Xlgt07 ( uint32_t function )
2021-11-30 15:03:57 +00:00
{
bool result = false ;
switch ( function ) {
case FUNC_SET_CHANNELS :
result = LscMcSetChannelsFromFunc ( ) ;
break ;
case FUNC_BUTTON_MULTI_PRESSED :
result = LscMcMultiButtonPressed ( ) ;
break ;
2021-12-15 10:15:30 +00:00
# ifdef USE_WEBSERVER
2024-11-11 14:17:22 +00:00
# ifndef FIRMWARE_MINIMAL
2021-12-15 10:15:30 +00:00
# ifdef USE_LSC_MCSL_GUI
case FUNC_WEB_ADD_MAIN_BUTTON :
LscMcAddFuctionButtons ( ) ;
break ;
case FUNC_WEB_GET_ARG :
LscMcWebGetArg ( ) ;
break ;
# endif // USE_LSC_MCSL_GUI
2024-11-11 14:17:22 +00:00
# endif // not FIRMWARE_MINIMAL
2021-12-15 10:15:30 +00:00
# endif // USE_WEBSERVER
2021-11-30 15:03:57 +00:00
case FUNC_MODULE_INIT :
LscMcModuleSelected ( ) ;
break ;
}
return result ;
}
# endif // USE_LSC_MCSL
# endif // USE_LIGHT