mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-28 21:26:33 +00:00
commit
dec6f51000
25
scripter.md
25
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)
|
**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 median filter variable with 5 entries (for elimination of outliers)
|
||||||
**M:**vname specifies a moving average filter variable with 8 entries (for smoothing data)
|
**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.
|
>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.
|
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
|
**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)
|
**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)
|
**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
|
**mqtts** = state of mqtt disconnected=0, connected>0
|
||||||
**wifis** = state of wifi disconnected=0, connected>0
|
**wifis** = state of wifi disconnected=0, connected>0
|
||||||
|
|
||||||
@ -225,7 +228,9 @@ tcnt=0
|
|||||||
hour=0
|
hour=0
|
||||||
state=1
|
state=1
|
||||||
m:med5=0
|
m:med5=0
|
||||||
M:movav=0
|
M:movav=0
|
||||||
|
; define array with 10 entries
|
||||||
|
m:array=0 10
|
||||||
|
|
||||||
**\>B**
|
**\>B**
|
||||||
|
|
||||||
@ -258,15 +263,14 @@ delay(100)
|
|||||||
=>power 0
|
=>power 0
|
||||||
|
|
||||||
**\>T**
|
**\>T**
|
||||||
|
|
||||||
hum=BME280#Humidity
|
hum=BME280#Humidity
|
||||||
temp=BME280#Temperature
|
temp=BME280#Temperature
|
||||||
rssi=Wifi#RSSI
|
rssi=Wifi#RSSI
|
||||||
string=SleepMode
|
string=SleepMode
|
||||||
|
|
||||||
; add to median filter
|
; add to median filter
|
||||||
median=temp
|
median=temp
|
||||||
; add to moving average filter
|
; add to moving average filter
|
||||||
movav=hum
|
movav=hum
|
||||||
|
|
||||||
; show filtered results
|
; show filtered results
|
||||||
@ -274,7 +278,7 @@ movav=hum
|
|||||||
|
|
||||||
if chg[rssi]>0
|
if chg[rssi]>0
|
||||||
then =>print rssi changed to %rssi%
|
then =>print rssi changed to %rssi%
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if temp\>30
|
if temp\>30
|
||||||
and hum\>70
|
and hum\>70
|
||||||
@ -286,6 +290,11 @@ endif
|
|||||||
; every second but not completely reliable time here
|
; every second but not completely reliable time here
|
||||||
; use upsecs and uptime or best t: for reliable timers
|
; 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
|
; call subrountines with parameters
|
||||||
=#sub1("hallo")
|
=#sub1("hallo")
|
||||||
=#sub2(999)
|
=#sub2(999)
|
||||||
@ -427,6 +436,8 @@ ends
|
|||||||
**\>E**
|
**\>E**
|
||||||
=\>print event executed!
|
=\>print event executed!
|
||||||
|
|
||||||
|
; get HSBColor 1. component
|
||||||
|
tmp=st(HSBColor , 1)
|
||||||
|
|
||||||
; check if switch changed state
|
; check if switch changed state
|
||||||
sw=sw[1]
|
sw=sw[1]
|
||||||
|
@ -20,17 +20,15 @@
|
|||||||
#ifdef USE_SCRIPT
|
#ifdef USE_SCRIPT
|
||||||
#ifndef USE_RULES
|
#ifndef USE_RULES
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
|
||||||
for documentation see up to date docs in file SCRIPTER.md
|
for documentation see up to date docs in file SCRIPTER.md
|
||||||
|
|
||||||
uses about 14,2 k of flash
|
uses about 14,2 k of flash
|
||||||
more stack could be needed for sendmail => -D CONT_STACKSIZE=4800 = +0.8k stack -0.8k heap
|
more stack could be needed for sendmail => -D CONT_STACKSIZE=4800 = +0.8k stack -0.8k heap
|
||||||
|
|
||||||
|
|
||||||
to do
|
to do
|
||||||
optimize code for space
|
optimize code for space
|
||||||
|
|
||||||
remarks
|
remarks
|
||||||
|
|
||||||
goal is fast execution time, minimal use of ram and intuitive syntax
|
goal is fast execution time, minimal use of ram and intuitive syntax
|
||||||
therefore =>
|
therefore =>
|
||||||
case sensitive cmds and vars (lowercase uses time and code)
|
case sensitive cmds and vars (lowercase uses time and code)
|
||||||
@ -38,6 +36,8 @@ no math hierarchy (costs ram and execution time, better group with brackets, an
|
|||||||
(will probably make math hierarchy an ifdefed option)
|
(will probably make math hierarchy an ifdefed option)
|
||||||
keywords if then else endif, or, and are better readable for beginners (others may use {})
|
keywords if then else endif, or, and are better readable for beginners (others may use {})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
|
||||||
#define XDRV_10 10
|
#define XDRV_10 10
|
||||||
@ -104,11 +104,14 @@ struct SCRIPT_MEM {
|
|||||||
uint8_t script_loglevel;
|
uint8_t script_loglevel;
|
||||||
} glob_script_mem;
|
} glob_script_mem;
|
||||||
|
|
||||||
|
|
||||||
|
int16_t last_findex;
|
||||||
uint8_t tasm_cmd_activ=0;
|
uint8_t tasm_cmd_activ=0;
|
||||||
|
|
||||||
uint32_t script_lastmillis;
|
uint32_t script_lastmillis;
|
||||||
|
|
||||||
char *GetNumericResult(char *lp,uint8_t lastop,float *fp,JsonObject *jo);
|
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) {
|
void ScriptEverySecond(void) {
|
||||||
|
|
||||||
@ -243,6 +246,19 @@ int16_t Init_Scripter(char *script) {
|
|||||||
if (nvars>MAXNVARS) {
|
if (nvars>MAXNVARS) {
|
||||||
return -1;
|
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 {
|
} else {
|
||||||
// string vars
|
// string vars
|
||||||
op++;
|
op++;
|
||||||
@ -445,9 +461,65 @@ int16_t Init_Scripter(char *script) {
|
|||||||
#define NTYPE 0
|
#define NTYPE 0
|
||||||
#define STYPE 0x80
|
#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; hcnt<len/2+1; hcnt++) {
|
||||||
|
for (uint8_t mcnt=0; mcnt<len; mcnt++) {
|
||||||
|
flg=0;
|
||||||
|
for (uint8_t icnt=0; icnt<index; icnt++) {
|
||||||
|
if (ind[icnt]==mcnt) {
|
||||||
|
flg=1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!flg) {
|
||||||
|
if (array[mcnt]<min) {
|
||||||
|
min=array[mcnt];
|
||||||
|
mind=mcnt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ind[index]=mind;
|
||||||
|
index++;
|
||||||
|
min=FLT_MAX;
|
||||||
|
}
|
||||||
|
return array[ind[len/2]];
|
||||||
|
}
|
||||||
|
|
||||||
|
float Get_MFVal(uint8_t index,uint8_t bind) {
|
||||||
|
uint8_t *mp=(uint8_t*)glob_script_mem.mfilt;
|
||||||
|
for (uint8_t count=0; count<MAXFILT; count++) {
|
||||||
|
struct M_FILT *mflp=(struct M_FILT*)mp;
|
||||||
|
if (count==index) {
|
||||||
|
uint8_t maxind=mflp->numvals&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; count<MAXFILT; count++) {
|
||||||
|
struct M_FILT *mflp=(struct M_FILT*)mp;
|
||||||
|
if (count==index) {
|
||||||
|
uint8_t maxind=mflp->numvals&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) {
|
float Get_MFilter(uint8_t index) {
|
||||||
uint8_t *mp=(uint8_t*)glob_script_mem.mfilt;
|
uint8_t *mp=(uint8_t*)glob_script_mem.mfilt;
|
||||||
@ -458,23 +530,8 @@ float Get_MFilter(uint8_t index) {
|
|||||||
// moving average
|
// moving average
|
||||||
return mflp->maccu/(mflp->numvals&0x7f);
|
return mflp->maccu/(mflp->numvals&0x7f);
|
||||||
} else {
|
} else {
|
||||||
// median, sort array
|
// median, sort array indices
|
||||||
float tbuff[mflp->numvals],tmp;
|
return median_array(mflp->rbuff,mflp->numvals);
|
||||||
uint8_t flag;
|
|
||||||
memmove(tbuff,mflp->rbuff,sizeof(tbuff));
|
|
||||||
for (uint8_t ocnt=0; ocnt<mflp->numvals; ocnt++) {
|
|
||||||
flag=0;
|
|
||||||
for (uint8_t count=0; count<mflp->numvals-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];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float);
|
mp+=sizeof(struct M_FILT)+((mflp->numvals&0x7f)-1)*sizeof(float);
|
||||||
@ -519,27 +576,10 @@ float DoMedian5(uint8_t index, float in) {
|
|||||||
if (index>=MEDIAN_FILTER_NUM) index=0;
|
if (index>=MEDIAN_FILTER_NUM) index=0;
|
||||||
|
|
||||||
struct MEDIAN_FILTER* mf=&script_mf[index];
|
struct MEDIAN_FILTER* mf=&script_mf[index];
|
||||||
|
|
||||||
float tbuff[MEDIAN_SIZE],tmp;
|
|
||||||
uint8_t flag;
|
|
||||||
mf->buffer[mf->index]=in;
|
mf->buffer[mf->index]=in;
|
||||||
mf->index++;
|
mf->index++;
|
||||||
if (mf->index>=MEDIAN_SIZE) mf->index=0;
|
if (mf->index>=MEDIAN_SIZE) mf->index=0;
|
||||||
// sort list and take median
|
return median_array(mf->buffer,MEDIAN_SIZE);
|
||||||
memmove(tbuff,mf->buffer,sizeof(tbuff));
|
|
||||||
for (uint8_t ocnt=0; ocnt<MEDIAN_SIZE; ocnt++) {
|
|
||||||
flag=0;
|
|
||||||
for (uint8_t count=0; count<MEDIAN_SIZE-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 tbuff[MEDIAN_SIZE/2];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -606,19 +646,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;
|
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; count<glob_script_mem.numvars; count++) {
|
for (count=0; count<glob_script_mem.numvars; count++) {
|
||||||
char *cp=glob_script_mem.glob_vnp+glob_script_mem.vnp_offset[count];
|
char *cp=glob_script_mem.glob_vnp+glob_script_mem.vnp_offset[count];
|
||||||
uint8_t slen=strlen(cp);
|
uint8_t slen=strlen(cp);
|
||||||
|
if (slen==olen && *cp==dvnam[0]) {
|
||||||
if (slen==len && *cp==vname[0]) {
|
if (!strncmp(cp,dvnam,olen)) {
|
||||||
if (!strncmp(cp,vname,len)) {
|
|
||||||
uint8_t index=vtp[count].index;
|
uint8_t index=vtp[count].index;
|
||||||
*tind=vtp[count];
|
*tind=vtp[count];
|
||||||
tind->index=count; // overwrite with global var index
|
tind->index=count; // overwrite with global var index
|
||||||
if (vtp[count].bits.is_string==0) {
|
if (vtp[count].bits.is_string==0) {
|
||||||
*vtype=NTYPE|index;
|
*vtype=NTYPE|index;
|
||||||
if (vtp[count].bits.is_filter) {
|
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 {
|
} else {
|
||||||
fvar=glob_script_mem.fvars[index];
|
fvar=glob_script_mem.fvars[index];
|
||||||
}
|
}
|
||||||
@ -943,6 +999,40 @@ chknext:
|
|||||||
fvar=strlen(Settings.rules[0]);
|
fvar=strlen(Settings.rules[0]);
|
||||||
goto exit;
|
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 defined(USE_TIMERS) && defined(USE_SUNRISE)
|
||||||
if (!strncmp(vname,"sunrise",7)) {
|
if (!strncmp(vname,"sunrise",7)) {
|
||||||
fvar=SunMinutes(0);
|
fvar=SunMinutes(0);
|
||||||
@ -1416,10 +1506,13 @@ void toSLog(const char *str) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define IF_NEST 8
|
#define IF_NEST 8
|
||||||
// execute section of scripter
|
// execute section of scripter
|
||||||
int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
|
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;
|
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_result[IF_NEST],and_or,ifstck=0,s_ifstck=0;
|
||||||
if_state[ifstck]=0;
|
if_state[ifstck]=0;
|
||||||
@ -1726,6 +1819,7 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
|
|||||||
if (vtype!=VAR_NV) {
|
if (vtype!=VAR_NV) {
|
||||||
// found variable as result
|
// found variable as result
|
||||||
globvindex=ind.index; // save destination var index here
|
globvindex=ind.index; // save destination var index here
|
||||||
|
globaindex=last_findex;
|
||||||
uint8_t index=glob_script_mem.type[ind.index].index;
|
uint8_t index=glob_script_mem.type[ind.index].index;
|
||||||
if ((vtype&STYPE)==0) {
|
if ((vtype&STYPE)==0) {
|
||||||
// numeric result
|
// numeric result
|
||||||
@ -1860,7 +1954,11 @@ int16_t Run_Scripter(const char *type, uint8_t tlen, char *js) {
|
|||||||
// var was changed
|
// var was changed
|
||||||
glob_script_mem.type[globvindex].bits.changed=1;
|
glob_script_mem.type[globvindex].bits.changed=1;
|
||||||
if (glob_script_mem.type[globvindex].bits.is_filter) {
|
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) {
|
if (sysv_type) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user