v5.12.0i - Add Timers webpage

5.12.0i
 * 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
This commit is contained in:
Theo Arends 2018-03-28 18:01:38 +02:00
parent d564615b7d
commit c4b3d42693
19 changed files with 382 additions and 79 deletions

View File

@ -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)

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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 "Энергия Вчера"

View File

@ -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 "昨日用电量"

View File

@ -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 "昨日用電量"

View File

@ -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

View File

@ -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

View File

@ -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,\"<table style='width:100%'>\").replace(/{s}/g,\"<tr><th>\").replace(/{m}/g,\"</th><td>\").replace(/{e}/g,\"</td></tr>\").replace(/{c}/g,\"%'><div style='text-align:center;font-weight:\");"
"document.getElementById('l1').innerHTML=s;"
"eb('l1').innerHTML=s;"
"}"
"};"
"x.open('GET','ay'+a,true);"
@ -110,9 +113,9 @@ const char HTTP_SCRIPT_CONSOL[] PROGMEM =
"var c,o,t;"
"clearTimeout(lt);"
"o='';"
"t=document.getElementById('t1');"
"t=eb('t1');"
"if(p==1){"
"c=document.getElementById('c1');"
"c=eb('c1');"
"o='&c1='+encodeURIComponent(c.value);"
"c.value='';"
"t.scrollTop=sn;"
@ -143,7 +146,7 @@ const char HTTP_SCRIPT_MODULE1[] PROGMEM =
"var os;"
"function sk(s,g){"
"var o=os.replace(\"value='\"+s+\"'\",\"selected value='\"+s+\"'\");"
"document.getElementById('g'+g).innerHTML=o;"
"eb('g'+g).innerHTML=o;"
"}"
"function sl(){"
"var o0=\"";
@ -158,7 +161,7 @@ const char HTTP_SCRIPT_INFO_BEGIN[] PROGMEM =
const char HTTP_SCRIPT_INFO_END[] PROGMEM =
"\";" // "}1" and "}2" means do not use "}x" in Information text
"s=o.replace(/}1/g,\"</td></tr><tr><th>\").replace(/}2/g,\"</th><td>\");"
"document.getElementById('i').innerHTML=s;"
"eb('i').innerHTML=s;"
"}"
"</script>";
const char HTTP_MSG_SLIDER1[] PROGMEM =
@ -180,6 +183,11 @@ const char HTTP_BTN_RSTRT[] PROGMEM =
"<br/><form action='rb' method='get' onsubmit='return confirm(\"" D_CONFIRM_RESTART "\");'><button>" D_RESTART "</button></form>";
const char HTTP_BTN_MENU2[] PROGMEM =
"<br/><form action='md' method='get'><button>" D_CONFIGURE_MODULE "</button></form>"
#ifdef USE_TIMERS
#ifdef USE_TIMERS_WEB
"<br/><form action='tm' method='get'><button>" D_CONFIGURE_TIMER "</button></form>"
#endif // USE_TIMERS_WEB
#endif // USE_TIMERS
"<br/><form action='w0' method='get'><button>" D_CONFIGURE_WIFI "</button></form>";
const char HTTP_BTN_MENU3[] PROGMEM =
"<br/><form action='mq' method='get'><button>" D_CONFIGURE_MQTT "</button></form>"
@ -206,7 +214,7 @@ const char HTTP_BTN_CONF[] PROGMEM =
"<br/><br/><form action='cn' method='get'><button>" D_CONFIGURATION "</button></form>";
const char HTTP_FORM_MODULE[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MODULE_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='6' hidden><input id='r' name='r' value='1' hidden>"
"<input id='w' name='w' value='6,1' hidden>"
"<br/><b>" D_MODULE_TYPE "</b> ({mt)<br/><select id='g99' name='g99'></select><br/>";
const char HTTP_LNK_ITEM[] PROGMEM =
"<div><a href='#p' onclick='c(this)'>{v}</a>&nbsp;<span class='q'>{i} {r}%</span></div>";
@ -214,7 +222,7 @@ const char HTTP_LNK_SCAN[] PROGMEM =
"<div><a href='/w1'>" D_SCAN_FOR_WIFI_NETWORKS "</a></div><br/>";
const char HTTP_FORM_WIFI[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_WIFI_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='1' hidden><input id='r' name='r' value='1' hidden>"
"<input id='w' name='w' value='1,1' hidden>"
"<br/><b>" D_AP1_SSID "</b> (" STA_SSID1 ")<br/><input id='s1' name='s1' placeholder='" STA_SSID1 "' value='{s1'><br/>"
"<br/><b>" D_AP1_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_AP1_PASSWORD "' value='********'><br/>"
"<br/><b>" D_AP2_SSID "</b> (" STA_SSID2 ")<br/><input id='s2' name='s2' placeholder='" STA_SSID2 "' value='{s2'><br/>"
@ -222,7 +230,7 @@ const char HTTP_FORM_WIFI[] PROGMEM =
"<br/><b>" D_HOSTNAME "</b> (" WIFI_HOSTNAME ")<br/><input id='h' name='h' placeholder='" WIFI_HOSTNAME" ' value='{h1'><br/>";
const char HTTP_FORM_MQTT[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_MQTT_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='2' hidden><input id='r' name='r' value='1' hidden>"
"<input id='w' name='w' value='2,1' hidden>"
"<br/><b>" D_HOST "</b> (" MQTT_HOST ")<br/><input id='mh' name='mh' placeholder='" MQTT_HOST" ' value='{m1'><br/>"
"<br/><b>" D_PORT "</b> (" STR(MQTT_PORT) ")<br/><input id='ml' name='ml' placeholder='" STR(MQTT_PORT) "' value='{m2'><br/>"
"<br/><b>" D_CLIENT "</b> ({m0)<br/><input id='mc' name='mc' placeholder='" MQTT_CLIENT_ID "' value='{m3'><br/>"
@ -232,7 +240,7 @@ const char HTTP_FORM_MQTT[] PROGMEM =
"<br/><b>" D_FULL_TOPIC "</b> (" MQTT_FULLTOPIC ")<br/><input id='mf' name='mf' placeholder='" MQTT_FULLTOPIC" ' value='{m7'><br/>";
const char HTTP_FORM_LOG1[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_LOGGING_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='3' hidden><input id='r' name='r' value='0' hidden>";
"<input id='w' name='w' value='3,0' hidden>";
const char HTTP_FORM_LOG2[] PROGMEM =
"<br/><b>{b0</b> ({b1)<br/><select id='{b2' name='{b2'>"
"<option{a0value='0'>0 " D_NONE "</option>"
@ -247,7 +255,7 @@ const char HTTP_FORM_LOG3[] PROGMEM =
"<br/><b>" D_TELEMETRY_PERIOD "</b> (" STR(TELE_PERIOD) ")<br/><input id='lt' name='lt' placeholder='" STR(TELE_PERIOD) "' value='{l4'><br/>";
const char HTTP_FORM_OTHER[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_OTHER_PARAMETERS "&nbsp;</b></legend><form method='get' action='sv'>"
"<input id='w' name='w' value='5' hidden><input id='r' name='r' value='1' hidden>"
"<input id='w' name='w' value='5,1' hidden>"
"<br/><b>" D_WEB_ADMIN_PASSWORD "</b><br/><input id='p1' name='p1' type='password' placeholder='" D_WEB_ADMIN_PASSWORD "' value='********'><br/>"
"<br/><input style='width:10%;' id='b1' name='b1' type='checkbox'{r1><b>" D_MQTT_ENABLE "</b><br/>";
const char HTTP_FORM_OTHER2[] PROGMEM =
@ -274,7 +282,7 @@ const char HTTP_FORM_UPG[] PROGMEM =
const char HTTP_FORM_RST_UPG[] PROGMEM =
"<form method='post' action='u2' enctype='multipart/form-data'>"
"<br/><input type='file' name='u2'><br/>"
"<br/><button type='submit' onclick='document.getElementById(\"f1\").style.display=\"none\";document.getElementById(\"f2\").style.display=\"block\";this.form.submit();'>" D_START " {r1</button></form>"
"<br/><button type='submit' onclick='eb(\"f1\").style.display=\"none\";eb(\"f2\").style.display=\"block\";this.form.submit();'>" D_START " {r1</button></form>"
"</fieldset>"
"</div>"
"<div id='f2' name='f2' style='display:none;text-align:center;'><b>" D_UPLOAD_STARTED " ...</b></div>";
@ -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));

View File

@ -22,7 +22,7 @@
#ifdef USE_WEBSERVER
const char HTTP_FORM_DOMOTICZ[] PROGMEM =
"<fieldset><legend><b>&nbsp;" D_DOMOTICZ_PARAMETERS "&nbsp;</b></legend><form method='post' action='sv'>"
"<input id='w' name='w' value='4' hidden><input id='r' name='r' value='1' hidden>"
"<input id='w' name='w' value='4,1' hidden>"
"<br/><table>";
const char HTTP_FORM_DOMOTICZ_RELAY[] PROGMEM =
"<tr><td style='width:260px'><b>" D_DOMOTICZ_IDX " {1</b></td><td style='width:70px'><input id='r{1' name='r{1' placeholder='0' value='{2'></td></tr>"

View File

@ -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
}
if (root[UpperCase_P(parm_uc, PSTR(D_JSON_TIMER_TIME))].success()) {
uint16_t itime = 0;
uint8_t value = 0;
char time_str[10];
} 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;
}
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 > 23) value = 23;
itime = value * 60;
substr = strtok(NULL, ":");
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;
}
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;
}
}
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_REPEAT))].success()) {
Settings.timer[index].repeat = (root[parm_uc] != 0);
}
}
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_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<tl.length;i++){tl[i].style.cssText=\"background-color:#ccc;color:#fff;font-weight:normal;\"}"
// Add the specific color to the button used to open the tab content
"e.style.cssText=\"background-color:#fff;color:#000;font-weight:bold;\";"
"s=pt[t];" // Get parameters from array
"p=s&0x7FF;" // Get time
"q=Math.floor(p/60);if(q<10){q='0'+q;}h.value=q;" // Set hours
"q=p%60;if(q<10){q='0'+q;}m.value=q;" // Set minutes
"for(i=0;i<7;i++){p=(s>>(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%;}"
"</style>";
const char HTTP_FORM_TIMER[] PROGMEM =
"<fieldset style='min-width:470px;text-align:center;'><legend style='text-align:left;'><b>&nbsp;" D_TIMER_PARAMETERS "&nbsp;</b></legend><form method='post' action='sv'>"
"<input id='w' name='w' value='7,0' hidden><input id='t0' name='t0' value='";
const char HTTP_FORM_TIMER1[] PROGMEM =
"</div><br/><br/><br/>"
"<div>"
"<b>" D_TIMER_DEVICE "</b>&nbsp;<span><select style='width:12%;' id='d1' name='d1'></select></span>&emsp;"
"<b>" D_TIMER_POWER "</b>&nbsp;<select style='width:25%;' id='p1' name='p1'>"
"<option value='0'>" D_OFF "</option>"
"<option value='1'>" D_ON "</option>"
"<option value='2'>" D_TOGGLE "</option>"
"<option value='3'>" D_BLINK "</option>"
"</select>"
"</div><br/>"
"<div>"
// "<b>Time</b>&nbsp;<input type='time' style='width:25%;' id='s1' name='s1' value='00:00' pattern='[0-9]{2}:[0-9]{2}'>&emsp;"
"<b>" D_TIMER_TIME "</b>&nbsp;<span><select style='width:12%;' id='ho' name='ho'></select></span>&nbsp;:&nbsp;<span><select style='width:12%;' id='mi' name='mi'></select></span>&emsp;"
"<input style='width:5%;' id='a0' name='a0' type='checkbox'><b>" D_TIMER_ARM "</b>&emsp;"
"<input style='width:5%;' id='r0' name='r0' type='checkbox'><b>" D_TIMER_REPEAT "</b>"
"</div><br/>"
"<div>";
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("</style>"), 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><div>");
for (byte i = 0; i < MAX_TIMERS; i++) {
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("<button type='button' class='tl' onclick=\"ot(%d,this)\"%s>%d</button>"),
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("<input style='width:5%%;' id='w%d' name='w%d' type='checkbox'><b>%s</b>"), i, i, day);
page += mqtt_data;
}
page += F("</div>");
page += FPSTR(HTTP_FORM_END);
page.replace(F("type='submit'"), FPSTR(HTTP_FORM_TIMER2));
page += F("<script>eb('dP').click();</script>"); // 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
\*********************************************************************************************/