2020-03-25 09:00:55 +01:00
|
|
|
#include "wled.h"
|
2020-03-31 02:38:08 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* JSON API (De)serialization
|
|
|
|
*/
|
2019-03-05 10:59:15 +01:00
|
|
|
|
2019-11-30 19:17:25 +01:00
|
|
|
void deserializeSegment(JsonObject elem, byte it)
|
|
|
|
{
|
2020-09-20 01:18:31 +02:00
|
|
|
byte id = elem[F("id")] | it;
|
2019-11-30 19:17:25 +01:00
|
|
|
if (id < strip.getMaxSegments())
|
|
|
|
{
|
|
|
|
WS2812FX::Segment& seg = strip.getSegment(id);
|
2020-09-20 01:18:31 +02:00
|
|
|
uint16_t start = elem[F("start")] | seg.start;
|
2020-11-08 23:44:10 +01:00
|
|
|
int stop = elem["stop"] | -1;
|
2019-11-30 19:17:25 +01:00
|
|
|
|
2020-01-14 10:57:23 +01:00
|
|
|
if (stop < 0) {
|
2020-09-20 01:18:31 +02:00
|
|
|
uint16_t len = elem[F("len")];
|
2020-01-14 10:57:23 +01:00
|
|
|
stop = (len > 0) ? start + len : seg.stop;
|
|
|
|
}
|
2020-09-20 01:18:31 +02:00
|
|
|
uint16_t grp = elem[F("grp")] | seg.grouping;
|
|
|
|
uint16_t spc = elem[F("spc")] | seg.spacing;
|
2020-01-14 10:57:23 +01:00
|
|
|
strip.setSegment(id, start, stop, grp, spc);
|
2020-04-23 23:52:33 +02:00
|
|
|
|
|
|
|
int segbri = elem["bri"] | -1;
|
|
|
|
if (segbri == 0) {
|
|
|
|
seg.setOption(SEG_OPTION_ON, 0);
|
|
|
|
} else if (segbri > 0) {
|
|
|
|
seg.opacity = segbri;
|
|
|
|
seg.setOption(SEG_OPTION_ON, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
seg.setOption(SEG_OPTION_ON, elem["on"] | seg.getOption(SEG_OPTION_ON));
|
2019-11-30 19:17:25 +01:00
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
JsonArray colarr = elem[F("col")];
|
2019-11-30 19:17:25 +01:00
|
|
|
if (!colarr.isNull())
|
|
|
|
{
|
|
|
|
for (uint8_t i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
JsonArray colX = colarr[i];
|
|
|
|
if (colX.isNull()) break;
|
|
|
|
byte sz = colX.size();
|
|
|
|
if (sz > 0 && sz < 5)
|
|
|
|
{
|
|
|
|
int rgbw[] = {0,0,0,0};
|
|
|
|
byte cp = copyArray(colX, rgbw);
|
2020-03-14 11:28:42 +01:00
|
|
|
|
2020-09-27 11:43:28 +02:00
|
|
|
if (cp == 1) {
|
|
|
|
if (rgbw[0] == 0) seg.colors[i] = 0;
|
|
|
|
else {
|
|
|
|
byte ctrgb[] = {0,0,0,0};
|
|
|
|
colorKtoRGB(rgbw[0], ctrgb);
|
|
|
|
for (uint8_t c = 0; c < 3; c++) rgbw[c] = ctrgb[c];
|
|
|
|
}
|
|
|
|
}
|
2020-03-14 11:28:42 +01:00
|
|
|
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
2019-11-30 19:17:25 +01:00
|
|
|
{
|
|
|
|
if (i == 0) {col[0] = rgbw[0]; col[1] = rgbw[1]; col[2] = rgbw[2]; col[3] = rgbw[3];}
|
|
|
|
if (i == 1) {colSec[0] = rgbw[0]; colSec[1] = rgbw[1]; colSec[2] = rgbw[2]; colSec[3] = rgbw[3];}
|
2020-03-14 11:28:42 +01:00
|
|
|
} else {
|
|
|
|
seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
|
2019-11-30 19:17:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-09-27 11:37:16 +02:00
|
|
|
|
|
|
|
// lx parser
|
2020-09-27 11:43:28 +02:00
|
|
|
#ifdef WLED_ENABLE_LOXONE
|
2020-09-27 11:37:16 +02:00
|
|
|
int lx = elem[F("lx")] | -1;
|
|
|
|
if (lx > 0) {
|
2020-09-27 11:43:28 +02:00
|
|
|
parseLxJson(lx, id, false);
|
2020-09-27 11:37:16 +02:00
|
|
|
}
|
|
|
|
int ly = elem[F("ly")] | -1;
|
|
|
|
if (ly > 0) {
|
2020-09-27 11:43:28 +02:00
|
|
|
parseLxJson(ly, id, true);
|
2020-09-27 11:37:16 +02:00
|
|
|
}
|
2020-09-27 11:43:28 +02:00
|
|
|
#endif
|
2019-11-30 19:17:25 +01:00
|
|
|
|
|
|
|
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
|
2020-09-20 01:18:31 +02:00
|
|
|
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
|
|
|
|
seg.setOption(SEG_OPTION_REVERSED, elem[F("rev")] | seg.getOption(SEG_OPTION_REVERSED));
|
|
|
|
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
|
2020-04-23 23:52:33 +02:00
|
|
|
|
2019-11-30 19:17:25 +01:00
|
|
|
//temporary, strip object gets updated via colorUpdated()
|
2019-12-01 01:42:52 +01:00
|
|
|
if (id == strip.getMainSegmentId()) {
|
2020-09-20 01:18:31 +02:00
|
|
|
effectCurrent = elem[F("fx")] | effectCurrent;
|
|
|
|
effectSpeed = elem[F("sx")] | effectSpeed;
|
|
|
|
effectIntensity = elem[F("ix")] | effectIntensity;
|
|
|
|
effectPalette = elem[F("pal")] | effectPalette;
|
2019-11-30 19:17:25 +01:00
|
|
|
} else { //permanent
|
2020-09-20 01:18:31 +02:00
|
|
|
byte fx = elem[F("fx")] | seg.mode;
|
2019-11-30 19:17:25 +01:00
|
|
|
if (fx != seg.mode && fx < strip.getModeCount()) strip.setMode(id, fx);
|
2020-09-20 01:18:31 +02:00
|
|
|
seg.speed = elem[F("sx")] | seg.speed;
|
|
|
|
seg.intensity = elem[F("ix")] | seg.intensity;
|
|
|
|
seg.palette = elem[F("pal")] | seg.palette;
|
2019-11-30 19:17:25 +01:00
|
|
|
}
|
2020-08-29 22:26:39 +02:00
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
JsonArray iarr = elem[F("i")]; //set individual LEDs
|
2020-08-29 22:26:39 +02:00
|
|
|
if (!iarr.isNull()) {
|
|
|
|
strip.setPixelSegment(id);
|
|
|
|
|
|
|
|
//freeze and init to black
|
|
|
|
if (!seg.getOption(SEG_OPTION_FREEZE)) {
|
|
|
|
seg.setOption(SEG_OPTION_FREEZE, true);
|
|
|
|
strip.fill(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
stop = iarr[i];
|
|
|
|
set = 2;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
JsonArray icol = iarr[i];
|
|
|
|
if (icol.isNull()) break;
|
|
|
|
|
|
|
|
byte sz = icol.size();
|
|
|
|
if (sz == 0 && sz > 4) break;
|
|
|
|
|
|
|
|
int rgbw[] = {0,0,0,0};
|
|
|
|
byte cp = copyArray(icol, rgbw);
|
|
|
|
|
|
|
|
if (set < 2) stop = start + 1;
|
|
|
|
for (uint16_t i = start; i < stop; i++) {
|
|
|
|
strip.setPixelColor(i, rgbw[0], rgbw[1], rgbw[2], rgbw[3]);
|
|
|
|
}
|
|
|
|
if (!set) start++;
|
|
|
|
set = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strip.setPixelSegment(255);
|
|
|
|
strip.trigger();
|
|
|
|
} else { //return to regular effect
|
|
|
|
seg.setOption(SEG_OPTION_FREEZE, false);
|
|
|
|
}
|
|
|
|
|
2019-11-30 19:17:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-21 23:12:58 +02:00
|
|
|
bool deserializeState(JsonObject root)
|
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;
|
2019-06-20 14:40:12 +02:00
|
|
|
|
2019-03-11 00:20:17 +01:00
|
|
|
bri = root["bri"] | bri;
|
2019-03-06 21:31:12 +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
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
int tr = root[F("transition")] | -1;
|
2019-11-30 19:17:25 +01:00
|
|
|
if (tr >= 0)
|
2019-03-06 01:20:38 +01:00
|
|
|
{
|
2019-11-30 19:17:25 +01:00
|
|
|
transitionDelay = tr;
|
2019-03-06 01:20:38 +01:00
|
|
|
transitionDelay *= 100;
|
|
|
|
}
|
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;
|
|
|
|
}
|
2019-03-06 21:31:12 +01:00
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
int cy = root[F("pl")] | -2;
|
2019-12-18 00:47:24 +01:00
|
|
|
if (cy > -2) presetCyclingEnabled = (cy >= 0);
|
2020-11-08 23:44:10 +01:00
|
|
|
JsonObject ccnf = root["ccnf"];
|
2020-09-20 01:18:31 +02:00
|
|
|
presetCycleMin = ccnf[F("min")] | presetCycleMin;
|
|
|
|
presetCycleMax = ccnf[F("max")] | presetCycleMax;
|
|
|
|
tr = ccnf[F("time")] | -1;
|
2020-05-18 16:36:31 +02:00
|
|
|
if (tr >= 2) presetCycleTime = tr;
|
2019-03-06 21:31:12 +01:00
|
|
|
|
2020-11-07 23:54:56 +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("fade")] | nightlightMode; //deprecated
|
|
|
|
nightlightMode = nl[F("mode")] | nightlightMode;
|
|
|
|
nightlightTargetBri = nl[F("tbri")] | nightlightTargetBri;
|
2019-03-06 01:20:38 +01:00
|
|
|
|
2020-11-08 23:44:10 +01:00
|
|
|
JsonObject udpn = root["udpn"];
|
2020-09-20 01:18:31 +02:00
|
|
|
notifyDirect = udpn[F("send")] | notifyDirect;
|
|
|
|
receiveNotifications = udpn[F("recv")] | receiveNotifications;
|
|
|
|
bool noNotification = udpn[F("nn")]; //send no notification just for this request
|
2019-03-06 01:20:38 +01:00
|
|
|
|
2020-11-15 12:41:51 +01:00
|
|
|
unsigned long timein = root[F("time")] | -1;
|
|
|
|
if (timein != -1) {
|
|
|
|
if (millis() - ntpLastSyncTime > 50000000L) setTime(timein);
|
|
|
|
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
|
|
|
|
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;
|
2019-12-04 02:01:47 +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
|
|
|
{
|
2020-09-20 01:18:31 +02:00
|
|
|
int id = segVar[F("id")] | -1;
|
2019-12-13 01:23:07 +01:00
|
|
|
|
2019-11-30 19:17:25 +01:00
|
|
|
if (id < 0) { //set all selected segments
|
2019-12-13 01:23:07 +01:00
|
|
|
bool didSet = false;
|
|
|
|
byte lowestActive = 99;
|
2019-11-30 19:17:25 +01:00
|
|
|
for (byte s = 0; s < strip.getMaxSegments(); s++)
|
2019-03-06 01:20:38 +01:00
|
|
|
{
|
2019-11-30 19:17:25 +01:00
|
|
|
WS2812FX::Segment sg = strip.getSegment(s);
|
2019-12-13 01:23:07 +01:00
|
|
|
if (sg.isActive())
|
2019-03-06 01:20:38 +01:00
|
|
|
{
|
2019-12-13 01:23:07 +01:00
|
|
|
if (lowestActive == 99) lowestActive = s;
|
|
|
|
if (sg.isSelected()) {
|
|
|
|
deserializeSegment(segVar, s);
|
|
|
|
didSet = true;
|
|
|
|
}
|
2019-03-06 01:20:38 +01:00
|
|
|
}
|
|
|
|
}
|
2019-12-13 01:23:07 +01:00
|
|
|
if (!didSet && lowestActive < strip.getMaxSegments()) deserializeSegment(segVar, lowestActive);
|
2019-11-30 19:17:25 +01:00
|
|
|
} else { //set only the segment with the specified ID
|
|
|
|
deserializeSegment(segVar, it);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
JsonArray segs = segVar.as<JsonArray>();
|
|
|
|
for (JsonObject elem : segs)
|
|
|
|
{
|
|
|
|
deserializeSegment(elem, it);
|
|
|
|
it++;
|
2019-03-06 01:20:38 +01:00
|
|
|
}
|
|
|
|
}
|
2019-11-30 19:17:25 +01:00
|
|
|
|
2020-05-28 02:20:02 +02:00
|
|
|
usermods.readFromJsonState(root);
|
|
|
|
|
2020-10-08 00:52:15 +02:00
|
|
|
int ps = root[F("psave")] | -1;
|
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 {
|
|
|
|
ps = root[F("pdel")] | -1; //deletion
|
|
|
|
if (ps > 0) {
|
|
|
|
deletePreset(ps);
|
|
|
|
}
|
2020-11-09 00:50:13 +01:00
|
|
|
ps = root["ps"] | -1; //load preset (clears state request!)
|
2020-11-08 23:44:10 +01:00
|
|
|
if (ps >= 0) {applyPreset(ps); 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")];
|
|
|
|
if (!playlist.isNull()) {
|
|
|
|
loadPlaylist(playlist); return stateResponse;
|
|
|
|
}
|
2020-03-03 17:53:47 +01:00
|
|
|
|
2020-11-08 23:44:10 +01:00
|
|
|
colorUpdated(noNotification ? NOTIFIER_CALL_MODE_NO_NOTIFY : NOTIFIER_CALL_MODE_DIRECT_CHANGE);
|
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
|
|
|
{
|
2020-09-20 01:18:31 +02:00
|
|
|
root[F("id")] = id;
|
2020-10-23 17:48:01 +02:00
|
|
|
if (segmentBounds) {
|
|
|
|
root[F("start")] = seg.start;
|
2020-11-08 23:44:10 +01:00
|
|
|
root["stop"] = seg.stop;
|
2020-10-23 17:48:01 +02:00
|
|
|
}
|
2020-09-21 19:48:12 +02:00
|
|
|
if (!forPreset) root[F("len")] = seg.stop - seg.start;
|
2020-09-20 01:18:31 +02:00
|
|
|
root[F("grp")] = seg.grouping;
|
|
|
|
root[F("spc")] = seg.spacing;
|
2020-04-23 23:52:33 +02:00
|
|
|
root["on"] = seg.getOption(SEG_OPTION_ON);
|
|
|
|
byte segbri = seg.opacity;
|
|
|
|
root["bri"] = (segbri) ? segbri : 255;
|
2019-07-23 17:35:40 +02:00
|
|
|
|
|
|
|
JsonArray colarr = root.createNestedArray("col");
|
2020-03-14 11:28:42 +01:00
|
|
|
|
2019-07-23 17:35:40 +02:00
|
|
|
for (uint8_t i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
JsonArray colX = colarr.createNestedArray();
|
2020-03-14 11:28:42 +01:00
|
|
|
if (id == strip.getMainSegmentId() && i < 2) //temporary, to make transition work on main segment
|
|
|
|
{
|
|
|
|
if (i == 0) {
|
|
|
|
colX.add(col[0]); colX.add(col[1]); colX.add(col[2]); if (useRGBW) colX.add(col[3]);
|
|
|
|
} else {
|
|
|
|
colX.add(colSec[0]); colX.add(colSec[1]); colX.add(colSec[2]); if (useRGBW) colX.add(colSec[3]);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
colX.add((seg.colors[i] >> 16) & 0xFF);
|
|
|
|
colX.add((seg.colors[i] >> 8) & 0xFF);
|
|
|
|
colX.add((seg.colors[i]) & 0xFF);
|
|
|
|
if (useRGBW)
|
|
|
|
colX.add((seg.colors[i] >> 24) & 0xFF);
|
|
|
|
}
|
2019-07-23 17:35:40 +02:00
|
|
|
}
|
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
root[F("fx")] = seg.mode;
|
|
|
|
root[F("sx")] = seg.speed;
|
|
|
|
root[F("ix")] = seg.intensity;
|
|
|
|
root[F("pal")] = seg.palette;
|
|
|
|
root[F("sel")] = seg.isSelected();
|
|
|
|
root[F("rev")] = seg.getOption(SEG_OPTION_REVERSED);
|
|
|
|
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)
|
2020-09-07 20:39:12 +02: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) {
|
2020-10-13 01:39:34 +02:00
|
|
|
if (errorFlag) root[F("error")] = errorFlag;
|
2020-09-21 19:48:12 +02:00
|
|
|
|
|
|
|
root[F("ps")] = currentPreset;
|
|
|
|
root[F("pss")] = savedPresets;
|
|
|
|
root[F("pl")] = (presetCyclingEnabled) ? 0: -1;
|
|
|
|
|
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
|
|
|
//temporary for preset cycle
|
|
|
|
JsonObject ccnf = root.createNestedObject("ccnf");
|
2020-09-21 19:48:12 +02:00
|
|
|
ccnf[F("min")] = presetCycleMin;
|
|
|
|
ccnf[F("max")] = presetCycleMax;
|
|
|
|
ccnf[F("time")] = presetCycleTime;
|
|
|
|
|
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("fade")] = (nightlightMode > NL_MODE_SET); //deprecated
|
|
|
|
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");
|
2020-09-21 19:48:12 +02:00
|
|
|
udpn[F("send")] = notifyDirect;
|
|
|
|
udpn[F("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");
|
2019-06-20 14:40:12 +02: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;
|
2019-03-05 10:59:15 +01:00
|
|
|
|
2019-06-21 23:12:58 +02:00
|
|
|
JsonObject leds = root.createNestedObject("leds");
|
2020-09-20 01:18:31 +02:00
|
|
|
leds[F("count")] = ledCount;
|
|
|
|
leds[F("rgbw")] = useRGBW;
|
|
|
|
leds[F("wv")] = useRGBW && (strip.rgbwMode == RGBW_MODE_MANUAL_ONLY || strip.rgbwMode == RGBW_MODE_DUAL); //should a white channel slider be displayed?
|
2019-06-21 23:12:58 +02:00
|
|
|
JsonArray leds_pin = leds.createNestedArray("pin");
|
2019-03-05 10:59:15 +01:00
|
|
|
leds_pin.add(LEDPIN);
|
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
leds[F("pwr")] = strip.currentMilliamps;
|
|
|
|
leds[F("maxpwr")] = (strip.currentMilliamps)? strip.ablMilliampsMax : 0;
|
|
|
|
leds[F("maxseg")] = strip.getMaxSegments();
|
|
|
|
leds[F("seglock")] = false; //will 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;
|
2019-03-06 01:20:38 +01:00
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
root[F("name")] = serverDescription;
|
|
|
|
root[F("udpport")] = udpPort;
|
|
|
|
root[F("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;
|
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
|
2020-09-20 01:18:31 +02:00
|
|
|
root[F("lwip")] = 0;
|
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
|
2019-10-29 02:21:23 +01:00
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
root[F("freeheap")] = ESP.getFreeHeap();
|
|
|
|
root[F("uptime")] = millis()/1000 + rolloverMillis*4294967;
|
2020-05-28 02:20:02 +02:00
|
|
|
|
2020-09-21 19:48:12 +02:00
|
|
|
|
2020-05-28 02:20:02 +02:00
|
|
|
usermods.addToJsonInfo(root);
|
2019-03-05 10:59:15 +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
|
|
|
|
#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;
|
2019-03-06 01:20:38 +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;
|
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;
|
2020-04-30 01:52:36 +02:00
|
|
|
else if (url.indexOf("si") > 0) subJson = 3;
|
2019-11-18 12:29:36 +01:00
|
|
|
else if (url.indexOf("live") > 0) {
|
|
|
|
serveLiveLeds(request);
|
|
|
|
return;
|
|
|
|
}
|
2020-09-20 01:18:31 +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;
|
|
|
|
}
|
2020-09-20 01:18:31 +02:00
|
|
|
else if (url.indexOf(F("pal")) > 0) {
|
2019-03-06 01:20:38 +01:00
|
|
|
request->send_P(200, "application/json", JSON_palette_names);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
2019-03-05 10:59:15 +01:00
|
|
|
|
2020-09-20 01:18:31 +02:00
|
|
|
AsyncJsonResponse* response = new AsyncJsonResponse(JSON_BUFFER_SIZE);
|
2019-06-21 23:12:58 +02:00
|
|
|
JsonObject doc = response->getRoot();
|
2019-03-05 10:59:15 +01:00
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
switch (subJson)
|
|
|
|
{
|
|
|
|
case 1: //state
|
|
|
|
serializeState(doc); break;
|
|
|
|
case 2: //info
|
|
|
|
serializeInfo(doc); break;
|
|
|
|
default: //all
|
2019-06-21 23:12:58 +02:00
|
|
|
JsonObject state = doc.createNestedObject("state");
|
2019-03-06 01:20:38 +01:00
|
|
|
serializeState(state);
|
2019-06-21 23:12:58 +02:00
|
|
|
JsonObject info = doc.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
|
|
|
}
|
|
|
|
|
2019-03-05 10:59:15 +01:00
|
|
|
response->setLength();
|
|
|
|
request->send(response);
|
|
|
|
}
|
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
|
|
|
{
|
2020-06-26 17:28:35 +02:00
|
|
|
AsyncWebSocketClient * wsc;
|
|
|
|
if (!request) { //not HTTP, use Websockets
|
|
|
|
#ifdef WLED_ENABLE_WEBSOCKETS
|
|
|
|
wsc = ws.client(wsClient);
|
|
|
|
if (!wsc || wsc->queueLength() > 0) return false; //only send if queue free
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2020-03-26 01:44:38 +01:00
|
|
|
uint16_t used = ledCount;
|
|
|
|
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-06-26 17:28:35 +02:00
|
|
|
olen += sprintf(obuf + olen, "\"%06X\",", strip.getPixelColor(i));
|
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
|
|
|
}
|