From 48eb9c437eaf986046cb3a3be121aea62d8aea04 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Wed, 22 May 2019 12:33:51 +0200 Subject: [PATCH 1/3] Update xdrv_10_scripter.ino optimized median filter, support for opt filter lenght, support for arrays string token support, at least needed to decode json comma seperated values (now all json result may be decoded) --- sonoff/xdrv_10_scripter.ino | 192 +++++++++++++++++++++++++++--------- 1 file changed, 146 insertions(+), 46 deletions(-) diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino index 9edd27a9f..288a052ee 100644 --- a/sonoff/xdrv_10_scripter.ino +++ b/sonoff/xdrv_10_scripter.ino @@ -20,17 +20,15 @@ #ifdef USE_SCRIPT #ifndef USE_RULES /*********************************************************************************************\ - for documentation see up to date docs in file SCRIPTER.md - uses about 14,2 k of flash more stack could be needed for sendmail => -D CONT_STACKSIZE=4800 = +0.8k stack -0.8k heap - to do optimize code for space remarks + goal is fast execution time, minimal use of ram and intuitive syntax therefore => case sensitive cmds and vars (lowercase uses time and code) @@ -38,6 +36,10 @@ 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 {}) +changelog after merging to Tasmota +1.01 optimized median filter, support for opt filter lenght, support for arrays +1.02 string token support + \*********************************************************************************************/ #define XDRV_10 10 @@ -104,11 +106,14 @@ struct SCRIPT_MEM { uint8_t script_loglevel; } glob_script_mem; + +int16_t last_findex; uint8_t tasm_cmd_activ=0; uint32_t script_lastmillis; char *GetNumericResult(char *lp,uint8_t lastop,float *fp,JsonObject *jo); +char *GetStringResult(char *lp,uint8_t lastop,char *cp,JsonObject *jo); void ScriptEverySecond(void) { @@ -243,6 +248,19 @@ int16_t Init_Scripter(char *script) { if (nvars>MAXNVARS) { return -1; } + if (vtypes[vars].bits.is_filter) { + while (isdigit(*op) || *op=='.' || *op=='-') { + op++; + } + while (*op==' ') op++; + if (isdigit(*op)) { + // lenght define follows + uint8_t flen=atoi(op); + mfilt[numflt-1].numvals&=0x7f; + mfilt[numflt-1].numvals|=flen&0x7f; + } + } + } else { // string vars op++; @@ -445,9 +463,65 @@ int16_t Init_Scripter(char *script) { #define NTYPE 0 #define STYPE 0x80 +#define FLT_MAX 99999999 + +float median_array(float *array,uint8_t len) { + uint8_t ind[len]; + uint8_t mind=0,index=0,flg; + float min=FLT_MAX; + + for (uint8_t hcnt=0; hcntnumvals&0x7f; + if (!bind) { + return mflp->index; + } + if (bind<1 || bind>maxind) bind=maxind; + return mflp->rbuff[bind-1]; + } + mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + } + return 0; +} + +void Set_MFVal(uint8_t index,uint8_t bind,float val) { + uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; + for (uint8_t count=0; countnumvals&0x7f; + if (bind<1 || bind>maxind) bind=maxind; + mflp->rbuff[bind-1]=val; + } + mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); + } +} -//Settings.seriallog_level -//Settings.weblog_level float Get_MFilter(uint8_t index) { uint8_t *mp=(uint8_t*)glob_script_mem.mfilt; @@ -458,23 +532,8 @@ float Get_MFilter(uint8_t index) { // moving average return mflp->maccu/(mflp->numvals&0x7f); } else { - // median, sort array - float tbuff[mflp->numvals],tmp; - uint8_t flag; - memmove(tbuff,mflp->rbuff,sizeof(tbuff)); - for (uint8_t ocnt=0; ocntnumvals; ocnt++) { - flag=0; - for (uint8_t count=0; countnumvals-1; count++) { - if (tbuff[count]>tbuff[count+1]) { - tmp=tbuff[count]; - tbuff[count]=tbuff[count+1]; - tbuff[count+1]=tmp; - flag=1; - } - } - if (!flag) break; - } - return mflp->rbuff[mflp->numvals/2]; + // median, sort array indices + return median_array(mflp->rbuff,mflp->numvals); } } mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float); @@ -519,27 +578,10 @@ float DoMedian5(uint8_t index, float in) { if (index>=MEDIAN_FILTER_NUM) index=0; struct MEDIAN_FILTER* mf=&script_mf[index]; - - float tbuff[MEDIAN_SIZE],tmp; - uint8_t flag; mf->buffer[mf->index]=in; mf->index++; if (mf->index>=MEDIAN_SIZE) mf->index=0; - // sort list and take median - memmove(tbuff,mf->buffer,sizeof(tbuff)); - for (uint8_t ocnt=0; ocnttbuff[count+1]) { - tmp=tbuff[count]; - tbuff[count]=tbuff[count+1]; - tbuff[count+1]=tmp; - flag=1; - } - } - if (!flag) break; - } - return tbuff[MEDIAN_SIZE/2]; + return median_array(mf->buffer,MEDIAN_SIZE); } @@ -606,19 +648,35 @@ char *isvar(char *lp, uint8_t *vtype,struct T_INDEX *tind,float *fp,char *sp,Jso } struct T_INDEX *vtp=glob_script_mem.type; + char dvnam[32]; + strcpy (dvnam,vname); + uint8_t olen=len; + last_findex=-1; + char *ja=strchr(dvnam,'['); + if (ja) { + *ja=0; + ja++; + olen=strlen(dvnam); + } for (count=0; countindex=count; // overwrite with global var index if (vtp[count].bits.is_string==0) { *vtype=NTYPE|index; if (vtp[count].bits.is_filter) { - fvar=Get_MFilter(index); + if (ja) { + GetNumericResult(ja,OPER_EQU,&fvar,0); + last_findex=fvar; + fvar=Get_MFVal(index,fvar); + len++; + } else { + fvar=Get_MFilter(index); + } } else { fvar=glob_script_mem.fvars[index]; } @@ -943,6 +1001,40 @@ chknext: fvar=strlen(Settings.rules[0]); goto exit; } + if (!strncmp(vname,"st(",3)) { + lp+=3; + char str[SCRIPT_MAXSSIZE]; + lp=GetStringResult(lp,OPER_EQU,str,0); + while (*lp==' ') lp++; + char token[2]; + token[0]=*lp++; + token[1]=0; + while (*lp==' ') lp++; + lp=GetNumericResult(lp,OPER_EQU,&fvar,0); + // skip ) bracket + lp++; + len=0; + if (sp) { + // get stringtoken + char *st=strtok(str,token); + if (!st) { + *sp=0; + } else { + for (uint8_t cnt=1; cnt<=fvar; cnt++) { + if (cnt==fvar) { + strcpy(sp,st); + break; + } + st=strtok(NULL,token); + if (!st) { + *sp=0; + break; + } + } + } + } + goto strexit; + } #if defined(USE_TIMERS) && defined(USE_SUNRISE) if (!strncmp(vname,"sunrise",7)) { fvar=SunMinutes(0); @@ -1416,10 +1508,13 @@ void toSLog(const char *str) { #endif } + + + #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; + uint8_t vtype=0,sindex,xflg,floop=0,globvindex,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; if_state[ifstck]=0; @@ -1726,6 +1821,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { if (vtype!=VAR_NV) { // found variable as result globvindex=ind.index; // save destination var index here + globaindex=last_findex; uint8_t index=glob_script_mem.type[ind.index].index; if ((vtype&STYPE)==0) { // numeric result @@ -1860,7 +1956,11 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) { // var was changed glob_script_mem.type[globvindex].bits.changed=1; if (glob_script_mem.type[globvindex].bits.is_filter) { - Set_MFilter(glob_script_mem.type[globvindex].index,*dfvar); + if (globaindex>=0) { + Set_MFVal(glob_script_mem.type[globvindex].index,globaindex,*dfvar); + } else { + Set_MFilter(glob_script_mem.type[globvindex].index,*dfvar); + } } if (sysv_type) { From c71b06614ebcb7bba27c418f2bfa380ff04ab039 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Wed, 22 May 2019 12:34:16 +0200 Subject: [PATCH 2/3] Update xdrv_10_scripter.ino --- sonoff/xdrv_10_scripter.ino | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sonoff/xdrv_10_scripter.ino b/sonoff/xdrv_10_scripter.ino index 288a052ee..83c29a42c 100644 --- a/sonoff/xdrv_10_scripter.ino +++ b/sonoff/xdrv_10_scripter.ino @@ -36,9 +36,7 @@ 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 {}) -changelog after merging to Tasmota -1.01 optimized median filter, support for opt filter lenght, support for arrays -1.02 string token support + \*********************************************************************************************/ From 1c7e013837ed03197f30cd9bd7446138f60c2ed5 Mon Sep 17 00:00:00 2001 From: gemu2015 Date: Wed, 22 May 2019 12:38:34 +0200 Subject: [PATCH 3/3] Update scripter.md --- scripter.md | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/scripter.md b/scripter.md index 5b9ac7840..dc4123192 100644 --- a/scripter.md +++ b/scripter.md @@ -39,7 +39,9 @@ numeric var=4 bytes, string var=lenght of string+1) **i:**vname specifies auto increment counters if >=0 (in seconds) **m:**vname specifies a median filter variable with 5 entries (for elimination of outliers) **M:**vname specifies a moving average filter variable with 8 entries (for smoothing data) -(max 5 filters in total m+M) +(max 5 filters in total m+M) optional another filter lenght (1..127) can be given after the definition. +filter vars can be accessed also in indexed mode vname[x] (index = 1...N, index 0 returns current array index pointer) +by this filter vars can be used as arrays >all variable names length taken together may not exceed 256 characters, so keep variable names as short as possible. memory is dynamically allocated as a result of the D section. @@ -84,7 +86,8 @@ special variables (read only): **pow(x y)** = calculates the power of x^y **med(n x)** = calculates a 5 value median filter of x (2 filters possible n=0,1) **int(x)** = gets the integer part of x (like floor) -**hn(x)** = converts x (0..255) zu a hex nibble string +**hn(x)** = converts x (0..255) to a hex nibble string +**st(svar c n)** = stringtoken gets the n th substring of svar separated by c **mqtts** = state of mqtt disconnected=0, connected>0 **wifis** = state of wifi disconnected=0, connected>0 @@ -225,7 +228,9 @@ tcnt=0 hour=0 state=1 m:med5=0 -M:movav=0 +M:movav=0 +; define array with 10 entries +m:array=0 10 **\>B** @@ -258,15 +263,14 @@ delay(100) =>power 0 **\>T** - hum=BME280#Humidity temp=BME280#Temperature rssi=Wifi#RSSI string=SleepMode -; add to median filter +; add to median filter median=temp -; add to moving average filter +; add to moving average filter movav=hum ; show filtered results @@ -274,7 +278,7 @@ movav=hum if chg[rssi]>0 then =>print rssi changed to %rssi% -endif +endif if temp\>30 and hum\>70 @@ -286,6 +290,11 @@ endif ; every second but not completely reliable time here ; use upsecs and uptime or best t: for reliable timers +; arrays +array[1]=4 +array[2]=5 +tmp=array[1]+array[2] + ; call subrountines with parameters =#sub1("hallo") =#sub2(999) @@ -427,6 +436,8 @@ ends **\>E** =\>print event executed! +; get HSBColor 1. component +tmp=st(HSBColor , 1) ; check if switch changed state sw=sw[1]