2020-03-25 09:00:55 +01:00
# include "wled.h"
2020-03-31 02:38:08 +02:00
2021-03-18 23:59:56 +01:00
# include "palettes.h"
2020-03-31 02:38:08 +02:00
/*
* JSON API ( De ) serialization
*/
2019-03-05 10:59:15 +01:00
2021-10-30 14:42:17 +02:00
bool getVal ( JsonVariant elem , byte * val , byte vmin = 0 , byte vmax = 255 ) {
if ( elem . is < int > ( ) ) {
2022-01-25 12:47:14 +01:00
if ( elem < 0 ) return false ; //ignore e.g. {"ps":-1}
2021-10-30 14:42:17 +02:00
* val = elem ;
return true ;
} else if ( elem . is < const char * > ( ) ) {
const char * str = elem ;
size_t len = strnlen ( str , 12 ) ;
if ( len = = 0 | | len > 10 ) return false ;
parseNumber ( str , val , vmin , vmax ) ;
return true ;
}
return false ; //key does not exist
}
2021-06-10 02:52:20 +02:00
void deserializeSegment ( JsonObject elem , byte it , byte presetId )
2019-11-30 19:17:25 +01:00
{
2021-03-13 22:04:37 +01:00
byte id = elem [ " id " ] | it ;
2021-07-02 00:24:14 +02:00
if ( id > = strip . getMaxSegments ( ) ) return ;
2019-11-30 19:17:25 +01:00
2021-07-02 00:24:14 +02:00
WS2812FX : : Segment & seg = strip . getSegment ( id ) ;
//WS2812FX::Segment prev;
//prev = seg; //make a backup so we can tell if something changed
2021-09-12 01:15:51 +02:00
uint16_t start = elem [ " start " ] | seg . start ;
2021-07-02 00:24:14 +02:00
int stop = elem [ " stop " ] | - 1 ;
2021-09-18 01:20:17 +02:00
if ( stop < 0 ) {
uint16_t len = elem [ F ( " len " ) ] ;
stop = ( len > 0 ) ? start + len : seg . stop ;
}
2021-07-02 00:24:14 +02:00
2022-01-24 16:44:47 +01:00
//repeat, multiplies segment until all LEDs are used, or max segments reached
2021-12-17 20:33:48 +01:00
bool repeat = elem [ " rpt " ] | false ;
if ( repeat & & stop > 0 ) {
elem . remove ( " id " ) ; // remove for recursive call
elem . remove ( " rpt " ) ; // remove for recursive call
elem . remove ( " n " ) ; // remove for recursive call
uint16_t len = stop - start ;
for ( byte i = id + 1 ; i < strip . getMaxSegments ( ) ; i + + ) {
start = start + len ;
if ( start > = strip . getLengthTotal ( ) ) break ;
elem [ " start " ] = start ;
elem [ " stop " ] = start + len ;
elem [ " rev " ] = ! elem [ " rev " ] ; // alternate reverse on even/odd segments
deserializeSegment ( elem , i , presetId ) ; // recursive call with new id
}
return ;
}
2021-09-12 01:15:51 +02:00
if ( elem [ " n " ] ) {
// name field exists
if ( seg . name ) { //clear old name
delete [ ] seg . name ;
seg . name = nullptr ;
}
const char * name = elem [ " n " ] . as < const char * > ( ) ;
size_t len = 0 ;
if ( name ! = nullptr ) len = strlen ( name ) ;
if ( len > 0 & & len < 33 ) {
seg . name = new char [ len + 1 ] ;
if ( seg . name ) strlcpy ( seg . name , name , 33 ) ;
} else {
// but is empty (already deleted above)
elem . remove ( " n " ) ;
2021-09-08 23:10:54 +02:00
}
2021-09-18 01:20:17 +02:00
} else if ( start ! = seg . start | | stop ! = seg . stop ) {
2021-09-12 01:15:51 +02:00
// clearing or setting segment without name field
if ( seg . name ) {
delete [ ] seg . name ;
seg . name = nullptr ;
}
}
2021-09-08 23:10:54 +02:00
2021-08-25 16:39:12 +02:00
uint16_t grp = elem [ " grp " ] | seg . grouping ;
2021-07-02 00:24:14 +02:00
uint16_t spc = elem [ F ( " spc " ) ] | seg . spacing ;
2022-01-25 12:47:14 +01:00
uint16_t of = seg . offset ;
2021-12-17 20:33:48 +01:00
if ( ! ( elem [ F ( " spc " ) ] . isNull ( ) & & elem [ " grp " ] . isNull ( ) ) ) effectChanged = true ; //send UDP
2021-07-04 00:55:32 +02:00
uint16_t len = 1 ;
if ( stop > start ) len = stop - start ;
int offset = elem [ F ( " of " ) ] | INT32_MAX ;
if ( offset ! = INT32_MAX ) {
int offsetAbs = abs ( offset ) ;
if ( offsetAbs > len - 1 ) offsetAbs % = len ;
if ( offset < 0 ) offsetAbs = len - offsetAbs ;
2021-12-02 00:52:36 +01:00
of = offsetAbs ;
2021-07-04 00:55:32 +02:00
}
2021-12-02 00:52:36 +01:00
if ( stop > start & & of > len - 1 ) of = len - 1 ;
2022-01-25 12:47:14 +01:00
strip . setSegment ( id , start , stop , grp , spc , of ) ;
2021-07-02 00:24:14 +02:00
2021-10-30 14:42:17 +02:00
byte segbri = 0 ;
if ( getVal ( elem [ " bri " ] , & segbri ) ) {
if ( segbri > 0 ) seg . setOpacity ( segbri , id ) ;
seg . setOption ( SEG_OPTION_ON , segbri , id ) ;
2021-07-02 00:24:14 +02:00
}
2021-09-20 21:22:04 +02:00
bool on = elem [ " on " ] | seg . getOption ( SEG_OPTION_ON ) ;
if ( elem [ " on " ] . is < const char * > ( ) & & elem [ " on " ] . as < const char * > ( ) [ 0 ] = = ' t ' ) on = ! on ;
seg . setOption ( SEG_OPTION_ON , on , id ) ;
2021-12-17 20:33:48 +01:00
bool frz = elem [ " frz " ] | seg . getOption ( SEG_OPTION_FREEZE ) ;
if ( elem [ " frz " ] . is < const char * > ( ) & & elem [ " frz " ] . as < const char * > ( ) [ 0 ] = = ' t ' ) frz = ! seg . getOption ( SEG_OPTION_FREEZE ) ;
seg . setOption ( SEG_OPTION_FREEZE , frz , id ) ;
2022-01-25 12:47:14 +01:00
uint8_t cctPrev = seg . cct ;
2021-11-27 01:33:48 +01:00
seg . setCCT ( elem [ " cct " ] | seg . cct , id ) ;
2022-01-25 12:47:14 +01:00
if ( seg . cct ! = cctPrev & & id = = strip . getMainSegmentId ( ) ) effectChanged = true ; //send UDP
2021-10-25 20:15:42 +02:00
2021-07-02 00:24:14 +02:00
JsonArray colarr = elem [ " col " ] ;
if ( ! colarr . isNull ( ) )
{
for ( uint8_t i = 0 ; i < 3 ; i + + )
2019-11-30 19:17:25 +01:00
{
2021-07-02 00:24:14 +02:00
int rgbw [ ] = { 0 , 0 , 0 , 0 } ;
bool colValid = false ;
JsonArray colX = colarr [ i ] ;
if ( colX . isNull ( ) ) {
byte brgbw [ ] = { 0 , 0 , 0 , 0 } ;
const char * hexCol = colarr [ i ] ;
if ( hexCol = = nullptr ) { //Kelvin color temperature (or invalid), e.g 2400
int kelvin = colarr [ i ] | - 1 ;
if ( kelvin < 0 ) continue ;
if ( kelvin = = 0 ) seg . setColor ( i , 0 , id ) ;
if ( kelvin > 0 ) colorKtoRGB ( kelvin , brgbw ) ;
2020-11-20 00:33:17 +01:00
colValid = true ;
2021-07-02 00:24:14 +02:00
} else { //HEX string, e.g. "FFAA00"
colValid = colorFromHexString ( brgbw , hexCol ) ;
2020-11-20 00:33:17 +01:00
}
2021-07-02 00:24:14 +02:00
for ( uint8_t c = 0 ; c < 4 ; c + + ) rgbw [ c ] = brgbw [ c ] ;
} else { //Array of ints (RGB or RGBW color), e.g. [255,160,0]
byte sz = colX . size ( ) ;
if ( sz = = 0 ) continue ; //do nothing on empty array
byte cp = copyArray ( colX , rgbw , 4 ) ;
if ( cp = = 1 & & rgbw [ 0 ] = = 0 )
seg . setColor ( i , 0 , id ) ;
colValid = true ;
}
2020-11-20 00:33:17 +01:00
2021-07-02 00:24:14 +02:00
if ( ! colValid ) continue ;
2022-01-15 14:04:16 +01:00
uint32_t color = RGBW32 ( rgbw [ 0 ] , rgbw [ 1 ] , rgbw [ 2 ] , rgbw [ 3 ] ) ;
colorChanged | = ( seg . colors [ i ] ! = color ) ;
seg . setColor ( i , color , id ) ;
if ( seg . mode = = FX_MODE_STATIC ) strip . trigger ( ) ; //instant refresh
2019-11-30 19:17:25 +01:00
}
2021-07-02 00:24:14 +02:00
}
2020-09-27 11:37:16 +02:00
2021-07-02 00:24:14 +02:00
// lx parser
# ifdef WLED_ENABLE_LOXONE
int lx = elem [ F ( " lx " ) ] | - 1 ;
if ( lx > 0 ) {
parseLxJson ( lx , id , false ) ;
}
int ly = elem [ F ( " ly " ) ] | - 1 ;
if ( ly > 0 ) {
parseLxJson ( ly , id , true ) ;
}
# endif
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
seg . setOption ( SEG_OPTION_SELECTED , elem [ F ( " sel " ) ] | seg . getOption ( SEG_OPTION_SELECTED ) ) ;
2021-11-28 04:01:58 +01:00
seg . setOption ( SEG_OPTION_REVERSED , elem [ " rev " ] | seg . getOption ( SEG_OPTION_REVERSED ) ) ;
2021-07-02 00:24:14 +02:00
seg . setOption ( SEG_OPTION_MIRROR , elem [ F ( " mi " ) ] | seg . getOption ( SEG_OPTION_MIRROR ) ) ;
2021-12-17 20:33:48 +01:00
if ( ! ( elem [ F ( " sel " ) ] . isNull ( ) & & elem [ " rev " ] . isNull ( ) & & elem [ " on " ] . isNull ( ) & & elem [ F ( " mi " ) ] . isNull ( ) ) ) effectChanged = true ; //send UDP
2022-01-15 14:04:16 +01:00
byte fx = seg . mode ;
byte fxPrev = fx ;
if ( getVal ( elem [ " fx " ] , & fx , 1 , strip . getModeCount ( ) ) ) { //load effect ('r' random, '~' inc/dec, 1-255 exact value)
strip . setMode ( id , fx ) ;
if ( ! presetId & & seg . mode ! = fxPrev ) effectChanged = true ; //send UDP
2021-07-02 00:24:14 +02:00
}
2022-01-15 14:04:16 +01:00
byte prevSpd = seg . speed ;
byte prevInt = seg . intensity ;
byte prevPal = seg . palette ;
if ( getVal ( elem [ F ( " sx " ) ] , & seg . speed , 0 , 255 ) & & ! presetId & & prevSpd ! = seg . speed ) effectChanged = true ; //also supports inc/decrementing and random
if ( getVal ( elem [ F ( " ix " ) ] , & seg . intensity , 0 , 255 ) & & ! presetId & & prevInt ! = seg . intensity ) effectChanged = true ; //also supports inc/decrementing and random
if ( getVal ( elem [ " pal " ] , & seg . palette , 1 , strip . getPaletteCount ( ) ) & & ! presetId & & prevPal ! = seg . palette ) effectChanged = true ; //also supports inc/decrementing and random
2020-08-29 22:26:39 +02:00
2021-07-02 00:24:14 +02:00
JsonArray iarr = elem [ F ( " i " ) ] ; //set individual LEDs
if ( ! iarr . isNull ( ) ) {
strip . setPixelSegment ( id ) ;
2020-08-29 22:26:39 +02:00
2021-07-02 00:24:14 +02:00
//freeze and init to black
if ( ! seg . getOption ( SEG_OPTION_FREEZE ) ) {
seg . setOption ( SEG_OPTION_FREEZE , true ) ;
strip . fill ( 0 ) ;
}
2020-08-29 22:26:39 +02:00
2021-07-02 00:24:14 +02:00
uint16_t start = 0 , stop = 0 ;
byte set = 0 ; //0 nothing set, 1 start set, 2 range set
for ( uint16_t i = 0 ; i < iarr . size ( ) ; i + + ) {
if ( iarr [ i ] . is < JsonInteger > ( ) ) {
if ( ! set ) {
start = iarr [ i ] ;
set = 1 ;
2020-08-29 22:26:39 +02:00
} else {
2021-07-02 00:24:14 +02:00
stop = iarr [ i ] ;
set = 2 ;
}
2021-07-10 16:14:17 +02:00
} else { //color
2021-07-02 00:24:14 +02:00
int rgbw [ ] = { 0 , 0 , 0 , 0 } ;
2021-07-10 16:14:17 +02:00
JsonArray icol = iarr [ i ] ;
if ( ! icol . isNull ( ) ) { //array, e.g. [255,0,0]
byte sz = icol . size ( ) ;
if ( sz > 0 | | sz < 5 ) copyArray ( icol , rgbw ) ;
} else { //hex string, e.g. "FF0000"
byte brgbw [ ] = { 0 , 0 , 0 , 0 } ;
const char * hexCol = iarr [ i ] ;
if ( colorFromHexString ( brgbw , hexCol ) ) {
for ( uint8_t c = 0 ; c < 4 ; c + + ) rgbw [ c ] = brgbw [ c ] ;
}
}
2020-08-29 22:26:39 +02:00
2021-07-02 00:24:14 +02:00
if ( set < 2 ) stop = start + 1 ;
for ( uint16_t i = start ; i < stop ; i + + ) {
2021-11-09 17:50:29 +01:00
if ( strip . gammaCorrectCol ) {
strip . setPixelColor ( i , strip . gamma8 ( rgbw [ 0 ] ) , strip . gamma8 ( rgbw [ 1 ] ) , strip . gamma8 ( rgbw [ 2 ] ) , strip . gamma8 ( rgbw [ 3 ] ) ) ;
} else {
strip . setPixelColor ( i , rgbw [ 0 ] , rgbw [ 1 ] , rgbw [ 2 ] , rgbw [ 3 ] ) ;
}
2020-08-29 22:26:39 +02:00
}
2021-07-02 00:24:14 +02:00
if ( ! set ) start + + ;
set = 0 ;
2020-08-29 22:26:39 +02:00
}
}
2021-07-02 00:24:14 +02:00
strip . setPixelSegment ( 255 ) ;
strip . trigger ( ) ;
2021-12-17 20:33:48 +01:00
} else if ( ! elem [ " frz " ] & & iarr . isNull ( ) ) { //return to regular effect
2021-07-02 00:24:14 +02:00
seg . setOption ( SEG_OPTION_FREEZE , false ) ;
2019-11-30 19:17:25 +01:00
}
2021-07-10 16:14:17 +02:00
return ; // seg.differs(prev);
2019-11-30 19:17:25 +01:00
}
2021-12-17 20:33:48 +01:00
// deserializes WLED state (fileDoc points to doc object if called from web server)
2021-07-09 18:42:52 +02:00
bool deserializeState ( JsonObject root , byte callMode , byte presetId )
2019-03-05 10:59:15 +01:00
{
2019-12-02 12:41:35 +01:00
strip . applyToAllSelected = false ;
2020-09-20 01:18:31 +02:00
bool stateResponse = root [ F ( " v " ) ] | false ;
2021-03-18 23:59:56 +01:00
2021-10-30 14:42:17 +02:00
getVal ( root [ " bri " ] , & bri ) ;
2021-03-18 23:59:56 +01:00
2019-03-06 01:20:38 +01:00
bool on = root [ " on " ] | ( bri > 0 ) ;
if ( ! on ! = ! bri ) toggleOnOff ( ) ;
2019-11-30 19:17:25 +01:00
2021-05-17 12:29:30 +02:00
if ( root [ " on " ] . is < const char * > ( ) & & root [ " on " ] . as < const char * > ( ) [ 0 ] = = ' t ' ) toggleOnOff ( ) ;
2021-06-10 02:52:20 +02:00
int tr = - 1 ;
if ( ! presetId | | currentPlaylist < 0 ) { //do not apply transition time from preset if playlist active, as it would override playlist transition times
tr = root [ F ( " transition " ) ] | - 1 ;
if ( tr > = 0 )
{
transitionDelay = tr ;
transitionDelay * = 100 ;
transitionDelayTemp = transitionDelay ;
}
2019-03-06 01:20:38 +01:00
}
2019-11-30 19:17:25 +01:00
2020-09-20 01:18:31 +02:00
tr = root [ F ( " tt " ) ] | - 1 ;
2019-11-30 19:17:25 +01:00
if ( tr > = 0 )
2019-10-29 02:21:23 +01:00
{
2019-11-30 19:17:25 +01:00
transitionDelayTemp = tr ;
2019-10-29 02:21:23 +01:00
transitionDelayTemp * = 100 ;
jsonTransitionOnce = true ;
}
2021-01-09 00:35:48 +01:00
strip . setTransition ( transitionDelayTemp ) ;
2021-04-21 17:21:55 +02:00
tr = root [ F ( " tb " ) ] | - 1 ;
if ( tr > = 0 ) strip . timebase = ( ( uint32_t ) tr ) - millis ( ) ;
2019-03-06 21:31:12 +01:00
2022-01-15 14:04:16 +01:00
JsonObject nl = root [ " nl " ] ;
2020-10-02 12:30:17 +02:00
nightlightActive = nl [ " on " ] | nightlightActive ;
2020-09-20 01:18:31 +02:00
nightlightDelayMins = nl [ F ( " dur " ) ] | nightlightDelayMins ;
nightlightMode = nl [ F ( " mode " ) ] | nightlightMode ;
nightlightTargetBri = nl [ F ( " tbri " ) ] | nightlightTargetBri ;
2019-03-06 01:20:38 +01:00
2022-01-15 14:04:16 +01:00
JsonObject udpn = root [ " udpn " ] ;
2021-03-13 22:04:37 +01:00
notifyDirect = udpn [ " send " ] | notifyDirect ;
receiveNotifications = udpn [ " recv " ] | receiveNotifications ;
2022-01-15 14:04:16 +01:00
if ( ( bool ) udpn [ F ( " nn " ) ] ) callMode = CALL_MODE_NO_NOTIFY ; //send no notification just for this request
2019-03-06 01:20:38 +01:00
2021-04-21 17:21:55 +02:00
unsigned long timein = root [ F ( " time " ) ] | UINT32_MAX ; //backup time source if NTP not synced
2021-02-27 01:50:08 +01:00
if ( timein ! = UINT32_MAX ) {
2021-05-27 02:02:02 +02:00
setTimeFromAPI ( timein ) ;
2020-11-15 12:41:51 +01:00
if ( presetsModifiedTime = = 0 ) presetsModifiedTime = timein ;
}
2020-09-20 01:18:31 +02:00
doReboot = root [ F ( " rb " ) ] | doReboot ;
2020-04-30 01:52:36 +02:00
2020-09-20 01:18:31 +02:00
realtimeOverride = root [ F ( " lor " ) ] | realtimeOverride ;
2020-04-30 01:52:36 +02:00
if ( realtimeOverride > 2 ) realtimeOverride = REALTIME_OVERRIDE_ALWAYS ;
2019-06-20 14:40:12 +02:00
2020-11-26 10:54:37 +01:00
if ( root . containsKey ( " live " ) ) {
bool lv = root [ " live " ] ;
if ( lv ) realtimeLock ( 65000 ) ; //enter realtime without timeout
else realtimeTimeout = 0 ; //cancel realtime mode immediately
}
2019-12-04 02:01:47 +01:00
byte prevMain = strip . getMainSegmentId ( ) ;
2020-09-20 01:18:31 +02:00
strip . mainSegment = root [ F ( " mainseg " ) ] | prevMain ;
2022-01-15 14:04:16 +01:00
//if (strip.getMainSegmentId() != prevMain) setValuesFromMainSeg();
2019-12-01 01:42:52 +01:00
2019-03-06 01:20:38 +01:00
int it = 0 ;
2020-11-08 23:44:10 +01:00
JsonVariant segVar = root [ " seg " ] ;
2019-11-30 19:17:25 +01:00
if ( segVar . is < JsonObject > ( ) )
2019-03-06 01:20:38 +01:00
{
2021-03-13 22:04:37 +01:00
int id = segVar [ " id " ] | - 1 ;
2022-01-15 14:04:16 +01:00
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
if ( id < 0 ) {
//apply all selected segments
2019-12-13 01:23:07 +01:00
bool didSet = false ;
byte lowestActive = 99 ;
2022-01-15 14:04:16 +01:00
for ( byte s = 0 ; s < strip . getMaxSegments ( ) ; s + + ) {
WS2812FX : : Segment & sg = strip . getSegment ( s ) ;
if ( sg . isActive ( ) ) {
2019-12-13 01:23:07 +01:00
if ( lowestActive = = 99 ) lowestActive = s ;
if ( sg . isSelected ( ) ) {
2021-06-10 02:52:20 +02:00
deserializeSegment ( segVar , s , presetId ) ;
2019-12-13 01:23:07 +01:00
didSet = true ;
}
2019-03-06 01:20:38 +01:00
}
}
2022-01-15 14:04:16 +01:00
//TODO: not sure if it is good idea to change first active but unselected segment
2021-06-10 02:52:20 +02:00
if ( ! didSet & & lowestActive < strip . getMaxSegments ( ) ) deserializeSegment ( segVar , lowestActive , presetId ) ;
2022-01-15 14:04:16 +01:00
} else {
deserializeSegment ( segVar , id , presetId ) ; //apply only the segment with the specified ID
2019-11-30 19:17:25 +01:00
}
} else {
JsonArray segs = segVar . as < JsonArray > ( ) ;
for ( JsonObject elem : segs )
{
2021-06-10 02:52:20 +02:00
deserializeSegment ( elem , it , presetId ) ;
2019-11-30 19:17:25 +01:00
it + + ;
2019-03-06 01:20:38 +01:00
}
}
2022-01-15 14:04:16 +01:00
setValuesFromMainSeg ( ) ; //to make transition work on main segment
if ( effectChanged ) unloadPlaylist ( ) ; //if any of the effect parameter changed unload playlist
2019-11-30 19:17:25 +01:00
2021-06-01 03:07:35 +02:00
# ifndef WLED_DISABLE_CRONIXIE
if ( root [ " nx " ] . is < const char * > ( ) ) {
strncpy ( cronixieDisplay , root [ " nx " ] , 6 ) ;
}
# endif
2021-05-21 22:23:12 +02:00
2020-05-28 02:20:02 +02:00
usermods . readFromJsonState ( root ) ;
2021-12-04 01:05:01 +01:00
loadLedmap = root [ F ( " ledmap " ) ] | loadLedmap ;
2021-10-30 14:42:17 +02:00
byte ps = root [ F ( " psave " ) ] ;
2020-10-03 00:29:36 +02:00
if ( ps > 0 ) {
2020-10-08 00:52:15 +02:00
savePreset ( ps , true , nullptr , root ) ;
2020-10-03 00:29:36 +02:00
} else {
2021-10-30 14:42:17 +02:00
ps = root [ F ( " pdel " ) ] ; //deletion
2020-10-03 00:29:36 +02:00
if ( ps > 0 ) {
deletePreset ( ps ) ;
}
2021-10-30 14:42:17 +02:00
2021-11-22 21:41:04 +01:00
ps = presetCycCurr ;
if ( getVal ( root [ " ps " ] , & ps , presetCycMin , presetCycMax ) ) { //load preset (clears state request!)
2021-06-10 02:52:20 +02:00
if ( ! presetId ) unloadPlaylist ( ) ; //stop playlist if preset changed manually
2021-11-22 21:41:04 +01:00
if ( ps > = presetCycMin & & ps < = presetCycMax ) presetCycCurr = ps ;
applyPreset ( ps , callMode ) ;
2021-06-10 02:52:20 +02:00
return stateResponse ;
}
2020-10-08 00:52:15 +02:00
2020-10-07 17:48:22 +02:00
//HTTP API commands
const char * httpwin = root [ " win " ] ;
if ( httpwin ) {
String apireq = " win& " ;
apireq + = httpwin ;
handleSet ( nullptr , apireq , false ) ;
}
2020-10-03 00:29:36 +02:00
}
2019-06-20 14:40:12 +02:00
2020-11-11 23:48:14 +01:00
JsonObject playlist = root [ F ( " playlist " ) ] ;
2021-07-11 02:38:31 +02:00
if ( ! playlist . isNull ( ) & & loadPlaylist ( playlist , presetId ) ) {
//do not notify here, because the first playlist entry will do
2022-01-15 14:04:16 +01:00
if ( root [ " on " ] . isNull ( ) ) callMode = CALL_MODE_NO_NOTIFY ;
else callMode = CALL_MODE_DIRECT_CHANGE ; // possible bugfix for playlist only containing HTTP API preset FX=~
2021-07-02 00:24:14 +02:00
} else {
2021-07-09 18:54:28 +02:00
interfaceUpdateCallMode = CALL_MODE_WS_SEND ;
2020-11-11 23:48:14 +01:00
}
2020-03-03 17:53:47 +01:00
2022-01-15 14:04:16 +01:00
colorUpdated ( callMode ) ;
2019-11-25 00:20:00 +01:00
2019-06-20 14:40:12 +02:00
return stateResponse ;
2019-03-06 01:20:38 +01:00
}
2020-10-13 01:39:34 +02:00
void serializeSegment ( JsonObject & root , WS2812FX : : Segment & seg , byte id , bool forPreset , bool segmentBounds )
2019-07-23 17:35:40 +02:00
{
2022-01-25 12:47:14 +01:00
root [ " id " ] = id ;
2020-10-23 17:48:01 +02:00
if ( segmentBounds ) {
2021-09-12 01:15:51 +02:00
root [ " start " ] = seg . start ;
2020-11-08 23:44:10 +01:00
root [ " stop " ] = seg . stop ;
2020-10-23 17:48:01 +02:00
}
2022-01-25 12:47:14 +01:00
if ( ! forPreset ) root [ F ( " len " ) ] = seg . stop - seg . start ;
2021-08-25 16:39:12 +02:00
root [ " grp " ] = seg . grouping ;
2020-09-20 01:18:31 +02:00
root [ F ( " spc " ) ] = seg . spacing ;
2021-06-30 00:45:36 +02:00
root [ F ( " of " ) ] = seg . offset ;
2020-04-23 23:52:33 +02:00
root [ " on " ] = seg . getOption ( SEG_OPTION_ON ) ;
2021-12-17 20:33:48 +01:00
root [ " frz " ] = seg . getOption ( SEG_OPTION_FREEZE ) ;
2020-04-23 23:52:33 +02:00
byte segbri = seg . opacity ;
root [ " bri " ] = ( segbri ) ? segbri : 255 ;
2021-11-28 04:01:58 +01:00
root [ " cct " ] = seg . cct ;
2019-07-23 17:35:40 +02:00
2021-09-18 01:20:17 +02:00
if ( segmentBounds & & seg . name ! = nullptr ) root [ " n " ] = reinterpret_cast < const char * > ( seg . name ) ; //not good practice, but decreases required JSON buffer
2021-09-08 23:10:54 +02:00
2022-01-15 14:04:16 +01:00
// to conserve RAM we will serialize the col array manually
// this will reduce RAM footprint from ~300 bytes to 84 bytes per segment
char colstr [ 70 ] ; colstr [ 0 ] = ' [ ' ; colstr [ 1 ] = ' \0 ' ; //max len 68 (5 chan, all 255)
const char * format = strip . isRgbw ? PSTR ( " [%u,%u,%u,%u] " ) : PSTR ( " [%u,%u,%u] " ) ;
for ( uint8_t i = 0 ; i < 3 ; i + + )
{
2021-06-19 11:13:05 +02:00
byte segcol [ 4 ] ; byte * c = segcol ;
2020-03-14 11:28:42 +01:00
if ( id = = strip . getMainSegmentId ( ) & & i < 2 ) //temporary, to make transition work on main segment
{
2021-06-19 11:13:05 +02:00
c = ( i = = 0 ) ? col : colSec ;
2020-03-14 11:28:42 +01:00
} else {
2022-01-15 14:04:16 +01:00
segcol [ 0 ] = R ( seg . colors [ i ] ) ;
segcol [ 1 ] = G ( seg . colors [ i ] ) ;
segcol [ 2 ] = B ( seg . colors [ i ] ) ;
segcol [ 3 ] = W ( seg . colors [ i ] ) ;
2020-03-14 11:28:42 +01:00
}
2021-06-19 11:13:05 +02:00
char tmpcol [ 22 ] ;
2022-01-15 14:04:16 +01:00
sprintf_P ( tmpcol , format , ( unsigned ) c [ 0 ] , ( unsigned ) c [ 1 ] , ( unsigned ) c [ 2 ] , ( unsigned ) c [ 3 ] ) ;
strcat ( colstr , i < 2 ? strcat_P ( tmpcol , PSTR ( " , " ) ) : tmpcol ) ;
}
strcat_P ( colstr , PSTR ( " ] " ) ) ;
2021-06-17 19:46:18 +02:00
root [ " col " ] = serialized ( colstr ) ;
2019-07-23 17:35:40 +02:00
2022-01-25 12:47:14 +01:00
root [ " fx " ] = seg . mode ;
root [ F ( " sx " ) ] = seg . speed ;
root [ F ( " ix " ) ] = seg . intensity ;
root [ " pal " ] = seg . palette ;
root [ F ( " sel " ) ] = seg . isSelected ( ) ;
root [ " rev " ] = seg . getOption ( SEG_OPTION_REVERSED ) ;
2020-09-20 01:18:31 +02:00
root [ F ( " mi " ) ] = seg . getOption ( SEG_OPTION_MIRROR ) ;
2019-07-23 17:35:40 +02:00
}
2020-10-13 01:39:34 +02:00
void serializeState ( JsonObject root , bool forPreset , bool includeBri , bool segmentBounds )
2021-03-18 23:59:56 +01:00
{
2020-10-13 01:39:34 +02:00
if ( includeBri ) {
root [ " on " ] = ( bri > 0 ) ;
root [ " bri " ] = briLast ;
root [ F ( " transition " ) ] = transitionDelay / 100 ; //in 100ms
}
2019-07-23 17:35:40 +02:00
2020-09-07 20:39:12 +02:00
if ( ! forPreset ) {
2022-01-15 14:04:16 +01:00
if ( errorFlag ) { root [ F ( " error " ) ] = errorFlag ; errorFlag = ERR_NONE ; } //prevent error message to persist on screen
2021-03-18 23:59:56 +01:00
2021-11-23 13:17:33 +01:00
root [ " ps " ] = ( currentPreset > 0 ) ? currentPreset : - 1 ;
2021-06-30 01:48:38 +02:00
root [ F ( " pl " ) ] = currentPlaylist ;
2021-03-18 23:59:56 +01:00
2020-09-07 20:39:12 +02:00
usermods . addToJsonState ( root ) ;
2019-12-01 01:42:52 +01:00
2020-09-07 20:39:12 +02:00
JsonObject nl = root . createNestedObject ( " nl " ) ;
nl [ " on " ] = nightlightActive ;
2020-09-21 19:48:12 +02:00
nl [ F ( " dur " ) ] = nightlightDelayMins ;
nl [ F ( " mode " ) ] = nightlightMode ;
nl [ F ( " tbri " ) ] = nightlightTargetBri ;
2020-11-12 11:12:10 +01:00
if ( nightlightActive ) {
2020-10-30 20:18:27 +01:00
nl [ F ( " rem " ) ] = ( nightlightDelayMs - ( millis ( ) - nightlightStartTime ) ) / 1000 ; // seconds remaining
2020-11-12 11:12:10 +01:00
} else {
2020-10-30 20:18:27 +01:00
nl [ F ( " rem " ) ] = - 1 ;
2020-11-12 11:12:10 +01:00
}
2020-10-30 20:18:27 +01:00
2020-09-07 20:39:12 +02:00
JsonObject udpn = root . createNestedObject ( " udpn " ) ;
2021-03-13 22:04:37 +01:00
udpn [ " send " ] = notifyDirect ;
udpn [ " recv " ] = receiveNotifications ;
2019-12-01 01:42:52 +01:00
2020-09-21 19:48:12 +02:00
root [ F ( " lor " ) ] = realtimeOverride ;
2020-09-07 20:39:12 +02:00
}
2020-04-30 01:52:36 +02:00
2020-09-20 01:18:31 +02:00
root [ F ( " mainseg " ) ] = strip . getMainSegmentId ( ) ;
2020-10-30 20:18:27 +01:00
2019-06-21 23:12:58 +02:00
JsonArray seg = root . createNestedArray ( " seg " ) ;
2022-01-15 14:04:16 +01:00
for ( byte s = 0 ; s < strip . getMaxSegments ( ) ; s + + ) {
WS2812FX : : Segment & sg = strip . getSegment ( s ) ;
if ( sg . isActive ( ) ) {
2019-06-21 23:12:58 +02:00
JsonObject seg0 = seg . createNestedObject ( ) ;
2020-10-13 01:39:34 +02:00
serializeSegment ( seg0 , sg , s , forPreset , segmentBounds ) ;
2020-11-08 23:44:10 +01:00
} else if ( forPreset & & segmentBounds ) { //disable segments not part of preset
JsonObject seg0 = seg . createNestedObject ( ) ;
seg0 [ " stop " ] = 0 ;
2019-06-20 14:40:12 +02:00
}
}
2019-03-05 10:59:15 +01:00
}
2020-03-30 10:41:42 +02:00
//by https://github.com/tzapu/WiFiManager/blob/master/WiFiManager.cpp
int getSignalQuality ( int rssi )
{
int quality = 0 ;
if ( rssi < = - 100 )
{
quality = 0 ;
}
else if ( rssi > = - 50 )
{
quality = 100 ;
}
else
{
quality = 2 * ( rssi + 100 ) ;
}
return quality ;
}
2019-06-21 23:12:58 +02:00
void serializeInfo ( JsonObject root )
2019-03-05 10:59:15 +01:00
{
2020-09-20 01:18:31 +02:00
root [ F ( " ver " ) ] = versionString ;
root [ F ( " vid " ) ] = VERSION ;
//root[F("cn")] = WLED_CODENAME;
2021-03-18 23:59:56 +01:00
2019-06-21 23:12:58 +02:00
JsonObject leds = root . createNestedObject ( " leds " ) ;
2021-10-31 11:57:41 +01:00
leds [ F ( " count " ) ] = strip . getLengthTotal ( ) ;
2021-03-29 02:28:34 +02:00
leds [ F ( " rgbw " ) ] = strip . isRgbw ;
2021-10-25 20:15:42 +02:00
leds [ F ( " wv " ) ] = false ;
2021-11-28 04:01:58 +01:00
leds [ " cct " ] = correctWB | | strip . hasCCTBus ( ) ;
2022-01-25 12:47:14 +01:00
switch ( Bus : : getAutoWhiteMode ( ) ) {
case RGBW_MODE_MANUAL_ONLY :
case RGBW_MODE_DUAL :
if ( strip . isRgbw ) leds [ F ( " wv " ) ] = true ;
break ;
}
2021-11-28 04:01:58 +01:00
2020-09-20 01:18:31 +02:00
leds [ F ( " pwr " ) ] = strip . currentMilliamps ;
2021-12-30 01:48:27 +01:00
leds [ " fps " ] = strip . getFps ( ) ;
2020-09-20 01:18:31 +02:00
leds [ F ( " maxpwr " ) ] = ( strip . currentMilliamps ) ? strip . ablMilliampsMax : 0 ;
leds [ F ( " maxseg " ) ] = strip . getMaxSegments ( ) ;
2021-11-17 01:18:19 +01:00
//leds[F("seglock")] = false; //might be used in the future to prevent modifications to segment config
2019-12-13 01:23:07 +01:00
2020-09-20 01:18:31 +02:00
root [ F ( " str " ) ] = syncToggleReceive ;
2021-03-18 23:59:56 +01:00
2020-09-20 01:18:31 +02:00
root [ F ( " name " ) ] = serverDescription ;
root [ F ( " udpport " ) ] = udpPort ;
2020-11-26 10:54:37 +01:00
root [ " live " ] = ( bool ) realtimeMode ;
2020-04-30 01:52:36 +02:00
switch ( realtimeMode ) {
case REALTIME_MODE_INACTIVE : root [ " lm " ] = " " ; break ;
case REALTIME_MODE_GENERIC : root [ " lm " ] = " " ; break ;
2020-09-20 01:18:31 +02:00
case REALTIME_MODE_UDP : root [ " lm " ] = F ( " UDP " ) ; break ;
case REALTIME_MODE_HYPERION : root [ " lm " ] = F ( " Hyperion " ) ; break ;
case REALTIME_MODE_E131 : root [ " lm " ] = F ( " E1.31 " ) ; break ;
2020-05-23 16:09:49 +02:00
case REALTIME_MODE_ADALIGHT : root [ " lm " ] = F ( " USB Adalight/TPM2 " ) ; break ;
2020-09-20 01:18:31 +02:00
case REALTIME_MODE_ARTNET : root [ " lm " ] = F ( " Art-Net " ) ; break ;
2020-05-18 16:36:31 +02:00
case REALTIME_MODE_TPM2NET : root [ " lm " ] = F ( " tpm2.net " ) ; break ;
2020-09-28 16:29:01 +02:00
case REALTIME_MODE_DDP : root [ " lm " ] = F ( " DDP " ) ; break ;
2020-04-30 01:52:36 +02:00
}
if ( realtimeIP [ 0 ] = = 0 )
{
2020-09-20 01:18:31 +02:00
root [ F ( " lip " ) ] = " " ;
2020-04-30 01:52:36 +02:00
} else {
2020-09-20 01:18:31 +02:00
root [ F ( " lip " ) ] = realtimeIP . toString ( ) ;
2020-04-30 01:52:36 +02:00
}
2020-06-26 17:28:35 +02:00
# ifdef WLED_ENABLE_WEBSOCKETS
2020-09-20 01:18:31 +02:00
root [ F ( " ws " ) ] = ws . count ( ) ;
2020-06-26 17:28:35 +02:00
# else
2020-09-20 01:18:31 +02:00
root [ F ( " ws " ) ] = - 1 ;
2020-06-26 17:28:35 +02:00
# endif
2020-09-20 01:18:31 +02:00
root [ F ( " fxcount " ) ] = strip . getModeCount ( ) ;
root [ F ( " palcount " ) ] = strip . getPaletteCount ( ) ;
2019-10-29 02:21:23 +01:00
JsonObject wifi_info = root . createNestedObject ( " wifi " ) ;
2020-09-20 01:18:31 +02:00
wifi_info [ F ( " bssid " ) ] = WiFi . BSSIDstr ( ) ;
2020-01-14 10:57:23 +01:00
int qrssi = WiFi . RSSI ( ) ;
2020-09-20 01:18:31 +02:00
wifi_info [ F ( " rssi " ) ] = qrssi ;
wifi_info [ F ( " signal " ) ] = getSignalQuality ( qrssi ) ;
wifi_info [ F ( " channel " ) ] = WiFi . channel ( ) ;
2020-09-15 21:28:43 +02:00
JsonObject fs_info = root . createNestedObject ( " fs " ) ;
2020-10-07 17:48:22 +02:00
fs_info [ " u " ] = fsBytesUsed / 1000 ;
fs_info [ " t " ] = fsBytesTotal / 1000 ;
2020-10-03 00:29:36 +02:00
fs_info [ F ( " pmt " ) ] = presetsModifiedTime ;
2021-03-09 16:23:19 +01:00
2021-03-13 22:04:37 +01:00
root [ F ( " ndc " ) ] = nodeListEnabled ? ( int ) Nodes . size ( ) : - 1 ;
2019-10-29 02:21:23 +01:00
2019-03-05 10:59:15 +01:00
# ifdef ARDUINO_ARCH_ESP32
2020-02-22 17:20:34 +01:00
# ifdef WLED_DEBUG
2020-09-20 01:18:31 +02:00
wifi_info [ F ( " txPower " ) ] = ( int ) WiFi . getTxPower ( ) ;
wifi_info [ F ( " sleep " ) ] = ( bool ) WiFi . getSleep ( ) ;
2020-02-22 17:20:34 +01:00
# endif
2020-09-20 01:18:31 +02:00
root [ F ( " arch " ) ] = " esp32 " ;
root [ F ( " core " ) ] = ESP . getSdkVersion ( ) ;
//root[F("maxalloc")] = ESP.getMaxAllocHeap();
2020-02-22 17:20:34 +01:00
# ifdef WLED_DEBUG
2020-09-20 01:18:31 +02:00
root [ F ( " resetReason0 " ) ] = ( int ) rtc_get_reset_reason ( 0 ) ;
root [ F ( " resetReason1 " ) ] = ( int ) rtc_get_reset_reason ( 1 ) ;
2020-02-22 17:20:34 +01:00
# endif
2021-11-17 01:18:19 +01:00
root [ F ( " lwip " ) ] = 0 ; //deprecated
2019-03-05 10:59:15 +01:00
# else
2020-09-20 01:18:31 +02:00
root [ F ( " arch " ) ] = " esp8266 " ;
root [ F ( " core " ) ] = ESP . getCoreVersion ( ) ;
//root[F("maxalloc")] = ESP.getMaxFreeBlockSize();
2020-02-22 17:20:34 +01:00
# ifdef WLED_DEBUG
2020-09-20 01:18:31 +02:00
root [ F ( " resetReason " ) ] = ( int ) ESP . getResetInfoPtr ( ) - > reason ;
2020-02-22 17:20:34 +01:00
# endif
2020-09-20 01:18:31 +02:00
root [ F ( " lwip " ) ] = LWIP_VERSION_MAJOR ;
2019-03-05 10:59:15 +01:00
# endif
2021-03-18 23:59:56 +01:00
2020-09-20 01:18:31 +02:00
root [ F ( " freeheap " ) ] = ESP . getFreeHeap ( ) ;
2022-01-15 14:04:16 +01:00
# if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
if ( psramFound ( ) ) root [ F ( " psram " ) ] = ESP . getFreePsram ( ) ;
# endif
2020-09-20 01:18:31 +02:00
root [ F ( " uptime " ) ] = millis ( ) / 1000 + rolloverMillis * 4294967 ;
2020-05-28 02:20:02 +02:00
usermods . addToJsonInfo ( root ) ;
2021-03-18 23:59:56 +01:00
2019-03-06 01:20:38 +01:00
byte os = 0 ;
# ifdef WLED_DEBUG
os = 0x80 ;
# endif
2019-03-05 10:59:15 +01:00
# ifndef WLED_DISABLE_ALEXA
2019-03-06 01:20:38 +01:00
os + = 0x40 ;
2019-03-05 10:59:15 +01:00
# endif
# ifndef WLED_DISABLE_BLYNK
2019-03-06 01:20:38 +01:00
os + = 0x20 ;
2019-03-05 10:59:15 +01:00
# endif
# ifndef WLED_DISABLE_CRONIXIE
2019-03-06 01:20:38 +01:00
os + = 0x10 ;
2019-03-05 10:59:15 +01:00
# endif
2019-03-16 02:09:37 +01:00
# ifndef WLED_DISABLE_FILESYSTEM
2019-03-06 01:20:38 +01:00
os + = 0x08 ;
2019-03-05 10:59:15 +01:00
# endif
# ifndef WLED_DISABLE_HUESYNC
2019-03-06 01:20:38 +01:00
os + = 0x04 ;
2019-03-05 10:59:15 +01:00
# endif
2019-12-03 14:15:12 +01:00
# ifdef WLED_ENABLE_ADALIGHT
2019-03-06 01:20:38 +01:00
os + = 0x02 ;
2019-03-05 10:59:15 +01:00
# endif
2021-03-18 23:59:56 +01:00
# ifndef WLED_DISABLE_OTA
2019-03-06 01:20:38 +01:00
os + = 0x01 ;
2019-03-05 10:59:15 +01:00
# endif
2020-09-20 01:18:31 +02:00
root [ F ( " opt " ) ] = os ;
2021-03-18 23:59:56 +01:00
2020-09-20 01:18:31 +02:00
root [ F ( " brand " ) ] = " WLED " ;
root [ F ( " product " ) ] = F ( " FOSS " ) ;
2020-09-27 11:43:28 +02:00
root [ " mac " ] = escapedMac ;
2021-04-25 01:37:16 +02:00
char s [ 16 ] = " " ;
if ( Network . isConnected ( ) )
{
IPAddress localIP = Network . localIP ( ) ;
sprintf ( s , " %d.%d.%d.%d " , localIP [ 0 ] , localIP [ 1 ] , localIP [ 2 ] , localIP [ 3 ] ) ;
}
root [ " ip " ] = s ;
2021-03-09 16:23:19 +01:00
}
2021-01-22 16:17:18 +01:00
2021-03-18 23:59:56 +01:00
void setPaletteColors ( JsonArray json , CRGBPalette16 palette )
{
for ( int i = 0 ; i < 16 ; i + + ) {
JsonArray colors = json . createNestedArray ( ) ;
CRGB color = palette [ i ] ;
2022-01-15 14:04:16 +01:00
colors . add ( i < < 4 ) ;
2021-03-18 23:59:56 +01:00
colors . add ( color . red ) ;
colors . add ( color . green ) ;
colors . add ( color . blue ) ;
}
}
void setPaletteColors ( JsonArray json , byte * tcp )
{
TRGBGradientPaletteEntryUnion * ent = ( TRGBGradientPaletteEntryUnion * ) ( tcp ) ;
TRGBGradientPaletteEntryUnion u ;
// Count entries
uint16_t count = 0 ;
do {
u = * ( ent + count ) ;
count + + ;
} while ( u . index ! = 255 ) ;
u = * ent ;
int indexstart = 0 ;
while ( indexstart < 255 ) {
indexstart = u . index ;
JsonArray colors = json . createNestedArray ( ) ;
colors . add ( u . index ) ;
colors . add ( u . r ) ;
colors . add ( u . g ) ;
colors . add ( u . b ) ;
ent + + ;
u = * ent ;
}
}
void serializePalettes ( JsonObject root , AsyncWebServerRequest * request )
{
# ifdef ESP8266
int itemPerPage = 5 ;
# else
int itemPerPage = 8 ;
# endif
int page = 0 ;
if ( request - > hasParam ( " page " ) ) {
page = request - > getParam ( " page " ) - > value ( ) . toInt ( ) ;
}
int palettesCount = strip . getPaletteCount ( ) ;
int maxPage = ( palettesCount - 1 ) / itemPerPage ;
if ( page > maxPage ) page = maxPage ;
int start = itemPerPage * page ;
int end = start + itemPerPage ;
if ( end > = palettesCount ) end = palettesCount ;
root [ F ( " m " ) ] = maxPage ;
JsonObject palettes = root . createNestedObject ( " p " ) ;
for ( int i = start ; i < end ; i + + ) {
JsonArray curPalette = palettes . createNestedArray ( String ( i ) ) ;
switch ( i ) {
case 0 : //default palette
setPaletteColors ( curPalette , PartyColors_p ) ;
break ;
case 1 : //random
curPalette . add ( " r " ) ;
curPalette . add ( " r " ) ;
curPalette . add ( " r " ) ;
curPalette . add ( " r " ) ;
break ;
case 2 : //primary color only
2021-09-18 00:31:39 +02:00
curPalette . add ( " c1 " ) ;
2021-03-18 23:59:56 +01:00
break ;
case 3 : //primary + secondary
2021-09-18 00:31:39 +02:00
curPalette . add ( " c1 " ) ;
curPalette . add ( " c1 " ) ;
curPalette . add ( " c2 " ) ;
curPalette . add ( " c2 " ) ;
2021-03-18 23:59:56 +01:00
break ;
case 4 : //primary + secondary + tertiary
2021-09-18 00:31:39 +02:00
curPalette . add ( " c3 " ) ;
curPalette . add ( " c2 " ) ;
curPalette . add ( " c1 " ) ;
2021-03-18 23:59:56 +01:00
break ;
case 5 : { //primary + secondary (+tert if not off), more distinct
2021-09-18 00:31:39 +02:00
curPalette . add ( " c1 " ) ;
curPalette . add ( " c1 " ) ;
curPalette . add ( " c1 " ) ;
curPalette . add ( " c1 " ) ;
curPalette . add ( " c1 " ) ;
curPalette . add ( " c2 " ) ;
curPalette . add ( " c2 " ) ;
curPalette . add ( " c2 " ) ;
curPalette . add ( " c2 " ) ;
curPalette . add ( " c2 " ) ;
curPalette . add ( " c3 " ) ;
curPalette . add ( " c3 " ) ;
curPalette . add ( " c3 " ) ;
curPalette . add ( " c3 " ) ;
curPalette . add ( " c3 " ) ;
curPalette . add ( " c1 " ) ;
2021-03-18 23:59:56 +01:00
break ; }
case 6 : //Party colors
setPaletteColors ( curPalette , PartyColors_p ) ;
break ;
case 7 : //Cloud colors
setPaletteColors ( curPalette , CloudColors_p ) ;
break ;
case 8 : //Lava colors
setPaletteColors ( curPalette , LavaColors_p ) ;
break ;
case 9 : //Ocean colors
setPaletteColors ( curPalette , OceanColors_p ) ;
break ;
case 10 : //Forest colors
setPaletteColors ( curPalette , ForestColors_p ) ;
break ;
case 11 : //Rainbow colors
setPaletteColors ( curPalette , RainbowColors_p ) ;
break ;
case 12 : //Rainbow stripe colors
setPaletteColors ( curPalette , RainbowStripeColors_p ) ;
break ;
default :
if ( i < 13 ) {
break ;
}
byte tcp [ 72 ] ;
memcpy_P ( tcp , ( byte * ) pgm_read_dword ( & ( gGradientPalettes [ i - 13 ] ) ) , 72 ) ;
setPaletteColors ( curPalette , tcp ) ;
break ;
}
}
}
2021-03-09 16:23:19 +01:00
void serializeNodes ( JsonObject root )
{
2021-01-22 16:17:18 +01:00
JsonArray nodes = root . createNestedArray ( " nodes " ) ;
2021-03-09 18:00:02 +01:00
2021-01-22 16:17:18 +01:00
for ( NodesMap : : iterator it = Nodes . begin ( ) ; it ! = Nodes . end ( ) ; + + it )
{
if ( it - > second . ip [ 0 ] ! = 0 )
{
JsonObject node = nodes . createNestedObject ( ) ;
node [ F ( " name " ) ] = it - > second . nodeName ;
2021-03-13 22:04:37 +01:00
node [ " type " ] = it - > second . nodeType ;
node [ " ip " ] = it - > second . ip . toString ( ) ;
2021-01-22 16:17:18 +01:00
node [ F ( " age " ) ] = it - > second . age ;
2021-03-13 22:04:37 +01:00
node [ F ( " vid " ) ] = it - > second . build ;
2021-01-22 16:17:18 +01:00
}
}
2019-03-06 01:20:38 +01:00
}
void serveJson ( AsyncWebServerRequest * request )
{
byte subJson = 0 ;
const String & url = request - > url ( ) ;
if ( url . indexOf ( " state " ) > 0 ) subJson = 1 ;
else if ( url . indexOf ( " info " ) > 0 ) subJson = 2 ;
2021-05-11 01:11:16 +02:00
else if ( url . indexOf ( " si " ) > 0 ) subJson = 3 ;
2021-03-09 16:23:19 +01:00
else if ( url . indexOf ( " nodes " ) > 0 ) subJson = 4 ;
2021-05-11 01:11:16 +02:00
else if ( url . indexOf ( " palx " ) > 0 ) subJson = 5 ;
2019-11-18 12:29:36 +01:00
else if ( url . indexOf ( " live " ) > 0 ) {
serveLiveLeds ( request ) ;
return ;
}
2021-05-11 01:11:16 +02:00
else if ( url . indexOf ( F ( " eff " ) ) > 0 ) {
2019-03-06 01:20:38 +01:00
request - > send_P ( 200 , " application/json " , JSON_mode_names ) ;
return ;
}
2021-05-11 01:11:16 +02:00
else if ( url . indexOf ( " pal " ) > 0 ) {
2019-03-06 01:20:38 +01:00
request - > send_P ( 200 , " application/json " , JSON_palette_names ) ;
return ;
}
2021-05-11 01:11:16 +02:00
else if ( url . indexOf ( " cfg " ) > 0 & & handleFileRead ( request , " /cfg.json " ) ) {
return ;
}
2019-03-06 01:20:38 +01:00
else if ( url . length ( ) > 6 ) { //not just /json
2020-02-25 02:19:12 +01:00
request - > send ( 501 , " application/json " , F ( " { \" error \" : \" Not implemented \" } " ) ) ;
2019-03-06 01:20:38 +01:00
return ;
}
2021-03-18 23:59:56 +01:00
2021-12-04 01:05:01 +01:00
# ifdef WLED_USE_DYNAMIC_JSON
2020-09-20 01:18:31 +02:00
AsyncJsonResponse * response = new AsyncJsonResponse ( JSON_BUFFER_SIZE ) ;
2021-12-04 01:05:01 +01:00
# else
if ( ! requestJSONBufferLock ( 17 ) ) return ;
AsyncJsonResponse * response = new AsyncJsonResponse ( & doc ) ;
# endif
JsonObject lDoc = response - > getRoot ( ) ;
2019-03-05 10:59:15 +01:00
2019-03-06 01:20:38 +01:00
switch ( subJson )
{
case 1 : //state
2021-12-04 01:05:01 +01:00
serializeState ( lDoc ) ; break ;
2019-03-06 01:20:38 +01:00
case 2 : //info
2021-12-04 01:05:01 +01:00
serializeInfo ( lDoc ) ; break ;
2021-03-09 16:23:19 +01:00
case 4 : //node list
2021-12-04 01:05:01 +01:00
serializeNodes ( lDoc ) ; break ;
2021-03-18 23:59:56 +01:00
case 5 : //palettes
2021-12-04 01:05:01 +01:00
serializePalettes ( lDoc , request ) ; break ;
2019-03-06 01:20:38 +01:00
default : //all
2021-12-04 01:05:01 +01:00
JsonObject state = lDoc . createNestedObject ( " state " ) ;
2019-03-06 01:20:38 +01:00
serializeState ( state ) ;
2021-12-04 01:05:01 +01:00
JsonObject info = lDoc . createNestedObject ( " info " ) ;
2019-03-06 01:20:38 +01:00
serializeInfo ( info ) ;
2020-04-30 01:52:36 +02:00
if ( subJson ! = 3 )
{
2020-09-20 01:18:31 +02:00
doc [ F ( " effects " ) ] = serialized ( ( const __FlashStringHelper * ) JSON_mode_names ) ;
doc [ F ( " palettes " ) ] = serialized ( ( const __FlashStringHelper * ) JSON_palette_names ) ;
2020-04-30 01:52:36 +02:00
}
2019-03-06 01:20:38 +01:00
}
2021-03-18 23:59:56 +01:00
2021-06-17 19:46:18 +02:00
DEBUG_PRINT ( " JSON buffer size: " ) ;
2021-12-04 01:05:01 +01:00
DEBUG_PRINTLN ( lDoc . memoryUsage ( ) ) ;
2021-06-17 19:46:18 +02:00
2019-03-05 10:59:15 +01:00
response - > setLength ( ) ;
request - > send ( response ) ;
2021-12-04 01:05:01 +01:00
releaseJSONBufferLock ( ) ;
2019-03-05 10:59:15 +01:00
}
2019-11-18 12:29:36 +01:00
# define MAX_LIVE_LEDS 180
2020-06-26 17:28:35 +02:00
bool serveLiveLeds ( AsyncWebServerRequest * request , uint32_t wsClient )
2019-11-18 12:29:36 +01:00
{
2022-01-15 14:04:16 +01:00
# ifdef WLED_ENABLE_WEBSOCKETS
2021-01-16 21:40:04 +01:00
AsyncWebSocketClient * wsc = nullptr ;
2020-06-26 17:28:35 +02:00
if ( ! request ) { //not HTTP, use Websockets
wsc = ws . client ( wsClient ) ;
if ( ! wsc | | wsc - > queueLength ( ) > 0 ) return false ; //only send if queue free
}
2022-01-15 14:04:16 +01:00
# endif
2020-06-26 17:28:35 +02:00
2021-10-31 11:57:41 +01:00
uint16_t used = strip . getLengthTotal ( ) ;
2020-03-26 01:44:38 +01:00
uint16_t n = ( used - 1 ) / MAX_LIVE_LEDS + 1 ; //only serve every n'th LED if count over MAX_LIVE_LEDS
2020-09-20 01:18:31 +02:00
char buffer [ 2000 ] ;
strcpy_P ( buffer , PSTR ( " { \" leds \" :[ " ) ) ;
2019-11-18 12:29:36 +01:00
obuf = buffer ;
2020-06-26 17:28:35 +02:00
olen = 9 ;
2019-11-18 12:29:36 +01:00
2019-12-01 01:42:52 +01:00
for ( uint16_t i = 0 ; i < used ; i + = n )
2019-11-18 12:29:36 +01:00
{
2020-12-07 01:39:42 +01:00
olen + = sprintf ( obuf + olen , " \" %06X \" , " , strip . getPixelColor ( i ) & 0xFFFFFF ) ;
2019-11-18 12:29:36 +01:00
}
olen - = 1 ;
2020-09-20 01:18:31 +02:00
oappend ( ( const char * ) F ( " ], \" n \" : " ) ) ;
2019-11-18 12:29:36 +01:00
oappendi ( n ) ;
oappend ( " } " ) ;
2020-06-26 17:28:35 +02:00
if ( request ) {
request - > send ( 200 , " application/json " , buffer ) ;
}
# ifdef WLED_ENABLE_WEBSOCKETS
else {
wsc - > text ( obuf , olen ) ;
}
# endif
return true ;
2019-11-18 12:29:36 +01:00
}