2019-03-05 10:59:15 +01:00
|
|
|
/*
|
|
|
|
* JSON API (De)serialization
|
|
|
|
*/
|
|
|
|
|
2019-06-20 14:40:12 +02:00
|
|
|
bool deserializeState(JsonObject& root)
|
2019-03-05 10:59:15 +01:00
|
|
|
{
|
2019-06-20 14:40:12 +02:00
|
|
|
bool stateResponse = root["v"] | false;
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
if (root.containsKey("transition"))
|
|
|
|
{
|
|
|
|
transitionDelay = root["transition"];
|
|
|
|
transitionDelay *= 100;
|
|
|
|
}
|
|
|
|
|
2019-03-06 21:31:12 +01:00
|
|
|
int ps = root["ps"] | -1;
|
|
|
|
if (ps >= 0) applyPreset(ps);
|
|
|
|
|
|
|
|
int cy = root["pl"] | -1;
|
|
|
|
presetCyclingEnabled = (cy >= 0);
|
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
JsonObject& nl = root["nl"];
|
|
|
|
nightlightActive = nl["on"] | nightlightActive;
|
|
|
|
nightlightDelayMins = nl["dur"] | nightlightDelayMins;
|
|
|
|
nightlightFade = nl["fade"] | nightlightFade;
|
|
|
|
nightlightTargetBri = nl["tbri"] | nightlightTargetBri;
|
|
|
|
|
|
|
|
JsonObject& udpn = root["udpn"];
|
|
|
|
notifyDirect = udpn["send"] | notifyDirect;
|
|
|
|
receiveNotifications = udpn["recv"] | receiveNotifications;
|
|
|
|
bool noNotification = udpn["nn"]; //send no notification just for this request
|
|
|
|
|
2019-06-20 14:40:12 +02:00
|
|
|
int timein = root["time"] | -1;
|
|
|
|
if (timein != -1) setTime(timein);
|
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
int it = 0;
|
|
|
|
JsonArray& segs = root["seg"];
|
|
|
|
for (JsonObject& elem : segs)
|
|
|
|
{
|
|
|
|
byte id = elem["id"] | it;
|
|
|
|
if (id < strip.getMaxSegments())
|
|
|
|
{
|
|
|
|
WS2812FX::Segment& seg = strip.getSegment(id);
|
2019-06-20 14:40:12 +02:00
|
|
|
uint16_t start = elem["start"] | seg.start;
|
2019-03-06 01:20:38 +01:00
|
|
|
int stop = elem["stop"] | -1;
|
2019-03-05 10:59:15 +01:00
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
if (stop < 0) {
|
|
|
|
uint16_t len = elem["len"];
|
|
|
|
stop = (len > 0) ? start + len : seg.stop;
|
|
|
|
}
|
2019-06-20 14:40:12 +02:00
|
|
|
strip.setSegment(id, start, stop);
|
2019-03-06 01:20:38 +01:00
|
|
|
|
|
|
|
JsonArray& colarr = elem["col"];
|
|
|
|
if (colarr.success())
|
|
|
|
{
|
|
|
|
for (uint8_t i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
JsonArray& colX = colarr[i];
|
|
|
|
if (!colX.success()) break;
|
|
|
|
byte sz = colX.size();
|
|
|
|
if (sz > 0 && sz < 5)
|
|
|
|
{
|
|
|
|
int rgbw[] = {0,0,0,0};
|
|
|
|
byte cp = colX.copyTo(rgbw);
|
|
|
|
seg.colors[i] = ((rgbw[3] << 24) | ((rgbw[0]&0xFF) << 16) | ((rgbw[1]&0xFF) << 8) | ((rgbw[2]&0xFF)));
|
|
|
|
if (cp == 1 && rgbw[0] == 0) seg.colors[i] = 0;
|
2019-06-20 14:40:12 +02:00
|
|
|
if (id == 0) //temporary
|
|
|
|
{
|
|
|
|
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];}
|
|
|
|
}
|
2019-03-06 01:20:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
byte fx = elem["fx"] | seg.mode;
|
2019-06-20 14:40:12 +02:00
|
|
|
if (fx != seg.mode && fx < strip.getModeCount()) strip.setMode(id, fx);
|
2019-03-06 01:20:38 +01:00
|
|
|
seg.speed = elem["sx"] | seg.speed;
|
|
|
|
seg.intensity = elem["ix"] | seg.intensity;
|
2019-06-20 14:40:12 +02:00
|
|
|
seg.palette = elem["pal"] | seg.palette;
|
|
|
|
//if (pal != seg.palette && pal < strip.getPaletteCount()) strip.setPalette(pal);
|
|
|
|
seg.setOption(0, elem["sel"] | seg.getOption(0)); //selected
|
|
|
|
seg.setOption(1, elem["rev"] | seg.getOption(1)); //reverse
|
2019-03-06 01:20:38 +01:00
|
|
|
//int cln = seg_0["cln"];
|
|
|
|
//temporary
|
2019-06-20 14:40:12 +02:00
|
|
|
if (id == 0) {
|
|
|
|
effectCurrent = seg.mode;
|
|
|
|
effectSpeed = seg.speed;
|
|
|
|
effectIntensity = seg.intensity;
|
|
|
|
effectPalette = seg.palette;
|
|
|
|
}
|
2019-03-06 01:20:38 +01:00
|
|
|
}
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
colorUpdated(noNotification ? 5:1);
|
2019-06-20 14:40:12 +02:00
|
|
|
|
|
|
|
return stateResponse;
|
2019-03-06 01:20:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void serializeState(JsonObject& root)
|
|
|
|
{
|
|
|
|
root["on"] = (bri > 0);
|
|
|
|
root["bri"] = briLast;
|
|
|
|
root["transition"] = transitionDelay/100; //in 100ms
|
2019-03-06 21:31:12 +01:00
|
|
|
|
|
|
|
root["ps"] = -1; //
|
|
|
|
root["pl"] = (presetCyclingEnabled) ? 0: -1;
|
2019-03-05 10:59:15 +01:00
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
JsonObject& nl = root.createNestedObject("nl");
|
2019-03-05 10:59:15 +01:00
|
|
|
nl["on"] = nightlightActive;
|
|
|
|
nl["dur"] = nightlightDelayMins;
|
|
|
|
nl["fade"] = nightlightFade;
|
|
|
|
nl["tbri"] = nightlightTargetBri;
|
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
JsonObject& udpn = root.createNestedObject("udpn");
|
2019-03-05 10:59:15 +01:00
|
|
|
udpn["send"] = notifyDirect;
|
|
|
|
udpn["recv"] = receiveNotifications;
|
|
|
|
|
2019-03-06 01:20:38 +01: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())
|
|
|
|
{
|
|
|
|
JsonObject& seg0 = seg.createNestedObject();
|
|
|
|
serializeSegment(seg0, sg, s);
|
|
|
|
}
|
|
|
|
}
|
2019-03-05 10:59:15 +01:00
|
|
|
}
|
|
|
|
|
2019-06-20 14:40:12 +02:00
|
|
|
void serializeSegment(JsonObject& root, WS2812FX::Segment& seg, byte id)
|
2019-03-05 10:59:15 +01:00
|
|
|
{
|
2019-06-20 14:40:12 +02:00
|
|
|
root["id"] = id;
|
2019-03-05 10:59:15 +01:00
|
|
|
root["start"] = seg.start;
|
|
|
|
root["stop"] = seg.stop;
|
|
|
|
root["len"] = seg.stop - seg.start;
|
|
|
|
|
|
|
|
JsonArray& colarr = root.createNestedArray("col");
|
|
|
|
|
2019-05-22 00:23:09 +02:00
|
|
|
for (uint8_t i = 0; i < 3; i++)
|
2019-03-05 10:59:15 +01:00
|
|
|
{
|
|
|
|
JsonArray& colX = colarr.createNestedArray();
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
root["fx"] = seg.mode;
|
|
|
|
root["sx"] = seg.speed;
|
|
|
|
root["ix"] = seg.intensity;
|
|
|
|
root["pal"] = seg.palette;
|
2019-06-20 14:40:12 +02:00
|
|
|
root["sel"] = seg.isSelected();
|
2019-03-06 01:20:38 +01:00
|
|
|
root["rev"] = seg.getOption(1);
|
2019-03-05 10:59:15 +01:00
|
|
|
root["cln"] = -1;
|
|
|
|
}
|
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
void serializeInfo(JsonObject& root)
|
2019-03-05 10:59:15 +01:00
|
|
|
{
|
2019-03-06 01:20:38 +01:00
|
|
|
root["ver"] = versionString;
|
|
|
|
root["vid"] = VERSION;
|
2019-03-05 10:59:15 +01:00
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
JsonObject& leds = root.createNestedObject("leds");
|
2019-03-05 10:59:15 +01:00
|
|
|
leds["count"] = ledCount;
|
|
|
|
leds["rgbw"] = useRGBW;
|
|
|
|
JsonArray& leds_pin = leds.createNestedArray("pin");
|
|
|
|
leds_pin.add(LEDPIN);
|
|
|
|
|
|
|
|
leds["pwr"] = strip.currentMilliamps;
|
|
|
|
leds["maxpwr"] = strip.ablMilliampsMax;
|
2019-03-06 01:20:38 +01:00
|
|
|
leds["maxseg"] = strip.getMaxSegments();
|
|
|
|
|
|
|
|
root["name"] = serverDescription;
|
|
|
|
root["udpport"] = udpPort;
|
|
|
|
root["live"] = realtimeActive;
|
|
|
|
root["fxcount"] = strip.getModeCount();
|
|
|
|
root["palcount"] = strip.getPaletteCount();
|
2019-03-05 10:59:15 +01:00
|
|
|
#ifdef ARDUINO_ARCH_ESP32
|
2019-03-06 01:20:38 +01:00
|
|
|
root["arch"] = "esp32";
|
|
|
|
root["core"] = ESP.getSdkVersion();
|
|
|
|
//root["maxalloc"] = ESP.getMaxAllocHeap();
|
2019-03-05 10:59:15 +01:00
|
|
|
#else
|
2019-03-06 01:20:38 +01:00
|
|
|
root["arch"] = "esp8266";
|
|
|
|
root["core"] = ESP.getCoreVersion();
|
|
|
|
//root["maxalloc"] = ESP.getMaxFreeBlockSize();
|
2019-03-05 10:59:15 +01:00
|
|
|
#endif
|
2019-03-06 01:20:38 +01:00
|
|
|
root["freeheap"] = ESP.getFreeHeap();
|
|
|
|
root["uptime"] = millis()/1000;
|
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
|
|
|
|
#ifndef WLED_DISABLE_MOBILE_UI
|
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
|
2019-03-06 01:20:38 +01:00
|
|
|
root["opt"] = os;
|
|
|
|
|
|
|
|
root["brand"] = "WLED";
|
|
|
|
root["product"] = "DIY light";
|
2019-05-22 00:23:09 +02:00
|
|
|
root["btype"] = "dev";
|
2019-03-06 01:20:38 +01:00
|
|
|
root["mac"] = escapedMac;
|
|
|
|
}
|
|
|
|
|
|
|
|
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("eff") > 0) {
|
|
|
|
request->send_P(200, "application/json", JSON_mode_names);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (url.indexOf("pal") > 0) {
|
|
|
|
request->send_P(200, "application/json", JSON_palette_names);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (url.length() > 6) { //not just /json
|
2019-03-06 21:31:12 +01:00
|
|
|
request->send( 501, "application/json", "{\"error\":\"Not implemented\"}");
|
2019-03-06 01:20:38 +01:00
|
|
|
return;
|
|
|
|
}
|
2019-03-05 10:59:15 +01:00
|
|
|
|
2019-03-06 01:20:38 +01:00
|
|
|
AsyncJsonResponse* response = new AsyncJsonResponse();
|
|
|
|
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
|
|
|
|
JsonObject& state = doc.createNestedObject("state");
|
|
|
|
serializeState(state);
|
|
|
|
JsonObject& info = doc.createNestedObject("info");
|
|
|
|
serializeInfo(info);
|
2019-03-11 17:57:06 +01:00
|
|
|
doc["effects"] = RawJson(String(JSON_mode_names));
|
|
|
|
doc["palettes"] = RawJson(String(JSON_palette_names));
|
2019-03-06 01:20:38 +01:00
|
|
|
}
|
|
|
|
|
2019-03-05 10:59:15 +01:00
|
|
|
response->setLength();
|
|
|
|
request->send(response);
|
|
|
|
}
|