From b0979f6ef3d669ab932da1fbba38c111cdabf393 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Tue, 16 Jul 2019 16:50:52 +0200 Subject: [PATCH] scripter update --- scripter.md | 8 +- sonoff/xdrv_10_scripter.ino | 159 +++++++++++++++++++++++++----------- 2 files changed, 118 insertions(+), 49 deletions(-) diff --git a/scripter.md b/scripter.md index 5a87602e3..5dd9ed462 100644 --- a/scripter.md +++ b/scripter.md @@ -53,6 +53,9 @@ executed on BOOT time >**\>T** executed on teleperiod time (**SENSOR** and **STATE**), get tele vars only in this section +>**\>F** +executed every 100 ms + >**\>S** executed every second @@ -76,6 +79,7 @@ special variables (read only): **gtopic** = mqtt group topic **prefixn** = prefix n = 1-3 **pwr[x]** = tasmota power state (x = 1-N) +**pc[x]** = tasmota pulse counter value (x = 1-4) **tbut[x]** = touch screen button state (x = 1-N) **sw[x]** = tasmota switch state (x = 1-N) >**pin[x]** = gpio pin level (x = 0-16) @@ -129,6 +133,7 @@ variable that special variable is discarded **Tasmota** cmds start with **=\>** within cmds you can replace text with variables with **%varname%** a single percent sign must be given as **%%** +**->** is equivalent but doesnt send mqtt or any weblog (silent execute, usefull to reduce traffic) **special** cmds: @@ -187,9 +192,10 @@ specifies a for next loop, (loop count must not be less then 1) **case a** **case b** **ends** -specifies a switch case selector +specifies a switch case selector (numeric or string) **sd card support** +(currently only works with 2.42 ???) enable by CARD_CS = gpio pin of card chip select (+ 10k flash) \#define USE_SCRIPT_FATFS CARD_CS sd card uses standard hardware spi gpios: mosi,miso,sclk diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino index dfda351cf..48487ddaf 100644 --- a/sonoff/xdrv_10_scripter.ino +++ b/sonoff/xdrv_10_scripter.ino @@ -35,8 +35,6 @@ no math hierarchy (costs ram and execution time, better group with brackets, an (will probably make math hierarchy an ifdefed option) keywords if then else endif, or, and are better readable for beginners (others may use {}) - - \*********************************************************************************************/ #define XDRV_10 10 @@ -151,7 +149,7 @@ struct SCRIPT_MEM { int16_t last_findex; uint8_t tasm_cmd_activ=0; - +uint8_t fast_script=0; uint32_t script_lastmillis; char *GetNumericResult(char *lp,uint8_t lastop,float *fp,JsonObject *jo); @@ -321,7 +319,7 @@ char *script; if (isdigit(*op)) { // lenght define follows uint8_t flen=atoi(op); - mfilt[numflt-1].numvals&=0x7f; + mfilt[numflt-1].numvals&=0x80; mfilt[numflt-1].numvals|=flen&0x7f; } } @@ -1295,7 +1293,16 @@ chknext: len+=1; goto exit; } + if (!strncmp(vname,"pc[",3)) { + GetNumericResult(vname+3,OPER_EQU,&fvar,0); + uint8_t index=fvar; + if (index<1 || index>MAX_COUNTERS) index=1; + fvar=RtcSettings.pulse_counter[index-1]; + len+=1; + goto exit; + } break; + case 'r': if (!strncmp(vname,"ram",3)) { fvar=glob_script_mem.script_mem_size+(glob_script_mem.script_size)+(MAX_RULE_MEMS*10); @@ -1878,13 +1885,20 @@ void toSLog(const char *str) { #define IF_NEST 8 // execute section of scripter -int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { - uint8_t vtype=0,sindex,xflg,floop=0,globvindex,globaindex; +int16_t Run_Scripter(const char *type, int8_t tlen, char *js) { + uint8_t vtype=0,sindex,xflg,floop=0,globvindex; + int8_t globaindex; struct T_INDEX ind; - uint8_t operand,lastop,numeric=1,if_state[IF_NEST],if_result[IF_NEST],and_or,ifstck=0,s_ifstck=0; + uint8_t operand,lastop,numeric=1,if_state[IF_NEST],if_exe[IF_NEST],if_result[IF_NEST],and_or,ifstck=0; if_state[ifstck]=0; if_result[ifstck]=0; + if_exe[ifstck]=1; char cmpstr[SCRIPT_MAXSSIZE]; + uint8_t check=0; + if (tlen<0) { + tlen=abs(tlen); + check=1; + } if (tasm_cmd_activ) return 0; @@ -1932,32 +1946,35 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { //#if SCRIPT_DEBUG>0 #ifdef IFTHEN_DEBUG char tbuff[128]; - sprintf(tbuff,"stack=%d,state=%d,cmpres=%d line: ",ifstck,if_state[ifstck],if_result[ifstck]); + sprintf(tbuff,"stack=%d,exe=%d,state=%d,cmpres=%d line: ",ifstck,if_exe[ifstck],if_state[ifstck],if_result[ifstck]); toLogEOL(tbuff,lp); #endif +//if (if_state[s_ifstck]==3 && if_result[s_ifstck]) goto next_line; +//if (if_state[s_ifstck]==2 && !if_result[s_ifstck]) goto next_line; + if (!strncmp(lp,"if",2)) { lp+=2; - if (if_state[ifstck]>0) { - if (ifstck=2) { lp+=5; - if_state[ifstck]=0; if (ifstck>0) { + if_state[ifstck]=0; ifstck--; } - if (if_state[ifstck]==3 && if_result[ifstck]) goto next_line; - if (if_state[ifstck]==2 && !if_result[ifstck]) goto next_line; - s_ifstck=ifstck; // >>>>> goto next_line; } else if (!strncmp(lp,"or",2) && if_state[ifstck]==1) { lp+=2; @@ -1970,6 +1987,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { if (*lp=='{' && if_state[ifstck]==1) { lp+=1; // then if_state[ifstck]=2; + if (if_exe[ifstck-1]) if_exe[ifstck]=if_result[ifstck]; } else if (*lp=='{' && if_state[ifstck]==3) { lp+=1; // after else //if_state[ifstck]=3; @@ -1985,8 +2003,11 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { if (!strncmp(lp,"else",4)) { // is before else, no endif if_state[ifstck]=3; + if (if_exe[ifstck-1]) if_exe[ifstck]=!if_result[ifstck]; lp+=4; iselse=1; + SCRIPT_SKIP_SPACES + if (*lp=='{') lp++; break; } lp++; @@ -1994,13 +2015,11 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { if (!iselse) { lp=slp; // endif - if_state[ifstck]=0; if (ifstck>0) { + if_state[ifstck]=0; ifstck--; } - if (if_state[ifstck]==3 && if_result[ifstck]) goto next_line; - if (if_state[ifstck]==2 && !if_result[ifstck]) goto next_line; - s_ifstck=ifstck; // >>>>> + goto next_line; } } @@ -2041,24 +2060,42 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { if (!strncmp(lp,"switch",6)) { lp+=6; SCRIPT_SKIP_SPACES + char *slp=lp; lp=GetNumericResult(lp,OPER_EQU,&swvar,0); - swflg=1; + if (glob_script_mem.glob_error==1) { + // was string, not number + lp=slp; + // get the string + lp=isvar(lp,&vtype,&ind,0,cmpstr,0); + swflg=0x81; + } else { + swflg=1; + } } else if (!strncmp(lp,"case",4) && swflg>0) { lp+=4; SCRIPT_SKIP_SPACES float cvar; - lp=GetNumericResult(lp,OPER_EQU,&cvar,0); - if (swvar!=cvar) { - swflg=2; + if (!(swflg&0x80)) { + lp=GetNumericResult(lp,OPER_EQU,&cvar,0); + if (swvar!=cvar) { + swflg=2; + } else { + swflg=1; + } } else { - swflg=1; + char str[SCRIPT_MAXSSIZE]; + lp=GetStringResult(lp,OPER_EQU,str,0); + if (!strcmp(cmpstr,str)) { + swflg=0x81; + } else { + swflg=0x82; + } } } else if (!strncmp(lp,"ends",4) && swflg>0) { lp+=4; swflg=0; } - - if (swflg==2) goto next_line; + if ((swflg&3)==2) goto next_line; SCRIPT_SKIP_SPACES //SCRIPT_SKIP_EOL @@ -2067,14 +2104,12 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { } //toLogN(lp,16); - if (if_state[s_ifstck]==3 && if_result[s_ifstck]) goto next_line; - if (if_state[s_ifstck]==2 && !if_result[s_ifstck]) goto next_line; + if (!if_exe[ifstck] && if_state[ifstck]!=1) goto next_line; #ifdef IFTHEN_DEBUG - sprintf(tbuff,"stack=%d,state=%d,cmpres=%d execute line: ",ifstck,if_state[ifstck],if_result[ifstck]); + sprintf(tbuff,"stack=%d,exe=%d,state=%d,cmpres=%d execute line: ",ifstck,if_exe[ifstck],if_state[ifstck],if_result[ifstck]); toLogEOL(tbuff,lp); #endif - s_ifstck=ifstck; if (!strncmp(lp,"break",5)) { if (floop) { @@ -2122,8 +2157,10 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { goto next_line; } - else if (!strncmp(lp,"=>",2)) { + else if (!strncmp(lp,"=>",2) || !strncmp(lp,"->",2)) { // execute cmd + uint8_t sflag=0,svmqtt,swll; + if (*lp=='-') sflag=1; lp+=2; char *slp=lp; SCRIPT_SKIP_SPACES @@ -2150,11 +2187,22 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { if (!strncmp(tmp,"print",5)) { toLog(&tmp[5]); } else { - snprintf_P(log_data, sizeof(log_data), PSTR("Script: performs \"%s\""), tmp); - AddLog(glob_script_mem.script_loglevel&0x7f); + if (!sflag) { + snprintf_P(log_data, sizeof(log_data), PSTR("Script: performs \"%s\""), tmp); + AddLog(glob_script_mem.script_loglevel&0x7f); + } else { + svmqtt=Settings.flag.mqtt_enabled; + swll=Settings.weblog_level; + Settings.flag.mqtt_enabled=0; + Settings.weblog_level=0; + } tasm_cmd_activ=1; ExecuteCommand((char*)tmp, SRC_RULE); tasm_cmd_activ=0; + if (sflag) { + Settings.flag.mqtt_enabled=svmqtt; + Settings.weblog_level=swll; + } } if (cmdmem) free(cmdmem); } @@ -2178,7 +2226,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { } // check for variable result - if (if_state[s_ifstck]==1) { + if (if_state[ifstck]==1) { // compare dfvar=&fvar; glob_script_mem.glob_error=0; @@ -2218,7 +2266,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { } // evaluate operand lp=getop(lp,&lastop); - if (if_state[s_ifstck]==1) { + if (if_state[ifstck]==1) { if (numeric) { uint8_t res=0; lp=GetNumericResult(lp,OPER_EQU,&fvar1,jo); @@ -2247,15 +2295,15 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { } if (!and_or) { - if_result[s_ifstck]=res; + if_result[ifstck]=res; } else if (and_or==1) { - if_result[s_ifstck]|=res; + if_result[ifstck]|=res; } else { - if_result[s_ifstck]&=res; + if_result[ifstck]&=res; } #if SCRIPT_DEBUG>0 char tbuff[128]; - sprintf(tbuff,"p1=%d,p2=%d,cmpres=%d line: ",(int32_t)*dfvar,(int32_t)fvar1,if_result[s_ifstck]); + sprintf(tbuff,"p1=%d,p2=%d,cmpres=%d line: ",(int32_t)*dfvar,(int32_t)fvar1,if_result[ifstck]); toLogEOL(tbuff,lp); #endif @@ -2268,11 +2316,11 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { res=strcmp(cmpstr,str); if (lastop==OPER_EQUEQU) res=!res; if (!and_or) { - if_result[s_ifstck]=res; + if_result[ifstck]=res; } else if (and_or==1) { - if_result[s_ifstck]|=res; + if_result[ifstck]|=res; } else { - if_result[s_ifstck]&=res; + if_result[ifstck]&=res; } } } @@ -2280,6 +2328,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { if (*lp=='{' && if_state[ifstck]==1) { lp+=1; // then if_state[ifstck]=2; + if (if_exe[ifstck-1]) if_exe[ifstck]=if_result[ifstck]; } goto next_line; } else { @@ -2393,6 +2442,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { if (!strncmp(lp,type,tlen)) { // found section section=1; + if (check) return 99; // check for subroutine if (*type=='#') { // check for parameter @@ -2451,6 +2501,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { lp++; } } + return 0; } uint8_t script_xsns_index = 0; @@ -2470,6 +2521,7 @@ void ScripterEvery100ms(void) { Run_Scripter(">T",2, mqtt_data); } } + if (fast_script==99) Run_Scripter(">F",2,0); } //mems[MAX_RULE_MEMS] is 50 bytes in 6.5 @@ -2925,6 +2977,7 @@ void ScriptSaveSettings(void) { return; } Run_Scripter(">B",2,0); + fast_script=Run_Scripter(">F",-2,0); } } @@ -2980,14 +3033,21 @@ bool ScriptCommand(void) { #ifdef USE_SCRIPT_FATFS -#ifdef FAT_DATE + +uint16_t xFAT_DATE(uint16_t year, uint8_t month, uint8_t day) { + return (year - 1980) << 9 | month << 5 | day; +} +uint16_t xFAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) { + return hour << 11 | minute << 5 | second >> 1; +} + void dateTime(uint16_t* date, uint16_t* time) { // return date using FAT_DATE macro to format fields - *date = FAT_DATE(RtcTime.year,RtcTime.month, RtcTime.day_of_month); + *date = xFAT_DATE(RtcTime.year,RtcTime.month, RtcTime.day_of_month); // return time using FAT_TIME macro to format fields - *time = FAT_TIME(RtcTime.hour,RtcTime.minute,RtcTime.second); + *time = xFAT_TIME(RtcTime.hour,RtcTime.minute,RtcTime.second); } -#endif + #endif /*********************************************************************************************\ @@ -3050,7 +3110,7 @@ bool Xdrv10(uint8_t function) glob_script_mem.flags=1; -#ifdef FAT_DATE +#if defined(ARDUINO_ESP8266_RELEASE_2_3_0) || defined(ARDUINO_ESP8266_RELEASE_2_4_2) // for unkonwn reasons is not defined in 2.52 SdFile::dateTimeCallback(dateTime); #endif @@ -3070,7 +3130,10 @@ bool Xdrv10(uint8_t function) if (bitRead(Settings.rule_enabled, 0)) Init_Scripter(); break; case FUNC_INIT: - if (bitRead(Settings.rule_enabled, 0)) Run_Scripter(">B",2,0); + if (bitRead(Settings.rule_enabled, 0)) { + Run_Scripter(">B",2,0); + fast_script=Run_Scripter(">F",-2,0); + } break; case FUNC_EVERY_100_MSECOND: ScripterEvery100ms();