Use "pd" JSON API call for direct preset apply (#2946)

This commit is contained in:
Christian Schwinne 2022-12-13 14:27:44 +01:00 committed by GitHub
parent 6bb158786b
commit f50c9e855c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 1954 additions and 1961 deletions

View File

@ -2194,12 +2194,12 @@ function setPreset(i)
{ {
var obj = {"ps":i}; var obj = {"ps":i};
if (pJson && pJson[i] && (!pJson[i].win || pJson[i].win.indexOf("Please") <= 0)) { 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 // we will send the complete preset content as to avoid delay introduced by
// async nature of applyPreset(). json.cpp has to decide wether to call applyPreset() // async nature of applyPreset() and having to read the preset from file system.
// or not (by looking at the JSON content, if "ps" only) obj = {"pd":i}; // use "pd" instead of "ps" to indicate that we are sending the preset content directly
Object.assign(obj, pJson[i]); Object.assign(obj, pJson[i]);
delete obj.ql; // no need for quick load delete obj.ql; // no need for quick load
delete obj.n; // no need for name delete obj.n; // no need for name
} }
if (isPlaylist(i)) obj.on = true; // force on if (isPlaylist(i)) obj.on = true; // force on
showToast("Loading preset " + pName(i) +" (" + i + ")"); 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 handleSet(nullptr, apireq, false); // may set stateChanged
} }
// applying preset (2 cases: a) API call includes all preset values, b) API only specifies preset ID) // applying preset (2 cases: a) API call includes all preset values ("pd"), b) API only specifies preset ID ("ps"))
if (!root["ps"].isNull()) { 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; ps = presetCycCurr;
if (stateChanged) { if (root["win"].isNull() && getVal(root["ps"], &ps, 0, 0) && ps > 0 && ps < 251 && ps != currentPreset) {
// 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) {
// b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal()) // b) preset ID only or preset that does not change state (use embedded cycling limits if they exist in getVal())
presetCycCurr = ps; presetCycCurr = ps;
presetId = ps; unloadPlaylist(); // applying a preset unloads the playlist
root.remove("v"); // may be added in UI call applyPreset(ps, callMode); // async load from file system (only preset ID was specified)
root.remove("time"); // may be added in UI call return stateResponse;
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;
}
} }
} }
@ -428,6 +421,7 @@ bool deserializeState(JsonObject root, byte callMode, byte presetId)
} }
stateUpdated(callMode); stateUpdated(callMode);
if (presetToRestore) currentPreset = presetToRestore;
return stateResponse; return stateResponse;
} }

View File

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