diff --git a/sonoff/_releasenotes.ino b/sonoff/_releasenotes.ino index d924953435d3..5583d95fc389 100644 --- a/sonoff/_releasenotes.ino +++ b/sonoff/_releasenotes.ino @@ -1,5 +1,8 @@ /* 5.12.0i * Add 16 timers using commands Timer and Timers (#1091) + * Add commands Timer 0 to clear timer and Timer 1..16 to copy timer + * Add optional Timer configuration webpage to be enabled in user_config.h with define USE_TIMERS_WEB + * Change webpage parameter communication * * 5.12.0h * Add optional Arduino OTA support to be enabled in user_config.h (#1998) diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index e78d0a8e0750..617524e2036d 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "AirQuality" #define D_DOMOTICZ_UPDATE_TIMER "Aktualizace stopek" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energie Dnes" #define D_ENERGY_YESTERDAY "Energie Včera" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index b0ea8033acad..f6f5c78a0906 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "AirQuality" #define D_DOMOTICZ_UPDATE_TIMER "Update timer" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energie heute" #define D_ENERGY_YESTERDAY "Energie gestern" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 5fb862b5e591..c7db040dbb10 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "AirQuality" #define D_DOMOTICZ_UPDATE_TIMER "Update timer" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energy Today" #define D_ENERGY_YESTERDAY "Energy Yesterday" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index dbe2417311bc..5ad7d344c506 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "Calidad del Aire" #define D_DOMOTICZ_UPDATE_TIMER "Intervalo de refresco" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energía Hoy" #define D_ENERGY_YESTERDAY "Energía Ayer" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index 7b9c0137f9e8..64953f3b3e5f 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "AirQuality" #define D_DOMOTICZ_UPDATE_TIMER "Update timer" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xsns_03_energy.ino #define D_ENERGY_TODAY "Energie aujourd'hui" #define D_ENERGY_YESTERDAY "Energie hier" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 82dde4c385c9..dd6ec3292910 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "Légminőség" #define D_DOMOTICZ_UPDATE_TIMER "Update időzítő" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Mai Energia" #define D_ENERGY_YESTERDAY "Tegnapi Energia" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index 4e16869a4a57..c9134c7dd27c 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "AirQuality" #define D_DOMOTICZ_UPDATE_TIMER "Intervallo di aggiornamento" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energia Oggi" #define D_ENERGY_YESTERDAY "Energia Ieri" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index 53bdb7f6724d..3b91d3d84cbf 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -110,7 +110,7 @@ #define D_OFF "Uit" #define D_OFFLINE "Offline" #define D_OK "Ok" -#define D_ON "Ann" +#define D_ON "Aan" #define D_ONLINE "Online" #define D_PASSWORD "Wachtwoord" #define D_PORT "Poort" @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "AirQuality" #define D_DOMOTICZ_UPDATE_TIMER "Bijwerk timer" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configureer Tijdschakelaar" +#define D_TIMER_PARAMETERS "Tijdschakelaar parameters" +#define D_TIMER_ARM "Actief" +#define D_TIMER_TIME "Tijd" +#define D_TIMER_DAYS "Dagen" +#define D_TIMER_REPEAT "Herhaal" +#define D_TIMER_DEVICE "Uitgang" +#define D_TIMER_POWER "Actie" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Verbruik vandaag" #define D_ENERGY_YESTERDAY "Verbruik gisteren" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 90a69afb516d..f1023e5e4faa 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "AirQuality" #define D_DOMOTICZ_UPDATE_TIMER "Zaktualizuj czasomierz" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Energia Dzisiaj" #define D_ENERGY_YESTERDAY "Energia Wczoraj" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index 7d8f0512c9a3..73a8b53ea6d1 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "Qualidade do Ar" #define D_DOMOTICZ_UPDATE_TIMER "Tempo de atualização" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Consumo energético de hoje" #define D_ENERGY_YESTERDAY "Consumo energético de ontem" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index 640b8bef7fe6..5c5b964e659a 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "AirQuality" #define D_DOMOTICZ_UPDATE_TIMER "Update timer" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "Энергия Сегодня" #define D_ENERGY_YESTERDAY "Энергия Вчера" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index 0cd86bcc8d51..86c352dbf546 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "空气质量" #define D_DOMOTICZ_UPDATE_TIMER "更新计时器" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "今日用电量" #define D_ENERGY_YESTERDAY "昨日用电量" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index c3efc118b272..f015232e3bec 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -358,6 +358,16 @@ #define D_DOMOTICZ_AIRQUALITY "空氣品質" #define D_DOMOTICZ_UPDATE_TIMER "更新計時器" +// xdrv_09_timers.ino +#define D_CONFIGURE_TIMER "Configure Timer" +#define D_TIMER_PARAMETERS "Timer parameters" +#define D_TIMER_ARM "Arm" +#define D_TIMER_TIME "Time" +#define D_TIMER_DAYS "Days" +#define D_TIMER_REPEAT "Repeat" +#define D_TIMER_DEVICE "Device" +#define D_TIMER_POWER "Power" + // xdrv_03_energy.ino #define D_ENERGY_TODAY "今日用電量" #define D_ENERGY_YESTERDAY "昨日用電量" diff --git a/sonoff/settings.h b/sonoff/settings.h index 173958b86022..5c18c9ca26df 100644 --- a/sonoff/settings.h +++ b/sonoff/settings.h @@ -93,10 +93,10 @@ typedef union { uint32_t data; struct { uint32_t time : 11; // bits 0 - 10 = minutes in a day - uint32_t mday : 5; // bits 11 - 15 = optional day in a month + uint32_t mday : 5; // bits 11 - 15 = 32 days in a month uint32_t days : 7; // bits 16 - 22 = week day mask uint32_t device : 4; // bits 23 - 26 = 16 devices - uint32_t power : 2; // bits 27 - 28 = 4 power states - Off, On, Toggle + uint32_t power : 2; // bits 27 - 28 = 4 power states - Off, On, Toggle, Blink uint32_t repeat : 1; // bit 29 uint32_t arm : 1; // bit 30 uint32_t spare : 1; // bit 31 diff --git a/sonoff/user_config.h b/sonoff/user_config.h index 5de54309a8f9..d49373f6788a 100644 --- a/sonoff/user_config.h +++ b/sonoff/user_config.h @@ -163,6 +163,7 @@ #define NTP_SERVER3 "0.nl.pool.ntp.org" // [NtpServer3] Select third NTP server by name or IP address (93.94.224.67) #define USE_TIMERS // Add support for up to 16 timers (+2k2 code) + #define USE_TIMERS_WEB // Add timer webpage support (+4k5 code) // -- Time - Start Daylight Saving Time and timezone offset from UTC in minutes #define TIME_DST North, Last, Sun, Mar, 2, +120 // Northern Hemisphere, Last sunday in march at 02:00 +120 minutes diff --git a/sonoff/webserver.ino b/sonoff/webserver.ino index cc843748f357..d314d09e4a55 100644 --- a/sonoff/webserver.ino +++ b/sonoff/webserver.ino @@ -39,16 +39,19 @@ const char HTTP_HEAD[] PROGMEM = "var cn,x,lt;" "cn=180;" "x=null;" // Allow for abortion + "function eb(s){" + "return document.getElementById(s);" // Save code space + "}" "function u(){" "if(cn>=0){" - "document.getElementById('t').innerHTML='" D_RESTART_IN " '+cn+' " D_SECONDS "';" + "eb('t').innerHTML='" D_RESTART_IN " '+cn+' " D_SECONDS "';" "cn--;" "setTimeout(u,1000);" "}" "}" "function c(l){" - "document.getElementById('s1').value=l.innerText||l.textContent;" - "document.getElementById('p1').focus();" + "eb('s1').value=l.innerText||l.textContent;" + "eb('p1').focus();" "}" "function la(p){" "var a='';" @@ -61,7 +64,7 @@ const char HTTP_HEAD[] PROGMEM = "x.onreadystatechange=function(){" "if(x.readyState==4&&x.status==200){" "var s=x.responseText.replace(/{t}/g,\"\").replace(/{s}/g,\"\").replace(/{c}/g,\"%'>
\").replace(/{m}/g,\"\").replace(/{e}/g,\"
\").replace(/}2/g,\"\");" - "document.getElementById('i').innerHTML=s;" + "eb('i').innerHTML=s;" "}" ""; const char HTTP_MSG_SLIDER1[] PROGMEM = @@ -180,6 +183,11 @@ const char HTTP_BTN_RSTRT[] PROGMEM = "
"; const char HTTP_BTN_MENU2[] PROGMEM = "
" +#ifdef USE_TIMERS +#ifdef USE_TIMERS_WEB + "
" +#endif // USE_TIMERS_WEB +#endif // USE_TIMERS "
"; const char HTTP_BTN_MENU3[] PROGMEM = "
" @@ -206,7 +214,7 @@ const char HTTP_BTN_CONF[] PROGMEM = "

"; const char HTTP_FORM_MODULE[] PROGMEM = "
 " D_MODULE_PARAMETERS " 
" - "" + "" "
" D_MODULE_TYPE " ({mt)

"; const char HTTP_LNK_ITEM[] PROGMEM = "
{v} {i} {r}%
"; @@ -214,7 +222,7 @@ const char HTTP_LNK_SCAN[] PROGMEM = "
"; const char HTTP_FORM_WIFI[] PROGMEM = "
 " D_WIFI_PARAMETERS " " - "" + "" "
" D_AP1_SSID " (" STA_SSID1 ")

" "
" D_AP1_PASSWORD "

" "
" D_AP2_SSID " (" STA_SSID2 ")

" @@ -222,7 +230,7 @@ const char HTTP_FORM_WIFI[] PROGMEM = "
" D_HOSTNAME " (" WIFI_HOSTNAME ")

"; const char HTTP_FORM_MQTT[] PROGMEM = "
 " D_MQTT_PARAMETERS " " - "" + "" "
" D_HOST " (" MQTT_HOST ")

" "
" D_PORT " (" STR(MQTT_PORT) ")

" "
" D_CLIENT " ({m0)

" @@ -232,7 +240,7 @@ const char HTTP_FORM_MQTT[] PROGMEM = "
" D_FULL_TOPIC " (" MQTT_FULLTOPIC ")

"; const char HTTP_FORM_LOG1[] PROGMEM = "
 " D_LOGGING_PARAMETERS " " - ""; + ""; const char HTTP_FORM_LOG2[] PROGMEM = "
{b0 ({b1)

"; const char HTTP_FORM_OTHER[] PROGMEM = "
 " D_OTHER_PARAMETERS " " - "" + "" "
" D_WEB_ADMIN_PASSWORD "

" "
" D_MQTT_ENABLE "
"; const char HTTP_FORM_OTHER2[] PROGMEM = @@ -274,7 +282,7 @@ const char HTTP_FORM_UPG[] PROGMEM = const char HTTP_FORM_RST_UPG[] PROGMEM = "" "

" - "
" + "
" "
" "" ""; @@ -330,6 +338,11 @@ void StartWebserver(int type, IPAddress ipweb) WebServer->on("/", HandleRoot); WebServer->on("/cn", HandleConfiguration); WebServer->on("/md", HandleModuleConfiguration); +#ifdef USE_TIMERS +#ifdef USE_TIMERS_WEB + WebServer->on("/tm", HandleTimerConfiguration); +#endif // USE_TIMERS_WEB +#endif // USE_TIMERS WebServer->on("/w1", HandleWifiConfigurationWithScan); WebServer->on("/w0", HandleWifiConfiguration); if (Settings.flag.mqtt_enabled) { @@ -1001,17 +1014,16 @@ void HandleSaveSettings() char stemp[TOPSZ]; char stemp2[TOPSZ]; - byte what = 0; - byte restart; String result = ""; AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_SAVE_CONFIGURATION); char tmp[100]; - WebGetArg("w", tmp, sizeof(tmp)); - if (strlen(tmp)) { - what = atoi(tmp); - } + WebGetArg("w", tmp, sizeof(tmp)); // Returns "5,1" where 5 is config type and 1 is restart flag + char *p = tmp; + uint8_t what = strtol(p, &p, 10); + p++; // Skip comma + uint8_t restart = strtol(p, &p, 10); switch (what) { case 1: WebGetArg("h", tmp, sizeof(tmp)); @@ -1085,6 +1097,13 @@ void HandleSaveSettings() Settings.seriallog_level, Settings.weblog_level, Settings.syslog_level, Settings.syslog_host, Settings.syslog_port, Settings.tele_period); AddLog(LOG_LEVEL_INFO); break; +#ifdef USE_TIMERS +#ifdef USE_TIMERS_WEB + case 7: + TimerSaveSettings(); + break; +#endif // USE_TIMERS_WEB +#endif // USE_TIMERS #ifdef USE_DOMOTICZ case 4: DomoticzSaveSettings(); @@ -1136,8 +1155,6 @@ void HandleSaveSettings() break; } - WebGetArg("r", tmp, sizeof(tmp)); - restart = (!strlen(tmp)) ? 1 : atoi(tmp); if (restart) { String page = FPSTR(HTTP_HEAD); page.replace(F("{v}"), FPSTR(S_SAVE_CONFIGURATION)); diff --git a/sonoff/xdrv_05_domoticz.ino b/sonoff/xdrv_05_domoticz.ino index 3e1dfdc4907f..5aa6a7c43f28 100644 --- a/sonoff/xdrv_05_domoticz.ino +++ b/sonoff/xdrv_05_domoticz.ino @@ -22,7 +22,7 @@ #ifdef USE_WEBSERVER const char HTTP_FORM_DOMOTICZ[] PROGMEM = "
 " D_DOMOTICZ_PARAMETERS " 
" - "" + "" "
"; const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM = "" diff --git a/sonoff/xdrv_09_timers.ino b/sonoff/xdrv_09_timers.ino index 350f49dfd6dd..d84b14358352 100644 --- a/sonoff/xdrv_09_timers.ino +++ b/sonoff/xdrv_09_timers.ino @@ -36,7 +36,7 @@ enum TimerCommands { CMND_TIMER, CMND_TIMERS }; const char kTimerCommands[] PROGMEM = D_CMND_TIMER "|" D_CMND_TIMERS ; -power_t fired = 0; +uint16_t fired = 0; void TimerEverySecond() { @@ -45,6 +45,7 @@ void TimerEverySecond() uint8_t days = 1 << (RtcTime.day_of_week -1); for (byte i = 0; i < MAX_TIMERS; i++) { + if (Settings.timer[i].device >= devices_present) Settings.timer[i].data = 0; // Reset timer due to change in devices present if (Settings.timer[i].arm) { if (time == Settings.timer[i].time) { if (!bitRead(fired, i) && (Settings.timer[i].days & days)) { @@ -88,67 +89,74 @@ boolean TimerCommand() int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kTimerCommands); if ((CMND_TIMER == command_code) && (index > 0) && (index <= MAX_TIMERS)) { uint8_t error = 0; - if (XdrvMailbox.data_len) { - StaticJsonBuffer<128> jsonBuffer; - JsonObject& root = jsonBuffer.parseObject(dataBufUc); - if (!root.success()) { - snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_INVALID_JSON "\"}"), index); // JSON decode failed - error = 1; - } - else { - char parm_uc[10]; - - index--; - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_ARM))].success()) { - Settings.timer[index].arm = (root[parm_uc] != 0); + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= MAX_TIMERS)) { + if (XdrvMailbox.payload == 0) { + Settings.timer[index -1].data = 0; // Clear timer + } else { + Settings.timer[index -1].data = Settings.timer[XdrvMailbox.payload -1].data; // Copy timer + } + } else { + StaticJsonBuffer<128> jsonBuffer; + JsonObject& root = jsonBuffer.parseObject(dataBufUc); + if (!root.success()) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_CMND_TIMER "%d\":\"" D_JSON_INVALID_JSON "\"}"), index); // JSON decode failed + error = 1; } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_TIME))].success()) { - uint16_t itime = 0; - uint8_t value = 0; - char time_str[10]; - - snprintf(time_str, sizeof(time_str), root[parm_uc]); - const char *substr = strtok(time_str, ":"); - if (substr != NULL) { - value = atoi(substr); - if (value > 23) value = 23; - itime = value * 60; - substr = strtok(NULL, ":"); + else { + char parm_uc[10]; + index--; + if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_ARM))].success()) { + Settings.timer[index].arm = (root[parm_uc] != 0); + } + if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_TIME))].success()) { + uint16_t itime = 0; + uint8_t value = 0; + char time_str[10]; + + snprintf(time_str, sizeof(time_str), root[parm_uc]); + const char *substr = strtok(time_str, ":"); if (substr != NULL) { value = atoi(substr); - if (value > 59) value = 59; - itime += value; + if (value > 23) value = 23; + itime = value * 60; + substr = strtok(NULL, ":"); + if (substr != NULL) { + value = atoi(substr); + if (value > 59) value = 59; + itime += value; + } } + Settings.timer[index].time = itime; } - Settings.timer[index].time = itime; - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_DAYS))].success()) { - // SMTWTFS = 1234567 = 0011001 = 00TW00S = --TW--S - Settings.timer[index].days = 0; - const char *tday = root[parm_uc]; - char ch = '.'; - - uint8_t i = 0; - while ((ch != '\0') && (i < 7)) { - ch = *tday++; - if (ch == '-') ch = '0'; - uint8_t mask = 1 << i++; - Settings.timer[index].days |= (ch == '0') ? 0 : mask; + if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_DAYS))].success()) { + // SMTWTFS = 1234567 = 0011001 = 00TW00S = --TW--S + Settings.timer[index].days = 0; + const char *tday = root[parm_uc]; + char ch = '.'; + + uint8_t i = 0; + while ((ch != '\0') && (i < 7)) { + ch = *tday++; + if (ch == '-') ch = '0'; + uint8_t mask = 1 << i++; + Settings.timer[index].days |= (ch == '0') ? 0 : mask; + } } - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_REPEAT))].success()) { - Settings.timer[index].repeat = (root[parm_uc] != 0); - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_DEVICE))].success()) { - Settings.timer[index].device = ((uint8_t)root[parm_uc] -1) & 0x0F; - } - if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_POWER))].success()) { - Settings.timer[index].power = (uint8_t)root[parm_uc] & 0x03; - } - if (Settings.timer[index].arm) bitClear(fired, index); + if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_REPEAT))].success()) { + Settings.timer[index].repeat = (root[parm_uc] != 0); + } + if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_DEVICE))].success()) { + uint8_t device = ((uint8_t)root[parm_uc] -1) & 0x0F; + Settings.timer[index].device = (device < devices_present) ? device : devices_present -1; + } + if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_POWER))].success()) { + Settings.timer[index].power = (uint8_t)root[parm_uc] & 0x03; + } + if (Settings.timer[index].arm) bitClear(fired, index); - index++; + index++; + } } } if (!error) { @@ -181,6 +189,150 @@ boolean TimerCommand() return serviced; } +/*********************************************************************************************\ + * Presentation +\*********************************************************************************************/ + +#ifdef USE_WEBSERVER +#ifdef USE_TIMERS_WEB +const char HTTP_TIMER_SCRIPT[] PROGMEM = + "var pt=[],ct=99;" + "function qs(s){" // Save code space + "return document.querySelector(s);" + "}" + "function ce(i,q){" // Create select option + "var o=document.createElement('option');" + "o.textContent=i;" + "q.appendChild(o);" + "}" + "function st(){" // Save parameters to hidden area + "var d,h,i,m,n,s,p;" + "h=qs('#ho');" + "m=qs('#mi');" + "d=qs('#d1');" + "s=0;" + "n=1<<30;if(eb('a0').checked){s|=n;}" // Get arm + "n=1<<29;if(eb('r0').checked){s|=n;}" // Get repeat + "for(i=0;i<7;i++){n=1<<(16+i);if(eb('w'+i).checked){s|=n;}}" // Get weekdays + "s|=(eb('p1').value<<27);" // Get power + "s|=(d.selectedIndex<<23);" // Get device + "s|=((h.selectedIndex*60)+m.selectedIndex)&0x7FF;" // Get time + "pt[ct]=s;" + "eb('t0').value=pt.join();" // Save parameters from array to hidden area + "}" + "function ot(t,e){" + "var d,h,i,m,n,s,tl,p,q;" + "h=qs('#ho');" + "m=qs('#mi');" + "d=qs('#d1');" + "if(ct==99){" // Do this once + "pt=eb('t0').value.split(',').map(Number);" // Get parameters from hidden area to array + "for(i=0;i<=23;i++){ce((i<10)?('0'+i):i,h);}" // Create hours select options + "for(i=0;i<=59;i++){ce((i<10)?('0'+i):i,m);}" // Create minutes select options + "for(i=0;i<}1;i++){ce(i+1,d);}" // Create devices + "}else{" + "st();" // Save changes + "}" + "tl=document.getElementsByClassName('tl');" // Remove the background color of all tablinks/buttons + "for(i=0;i>(16+i))&1;eb('w'+i).checked=p;}" // Set weekdays + "p=(s>>23)&0xF;d.value=p+1;" // Set device + "p=(s>>27)&3;eb('p1').value=p;" // Set power + "p=(s>>29)&1;eb('r0').checked=p;" // Set repeat + "p=(s>>30)&1;eb('a0').checked=p;" // Set arm + "ct=t;" + "}"; +const char HTTP_TIMER_STYLE[] PROGMEM = + ".tl{float:left;border-radius:0;border:1px solid #fff;padding:1px;width:6.25%;}" + ""; +const char HTTP_FORM_TIMER[] PROGMEM = + "
 " D_TIMER_PARAMETERS " " + " " + "" D_TIMER_POWER " " + "
