Use "pd" JSON API call for direct preset apply

This commit is contained in:
cschwinne 2022-12-12 01:06:39 +01:00
parent 6bb158786b
commit 18a54b7693
4 changed files with 1954 additions and 1961 deletions

View File

@ -2194,12 +2194,12 @@ function setPreset(i)
{
var obj = {"ps":i};
if (pJson && pJson[i] && (!pJson[i].win || pJson[i].win.indexOf("Please") <= 0)) {
// we will send complete preset content as to avoid delay introduced by
// async nature of applyPreset(). json.cpp has to decide wether to call applyPreset()
// or not (by looking at the JSON content, if "ps" only)
// we will send the complete preset content as to avoid delay introduced by
// async nature of applyPreset() and having to read the preset from file system.
obj = {"pd":i}; // use "pd" instead of "ps" to indicate that we are sending the preset content directly
Object.assign(obj, pJson[i]);
delete obj.ql; // no need for quick load
delete obj.n; // no need for name
delete obj.ql; // no need for quick load
delete obj.n; // no need for name
}
if (isPlaylist(i)) obj.on = true; // force on
showToast("Loading preset " + pName(i) +" (" + i + ")");

File diff suppressed because it is too large Load Diff

View File

@ -394,29 +394,22 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
handleSet(nullptr, apireq, false); // may set stateChanged
}
// applying preset (2 cases: a) API call includes all preset values, b) API only specifies preset ID)
if (!root["ps"].isNull()) {
// applying preset (2 cases: a) API call includes all preset values ("pd"), b) API only specifies preset ID ("ps"))
byte presetToRestore = 0;
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
if (!root["pd"].isNull() && stateChanged) {
currentPreset = root[F("pd")] | currentPreset;
if (root["win"].isNull()) presetCycCurr = currentPreset;
presetToRestore = currentPreset; // stateUpdated() will clear the preset, so we need to restore it after
//unloadPlaylist(); // applying a preset unloads the playlist, may be needed here too?
} else if (!root["ps"].isNull()) {
ps = presetCycCurr;
if (stateChanged) {
// a) already applied preset content (requires "seg" or "win" but will ignore the rest)
currentPreset = root["ps"] | currentPreset;
// if preset contains HTTP API call do not change presetCycCurr
if (root["win"].isNull()) presetCycCurr = currentPreset;
stateChanged = false; // cancel state change update (preset was set directly by applying values stored in UI JSON array)
notify(callMode);
} else if (root["win"].isNull() && getVal(root["ps"], &ps, 0, 0) && ps > 0 && ps < 251 && ps != currentPreset) {
if (root["win"].isNull() && getVal(root["ps"], &ps, 0, 0) && ps > 0 && ps < 251 && ps != currentPreset) {
// b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal())
presetCycCurr = ps;
presetId = ps;
root.remove("v"); // may be added in UI call
root.remove("time"); // may be added in UI call
root.remove("ps");
root.remove("on"); // some external calls add "on" to "ps" call
if (root.size() == 0) {
unloadPlaylist(); // we need to unload playlist
applyPreset(ps, callMode); // async load (only preset ID was specified)
return stateResponse;
}
unloadPlaylist(); // applying a preset unloads the playlist
applyPreset(ps, callMode); // async load from file system (only preset ID was specified)
return stateResponse;
}
}
@ -428,6 +421,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
}
stateUpdated(callMode);
if (presetToRestore) currentPreset = presetToRestore;
return stateResponse;
}

View File

