WLED/wled00/set.cpp

892 lines
30 KiB
C++
Raw Normal View History

2020-04-10 12:30:08 +02:00
#include "wled.h"
/*
* Receives client input
*/
2018-09-17 11:15:08 +02:00
//called upon POST settings form submit
2019-02-16 00:21:22 +01:00
void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
{
//0: menu 1: wifi 2: leds 3: ui 4: sync 5: time 6: sec 7: DMX 8: usermods
if (subPage <1 || subPage >8) return;
2019-08-17 12:27:06 +02:00
2018-02-20 22:29:48 +01:00
//WIFI SETTINGS
if (subPage == 1)
{
2020-09-20 01:18:31 +02:00
strlcpy(clientSSID,request->arg(F("CS")).c_str(), 33);
2020-09-20 01:18:31 +02:00
if (!isAsterisksOnly(request->arg(F("CP")).c_str(), 65)) strlcpy(clientPass, request->arg(F("CP")).c_str(), 65);
2018-09-17 11:15:08 +02:00
2020-09-20 01:18:31 +02:00
strlcpy(cmDNS, request->arg(F("CM")).c_str(), 33);
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
apBehavior = request->arg(F("AB")).toInt();
strlcpy(apSSID, request->arg(F("AS")).c_str(), 33);
apHide = request->hasArg(F("AH"));
int passlen = request->arg(F("AP")).length();
if (passlen == 0 || (passlen > 7 && !isAsterisksOnly(request->arg(F("AP")).c_str(), 65))) strlcpy(apPass, request->arg(F("AP")).c_str(), 65);
int t = request->arg(F("AC")).toInt(); if (t > 0 && t < 14) apChannel = t;
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
noWifiSleep = request->hasArg(F("WS"));
#ifdef WLED_USE_ETHERNET
ethernetType = request->arg(F("ETH")).toInt();
WLED::instance().initEthernet();
#endif
2018-09-17 11:15:08 +02:00
char k[3]; k[2] = 0;
2018-07-21 23:21:07 +02:00
for (int i = 0; i<4; i++)
{
2018-09-17 11:15:08 +02:00
k[1] = i+48;//ascii 0,1,2,3
2019-08-17 12:27:06 +02:00
2018-07-21 23:21:07 +02:00
k[0] = 'I'; //static IP
2019-02-16 00:21:22 +01:00
staticIP[i] = request->arg(k).toInt();
2019-08-17 12:27:06 +02:00
2018-07-21 23:21:07 +02:00
k[0] = 'G'; //gateway
2019-02-16 00:21:22 +01:00
staticGateway[i] = request->arg(k).toInt();
2019-08-17 12:27:06 +02:00
2018-07-21 23:21:07 +02:00
k[0] = 'S'; //subnet
2019-02-16 00:21:22 +01:00
staticSubnet[i] = request->arg(k).toInt();
2016-11-27 16:45:54 +01:00
}
}
2018-02-20 22:29:48 +01:00
//LED SETTINGS
if (subPage == 2)
{
int t = 0;
if (rlyPin>=0 && pinManager.isPinAllocated(rlyPin, PinOwner::Relay)) {
pinManager.deallocatePin(rlyPin, PinOwner::Relay);
}
if (irPin>=0 && pinManager.isPinAllocated(irPin, PinOwner::IR)) {
pinManager.deallocatePin(irPin, PinOwner::IR);
}
for (uint8_t s=0; s<WLED_MAX_BUTTONS; s++) {
if (btnPin[s]>=0 && pinManager.isPinAllocated(btnPin[s], PinOwner::Button)) {
pinManager.deallocatePin(btnPin[s], PinOwner::Button);
}
}
2021-01-17 00:20:31 +01:00
2021-12-02 13:09:53 +01:00
uint8_t colorOrder, type, skip;
2021-01-26 00:19:41 +01:00
uint16_t length, start;
2021-02-24 20:23:32 +01:00
uint8_t pins[5] = {255, 255, 255, 255, 255};
2021-09-11 01:17:42 +02:00
autoSegments = request->hasArg(F("MS"));
correctWB = request->hasArg(F("CCT"));
2021-11-26 20:18:38 +01:00
cctFromRgb = request->hasArg(F("CR"));
2021-11-27 16:49:42 +01:00
strip.cctBlending = request->arg(F("CB")).toInt();
Bus::setCCTBlend(strip.cctBlending);
Bus::setAutoWhiteMode(request->arg(F("AW")).toInt());
strip.setTargetFps(request->arg(F("FR")).toInt());
2021-09-11 01:17:42 +02:00
2021-01-30 20:51:36 +01:00
for (uint8_t s = 0; s < WLED_MAX_BUSSES; s++) {
char lp[4] = "L0"; lp[2] = 48+s; lp[3] = 0; //ascii 0-9 //strip data pin
char lc[4] = "LC"; lc[2] = 48+s; lc[3] = 0; //strip length
char co[4] = "CO"; co[2] = 48+s; co[3] = 0; //strip color order
char lt[4] = "LT"; lt[2] = 48+s; lt[3] = 0; //strip type
char ls[4] = "LS"; ls[2] = 48+s; ls[3] = 0; //strip start LED
char cv[4] = "CV"; cv[2] = 48+s; cv[3] = 0; //strip reverse
char sl[4] = "SL"; sl[2] = 48+s; sl[3] = 0; //skip 1st LED
2021-10-07 22:57:07 +02:00
char rf[4] = "RF"; rf[2] = 48+s; rf[3] = 0; //refresh required
2021-01-30 20:51:36 +01:00
if (!request->hasArg(lp)) {
2021-04-01 12:53:01 +02:00
DEBUG_PRINTLN(F("No data.")); break;
2021-01-17 00:20:31 +01:00
}
for (uint8_t i = 0; i < 5; i++) {
lp[1] = 48+i;
if (!request->hasArg(lp)) break;
pins[i] = (request->arg(lp).length() > 0) ? request->arg(lp).toInt() : 255;
2021-01-30 20:51:36 +01:00
}
type = request->arg(lt).toInt();
2021-10-07 22:57:07 +02:00
type |= request->hasArg(rf) << 7; // off refresh override
skip = request->hasArg(sl) ? LED_SKIP_AMOUNT : 0;
colorOrder = request->arg(co).toInt();
start = (request->hasArg(ls)) ? request->arg(ls).toInt() : t;
2021-01-30 20:51:36 +01:00
if (request->hasArg(lc) && request->arg(lc).toInt() > 0) {
t += length = request->arg(lc).toInt();
2021-01-30 20:51:36 +01:00
} else {
break; // no parameter
}
// actual finalization is done in WLED::loop() (removing old busses and adding new)
2021-01-30 20:51:36 +01:00
if (busConfigs[s] != nullptr) delete busConfigs[s];
2021-12-02 13:09:53 +01:00
busConfigs[s] = new BusConfig(type, pins, start, length, colorOrder, request->hasArg(cv), skip);
2021-03-23 07:05:40 +01:00
doInitBusses = true;
2021-01-17 00:20:31 +01:00
}
// upate other pins
int hw_ir_pin = request->arg(F("IR")).toInt();
if (pinManager.allocatePin(hw_ir_pin,false, PinOwner::IR)) {
2021-01-17 00:20:31 +01:00
irPin = hw_ir_pin;
} else {
irPin = -1;
}
2021-05-19 18:39:16 +02:00
irEnabled = request->arg(F("IT")).toInt();
2021-01-17 00:20:31 +01:00
int hw_rly_pin = request->arg(F("RL")).toInt();
if (pinManager.allocatePin(hw_rly_pin,true, PinOwner::Relay)) {
2021-01-17 00:20:31 +01:00
rlyPin = hw_rly_pin;
} else {
rlyPin = -1;
}
rlyMde = (bool)request->hasArg(F("RM"));
2021-05-19 18:39:16 +02:00
for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) {
2021-11-28 11:24:58 +01:00
char bt[4] = "BT"; bt[2] = (i<10?48:55)+i; bt[3] = 0; // button pin (use A,B,C,... if WLED_MAX_BUTTONS>10)
char be[4] = "BE"; be[2] = (i<10?48:55)+i; be[3] = 0; // button type (use A,B,C,... if WLED_MAX_BUTTONS>10)
int hw_btn_pin = request->arg(bt).toInt();
if (pinManager.allocatePin(hw_btn_pin,false,PinOwner::Button)) {
btnPin[i] = hw_btn_pin;
pinMode(btnPin[i], INPUT_PULLUP);
buttonType[i] = request->arg(be).toInt();
} else {
btnPin[i] = -1;
buttonType[i] = BTN_TYPE_NONE;
}
2021-01-17 00:20:31 +01:00
}
touchThreshold = request->arg(F("TT")).toInt();
2021-01-17 00:20:31 +01:00
2020-09-20 01:18:31 +02:00
strip.ablMilliampsMax = request->arg(F("MA")).toInt();
strip.milliampsPerLed = request->arg(F("LA")).toInt();
2020-09-20 01:18:31 +02:00
briS = request->arg(F("CA")).toInt();
2020-09-20 01:18:31 +02:00
turnOnAtBoot = request->hasArg(F("BO"));
t = request->arg(F("BP")).toInt();
2021-01-13 11:24:27 +01:00
if (t <= 250) bootPreset = t;
2020-09-20 01:18:31 +02:00
strip.gammaCorrectBri = request->hasArg(F("GB"));
strip.gammaCorrectCol = request->hasArg(F("GC"));
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
fadeTransition = request->hasArg(F("TF"));
t = request->arg(F("TD")).toInt();
if (t >= 0) transitionDelay = t;
transitionDelayDefault = t;
2020-09-20 01:18:31 +02:00
strip.paletteFade = request->hasArg(F("PF"));
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
nightlightTargetBri = request->arg(F("TB")).toInt();
t = request->arg(F("TL")).toInt();
if (t > 0) nightlightDelayMinsDefault = t;
2019-09-19 21:15:20 +02:00
nightlightDelayMins = nightlightDelayMinsDefault;
2020-09-20 01:18:31 +02:00
nightlightMode = request->arg(F("TW")).toInt();
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
t = request->arg(F("PB")).toInt();
2018-09-17 11:15:08 +02:00
if (t >= 0 && t < 4) strip.paletteBlend = t;
2020-09-20 01:18:31 +02:00
t = request->arg(F("BF")).toInt();
2018-09-17 11:15:08 +02:00
if (t > 0) briMultiplier = t;
}
2018-02-20 22:29:48 +01:00
//UI
if (subPage == 3)
{
2020-09-20 01:18:31 +02:00
strlcpy(serverDescription, request->arg(F("DS")).c_str(), 33);
syncToggleReceive = request->hasArg(F("ST"));
#ifndef WLED_DISABLE_SIMPLE_UI
if (simplifiedUI ^ request->hasArg(F("SU"))) {
// UI selection changed, invalidate browser cache
cacheInvalidate++;
}
simplifiedUI = request->hasArg(F("SU"));
#endif
}
2018-02-20 22:29:48 +01:00
//SYNC
if (subPage == 4)
{
2020-09-20 01:18:31 +02:00
int t = request->arg(F("UP")).toInt();
2018-09-17 11:15:08 +02:00
if (t > 0) udpPort = t;
t = request->arg(F("U2")).toInt();
if (t > 0) udpPort2 = t;
2021-08-21 12:22:26 +02:00
syncGroups = request->arg(F("GS")).toInt();
receiveGroups = request->arg(F("GR")).toInt();
2021-08-21 12:22:26 +02:00
2020-09-20 01:18:31 +02:00
receiveNotificationBrightness = request->hasArg(F("RB"));
receiveNotificationColor = request->hasArg(F("RC"));
receiveNotificationEffects = request->hasArg(F("RX"));
2021-12-17 11:22:20 +01:00
receiveSegmentOptions = request->hasArg(F("SO"));
receiveNotifications = (receiveNotificationBrightness || receiveNotificationColor || receiveNotificationEffects || receiveSegmentOptions);
2020-09-20 01:18:31 +02:00
notifyDirectDefault = request->hasArg(F("SD"));
2018-02-20 22:29:48 +01:00
notifyDirect = notifyDirectDefault;
2020-09-20 01:18:31 +02:00
notifyButton = request->hasArg(F("SB"));
notifyAlexa = request->hasArg(F("SA"));
notifyHue = request->hasArg(F("SH"));
notifyMacro = request->hasArg(F("SM"));
notifyTwice = request->hasArg(F("S2"));
nodeListEnabled = request->hasArg(F("NL"));
if (!nodeListEnabled) Nodes.clear();
nodeBroadcastEnabled = request->hasArg(F("NB"));
2020-09-20 01:18:31 +02:00
receiveDirect = request->hasArg(F("RD"));
e131SkipOutOfSequence = request->hasArg(F("ES"));
e131Multicast = request->hasArg(F("EM"));
t = request->arg(F("EP")).toInt();
2020-04-13 00:42:27 +02:00
if (t > 0) e131Port = t;
2020-09-20 01:18:31 +02:00
t = request->arg(F("EU")).toInt();
2020-04-13 00:42:27 +02:00
if (t >= 0 && t <= 63999) e131Universe = t;
2020-09-20 01:18:31 +02:00
t = request->arg(F("DA")).toInt();
2020-04-13 00:42:27 +02:00
if (t >= 0 && t <= 510) DMXAddress = t;
2020-09-20 01:18:31 +02:00
t = request->arg(F("DM")).toInt();
if (t >= DMX_MODE_DISABLED && t <= DMX_MODE_MULTIPLE_RGBW) DMXMode = t;
2020-09-20 01:18:31 +02:00
t = request->arg(F("ET")).toInt();
2018-09-17 11:15:08 +02:00
if (t > 99 && t <= 65000) realtimeTimeoutMs = t;
2020-09-20 01:18:31 +02:00
arlsForceMaxBri = request->hasArg(F("FB"));
arlsDisableGammaCorrection = request->hasArg(F("RG"));
t = request->arg(F("WO")).toInt();
2018-09-17 11:15:08 +02:00
if (t >= -255 && t <= 255) arlsOffset = t;
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
alexaEnabled = request->hasArg(F("AL"));
strlcpy(alexaInvocationName, request->arg(F("AI")).c_str(), 33);
2019-08-17 12:27:06 +02:00
#ifndef WLED_DISABLE_BLYNK
strlcpy(blynkHost, request->arg("BH").c_str(), 33);
t = request->arg(F("BP")).toInt();
if (t > 0) blynkPort = t;
2020-09-20 01:18:31 +02:00
if (request->hasArg("BK") && !request->arg("BK").equals(F("Hidden"))) {
strlcpy(blynkApiKey, request->arg("BK").c_str(), 36); initBlynk(blynkApiKey, blynkHost, blynkPort);
}
#endif
#ifdef WLED_ENABLE_MQTT
2020-09-20 01:18:31 +02:00
mqttEnabled = request->hasArg(F("MQ"));
strlcpy(mqttServer, request->arg(F("MS")).c_str(), 33);
t = request->arg(F("MQPORT")).toInt();
if (t > 0) mqttPort = t;
2020-09-20 01:18:31 +02:00
strlcpy(mqttUser, request->arg(F("MQUSER")).c_str(), 41);
if (!isAsterisksOnly(request->arg(F("MQPASS")).c_str(), 41)) strlcpy(mqttPass, request->arg(F("MQPASS")).c_str(), 65);
2020-09-20 01:18:31 +02:00
strlcpy(mqttClientID, request->arg(F("MQCID")).c_str(), 41);
strlcpy(mqttDeviceTopic, request->arg(F("MD")).c_str(), 33);
strlcpy(mqttGroupTopic, request->arg(F("MG")).c_str(), 33);
2021-07-01 20:51:52 +02:00
buttonPublishMqtt = request->hasArg(F("BM"));
#endif
2019-08-17 12:27:06 +02:00
#ifndef WLED_DISABLE_HUESYNC
for (int i=0;i<4;i++){
String a = "H"+String(i);
2019-02-16 00:21:22 +01:00
hueIP[i] = request->arg(a).toInt();
}
2018-09-17 11:15:08 +02:00
2020-09-20 01:18:31 +02:00
t = request->arg(F("HL")).toInt();
2018-09-17 11:15:08 +02:00
if (t > 0) huePollLightId = t;
2020-09-20 01:18:31 +02:00
t = request->arg(F("HI")).toInt();
2018-09-17 11:15:08 +02:00
if (t > 50) huePollIntervalMs = t;
2020-09-20 01:18:31 +02:00
hueApplyOnOff = request->hasArg(F("HO"));
hueApplyBri = request->hasArg(F("HB"));
hueApplyColor = request->hasArg(F("HC"));
huePollingEnabled = request->hasArg(F("HP"));
2019-02-18 22:34:21 +01:00
hueStoreAllowed = true;
reconnectHue();
#endif
}
2018-02-20 22:29:48 +01:00
//TIME
if (subPage == 5)
{
2020-09-20 01:18:31 +02:00
ntpEnabled = request->hasArg(F("NT"));
strlcpy(ntpServerName, request->arg(F("NS")).c_str(), 33);
useAMPM = !request->hasArg(F("CF"));
currentTimezone = request->arg(F("TZ")).toInt();
utcOffsetSecs = request->arg(F("UO")).toInt();
//start ntp if not already connected
2019-10-18 13:26:39 +02:00
if (ntpEnabled && WLED_CONNECTED && !ntpConnected) ntpConnected = ntpUdp.begin(ntpLocalPort);
ntpLastSyncTime = 0; // force new NTP query
2021-03-05 23:05:09 +01:00
longitude = request->arg(F("LN")).toFloat();
latitude = request->arg(F("LT")).toFloat();
// force a sunrise/sunset re-calculation
calculateSunriseAndSunset();
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
if (request->hasArg(F("OL"))) {
overlayDefault = request->arg(F("OL")).toInt();
overlayCurrent = overlayDefault;
}
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
overlayMin = request->arg(F("O1")).toInt();
overlayMax = request->arg(F("O2")).toInt();
analogClock12pixel = request->arg(F("OM")).toInt();
analogClock5MinuteMarks = request->hasArg(F("O5"));
analogClockSecondsTrail = request->hasArg(F("OS"));
#ifndef WLED_DISABLE_CRONIXIE
2021-09-11 01:17:42 +02:00
strlcpy(cronixieDisplay,request->arg(F("CX")).c_str(),7);
2020-09-20 01:18:31 +02:00
cronixieBacklight = request->hasArg(F("CB"));
#endif
2020-09-20 01:18:31 +02:00
countdownMode = request->hasArg(F("CE"));
countdownYear = request->arg(F("CY")).toInt();
countdownMonth = request->arg(F("CI")).toInt();
countdownDay = request->arg(F("CD")).toInt();
countdownHour = request->arg(F("CH")).toInt();
countdownMin = request->arg(F("CM")).toInt();
countdownSec = request->arg(F("CS")).toInt();
2020-12-31 20:47:38 +01:00
setCountdown();
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
macroAlexaOn = request->arg(F("A0")).toInt();
macroAlexaOff = request->arg(F("A1")).toInt();
macroCountdown = request->arg(F("MC")).toInt();
macroNl = request->arg(F("MN")).toInt();
2021-05-19 18:39:16 +02:00
for (uint8_t i=0; i<WLED_MAX_BUTTONS; i++) {
char mp[4] = "MP"; mp[2] = (i<10?48:55)+i; mp[3] = 0; // short
char ml[4] = "ML"; ml[2] = (i<10?48:55)+i; ml[3] = 0; // long
char md[4] = "MD"; md[2] = (i<10?48:55)+i; md[3] = 0; // double
//if (!request->hasArg(mp)) break;
macroButton[i] = request->arg(mp).toInt(); // these will default to 0 if not present
2021-05-19 18:39:16 +02:00
macroLongPress[i] = request->arg(ml).toInt();
macroDoublePress[i] = request->arg(md).toInt();
}
char k[3]; k[2] = 0;
2021-12-25 18:46:43 +01:00
for (int i = 0; i<10; i++) {
k[1] = i+48;//ascii 0,1,2,3,...
k[0] = 'H'; //timer hours
2019-02-16 00:21:22 +01:00
timerHours[i] = request->arg(k).toInt();
k[0] = 'N'; //minutes
2019-02-16 00:21:22 +01:00
timerMinutes[i] = request->arg(k).toInt();
k[0] = 'T'; //macros
2019-02-16 00:21:22 +01:00
timerMacro[i] = request->arg(k).toInt();
2019-01-31 00:09:44 +01:00
k[0] = 'W'; //weekdays
2019-02-16 00:21:22 +01:00
timerWeekday[i] = request->arg(k).toInt();
2021-12-25 18:46:43 +01:00
if (i<8) {
k[0] = 'M'; //start month
timerMonth[i] = request->arg(k).toInt() & 0x0F;
timerMonth[i] <<= 4;
k[0] = 'P'; //end month
timerMonth[i] += (request->arg(k).toInt() & 0x0F);
k[0] = 'D'; //start day
timerDay[i] = request->arg(k).toInt();
k[0] = 'E'; //end day
timerDayEnd[i] = request->arg(k).toInt();
2021-12-25 18:46:43 +01:00
}
}
}
2018-02-20 22:29:48 +01:00
//SECURITY
if (subPage == 6)
{
2020-09-20 01:18:31 +02:00
if (request->hasArg(F("RS"))) //complete factory reset
{
2020-11-06 22:12:48 +01:00
WLED_FS.format();
2020-12-10 16:27:23 +01:00
clearEEPROM();
2020-09-20 01:18:31 +02:00
serveMessage(request, 200, F("All Settings erased."), F("Connect to WLED-AP to setup again"),255);
doReboot = true;
2018-02-20 22:29:48 +01:00
}
bool pwdCorrect = !otaLock; //always allow access if ota not locked
2020-09-20 01:18:31 +02:00
if (request->hasArg(F("OP")))
{
2020-09-20 01:18:31 +02:00
if (otaLock && strcmp(otaPass,request->arg(F("OP")).c_str()) == 0)
2018-02-20 22:29:48 +01:00
{
pwdCorrect = true;
}
2020-09-20 01:18:31 +02:00
if (!otaLock && request->arg(F("OP")).length() > 0)
{
2020-09-20 01:18:31 +02:00
strlcpy(otaPass,request->arg(F("OP")).c_str(), 33);
}
}
2019-08-17 12:27:06 +02:00
if (pwdCorrect) //allow changes if correct pwd or no ota active
2018-02-20 22:29:48 +01:00
{
2020-09-20 01:18:31 +02:00
otaLock = request->hasArg(F("NO"));
wifiLock = request->hasArg(F("OW"));
aOtaEnabled = request->hasArg(F("AO"));
2018-02-20 22:29:48 +01:00
}
}
#ifdef WLED_ENABLE_DMX // include only if DMX is enabled
if (subPage == 7)
{
2020-09-20 01:18:31 +02:00
int t = request->arg(F("PU")).toInt();
if (t >= 0 && t <= 63999) e131ProxyUniverse = t;
2020-09-20 01:18:31 +02:00
t = request->arg(F("CN")).toInt();
if (t>0 && t<16) {
DMXChannels = t;
}
2020-09-20 01:18:31 +02:00
t = request->arg(F("CS")).toInt();
if (t>0 && t<513) {
DMXStart = t;
}
2020-09-20 01:18:31 +02:00
t = request->arg(F("CG")).toInt();
if (t>0 && t<513) {
DMXGap = t;
}
2020-09-20 01:18:31 +02:00
t = request->arg(F("SL")).toInt();
2020-04-10 12:30:08 +02:00
if (t>=0 && t < MAX_LEDS) {
DMXStartLED = t;
}
for (int i=0; i<15; i++) {
String argname = "CH" + String((i+1));
t = request->arg(argname).toInt();
DMXFixtureMap[i] = t;
}
}
#endif
2021-01-17 00:20:31 +01:00
//USERMODS
if (subPage == 8)
{
if (!requestJSONBufferLock(5)) return;
2021-11-03 14:52:22 +01:00
2021-04-25 21:15:57 +02:00
JsonObject um = doc.createNestedObject("um");
size_t args = request->args();
uint j=0;
for (size_t i=0; i<args; i++) {
String name = request->argName(i);
String value = request->arg(i);
// POST request parameters are combined as <usermodname>_<usermodparameter>
int umNameEnd = name.indexOf(":");
if (umNameEnd<1) break; // parameter does not contain ":" or on 1st place -> wrong
JsonObject mod = um[name.substring(0,umNameEnd)]; // get a usermod JSON object
if (mod.isNull()) {
mod = um.createNestedObject(name.substring(0,umNameEnd)); // if it does not exist create it
}
DEBUG_PRINT(name.substring(0,umNameEnd));
DEBUG_PRINT(":");
name = name.substring(umNameEnd+1); // remove mod name from string
// if the resulting name still contains ":" this means nested object
JsonObject subObj;
int umSubObj = name.indexOf(":");
DEBUG_PRINTF("(%d):",umSubObj);
if (umSubObj>0) {
subObj = mod[name.substring(0,umSubObj)];
if (subObj.isNull())
subObj = mod.createNestedObject(name.substring(0,umSubObj));
name = name.substring(umSubObj+1); // remove nested object name from string
} else {
subObj = mod;
}
DEBUG_PRINT(name);
// check if parameters represent array
if (name.endsWith("[]")) {
name.replace("[]","");
if (!subObj[name].is<JsonArray>()) {
JsonArray ar = subObj.createNestedArray(name);
ar.add(value.toInt());
j=0;
} else {
subObj[name].add(value.toInt());
j++;
}
DEBUG_PRINT("[");
DEBUG_PRINT(j);
DEBUG_PRINT("] = ");
DEBUG_PRINTLN(value);
} else {
// we are using a hidden field with the same name as our parameter (!before the actual parameter!)
// to describe the type of parameter (text,float,int), for boolean patameters the first field contains "off"
// so checkboxes have one or two fields (first is always "false", existence of second depends on checkmark and may be "true")
if (subObj[name].isNull()) {
// the first occurence of the field describes the parameter type (used in next loop)
if (value == "false") subObj[name] = false; // checkboxes may have only one field
else subObj[name] = value;
} else {
String type = subObj[name].as<String>(); // get previously stored value as a type
if (subObj[name].is<bool>()) subObj[name] = true; // checkbox/boolean
else if (type == "number") {
value.replace(",","."); // just in case conversion
if (value.indexOf(".") >= 0) subObj[name] = value.toFloat(); // we do have a float
else subObj[name] = value.toInt(); // we may have an int
} else if (type == "int") subObj[name] = value.toInt();
else subObj[name] = value; // text fields
}
DEBUG_PRINT(" = ");
DEBUG_PRINTLN(value);
}
}
usermods.readFromConfig(um); // force change of usermod parameters
2021-12-10 13:29:42 +01:00
releaseJSONBufferLock();
}
2021-11-03 14:52:22 +01:00
2021-01-31 00:38:27 +01:00
if (subPage != 2 && (subPage != 6 || !doReboot)) serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
2019-01-09 22:52:42 +01:00
if (subPage == 4) alexaInit();
}
2018-11-25 00:00:02 +01:00
//HTTP API request parser
bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply)
{
if (!(req.indexOf("win") >= 0)) return false;
2018-09-17 11:15:08 +02:00
int pos = 0;
2020-09-20 01:18:31 +02:00
DEBUG_PRINT(F("API req: "));
DEBUG_PRINTLN(req);
2019-08-17 12:27:06 +02:00
strip.applyToAllSelected = true;
2019-12-02 12:41:35 +01:00
2019-12-01 01:42:52 +01:00
//segment select (sets main segment)
byte prevMain = strip.getMainSegmentId();
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("SM="));
2019-12-01 01:42:52 +01:00
if (pos > 0) {
strip.mainSegment = getNumVal(&req, pos);
}
byte selectedSeg = strip.getMainSegmentId();
if (selectedSeg != prevMain) setValuesFromMainSeg();
//snapshot to check if request changed values later, temporary.
byte prevCol[4] = {col[0], col[1], col[2], col[3]};
byte prevColSec[4] = {colSec[0], colSec[1], colSec[2], colSec[3]};
byte prevEffect = effectCurrent;
byte prevSpeed = effectSpeed;
byte prevIntensity = effectIntensity;
byte prevPalette = effectPalette;
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("SS="));
if (pos > 0) {
byte t = getNumVal(&req, pos);
if (t < strip.getMaxSegments()) {
selectedSeg = t;
strip.applyToAllSelected = false;
}
}
WS2812FX::Segment& selseg = strip.getSegment(selectedSeg);
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("SV=")); //segment selected
if (pos > 0) {
byte t = getNumVal(&req, pos);
if (t == 2) for (uint8_t i = 0; i < strip.getMaxSegments(); i++) strip.getSegment(i).setOption(SEG_OPTION_SELECTED, 0); // unselect other segments
selseg.setOption(SEG_OPTION_SELECTED, t);
}
2019-12-01 01:42:52 +01:00
uint16_t startI = selseg.start;
uint16_t stopI = selseg.stop;
uint8_t grpI = selseg.grouping;
uint16_t spcI = selseg.spacing;
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("&S=")); //segment start
2019-12-01 01:42:52 +01:00
if (pos > 0) {
startI = getNumVal(&req, pos);
}
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("S2=")); //segment stop
2019-12-01 01:42:52 +01:00
if (pos > 0) {
stopI = getNumVal(&req, pos);
}
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("GP=")); //segment grouping
if (pos > 0) {
grpI = getNumVal(&req, pos);
if (grpI == 0) grpI = 1;
}
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("SP=")); //segment spacing
if (pos > 0) {
spcI = getNumVal(&req, pos);
}
strip.setSegment(selectedSeg, startI, stopI, grpI, spcI);
2019-12-01 01:42:52 +01:00
pos = req.indexOf(F("RV=")); //Segment reverse
if (pos > 0) selseg.setOption(SEG_OPTION_REVERSED, req.charAt(pos+3) != '0');
pos = req.indexOf(F("MI=")); //Segment mirror
if (pos > 0) selseg.setOption(SEG_OPTION_MIRROR, req.charAt(pos+3) != '0');
pos = req.indexOf(F("SB=")); //Segment brightness/opacity
if (pos > 0) {
byte segbri = getNumVal(&req, pos);
selseg.setOption(SEG_OPTION_ON, segbri, selectedSeg);
if (segbri) {
selseg.setOpacity(segbri, selectedSeg);
}
}
pos = req.indexOf(F("SW=")); //segment power
if (pos > 0) {
switch (getNumVal(&req, pos)) {
case 0: selseg.setOption(SEG_OPTION_ON, false); break;
case 1: selseg.setOption(SEG_OPTION_ON, true); break;
default: selseg.setOption(SEG_OPTION_ON, !selseg.getOption(SEG_OPTION_ON)); break;
}
}
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("PS=")); //saves current in preset
2020-10-08 00:52:15 +02:00
if (pos > 0) savePreset(getNumVal(&req, pos));
pos = req.indexOf(F("P1=")); //sets first preset for cycle
if (pos > 0) presetCycMin = getNumVal(&req, pos);
pos = req.indexOf(F("P2=")); //sets last preset for cycle
if (pos > 0) presetCycMax = getNumVal(&req, pos);
//apply preset
if (updateVal(&req, "PL=", &presetCycCurr, presetCycMin, presetCycMax)) {
2021-12-01 00:20:33 +01:00
unloadPlaylist();
applyPreset(presetCycCurr);
}
2019-02-22 22:53:33 +01:00
//set brightness
updateVal(&req, "&A=", &bri);
2022-01-15 21:15:37 +01:00
bool col0Changed = false, col1Changed = false, col2Changed = false;
2019-02-22 22:53:33 +01:00
//set colors
updateVal(&req, "&R=", &col[0]);
updateVal(&req, "&G=", &col[1]);
updateVal(&req, "&B=", &col[2]);
updateVal(&req, "&W=", &col[3]);
for (byte i=0; i<4; i++) if (prevCol[i]!=col[i]) col0Changed = colorChanged = true;
2019-02-22 22:53:33 +01:00
updateVal(&req, "R2=", &colSec[0]);
updateVal(&req, "G2=", &colSec[1]);
updateVal(&req, "B2=", &colSec[2]);
updateVal(&req, "W2=", &colSec[3]);
for (byte i=0; i<4; i++) if (prevColSec[i]!=colSec[i]) col1Changed = colorChanged = true;
#ifdef WLED_ENABLE_LOXONE
//lox parser
pos = req.indexOf(F("LX=")); // Lox primary color
if (pos > 0) {
int lxValue = getNumVal(&req, pos);
if (parseLx(lxValue, col)) {
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
}
}
pos = req.indexOf(F("LY=")); // Lox secondary color
if (pos > 0) {
int lxValue = getNumVal(&req, pos);
if(parseLx(lxValue, colSec)) {
bri = 255;
nightlightActive = false; //always disable nightlight when toggling
}
}
#endif
//set hue
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("HU="));
if (pos > 0) {
2018-11-25 00:00:02 +01:00
uint16_t temphue = getNumVal(&req, pos);
byte tempsat = 255;
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("SA="));
if (pos > 0) {
2018-11-25 00:00:02 +01:00
tempsat = getNumVal(&req, pos);
}
2022-01-15 21:15:37 +01:00
byte sec = req.indexOf(F("H2"));
colorHStoRGB(temphue, tempsat, (sec>0) ? colSec : col);
if (sec>0) col1Changed = true;
else col0Changed = true;
colorChanged = true;
}
2019-08-17 12:27:06 +02:00
//set white spectrum (kelvin)
pos = req.indexOf(F("&K="));
if (pos > 0) {
2022-01-15 21:15:37 +01:00
byte sec = req.indexOf(F("K2"));
colorKtoRGB(getNumVal(&req, pos), (sec>0) ? colSec : col);
if (sec>0) col1Changed = true;
else col0Changed = true;
colorChanged = true;
}
//set color from HEX or 32bit DEC
2022-01-15 21:15:37 +01:00
byte tmpCol[4];
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("CL="));
if (pos > 0) {
2022-01-15 21:15:37 +01:00
colorFromDecOrHexString(col, (char*)req.substring(pos + 3).c_str());
selseg.setColor(0, RGBW32(col[0], col[1], col[2], col[3]), selectedSeg); // defined above (SS= or main)
col0Changed = colorChanged = true;
}
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("C2="));
if (pos > 0) {
colorFromDecOrHexString(colSec, (char*)req.substring(pos + 3).c_str());
2022-01-15 21:15:37 +01:00
selseg.setColor(1, RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]), selectedSeg); // defined above (SS= or main)
col1Changed = colorChanged = true;
}
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("C3="));
if (pos > 0) {
2022-01-15 21:15:37 +01:00
colorFromDecOrHexString(tmpCol, (char*)req.substring(pos + 3).c_str());
selseg.setColor(2, RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]), selectedSeg); // defined above (SS= or main)
col2Changed = colorChanged = true;
}
2019-08-17 12:27:06 +02:00
//set to random hue SR=0->1st SR=1->2nd
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("SR"));
if (pos > 0) {
2022-01-15 21:15:37 +01:00
byte sec = getNumVal(&req, pos);
_setRandomColor(sec);
if (sec>0) col1Changed = true;
else col0Changed = true;
colorChanged = true;
}
2019-08-17 12:27:06 +02:00
//swap 2nd & 1st
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("SC"));
if (pos > 0) {
byte temp;
2022-01-15 21:15:37 +01:00
for (uint8_t i=0; i<4; i++) {
temp = col[i];
col[i] = colSec[i];
colSec[i] = temp;
}
2022-01-15 21:15:37 +01:00
col0Changed = col1Changed = colorChanged = true;
}
2019-08-17 12:27:06 +02:00
2019-02-22 22:53:33 +01:00
//set effect parameters
if (updateVal(&req, "FX=", &effectCurrent, 0, strip.getModeCount()-1) && request != nullptr) unloadPlaylist(); //unload playlist if changing FX using web request
2019-02-22 22:53:33 +01:00
updateVal(&req, "SX=", &effectSpeed);
updateVal(&req, "IX=", &effectIntensity);
updateVal(&req, "FP=", &effectPalette, 0, strip.getPaletteCount()-1);
strip.setMode(selectedSeg, effectCurrent);
selseg.speed = effectSpeed;
selseg.intensity = effectIntensity;
selseg.palette = effectPalette;
if (effectCurrent != prevEffect || effectSpeed != prevSpeed || effectIntensity != prevIntensity || effectPalette != prevPalette) effectChanged = true;
//set advanced overlay
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("OL="));
if (pos > 0) {
2018-11-25 00:00:02 +01:00
overlayCurrent = getNumVal(&req, pos);
}
2020-11-06 22:12:48 +01:00
//apply macro (deprecated, added for compatibility with pre-0.11 automations)
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("&M="));
if (pos > 0) {
2020-11-06 22:12:48 +01:00
applyPreset(getNumVal(&req, pos) + 16);
}
2019-08-17 12:27:06 +02:00
//toggle send UDP direct notifications
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("SN="));
2019-02-22 22:53:33 +01:00
if (pos > 0) notifyDirect = (req.charAt(pos+3) != '0');
2019-08-17 12:27:06 +02:00
//toggle receive UDP direct notifications
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("RN="));
2019-02-22 22:53:33 +01:00
if (pos > 0) receiveNotifications = (req.charAt(pos+3) != '0');
//receive live data via UDP/Hyperion
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("RD="));
if (pos > 0) receiveDirect = (req.charAt(pos+3) != '0');
2019-08-17 12:27:06 +02:00
//main toggle on/off (parse before nightlight, #1214)
pos = req.indexOf(F("&T="));
if (pos > 0) {
nightlightActive = false; //always disable nightlight when toggling
switch (getNumVal(&req, pos))
{
case 0: if (bri != 0){briLast = bri; bri = 0;} break; //off, only if it was previously on
case 1: if (bri == 0) bri = briLast; break; //on, only if it was previously off
default: toggleOnOff(); //toggle
}
}
//toggle nightlight mode
bool aNlDef = false;
2020-09-20 01:18:31 +02:00
if (req.indexOf(F("&ND")) > 0) aNlDef = true;
pos = req.indexOf(F("NL="));
if (pos > 0)
{
2019-02-22 22:53:33 +01:00
if (req.charAt(pos+3) == '0')
{
nightlightActive = false;
} else {
nightlightActive = true;
2018-11-25 00:00:02 +01:00
if (!aNlDef) nightlightDelayMins = getNumVal(&req, pos);
nightlightStartTime = millis();
}
} else if (aNlDef)
{
nightlightActive = true;
nightlightStartTime = millis();
}
2019-08-17 12:27:06 +02:00
//set nightlight target brightness
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("NT="));
if (pos > 0) {
2018-11-25 00:00:02 +01:00
nightlightTargetBri = getNumVal(&req, pos);
nightlightActiveOld = false; //re-init
}
2019-08-17 12:27:06 +02:00
//toggle nightlight fade
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("NF="));
2019-02-22 22:53:33 +01:00
if (pos > 0)
{
nightlightMode = getNumVal(&req, pos);
nightlightActiveOld = false; //re-init
}
if (nightlightMode > NL_MODE_SUN) nightlightMode = NL_MODE_SUN;
2019-02-25 19:14:13 +01:00
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("TT="));
2019-02-22 22:53:33 +01:00
if (pos > 0) transitionDelay = getNumVal(&req, pos);
//set time (unix timestamp)
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("ST="));
if (pos > 0) {
2021-05-27 02:02:02 +02:00
setTimeFromAPI(getNumVal(&req, pos));
}
2019-08-17 12:27:06 +02:00
//set countdown goal (unix timestamp)
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("CT="));
if (pos > 0) {
2018-11-25 00:00:02 +01:00
countdownTime = getNumVal(&req, pos);
2021-05-25 09:59:19 +02:00
if (countdownTime - toki.second() > 0) countdownOverTriggered = false;
}
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("LO="));
if (pos > 0) {
realtimeOverride = getNumVal(&req, pos);
if (realtimeOverride > 2) realtimeOverride = REALTIME_OVERRIDE_ALWAYS;
}
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("RB"));
if (pos > 0) doReboot = true;
//cronixie
2019-03-01 17:10:42 +01:00
#ifndef WLED_DISABLE_CRONIXIE
2020-01-01 01:04:54 +01:00
//mode, 1 countdown
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("NM="));
2020-01-01 01:04:54 +01:00
if (pos > 0) countdownMode = (req.charAt(pos+3) != '0');
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("NX=")); //sets digits to code
if (pos > 0) {
2021-06-09 12:57:16 +02:00
strlcpy(cronixieDisplay, req.substring(pos + 3, pos + 9).c_str(), 7);
setCronixie();
}
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("NB="));
if (pos > 0) //sets backlight
{
cronixieBacklight = (req.charAt(pos+3) != '0');
}
2019-03-01 17:10:42 +01:00
#endif
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("U0=")); //user var 0
if (pos > 0) {
2018-11-25 00:00:02 +01:00
userVar0 = getNumVal(&req, pos);
}
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("U1=")); //user var 1
if (pos > 0) {
2018-11-25 00:00:02 +01:00
userVar1 = getNumVal(&req, pos);
}
//you can add more if you need
2019-08-17 12:27:06 +02:00
//apply to all selected manually to prevent #1618. Temporary
if (strip.applyToAllSelected) {
for (uint8_t i = 0; i < strip.getMaxSegments(); i++) {
WS2812FX::Segment& seg = strip.getSegment(i);
if (!seg.isActive() || !seg.isSelected() || i == selectedSeg) continue;
if (effectCurrent != prevEffect) strip.setMode(i, effectCurrent);
if (effectSpeed != prevSpeed) seg.speed = effectSpeed;
if (effectIntensity != prevIntensity) seg.intensity = effectIntensity;
if (effectPalette != prevPalette) seg.palette = effectPalette;
2022-01-15 21:15:37 +01:00
if (col0Changed) seg.colors[0] = RGBW32(col[0], col[1], col[2], col[3]);
if (col1Changed) seg.colors[1] = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
if (col2Changed) seg.colors[2] = RGBW32(tmpCol[0], tmpCol[1], tmpCol[2], tmpCol[3]);
}
}
strip.applyToAllSelected = false;
setValuesFromMainSeg();
//end of temporary fix code
if (!apply) return true; //when called by JSON API, do not call colorUpdated() here
//internal call, does not send XML response
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("IN"));
if (pos < 1) XML_response(request);
2019-08-17 12:27:06 +02:00
2020-09-20 01:18:31 +02:00
pos = req.indexOf(F("&NN")); //do not send UDP notifications this time
colorUpdated((pos > 0) ? CALL_MODE_NO_NOTIFY : CALL_MODE_DIRECT_CHANGE);
2019-08-17 12:27:06 +02:00
return true;
}