" + "
" +// "Time  " + "" D_TIMER_TIME "  :  " + "" D_TIMER_ARM " " + "" D_TIMER_REPEAT "" + "

" + "
"; +const char HTTP_FORM_TIMER2[] PROGMEM = + "type='submit' onclick='st();this.form.submit();'"; + +const char S_CONFIGURE_TIMER[] PROGMEM = D_CONFIGURE_TIMER; + +void HandleTimerConfiguration() +{ + if (HTTP_USER == webserver_state) { + HandleRoot(); + return; + } + AddLog_P(LOG_LEVEL_DEBUG, S_LOG_HTTP, S_CONFIGURE_TIMER); + + String page = FPSTR(HTTP_HEAD); + page.replace(F("{v}"), FPSTR(S_CONFIGURE_TIMER)); + page += FPSTR(HTTP_TIMER_SCRIPT); + page += FPSTR(HTTP_HEAD_STYLE); + page.replace(F(""), FPSTR(HTTP_TIMER_STYLE)); + page += FPSTR(HTTP_FORM_TIMER); + for (byte i = 0; i < MAX_TIMERS; i++) { + if (i > 0) page += F(","); + page += String(Settings.timer[i].data); + } + page += F("' hidden>
"); + for (byte i = 0; i < MAX_TIMERS; i++) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR(""), + i, (0 == i) ? " id='dP'" : "", i +1); + page += mqtt_data; + } + page += FPSTR(HTTP_FORM_TIMER1); + page.replace(F("}1"), String(devices_present)); + char day[4] = { 0 }; + for (byte i = 0; i < 7; i++) { + strncpy_P(day, PSTR(D_DAY3LIST) + (i *3), 3); + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s"), i, i, day); + page += mqtt_data; + } + page += F("
"); + + page += FPSTR(HTTP_FORM_END); + page.replace(F("type='submit'"), FPSTR(HTTP_FORM_TIMER2)); + page += F(""); // Get the element with id='defaultOpen' and click on it + page += FPSTR(HTTP_BTN_CONF); + ShowPage(page); +} + +void TimerSaveSettings() +{ + char tmp[MAX_TIMERS *12]; // Need space for MAX_TIMERS x 10 digit numbers separated by a comma + + WebGetArg("t0", tmp, sizeof(tmp)); + char *p = tmp; + for (byte i = 0; i < MAX_TIMERS; i++) { + uint32_t data = strtol(p, &p, 10); + p++; // Skip comma + if ((data & 0x7FF) < 1440) Settings.timer[i].data = data; + } +} +#endif // USE_TIMERS_WEB +#endif // USE_WEBSERVER + /*********************************************************************************************\ * Interface \*********************************************************************************************/
" D_DOMOTICZ_IDX " {1