Merge pull request #6480 from gemu2015/scripter-update

Scripter update
This commit is contained in:
Theo Arends 2019-09-24 16:39:38 +02:00 committed by GitHub
commit d984646731
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 263 additions and 69 deletions

View File

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

View File

@ -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,\"<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:\");"
"eb('l1').innerHTML=s;"
"}"
"};"
"if (rfsh) {"
"x.open('GET','.?m=1'+a,true);" // ?m related to WebServer->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("<div id='l1' name='l1'></div>"));

View File

@ -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 <Event>, <Topic> [, <Key>]
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 <Event>
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 =
"<button type='submit' style=\"width:%d%%\" onclick='seva(%d,\"%s\")'>%s</button>";
const char SCRIPT_MSG_BUTTONa_TBL[] PROGMEM =
"<td style=\"width:%d%%\"><button type='submit' onclick='seva(%d,\"%s\")'>%s</button></td>";
const char SCRIPT_MSG_BUTTONb[] PROGMEM =
"<img width=\"%d%%\"><\img>";
const char SCRIPT_MSG_BUT_START[] PROGMEM =
"<div>";
const char SCRIPT_MSG_BUT_START_TBL[] PROGMEM =
"<table style='width:100%%'><tr>";
const char SCRIPT_MSG_BUT_STOP[] PROGMEM =
"</div>";
const char SCRIPT_MSG_BUT_STOP_TBL[] PROGMEM =
"</tr></table>";
const char SCRIPT_MSG_SLIDER[] PROGMEM =
"<div><span class='p'>%s</span><center><b>%s</b><span class='q'>%s</span></div>"
"<div><input type='range' min='%d' max='%d' value='%d' onchange='seva(value,\"%s\")'></div>";
const char SCRIPT_MSG_BUTTON[] PROGMEM =
"<div><button type='submit' onclick='seva(%d,\"%s\")'>%s</button></div>";
const char SCRIPT_MSG_CHKBOX[] PROGMEM =
"<div><center><label><b>%s</b><input type='checkbox' %s onchange='seva(%d,\"%s\")'></label></div>";
const char SCRIPT_MSG_TEXTINP[] PROGMEM =
"<div><center><label><b>%s</b><input type='text' value='%s' style='width:200px' onchange='seva(value,\"%s\")'></label></div>";
"<div><center><label><b>%s</b><input type='text' value='%s' style='width:200px' onfocusin='pr(0)' onfocusout='pr(1)' onchange='siva(value,\"%s\")'></label></div>";
const char SCRIPT_MSG_NUMINP[] PROGMEM =
"<div><center><label><b>%s</b><input min='%s' max='%s' step='%s' value='%s' type='number' style='width:200px' onfocusin='pr(0)' onfocusout='pr(1)' onchange='siva(value,\"%s\")'></label></div>";
//<input onkeypress="if(event.key == 'Enter') {console.log('Test')}">
//<input onBlur="if (this.value == '') { var field = this; setTimeout(function() { field.focus(); }, 0); }" type="text">
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;cnt<bcnt;cnt++) {
float val;
char *slp=lp;
lp=GetNumericResult(lp,OPER_EQU,&val,0);
SCRIPT_SKIP_SPACES
} else if (!strncmp(line,"tx(",3)) {
char *lp=line+3;
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;
}
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<bcnt-1) {
if (!optflg) WSContentSend_PD(SCRIPT_MSG_BUTTONb,2);
}
lp+=4;
}
if (optflg) WSContentSend_PD(SCRIPT_MSG_BUT_STOP_TBL);
else WSContentSend_PD(SCRIPT_MSG_BUT_STOP);
} else if (!strncmp(lin,"tx(",3)) {
char *lp=lin+3;
char *slp=lp;
char str[SCRIPT_MAXSSIZE];
lp=ForceStringVar(lp,str);
@ -3780,11 +3895,38 @@ void ScriptWebShow(void) {
WSContentSend_PD(SCRIPT_MSG_TEXTINP,label,str,vname);
}
else {
Replace_Cmd_Vars(line,tmp,sizeof(tmp));
if (tmp[0]=='@') {
WSContentSend_PD(PSTR("<div>%s</div>"),&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("<div>%s</div>"),tmp);
} else {
WSContentSend_PD(PSTR("{s}%s{e}"),tmp);
}