diff --git a/sonoff/support_command.ino b/sonoff/support_command.ino index fff2831cb..809b3e154 100644 --- a/sonoff/support_command.ino +++ b/sonoff/support_command.ino @@ -185,6 +185,16 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len) XdrvMailbox.topic = type; XdrvMailbox.data = dataBuf; +#ifdef USE_SCRIPT_SUB_COMMAND + // allow overwrite tasmota cmds + if (!XdrvCall(FUNC_COMMAND)) { + if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) { + if (!XsnsCall(FUNC_COMMAND)) { + type = nullptr; // Unknown command + } + } + } +#else if (!DecodeCommand(kTasmotaCommands, TasmotaCommand)) { if (!XdrvCall(FUNC_COMMAND)) { if (!XsnsCall(FUNC_COMMAND)) { @@ -192,6 +202,8 @@ void CommandHandler(char* topic, uint8_t* data, uint32_t data_len) } } } +#endif + } if (type == nullptr) { diff --git a/sonoff/xdrv_01_webserver.ino b/sonoff/xdrv_01_webserver.ino index ec1303c33..c85c6a252 100644 --- a/sonoff/xdrv_01_webserver.ino +++ b/sonoff/xdrv_01_webserver.ino @@ -91,8 +91,48 @@ const char HTTP_SCRIPT_COUNTER[] PROGMEM = "}" "wl(u);"; -const char HTTP_SCRIPT_ROOT[] PROGMEM = +const char HTTP_SCRIPT_ROOT[] PROGMEM = +#ifdef USE_SCRIPT_WEB_DISPLAY + "var rfsh=1;" + "function la(p){" + "var a='';" + "if(la.arguments.length==1){" + "a=p;" + "clearTimeout(lt);" + "}" + "if(x!=null){x.abort();}" // Abort if no response within 2 seconds (happens on restart 1) + "x=new XMLHttpRequest();" + "x.onreadystatechange=function(){" + "if(x.readyState==4&&x.status==200){" + "var s=x.responseText.replace(/{t}/g,\"\").replace(/{s}/g,\"\").replace(/{c}/g,\"%%'>
hasArg("m") + "x.send();" + "lt=setTimeout(la,%d);" // Settings.web_refresh + "}" + "}" + "function seva(par,ivar){" + "la('&sv='+ivar+'_'+par);" + "}" + "function siva(par,ivar){" + "rfsh=1;" + "la('&sv='+ivar+'_'+par);" + "rfsh=0;" + "}" + "function pr(f){" + "if (f) {" + "lt=setTimeout(la,%d);" + "rfsh=1;" + "} else {" + "clearTimeout(lt);" + "rfsh=0;" + "}" + "}" +#else // USE_SCRIPT_WEB_DISPLAY "function la(p){" "var a='';" "if(la.arguments.length==1){" @@ -111,11 +151,7 @@ const char HTTP_SCRIPT_ROOT[] PROGMEM = "x.send();" "lt=setTimeout(la,%d);" // Settings.web_refresh "}" -#ifdef USE_SCRIPT_WEB_DISPLAY - "function seva(par,ivar){" - "la('&sv='+ivar+'_'+par);" - "}" -#endif +#endif // USE_SCRIPT_WEB_DISPLAY #ifdef USE_JAVASCRIPT_ES6 @@ -939,7 +975,11 @@ void HandleRoot(void) char stemp[5]; WSContentStart_P(S_MAIN_MENU); +#ifdef USE_SCRIPT_WEB_DISPLAY + WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh, Settings.web_refresh); +#else WSContentSend_P(HTTP_SCRIPT_ROOT, Settings.web_refresh); +#endif WSContentSendStyle(); WSContentSend_P(PSTR("
")); diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino index 265411637..40fa40391 100644 --- a/sonoff/xdrv_10_scripter.ino +++ b/sonoff/xdrv_10_scripter.ino @@ -42,8 +42,9 @@ keywords if then else endif, or, and are better readable for beginners (others m #define SCRIPT_DEBUG 0 #define MAXVARS 50 -#define MAXNVARS 45 #define MAXSVARS 5 +#define MAXNVARS MAXVARS-MAXSVARS + #define MAXFILT 5 #define SCRIPT_SVARSIZE 20 #define SCRIPT_MAXSSIZE 48 @@ -465,6 +466,10 @@ char *script; } namep++; index++; + if (index>255) { + free(glob_script_mem.script_mem); + return -5; + } } // copy string variables @@ -1103,7 +1108,7 @@ chknext: fvar=cnt; glob_script_mem.file_flags[cnt].is_open=1; } else { - toLog("file open failed"); + AddLog_P(LOG_LEVEL_INFO,PSTR("file open failed")); } break; } @@ -2103,6 +2108,7 @@ void toLog(const char *str) { AddLog(LOG_LEVEL_INFO); } + void toLogN(const char *cp,uint8_t len) { if (!cp) return; char str[32]; @@ -2295,12 +2301,10 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { if (section) { // we are in section if (*lp=='>') { - section=0; - break; + return 0; } if (*lp=='#') { - section=0; - break; + return 0; } glob_script_mem.var_not_found=0; @@ -2734,6 +2738,7 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { char str[SCRIPT_MAXSSIZE]; lp=getop(lp,&lastop); char *slp=lp; + glob_script_mem.glob_error=0; lp=GetStringResult(lp,OPER_EQU,str,jo); if (!js && glob_script_mem.glob_error) { // mismatch @@ -2778,19 +2783,20 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { return 99; } // check for subroutine - if (*type=='#') { + char *ctype=(char*)type; + if (*ctype=='#') { // check for parameter - type+=tlen; - if (*type=='(') { + ctype+=tlen; + if (*ctype=='(' && *(lp+tlen)=='(') { float fparam; numeric=1; glob_script_mem.glob_error=0; - GetNumericResult((char*)type,OPER_EQU,&fparam,0); + GetNumericResult((char*)ctype,OPER_EQU,&fparam,0); if (glob_script_mem.glob_error==1) { // was string, not number numeric=0; // get the string - GetStringResult((char*)type+1,OPER_EQU,cmpstr,0); + GetStringResult((char*)ctype+1,OPER_EQU,cmpstr,0); } lp+=tlen; if (*lp=='(') { @@ -2821,6 +2827,12 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { } } } + } else { + lp+=tlen; + if (*ctype=='(' || (*lp!=SCRIPT_EOL && *lp!='?')) { + // revert + section=0; + } } } } @@ -2831,11 +2843,17 @@ int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { lp++; } else { lp = strchr(lp, SCRIPT_EOL); - if (!lp) break; + if (!lp) { + if (section) { + return 0; + } else { + return -1; + } + } lp++; } } - return 0; + return -1; } uint8_t script_xsns_index = 0; @@ -3151,13 +3169,13 @@ uint8_t DownloadFile(char *file) { WiFiClient download_Client; if (!SD.exists(file)) { - toLog("file not found"); + AddLog_P(LOG_LEVEL_INFO,PSTR("file not found")); return 0; } download_file=SD.open(file,FILE_READ); if (!download_file) { - toLog("could not open file"); + AddLog_P(LOG_LEVEL_INFO,PSTR("could not open file")); return 0; } @@ -3320,6 +3338,36 @@ void ScriptSaveSettings(void) { #endif + +#ifdef USE_SCRIPT_SUB_COMMAND +bool Script_SubCmd(void) { + if (!bitRead(Settings.rule_enabled, 0)) return false; + + char cmdbuff[128]; + char *cp=cmdbuff; + *cp++='#'; + strcpy(cp,XdrvMailbox.topic); + uint8_t tlen=strlen(XdrvMailbox.topic); + cp+=tlen; + if (XdrvMailbox.index > 0) { + *cp++=XdrvMailbox.index|0x30; + tlen++; + } + if ((XdrvMailbox.payload>0) || (XdrvMailbox.data_len>0)) { + *cp++='('; + strncpy(cp,XdrvMailbox.data,XdrvMailbox.data_len); + cp+=XdrvMailbox.data_len; + *cp++=')'; + *cp=0; + } + //toLog(cmdbuff); + uint32_t res=Run_Scripter(cmdbuff,tlen+1,0); + //AddLog_P2(LOG_LEVEL_INFO,">>%d",res); + if (res) return false; + else return true; +} +#endif + void execute_script(char *script) { char *svd_sp=glob_script_mem.scriptptr; strcat(script,"\n#"); @@ -3341,6 +3389,20 @@ bool ScriptCommand(void) { int command_code = GetCommandCode(command, sizeof(command), XdrvMailbox.topic, kScriptCommands); if (-1 == command_code) { +#ifdef USE_SCRIPT_SUB_COMMAND + strlcpy(command,XdrvMailbox.topic,CMDSZ); + uint32_t pl=XdrvMailbox.payload; + char pld[64]; + strlcpy(pld,XdrvMailbox.data,sizeof(pld)); + if (Script_SubCmd()) { + if (pl>=0) { + Response_P(S_JSON_COMMAND_NVALUE, command, pl); + } else { + Response_P(S_JSON_COMMAND_SVALUE, command, pld); + } + return serviced; + } +#endif serviced = false; // Unknown command } else if ((CMND_SCRIPT == command_code) && (index > 0)) { @@ -3365,15 +3427,15 @@ bool ScriptCommand(void) { return serviced; } snprintf_P (mqtt_data, sizeof(mqtt_data), PSTR("{\"%s\":\"%s\",\"Free\":%d}"),command, GetStateText(bitRead(Settings.rule_enabled,0)),glob_script_mem.script_size-strlen(glob_script_mem.script_ram)); - #ifdef SUPPORT_MQTT_EVENT +#ifdef SUPPORT_MQTT_EVENT } else if (CMND_SUBSCRIBE == command_code) { //MQTT Subscribe command. Subscribe , [, ] String result = ScriptSubscribe(XdrvMailbox.data, XdrvMailbox.data_len); Response_P(S_JSON_COMMAND_SVALUE, command, result.c_str()); } else if (CMND_UNSUBSCRIBE == command_code) { //MQTT Un-subscribe command. UnSubscribe String result = ScriptUnsubscribe(XdrvMailbox.data, XdrvMailbox.data_len); Response_P(S_JSON_COMMAND_SVALUE, command, result.c_str()); - #endif //SUPPORT_MQTT_EVENT - } +#endif //SUPPORT_MQTT_EVENT + } return serviced; } @@ -3628,24 +3690,43 @@ void Script_Check_HTML_Setvars(void) { //toLog(cmdbuf); execute_script(cmdbuf); + Run_Scripter(">E",2,0); } } + +const char SCRIPT_MSG_BUTTONa[] PROGMEM = + ""; + +const char SCRIPT_MSG_BUTTONa_TBL[] PROGMEM = + "
"; + +const char SCRIPT_MSG_BUTTONb[] PROGMEM = + "<\img>"; + +const char SCRIPT_MSG_BUT_START[] PROGMEM = + "
"; +const char SCRIPT_MSG_BUT_START_TBL[] PROGMEM = + "
\").replace(/{m}/g,\"\").replace(/{e}/g,\"
"; + +const char SCRIPT_MSG_BUT_STOP[] PROGMEM = + ""; +const char SCRIPT_MSG_BUT_STOP_TBL[] PROGMEM = + "
"; + const char SCRIPT_MSG_SLIDER[] PROGMEM = "
%s
%s%s
" "
"; -const char SCRIPT_MSG_BUTTON[] PROGMEM = - "
"; - const char SCRIPT_MSG_CHKBOX[] PROGMEM = "
"; const char SCRIPT_MSG_TEXTINP[] PROGMEM = - "
"; + "
"; + +const char SCRIPT_MSG_NUMINP[] PROGMEM = + "
"; -// -// void ScriptGetVarname(char *nbuf,char *sp, uint32_t blen) { uint32_t cnt; @@ -3663,6 +3744,7 @@ void ScriptWebShow(void) { if (web_script==99) { char line[128]; char tmp[128]; + uint8_t optflg=0; char *lp=glob_script_mem.section_ptr+2; while (lp) { while (*lp==SCRIPT_EOL) { @@ -3683,10 +3765,17 @@ void ScriptWebShow(void) { } cp++; } + char *lin=line; + if (*lin=='@') { + lin++; + optflg=1; + } else { + optflg=0; + } // check for input elements - if (!strncmp(line,"sl(",3)) { + if (!strncmp(lin,"sl(",3)) { // insert slider sl(min max var left mid right) - char *lp=line; + char *lp=lin; float min; lp=GetNumericResult(lp+3,OPER_EQU,&min,0); SCRIPT_SKIP_SPACES @@ -3715,8 +3804,8 @@ void ScriptWebShow(void) { WSContentSend_PD(SCRIPT_MSG_SLIDER,left,mid,right,(uint32_t)min,(uint32_t)max,(uint32_t)val,vname); - } else if (!strncmp(line,"ck(",3)) { - char *lp=line+3; + } else if (!strncmp(lin,"ck(",3)) { + char *lp=lin+3; char *slp=lp; float val; lp=GetNumericResult(lp,OPER_EQU,&val,0); @@ -3727,7 +3816,7 @@ void ScriptWebShow(void) { char label[SCRIPT_MAXSSIZE]; lp=GetStringResult(lp,OPER_EQU,label,0); - char *cp; + const char *cp; uint8_t uval; if (val>0) { cp="checked='checked'"; @@ -3736,38 +3825,64 @@ void ScriptWebShow(void) { cp=""; uval=1; } - WSContentSend_PD(SCRIPT_MSG_CHKBOX,label,cp,uval,vname); + WSContentSend_PD(SCRIPT_MSG_CHKBOX,label,(char*)cp,uval,vname); - } else if (!strncmp(line,"bu(",3)) { - char *lp=line+3; - char *slp=lp; - float val; - lp=GetNumericResult(lp,OPER_EQU,&val,0); - SCRIPT_SKIP_SPACES - - char vname[16]; - ScriptGetVarname(vname,slp,sizeof(vname)); - - SCRIPT_SKIP_SPACES - char ontxt[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,ontxt,0); - SCRIPT_SKIP_SPACES - char offtxt[SCRIPT_MAXSSIZE]; - lp=GetStringResult(lp,OPER_EQU,offtxt,0); - - char *cp; - uint8_t uval; - if (val>0) { - cp=ontxt; - uval=0; - } else { - cp=offtxt; - uval=1; + } else if (!strncmp(lin,"bu(",3)) { + char *lp=lin+3; + uint8_t bcnt=0; + char *found=lin; + while (bcnt<4) { + found=strstr(found,"bu("); + if (!found) break; + found+=3; + bcnt++; } - WSContentSend_PD(SCRIPT_MSG_BUTTON,uval,vname,cp); + uint8_t proz=100/bcnt; + if (!optflg && bcnt>1) proz-=2; + if (optflg) WSContentSend_PD(SCRIPT_MSG_BUT_START_TBL); + else WSContentSend_PD(SCRIPT_MSG_BUT_START); + for (uint32_t cnt=0;cnt0) { + cp=ontxt; + uval=0; + } else { + cp=offtxt; + uval=1; + } + if (bcnt>1 && cnt==bcnt-1) { + if (!optflg) proz+=2; + } + if (!optflg) { + WSContentSend_PD(SCRIPT_MSG_BUTTONa,proz,uval,vname,cp); + } else { + WSContentSend_PD(SCRIPT_MSG_BUTTONa_TBL,proz,uval,vname,cp); + } + if (bcnt>1 && cnt%s"),&tmp[1]); + } else if (!strncmp(lin,"nm(",3)) { + char *lp=lin; + float min; + lp=GetNumericResult(lp+3,OPER_EQU,&min,0); + SCRIPT_SKIP_SPACES + float max; + lp=GetNumericResult(lp,OPER_EQU,&max,0); + SCRIPT_SKIP_SPACES + float step; + lp=GetNumericResult(lp,OPER_EQU,&step,0); + SCRIPT_SKIP_SPACES + float val; + char *slp=lp; + lp=GetNumericResult(lp,OPER_EQU,&val,0); + SCRIPT_SKIP_SPACES + char vname[16]; + ScriptGetVarname(vname,slp,sizeof(vname)); + + char label[SCRIPT_MAXSSIZE]; + lp=GetStringResult(lp,OPER_EQU,label,0); + + char vstr[16],minstr[16],maxstr[16],stepstr[16]; + dtostrfd(val,4,vstr); + dtostrfd(min,4,minstr); + dtostrfd(max,4,maxstr); + dtostrfd(step,4,stepstr); + WSContentSend_PD(SCRIPT_MSG_NUMINP,label,minstr,maxstr,stepstr,vstr,vname); + + } else { + Replace_Cmd_Vars(lin,tmp,sizeof(tmp)); + if (optflg) { + WSContentSend_PD(PSTR("
%s
"),tmp); } else { WSContentSend_PD(PSTR("{s}%s{e}"),tmp); }