2020-11-06 22:12:48 +01:00
# include "wled.h"
/*
* Methods to handle saving and loading presets to / from the filesystem
*/
2022-01-01 12:52:50 +01:00
# ifdef ARDUINO_ARCH_ESP32
static char * tmpRAMbuffer = nullptr ;
# endif
static volatile byte presetToApply = 0 ;
static volatile byte callModeToApply = 0 ;
2022-02-02 20:53:16 +01:00
static volatile bool checkPlaylist = false ;
2022-01-01 12:52:50 +01:00
2022-02-02 20:53:16 +01:00
bool applyPreset ( byte index , byte callMode , bool fromJson )
2020-11-06 22:12:48 +01:00
{
2022-01-01 12:52:50 +01:00
presetToApply = index ;
callModeToApply = callMode ;
2022-02-02 20:53:16 +01:00
checkPlaylist = fromJson ;
2022-01-01 12:52:50 +01:00
return true ;
}
void handlePresets ( )
{
if ( presetToApply = = 0 | | fileDoc ) return ; //JSON buffer allocated (apply preset in next cycle) or no preset waiting
JsonObject fdo ;
2022-02-02 22:00:31 +01:00
const char * filename = presetToApply < 255 ? " /presets.json " : " /tmp.json " ;
2022-01-01 12:52:50 +01:00
// allocate buffer
DEBUG_PRINTLN ( F ( " Apply preset JSON buffer requested. " ) ) ;
if ( ! requestJSONBufferLock ( 9 ) ) return ; // will also assign fileDoc
# ifdef ARDUINO_ARCH_ESP32
if ( presetToApply = = 255 & & tmpRAMbuffer ! = nullptr ) {
deserializeJson ( * fileDoc , tmpRAMbuffer ) ;
errorFlag = ERR_NONE ;
} else
# endif
{
errorFlag = readObjectFromFileUsingId ( filename , presetToApply , fileDoc ) ? ERR_NONE : ERR_FS_PLOAD ;
2020-11-06 22:12:48 +01:00
}
2022-01-01 12:52:50 +01:00
fdo = fileDoc - > as < JsonObject > ( ) ;
2022-01-03 22:23:03 +01:00
//HTTP API commands
const char * httpwin = fdo [ " win " ] ;
if ( httpwin ) {
String apireq = " win& " ;
apireq + = httpwin ;
handleSet ( nullptr , apireq , false ) ;
} else {
fdo . remove ( " ps " ) ; //remove load request for presets to prevent recursive crash
2022-02-02 20:53:16 +01:00
// if we applyPreset from JSON and preset contains "seg" we must unload playlist
if ( checkPlaylist & & ! fdo [ " seg " ] . isNull ( ) ) unloadPlaylist ( ) ;
2022-01-03 22:23:03 +01:00
deserializeState ( fdo , CALL_MODE_NO_NOTIFY , presetToApply ) ;
}
2020-11-06 22:12:48 +01:00
2022-01-01 12:52:50 +01:00
# if defined(ARDUINO_ARCH_ESP32)
//Aircoookie recommended not to delete buffer
if ( presetToApply = = 255 & & tmpRAMbuffer ! = nullptr ) {
free ( tmpRAMbuffer ) ;
tmpRAMbuffer = nullptr ;
2020-11-06 22:12:48 +01:00
}
2022-01-01 12:52:50 +01:00
# endif
releaseJSONBufferLock ( ) ; // will also clear fileDoc
if ( ! errorFlag & & presetToApply < 255 ) currentPreset = presetToApply ;
2022-01-03 22:23:03 +01:00
colorUpdated ( callModeToApply ) ;
updateInterfaces ( callModeToApply ) ;
2022-01-01 12:52:50 +01:00
presetToApply = 0 ; //clear request for preset
callModeToApply = 0 ;
2022-02-02 20:53:16 +01:00
checkPlaylist = false ;
2020-11-06 22:12:48 +01:00
}
2022-01-01 12:52:50 +01:00
//called from handleSet(PS=) [network callback (fileDoc==nullptr), IR (irrational), deserializeState, UDP] and deserializeState() [network callback (filedoc!=nullptr)]
2020-11-06 22:12:48 +01:00
void savePreset ( byte index , bool persist , const char * pname , JsonObject saveobj )
{
2021-10-04 20:22:04 +02:00
if ( index = = 0 | | ( index > 250 & & persist ) | | ( index < 255 & & ! persist ) ) return ;
2022-01-01 12:52:50 +01:00
2020-11-06 22:12:48 +01:00
JsonObject sObj = saveobj ;
2022-01-01 12:52:50 +01:00
bool bufferAllocated = false ;
2020-11-06 22:12:48 +01:00
2022-02-02 22:00:31 +01:00
const char * filename = persist ? " /presets.json " : " /tmp.json " ;
2021-10-04 20:22:04 +02:00
2021-11-03 14:52:22 +01:00
if ( ! fileDoc ) {
2022-01-01 12:52:50 +01:00
// called from handleSet() HTTP API
2021-11-12 23:33:10 +01:00
DEBUG_PRINTLN ( F ( " Save preset JSON buffer requested. " ) ) ;
2021-11-14 16:56:34 +01:00
if ( ! requestJSONBufferLock ( 10 ) ) return ;
2022-01-01 12:52:50 +01:00
sObj = fileDoc - > to < JsonObject > ( ) ;
bufferAllocated = true ;
}
if ( pname ) sObj [ " n " ] = pname ;
2020-11-29 22:07:12 +01:00
2022-01-01 12:52:50 +01:00
sObj . remove ( F ( " psave " ) ) ;
sObj . remove ( F ( " v " ) ) ;
2021-11-03 14:52:22 +01:00
2022-01-01 12:52:50 +01:00
if ( ! sObj [ " o " ] ) {
DEBUGFS_PRINTLN ( F ( " Serialize current state " ) ) ;
if ( sObj [ " ib " ] . isNull ( ) & & sObj [ " sb " ] . isNull ( ) ) serializeState ( sObj , true ) ;
else serializeState ( sObj , true , sObj [ " ib " ] , sObj [ " sb " ] ) ;
if ( persist ) currentPreset = index ;
}
sObj . remove ( " o " ) ;
sObj . remove ( " ib " ) ;
sObj . remove ( " sb " ) ;
2022-01-14 14:27:11 +01:00
sObj . remove ( F ( " sc " ) ) ;
2022-01-01 12:52:50 +01:00
sObj . remove ( F ( " error " ) ) ;
sObj . remove ( F ( " time " ) ) ;
2020-11-06 22:12:48 +01:00
2022-01-01 12:52:50 +01:00
# if defined(ARDUINO_ARCH_ESP32)
if ( index = = 255 ) {
if ( tmpRAMbuffer ! = nullptr ) free ( tmpRAMbuffer ) ;
size_t len = measureJson ( * fileDoc ) + 1 ;
DEBUG_PRINTLN ( len ) ;
// if possible use SPI RAM on ESP32
# ifdef WLED_USE_PSRAM
if ( psramFound ( ) )
tmpRAMbuffer = ( char * ) ps_malloc ( len ) ;
else
# endif
tmpRAMbuffer = ( char * ) malloc ( len ) ;
if ( tmpRAMbuffer ! = nullptr ) {
serializeJson ( * fileDoc , tmpRAMbuffer , len ) ;
} else {
writeObjectToFileUsingId ( filename , index , fileDoc ) ;
2020-11-29 22:07:12 +01:00
}
2022-01-01 12:52:50 +01:00
} else
# endif
writeObjectToFileUsingId ( filename , index , fileDoc ) ;
2020-11-06 22:12:48 +01:00
2021-10-04 20:22:04 +02:00
if ( persist ) presetsModifiedTime = toki . second ( ) ; //unix time
2022-01-01 12:52:50 +01:00
if ( bufferAllocated ) releaseJSONBufferLock ( ) ;
2020-11-06 22:12:48 +01:00
updateFSInfo ( ) ;
}
void deletePreset ( byte index ) {
StaticJsonDocument < 24 > empty ;
writeObjectToFileUsingId ( " /presets.json " , index , & empty ) ;
2021-05-25 09:59:19 +02:00
presetsModifiedTime = toki . second ( ) ; //unix time
2020-11-06 22:12:48 +01:00
updateFSInfo ( ) ;
}