@ -16,15 +16,15 @@ static char quickLoad[9];
static char saveName[33];
static bool includeBri = true, segBounds = true, selectedOnly = false, playlistSave = false;;
static const char *getName(bool persist = true) {
static const char *getFileName(bool persist = true) {
return persist ? "/presets.json" : "/tmp.json";
}
static void doSaveState() {
bool persist = (presetToSave < 251);
const char *filename = getName(persist);
const char *filename = getFileName(persist);
if (!requestJSONBufferLock(10)) return; // will set fileDoc
if (!requestJSONBufferLock(10)) return; // will set fileDoc
initPresetsFile(); // just in case if someone deleted presets.json using /edit
JsonObject sObj = doc.to<JsonObject>();
@ -83,7 +83,7 @@ bool getPresetName(byte index, String& name)
{
if (!requestJSONBufferLock(9)) return false;
bool presetExists = false;
if (readObjectFromFileUsingId(getName(), index, &doc))
if (readObjectFromFileUsingId(getFileName(), index, &doc))
{
JsonObject fdo = doc.as<JsonObject>();
if (fdo["n"]) {
@ -97,12 +97,12 @@ bool getPresetName(byte index, String& name)
void initPresetsFile()
{
if (WLED_FS.exists(getName())) return;
if (WLED_FS.exists(getFileName())) return;
StaticJsonDocument<64> doc;
JsonObject sObj = doc.to<JsonObject>();
sObj.createNestedObject("0");
File f = WLED_FS.open(getName(), "w");
File f = WLED_FS.open(getFileName(), "w");
if (!f) {
errorFlag = ERR_FS_GENERAL;
return;
@ -127,14 +127,14 @@ void handlePresets()
return;
}
if (presetToApply == 0 || fileDoc) return; // no preset waiting to apply, or JSON buffer is already allocated, return to loop until free
bool changePreset = false;
uint8_t tmpPreset = presetToApply; // store temporary since deserializeState() may call applyPreset()
uint8_t tmpMode = callModeToApply;
if (tmpPreset == 0 || (fileDoc /*&& !force*/)) return; // JSON buffer already allocated and not force apply or no preset waiting
JsonObject fdo;
const char *filename = getName(tmpPreset < 255);
const char *filename = getFileName(tmpPreset < 255);
// allocate buffer
if (!requestJSONBufferLock(9)) return; // will also assign fileDoc
@ -201,30 +201,28 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
presetToSave = index;
playlistSave = false;
if (sObj[F("ql")].is<const char*>()) strlcpy(quickLoad, sObj[F("ql")].as<const char*>(), 9); // client limits QL to 2 chars, buffer for 8 bytes to allow unicode
sObj.remove("v");
sObj.remove("time");
sObj.remove(F("error"));
sObj.remove(F("psave"));
if (sObj["o"].isNull()) { // "o" marks a playlist or manually entered API
if (sObj["o"].isNull()) { // no "o" means not a playlist or custom API call, saving of state is async (not immediately)
includeBri = sObj["ib"].as<bool>() || index==255; // temporary preset needs brightness
segBounds = sObj["sb"].as<bool>() || index==255; // temporary preset needs bounds
selectedOnly = sObj[F("sc")].as<bool>();
saveLedmap = sObj[F("ledmap")] | -1;
sObj.remove("ib");
sObj.remove("sb");
sObj.remove(F("sc"));
} else {
// this is a playlist or API
sObj.remove("o");
// this is a playlist or API call
if (sObj[F("playlist")].isNull()) {
presetToSave = 0; // we will save API immediately
if (index < 251 && fileDoc) {
if (sObj["n"].isNull()) sObj["n"] = saveName;
initPresetsFile(); // just in case if someone deleted presets.json using /edit
writeObjectToFileUsingId(getName(index), index, fileDoc);
presetsModifiedTime = toki.second(); //unix time
updateFSInfo();
}
// we will save API call immediately
presetToSave = 0;
if (index > 250 || !fileDoc) return; // cannot save API calls to temporary preset (255)
sObj.remove("o");
sObj.remove("v");
sObj.remove("time");
sObj.remove(F("error"));
sObj.remove(F("psave"));
if (sObj["n"].isNull()) sObj["n"] = saveName;
initPresetsFile(); // just in case if someone deleted presets.json using /edit
writeObjectToFileUsingId(getFileName(index), index, fileDoc);
presetsModifiedTime = toki.second(); //unix time
updateFSInfo();
} else {
// store playlist
includeBri = true; // !sObj["on"].isNull();
@ -235,7 +233,7 @@ void savePreset(byte index, const char* pname, JsonObject sObj)
void deletePreset(byte index) {
StaticJsonDocument<24> empty;
writeObjectToFileUsingId(getName(), index, &empty);
writeObjectToFileUsingId(getFileName(), index, &empty);
presetsModifiedTime = toki.second(); //unix time
updateFSInfo();
}