WLED/wled00/json.cpp

932 lines
28 KiB
C++
Raw Normal View History

#include "wled.h"
#include "palettes.h"
/*
* JSON API (De)serialization
*/
2019-03-05 10:59:15 +01:00
JSON in/decrementing (#2258) * Initial JSON in/decrementing * Segment brightness in/decrement * Update json-increment (#2290) * Add Basic Overlay support to Usermods. * Add seven segment overlay usermod * Add seven_seg debug build * Add scrolling message to seven seg um * Fixed red color on IP address * bh1750 * Add msg scroll. Add MQTT and Config support * Add readme * Restore platformio.inii * Edit comments * Add strip off refresh option in LED settings. (#2259) * Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <dev.aircoookie@gmail.com> * Exclude virtual busses from current calculation (#2262) * Refactor string usage * 0.13.0-b4 * Fix MQTT Null publish * Additional Flash string concat * Add AKST/AKDT * UM RGB-Rotary-Encoder: Properly used PinOwner * Cycling bugfix. Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com> * Working JSON preset cycle * Fix some Codacy style issues Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com>
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}
JSON in/decrementing (#2258) * Initial JSON in/decrementing * Segment brightness in/decrement * Update json-increment (#2290) * Add Basic Overlay support to Usermods. * Add seven segment overlay usermod * Add seven_seg debug build * Add scrolling message to seven seg um * Fixed red color on IP address * bh1750 * Add msg scroll. Add MQTT and Config support * Add readme * Restore platformio.inii * Edit comments * Add strip off refresh option in LED settings. (#2259) * Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <dev.aircoookie@gmail.com> * Exclude virtual busses from current calculation (#2262) * Refactor string usage * 0.13.0-b4 * Fix MQTT Null publish * Additional Flash string concat * Add AKST/AKDT * UM RGB-Rotary-Encoder: Properly used PinOwner * Cycling bugfix. Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com> * Working JSON preset cycle * Fix some Codacy style issues Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com>
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
{
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;
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
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
}
} 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
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;
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;
of = offsetAbs;
2021-07-04 00:55:32 +02: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
JSON in/decrementing (#2258) * Initial JSON in/decrementing * Segment brightness in/decrement * Update json-increment (#2290) * Add Basic Overlay support to Usermods. * Add seven segment overlay usermod * Add seven_seg debug build * Add scrolling message to seven seg um * Fixed red color on IP address * bh1750 * Add msg scroll. Add MQTT and Config support * Add readme * Restore platformio.inii * Edit comments * Add strip off refresh option in LED settings. (#2259) * Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <dev.aircoookie@gmail.com> * Exclude virtual busses from current calculation (#2262) * Refactor string usage * 0.13.0-b4 * Fix MQTT Null publish * Additional Flash string concat * Add AKST/AKDT * UM RGB-Rotary-Encoder: Properly used PinOwner * Cycling bugfix. Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com> * Working JSON preset cycle * Fix some Codacy style issues Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com>
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);
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-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);
colValid = true;
2021-07-02 00:24:14 +02:00
} else { //HEX string, e.g. "FFAA00"
colValid = colorFromHexString(brgbw, hexCol);
}
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;
}
2021-07-02 00:24:14 +02:00
if (!colValid) continue;
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
}
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 ));
if (!(elem[F("sel")].isNull() && elem["rev"].isNull() && elem["on"].isNull() && elem[F("mi")].isNull())) effectChanged = true; //send UDP
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)
2022-01-27 21:00:43 +01:00
if (!presetId && currentPlaylist>=0) unloadPlaylist();
strip.setMode(id, fx);
if (!presetId && seg.mode != fxPrev) effectChanged = true; //send UDP
2021-07-02 00:24:14 +02: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
2021-07-02 00:24:14 +02:00
JsonArray iarr = elem[F("i")]; //set individual LEDs
if (!iarr.isNull()) {
strip.setPixelSegment(id);
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);
}
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;
} else {
2021-07-02 00:24:14 +02:00
stop = iarr[i];
set = 2;
}
} else { //color
2021-07-02 00:24:14 +02:00
int rgbw[] = {0,0,0,0};
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];
}
}
2021-07-02 00:24:14 +02:00
if (set < 2) stop = start + 1;
for (uint16_t i = start; i < stop; i++) {
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]);
}
}
2021-07-02 00:24:14 +02:00
if (!set) start++;
set = 0;
}
}
2021-07-02 00:24:14 +02:00
strip.setPixelSegment(255);
strip.trigger();
} 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
}
return; // seg.differs(prev);
2019-11-30 19:17:25 +01:00
}
// deserializes WLED state (fileDoc points to doc object if called from web server)
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;
JSON in/decrementing (#2258) * Initial JSON in/decrementing * Segment brightness in/decrement * Update json-increment (#2290) * Add Basic Overlay support to Usermods. * Add seven segment overlay usermod * Add seven_seg debug build * Add scrolling message to seven seg um * Fixed red color on IP address * bh1750 * Add msg scroll. Add MQTT and Config support * Add readme * Restore platformio.inii * Edit comments * Add strip off refresh option in LED settings. (#2259) * Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <dev.aircoookie@gmail.com> * Exclude virtual busses from current calculation (#2262) * Refactor string usage * 0.13.0-b4 * Fix MQTT Null publish * Additional Flash string concat * Add AKST/AKDT * UM RGB-Rotary-Encoder: Properly used PinOwner * Cycling bugfix. Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com> * Working JSON preset cycle * Fix some Codacy style issues Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com>
2021-10-30 14:42:17 +02:00
getVal(root["bri"], &bri);
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
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-11-30 19:17:25 +01:00
transitionDelayTemp = tr;
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();
JsonObject nl = root["nl"];
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
JsonObject udpn = root["udpn"];
notifyDirect = udpn["send"] | notifyDirect;
receiveNotifications = udpn["recv"] | receiveNotifications;
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-09-20 01:18:31 +02:00
realtimeOverride = root[F("lor")] | realtimeOverride;
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
if (root.containsKey("live")) {
bool lv = root["live"];
if (lv) realtimeLock(65000); //enter realtime without timeout
else realtimeTimeout = 0; //cancel realtime mode immediately
}
byte prevMain = strip.getMainSegmentId();
2020-09-20 01:18:31 +02:00
strip.mainSegment = root[F("mainseg")] | prevMain;
//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
{
int id = segVar["id"] | -1;
//if "seg" is not an array and ID not specified, apply to all selected/checked segments
if (id < 0) {
//apply all selected segments
bool didSet = false;
byte lowestActive = 99;
for (byte s = 0; s < strip.getMaxSegments(); s++) {
WS2812FX::Segment &sg = strip.getSegment(s);
if (sg.isActive()) {
if (lowestActive == 99) lowestActive = s;
if (sg.isSelected()) {
2021-06-10 02:52:20 +02:00
deserializeSegment(segVar, s, presetId);
didSet = true;
}
2019-03-06 01:20:38 +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);
} 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
}
}
setValuesFromMainSeg(); //to make transition work on main segment
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
2020-05-28 02:20:02 +02:00
usermods.readFromJsonState(root);
loadLedmap = root[F("ledmap")] | loadLedmap;
JSON in/decrementing (#2258) * Initial JSON in/decrementing * Segment brightness in/decrement * Update json-increment (#2290) * Add Basic Overlay support to Usermods. * Add seven segment overlay usermod * Add seven_seg debug build * Add scrolling message to seven seg um * Fixed red color on IP address * bh1750 * Add msg scroll. Add MQTT and Config support * Add readme * Restore platformio.inii * Edit comments * Add strip off refresh option in LED settings. (#2259) * Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <dev.aircoookie@gmail.com> * Exclude virtual busses from current calculation (#2262) * Refactor string usage * 0.13.0-b4 * Fix MQTT Null publish * Additional Flash string concat * Add AKST/AKDT * UM RGB-Rotary-Encoder: Properly used PinOwner * Cycling bugfix. Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com> * Working JSON preset cycle * Fix some Codacy style issues Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com>
2021-10-30 14:42:17 +02:00
byte ps = root[F("psave")];
if (ps > 0) {
2020-10-08 00:52:15 +02:00
savePreset(ps, true, nullptr, root);
} else {
JSON in/decrementing (#2258) * Initial JSON in/decrementing * Segment brightness in/decrement * Update json-increment (#2290) * Add Basic Overlay support to Usermods. * Add seven segment overlay usermod * Add seven_seg debug build * Add scrolling message to seven seg um * Fixed red color on IP address * bh1750 * Add msg scroll. Add MQTT and Config support * Add readme * Restore platformio.inii * Edit comments * Add strip off refresh option in LED settings. (#2259) * Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <dev.aircoookie@gmail.com> * Exclude virtual busses from current calculation (#2262) * Refactor string usage * 0.13.0-b4 * Fix MQTT Null publish * Additional Flash string concat * Add AKST/AKDT * UM RGB-Rotary-Encoder: Properly used PinOwner * Cycling bugfix. Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com> * Working JSON preset cycle * Fix some Codacy style issues Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com>
2021-10-30 14:42:17 +02:00
ps = root[F("pdel")]; //deletion
if (ps > 0) {
deletePreset(ps);
}
JSON in/decrementing (#2258) * Initial JSON in/decrementing * Segment brightness in/decrement * Update json-increment (#2290) * Add Basic Overlay support to Usermods. * Add seven segment overlay usermod * Add seven_seg debug build * Add scrolling message to seven seg um * Fixed red color on IP address * bh1750 * Add msg scroll. Add MQTT and Config support * Add readme * Restore platformio.inii * Edit comments * Add strip off refresh option in LED settings. (#2259) * Add strip off refresh option in LED settings. New strip initialization logic. Minor code clen-up. * Dev code removal. * Missing ethernet include * Renamed mainseg to selseg * Fix for preset cycling bounds. * "Preset 0" bugfix. * Auto segments only if segments were not modified Co-authored-by: cschwinne <dev.aircoookie@gmail.com> * Exclude virtual busses from current calculation (#2262) * Refactor string usage * 0.13.0-b4 * Fix MQTT Null publish * Additional Flash string concat * Add AKST/AKDT * UM RGB-Rotary-Encoder: Properly used PinOwner * Cycling bugfix. Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com> * Working JSON preset cycle * Fix some Codacy style issues Co-authored-by: Gregory Schmidt <gregory.b.schmidt@hotmail.com> Co-authored-by: Blaž Kristan <blaz@kristan-sp.si> Co-authored-by: Caleb Mah <calebmah@gmail.com> Co-authored-by: ezcGman <ich@andy-hofmann.com>
2021-10-30 14:42:17 +02: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
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-11-11 23:48:14 +01:00
JsonObject playlist = root[F("playlist")];
if (!playlist.isNull() && loadPlaylist(playlist, presetId)) {
//do not notify here, because the first playlist entry will do
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 {
interfaceUpdateCallMode = CALL_MODE_WS_SEND;
2020-11-11 23:48:14 +01:00
}
colorUpdated(callMode);
2019-11-25 00:20:00 +01: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)
{
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;
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;
root["on"] = seg.getOption(SEG_OPTION_ON);
root["frz"] = seg.getOption(SEG_OPTION_FREEZE);
byte segbri = seg.opacity;
root["bri"] = (segbri) ? segbri : 255;
2021-11-28 04:01:58 +01:00
root["cct"] = seg.cct;
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
// 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++)
{
byte segcol[4]; byte* c = segcol;
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
{
c = (i == 0)? col:colSec;
} else {
segcol[0] = R(seg.colors[i]);
segcol[1] = G(seg.colors[i]);
segcol[2] = B(seg.colors[i]);
segcol[3] = W(seg.colors[i]);
}
char tmpcol[22];
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("]"));
root["col"] = serialized(colstr);
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);
}
2020-10-13 01:39:34 +02:00
void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segmentBounds)
{
2020-10-13 01:39:34 +02:00
if (includeBri) {
root["on"] = (bri > 0);
root["bri"] = briLast;
root[F("transition")] = transitionDelay/100; //in 100ms
}
2020-09-07 20:39:12 +02:00
if (!forPreset) {
if (errorFlag) {root[F("error")] = errorFlag; errorFlag = ERR_NONE;} //prevent error message to persist on screen
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;
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;
nl[F("dur")] = nightlightDelayMins;
nl[F("mode")] = nightlightMode;
nl[F("tbri")] = nightlightTargetBri;
if (nightlightActive) {
nl[F("rem")] = (nightlightDelayMs - (millis() - nightlightStartTime)) / 1000; // seconds remaining
} else {
nl[F("rem")] = -1;
}
2020-09-07 20:39:12 +02:00
JsonObject udpn = root.createNestedObject("udpn");
udpn["send"] = notifyDirect;
udpn["recv"] = receiveNotifications;
2019-12-01 01:42:52 +01:00
root[F("lor")] = realtimeOverride;
2020-09-07 20:39:12 +02:00
}
2020-09-20 01:18:31 +02:00
root[F("mainseg")] = strip.getMainSegmentId();
JsonArray seg = root.createNestedArray("seg");
for (byte s = 0; s < strip.getMaxSegments(); s++) {
WS2812FX::Segment &sg = strip.getSegment(s);
if (sg.isActive()) {
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-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;
}
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;
JsonObject leds = root.createNestedObject("leds");
leds[F("count")] = strip.getLengthTotal();
2021-03-29 02:28:34 +02:00
leds[F("rgbw")] = strip.isRgbw;
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;
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
2020-09-20 01:18:31 +02:00
root[F("str")] = syncToggleReceive;
2020-09-20 01:18:31 +02:00
root[F("name")] = serverDescription;
root[F("udpport")] = udpPort;
root["live"] = (bool)realtimeMode;
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;
}
if (realtimeIP[0] == 0)
{
2020-09-20 01:18:31 +02:00
root[F("lip")] = "";
} else {
2020-09-20 01:18:31 +02:00
root[F("lip")] = realtimeIP.toString();
}
#ifdef WLED_ENABLE_WEBSOCKETS
2020-09-20 01:18:31 +02:00
root[F("ws")] = ws.count();
#else
2020-09-20 01:18:31 +02:00
root[F("ws")] = -1;
#endif
2020-09-20 01:18:31 +02:00
root[F("fxcount")] = strip.getModeCount();
root[F("palcount")] = strip.getPaletteCount();
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();
JsonObject fs_info = root.createNestedObject("fs");
2020-10-07 17:48:22 +02:00
fs_info["u"] = fsBytesUsed / 1000;
fs_info["t"] = fsBytesTotal / 1000;
fs_info[F("pmt")] = presetsModifiedTime;
2021-03-09 16:23:19 +01:00
root[F("ndc")] = nodeListEnabled ? (int)Nodes.size() : -1;
2019-03-05 10:59:15 +01:00
#ifdef ARDUINO_ARCH_ESP32
#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();
#endif
2020-09-20 01:18:31 +02:00
root[F("arch")] = "esp32";
root[F("core")] = ESP.getSdkVersion();
//root[F("maxalloc")] = ESP.getMaxAllocHeap();
#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);
#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();
#ifdef WLED_DEBUG
2020-09-20 01:18:31 +02:00
root[F("resetReason")] = (int)ESP.getResetInfoPtr()->reason;
#endif
2020-09-20 01:18:31 +02:00
root[F("lwip")] = LWIP_VERSION_MAJOR;
2019-03-05 10:59:15 +01:00
#endif
2020-09-20 01:18:31 +02:00
root[F("freeheap")] = ESP.getFreeHeap();
#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);
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
#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;
2020-09-20 01:18:31 +02:00
root[F("brand")] = "WLED";
root[F("product")] = F("FOSS");
root["mac"] = escapedMac;
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
void setPaletteColors(JsonArray json, CRGBPalette16 palette)
{
for (int i = 0; i < 16; i++) {
JsonArray colors = json.createNestedArray();
CRGB color = palette[i];
colors.add(i<<4);
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
curPalette.add("c1");
break;
case 3: //primary + secondary
curPalette.add("c1");
curPalette.add("c1");
curPalette.add("c2");
curPalette.add("c2");
break;
case 4: //primary + secondary + tertiary
curPalette.add("c3");
curPalette.add("c2");
curPalette.add("c1");
break;
case 5: {//primary + secondary (+tert if not off), more distinct
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");
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;
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;
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;
else if (url.indexOf("si") > 0) subJson = 3;
2021-03-09 16:23:19 +01:00
else if (url.indexOf("nodes") > 0) subJson = 4;
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;
}
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;
}
else if (url.indexOf("pal") > 0) {
2019-03-06 01:20:38 +01:00
request->send_P(200, "application/json", JSON_palette_names);
return;
}
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
request->send( 501, "application/json", F("{\"error\":\"Not implemented\"}"));
2019-03-06 01:20:38 +01:00
return;
}
#ifdef WLED_USE_DYNAMIC_JSON
2020-09-20 01:18:31 +02:00
AsyncJsonResponse* response = new AsyncJsonResponse(JSON_BUFFER_SIZE);
#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
serializeState(lDoc); break;
2019-03-06 01:20:38 +01:00
case 2: //info
serializeInfo(lDoc); break;
2021-03-09 16:23:19 +01:00
case 4: //node list
serializeNodes(lDoc); break;
case 5: //palettes
serializePalettes(lDoc, request); break;
2019-03-06 01:20:38 +01:00
default: //all
JsonObject state = lDoc.createNestedObject("state");
2019-03-06 01:20:38 +01:00
serializeState(state);
JsonObject info = lDoc.createNestedObject("info");
2019-03-06 01:20:38 +01:00
serializeInfo(info);
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);
}
2019-03-06 01:20:38 +01:00
}
DEBUG_PRINT("JSON buffer size: ");
DEBUG_PRINTLN(lDoc.memoryUsage());
2019-03-05 10:59:15 +01:00
response->setLength();
request->send(response);
releaseJSONBufferLock();
2019-03-05 10:59:15 +01:00
}
2019-11-18 12:29:36 +01:00
#define MAX_LIVE_LEDS 180
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient)
2019-11-18 12:29:36 +01:00
{
#ifdef WLED_ENABLE_WEBSOCKETS
2021-01-16 21:40:04 +01:00
AsyncWebSocketClient * wsc = nullptr;
if (!request) { //not HTTP, use Websockets
wsc = ws.client(wsClient);
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
}
#endif
uint16_t used = strip.getLengthTotal();
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;
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
{
uint32_t c = strip.getPixelColor(i);
uint8_t r = qadd8(W(c), R(c)); //add white channel to RGB channels as a simple RGBW -> RGB map
uint8_t g = qadd8(W(c), G(c));
uint8_t b = qadd8(W(c), B(c));
olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0));
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("}");
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
}