diff --git a/sonoff/xsns_53_sml.ino b/sonoff/xsns_53_sml.ino index 3e0d56300..b5421c966 100644 --- a/sonoff/xsns_53_sml.ino +++ b/sonoff/xsns_53_sml.ino @@ -140,6 +140,11 @@ struct METER_DESC { uint16_t flag; int32_t params; char prefix[8]; + int8_t trxpin; + uint8_t tsecs; + char *txmem; + uint8_t index; + uint8_t max_index; }; // meter list , enter new meters here @@ -167,7 +172,7 @@ struct METER_DESC { #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS"}}; + [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; const uint8_t meter[]= "1,1-0:1.8.0*255(@1," D_TPWRIN ",KWh," DJ_TPWRIN ",4|" "1,1-0:2.8.0*255(@1," D_TPWROUT ",KWh," DJ_TPWROUT ",4|" @@ -185,7 +190,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS"}}; + [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; const uint8_t meter[]= "1,1-0:1.8.1*255(@1," D_TPWRIN ",KWh," DJ_TPWRIN ",4|" "1,1-0:2.8.1*255(@1," D_TPWROUT ",KWh," DJ_TPWROUT ",4|" @@ -199,7 +204,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML"}}; + [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; // 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär const uint8_t meter[]= //0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff @@ -218,7 +223,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML"}}; + [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; // 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär // verbrauch total const uint8_t meter[]= @@ -236,7 +241,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML"}}; + [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; // 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär // verbrauch total const uint8_t meter[]= @@ -252,7 +257,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"strom"}}; + [0]={3,'s',0,SML_BAUDRATE,"strom",-1,1,0}}; const uint8_t meter[]= //0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff "1,77070100010800ff@1000," D_TPWRIN ",KWh," DJ_TPWRIN ",4|" @@ -275,7 +280,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'s',0,SML_BAUDRATE,"SML"}}; + [0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; const uint8_t meter[]= //0x77,0x07,0x01,0x00,0x01,0x08,0x01,0xff "1,77070100010800ff@1000," D_TPWRIN ",KWh," DJ_TPWRIN ",4|" @@ -291,9 +296,9 @@ const uint8_t meter[]= #define METERS_USED 3 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS"}, // harware serial RX pin - [1]={14,'s',0,SML_BAUDRATE,"SML"}, // GPIO14 software serial - [2]={4,'o',0,SML_BAUDRATE,"OBIS2"}}; // GPIO4 software serial + [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}, // harware serial RX pin + [1]={14,'s',0,SML_BAUDRATE,"SML",-1,1,0}, // GPIO14 software serial + [2]={4,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}}; // GPIO4 software serial // 3 Zähler definiert const uint8_t meter[]= @@ -320,8 +325,8 @@ const uint8_t meter[]= #define METERS_USED 2 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS1"}, // harware serial RX pin - [1]={14,'o',0,SML_BAUDRATE,"OBIS2"}}; // GPIO14 software serial + [0]={3,'o',0,SML_BAUDRATE,"OBIS1",-1,1,0}, // harware serial RX pin + [1]={14,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}}; // GPIO14 software serial // 2 Zähler definiert const uint8_t meter[]= @@ -342,9 +347,9 @@ const uint8_t meter[]= #define METERS_USED 3 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS1"}, // harware serial RX pin - [1]={14,'o',0,SML_BAUDRATE,"OBIS2"}, - [2]={1,'o',0,SML_BAUDRATE,"OBIS3"}}; + [0]={3,'o',0,SML_BAUDRATE,"OBIS1",-1,1,0}, // harware serial RX pin + [1]={14,'o',0,SML_BAUDRATE,"OBIS2",-1,1,0}, + [2]={1,'o',0,SML_BAUDRATE,"OBIS3",-1,1,0}}; // 3 Zähler definiert const uint8_t meter[]= @@ -372,7 +377,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ -[0]={3,'o',0,SML_BAUDRATE,"OBIS"}}; +[0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}}; const uint8_t meter[]= "1,1-0:1.8.1*255(@1," D_TPWRIN ",KWh," DJ_TPWRIN ",4|" "1,=d 1 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|" @@ -385,7 +390,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 1 struct METER_DESC const meter_desc[METERS_USED]={ -[0]={3,'s',0,SML_BAUDRATE,"SML"}}; +[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; // 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär const uint8_t meter[]= //0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff @@ -407,7 +412,7 @@ const uint8_t meter[]= #undef METERS_USED #define METERS_USED 3 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={3,'o',0,SML_BAUDRATE,"OBIS"}, // harware serial RX pin + [0]={3,'o',0,SML_BAUDRATE,"OBIS",-1,1,0}, // harware serial RX pin [1]={14,'c',0,50,"Gas"}, // GPIO14 gas counter [2]={1,'c',0,10,"Wasser"}}; // water counter @@ -430,9 +435,9 @@ const uint8_t meter[]= #define METERS_USED 3 struct METER_DESC const meter_desc[METERS_USED]={ - [0]={1,'c',0,10,"H20"}, // GPIO1 Wasser Zähler - [1]={4,'c',0,50,"GAS"}, // GPIO4 gas Zähler - [2]={3,'s',0,SML_BAUDRATE,"SML"}}; // SML harware serial RX pin + [0]={1,'c',0,10,"H20",-1,1,0}, // GPIO1 Wasser Zähler + [1]={4,'c',0,50,"GAS",-1,1,0}, // GPIO4 gas Zähler + [2]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; // SML harware serial RX pin const uint8_t meter[]= //----------------------------Wasserzähler--sensor53 c1------------------------------------ @@ -516,7 +521,7 @@ char meter_id[MAX_METERS][METER_ID_SIZE]; #define EBUS_SYNC 0xaa #define EBUS_ESC 0xa9 uint8_t ebus_pos; - +uint8_t mbus_pos; #ifdef USE_MEDIAN_FILTER // median filter, should be odd size @@ -786,32 +791,20 @@ uint8_t dump2log=0; bool Serial_available() { uint8_t num=dump2log&7; - if (num<1 || num>meters_used) return Serial.available(); - if (num==1) { - return Serial.available(); - } else { - return meter_ss[num-1]->available(); - } + if (num<1 || num>meters_used) num=1; + return meter_ss[num-1]->available(); } uint8_t Serial_read() { uint8_t num=dump2log&7; - if (num<1 || num>meters_used) return Serial.read(); - if (num==1) { - return Serial.read(); - } else { - return meter_ss[num-1]->read(); - } + if (num<1 || num>meters_used) num=1; + return meter_ss[num-1]->read(); } uint8_t Serial_peek() { uint8_t num=dump2log&7; - if (num<1 || num>meters_used) return Serial.peek(); - if (num==1) { - return Serial.peek(); - } else { - return meter_ss[num-1]->peek(); - } + if (num<1 || num>meters_used) num=1; + return meter_ss[num-1]->peek(); } void Dump2log(void) { @@ -1154,15 +1147,13 @@ uint8_t ebus_CalculateCRC( uint8_t *Data, uint16_t DataLen ) { void sml_shift_in(uint32_t meters,uint32_t shard) { uint32_t count; - if (meter_desc_p[meters].type!='e') { + if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m') { // shift in for (count=0; countread(); + uint8_t iob=(uint8_t)meter_ss[meters]->read(); if (meter_desc_p[meters].type=='o') { smltbuf[meters][SML_BSIZ-1]=iob&0x7f; @@ -1170,6 +1161,13 @@ void sml_shift_in(uint32_t meters,uint32_t shard) { smltbuf[meters][SML_BSIZ-1]=iob; } else if (meter_desc_p[meters].type=='r') { smltbuf[meters][SML_BSIZ-1]=iob; + } else if (meter_desc_p[meters].type=='m') { + smltbuf[meters][mbus_pos] = iob; + mbus_pos++; + if (mbus_pos>=9) { + SML_Decode(meters); + mbus_pos=0; + } } else { if (iob==EBUS_SYNC) { // should be end of telegramm @@ -1200,7 +1198,7 @@ void sml_shift_in(uint32_t meters,uint32_t shard) { } } sb_counter++; - if (meter_desc_p[meters].type!='e') SML_Decode(meters); + if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m') SML_Decode(meters); } @@ -1211,14 +1209,8 @@ uint32_t meters; for (meters=0; metersavailable()) { - sml_shift_in(meters,0); - } + while (meter_ss[meters]->available()) { + sml_shift_in(meters,0); } } } @@ -1348,7 +1340,8 @@ void SML_Decode(uint8_t index) { } else { // compare value uint8_t found=1; - int32_t ebus_dval=99; + uint32_t ebus_dval=99; + float mbus_dval=99; while (*mp!='@') { if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') { if (*mp++!=*cp++) { @@ -1363,7 +1356,7 @@ void SML_Decode(uint8_t index) { found=0; } } else { - // ebus or raw + // ebus mbus or raw // XXHHHHSSUU if (*mp=='x' && *(mp+1)=='x') { //ignore @@ -1379,7 +1372,7 @@ void SML_Decode(uint8_t index) { ebus_dval=val; mp+=2; } - else if (*mp=='s' && *(mp+1)=='s' && *(mp+2)=='s' && *(mp+3)=='s'){ + else if (*mp=='s' && *(mp+1)=='s' && *(mp+2)=='s' && *(mp+3)=='s') { int16_t val = *cp|(*(cp+1)<<8); ebus_dval=val; mp+=4; @@ -1389,7 +1382,15 @@ void SML_Decode(uint8_t index) { int8_t val = *cp++; ebus_dval=val; mp+=2; - } else { + } + else if (*mp=='f' && *(mp+1)=='f' && *(mp+2)=='f' && *(mp+3)=='f' && *(mp+4)=='f' && *(mp+5)=='f' && *(mp+6)=='f' && *(mp+7)=='f') { + uint32_t val= (*(cp+0)<<24)|(*(cp+1)<<16)|(*(cp+2)<<8)|(*(cp+3)<<0); + float *fp=(float*)&val; + mbus_dval=*fp; + mp+=8; + cp+=4; + } + else { uint8_t val = hexnibble(*mp++) << 4; val |= hexnibble(*mp++); if (val!=*cp++) { @@ -1418,7 +1419,7 @@ void SML_Decode(uint8_t index) { } } else { double dval; - if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r') { + if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r' && meter_desc_p[mindex].type!='m') { // get numeric values if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') { dval=xCharToDouble((char*)cp); @@ -1426,7 +1427,7 @@ void SML_Decode(uint8_t index) { dval=sml_getvalue(cp,mindex); } } else { - // ebus + // ebus or mbus if (*mp=='b') { mp++; uint8_t shift=*mp&7; @@ -1434,7 +1435,23 @@ void SML_Decode(uint8_t index) { ebus_dval&=1; mp+=2; } - dval=ebus_dval; + if (*mp=='i') { + // mbus index + mp++; + uint8_t mb_index=strtol((char*)mp,(char**)&mp,10); + if (mb_index!=meter_desc_p[mindex].index) { + goto nextsect; + } + uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0],7); + if (lowByte(crc)!=smltbuf[mindex][7]) goto nextsect; + if (highByte(crc)!=smltbuf[mindex][8]) goto nextsect; + dval=mbus_dval; + //AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %s"),mp); + mp++; + } else { + dval=ebus_dval; + } + } #ifdef USE_MEDIAN_FILTER meter_vars[vindex]=median(&sml_mf[vindex],dval); @@ -1723,6 +1740,14 @@ void SML_Init(void) { #ifdef USE_SCRIPT + + for (uint32_t cnt=0;cntM",-2,0); if (meter_script==99) { // use script definition @@ -1782,13 +1807,42 @@ void SML_Init(void) { lp++; script_meter_desc[index].prefix[7]=0; for (uint32_t cnt=0; cnt<8; cnt++) { - if (*lp==SCRIPT_EOL) { + if (*lp==SCRIPT_EOL || *lp==',') { script_meter_desc[index].prefix[cnt]=0; - lp--; break; } script_meter_desc[index].prefix[cnt]=*lp++; } + if (*lp==',') { + lp++; + script_meter_desc[index].trxpin=strtol(lp,&lp,10); + if (*lp!=',') goto next_line; + lp++; + script_meter_desc[index].tsecs=strtol(lp,&lp,10); + if (*lp==',') { + lp++; + char txbuff[256]; + uint32_t txlen=0,tx_entries=1; + for (uint32_t cnt=0; cntbegin(meter_desc_p[meters].params)) { meter_ss[meters]->flush(); } - } + if (meter_ss[meters]->hardwareSerial()) { ClaimSerial(); } + } } @@ -1958,25 +2013,102 @@ uint32_t ctime=millis(); } } -#ifdef SML_SEND_SEQ -#define SML_SEQ_PERIOD 5 -uint8_t sml_seq_cnt; -void SendSeq(void) { - sml_seq_cnt++; - if (sml_seq_cnt>SML_SEQ_PERIOD) { - sml_seq_cnt=0; - // send sequence every N Seconds - uint8_t sequence[]={0x2F,0x3F,0x21,0x0D,0x0A,0}; - uint8_t *ucp=sequence; - while (*ucp) { - uint8_t iob=*ucp++; - // for no parity disable next line - iob|=(CalcEvenParity(iob)<<7); - Serial.write(iob); +#ifdef USE_SCRIPT +char *SML_Get_Sequence(char *cp,uint32_t index) { + if (!index) return cp; + uint32_t cindex=0; + while (cp) { + cp=strchr(cp,','); + if (cp) { + cp++; + cindex++; + if (cindex==index) { + return cp; + } } } } +uint8_t sml_250ms_cnt; + + +void SML_Check_Send(void) { + sml_250ms_cnt++; + for (uint32_t cnt=0; cnt=0 && script_meter_desc[cnt].txmem) { + if ((sml_250ms_cnt%script_meter_desc[cnt].tsecs)==0) { + if (script_meter_desc[cnt].max_index>1) { + script_meter_desc[cnt].index++; + if (script_meter_desc[cnt].index>=script_meter_desc[cnt].max_index) { + script_meter_desc[cnt].index=0; + } + char *cp=SML_Get_Sequence(script_meter_desc[cnt].txmem,script_meter_desc[cnt].index); + SML_Send_Seq(cnt,cp); + //AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %s"),cp); + } else { + SML_Send_Seq(cnt,script_meter_desc[cnt].txmem); + } + } + } + } +} + +uint8_t sml_hexnibble(char chr) { + uint8_t rVal = 0; + if (isdigit(chr)) { + rVal = chr - '0'; + } else { + if (chr >= 'A' && chr <= 'F') rVal = chr + 10 - 'A'; + if (chr >= 'a' && chr <= 'f') rVal = chr + 10 - 'a'; + } + return rVal; +} + +// send sequence every N Seconds +void SML_Send_Seq(uint32_t meter,char *seq) { + uint8_t sbuff[32]; + uint8_t *ucp=sbuff,slen; + char *cp=seq; + while (*cp) { + if (!*cp || !*(cp+1)) break; + if (*cp==',') break; + uint8_t iob=(sml_hexnibble(*cp) << 4) | sml_hexnibble(*(cp+1)); + cp+=2; + *ucp++=iob; + slen++; + if (slen>=sizeof(sbuff)) break; + } + if (script_meter_desc[meter].type=='m') { + *ucp++=0; + *ucp++=2; + // append crc + uint16_t crc = MBUS_calculateCRC(sbuff,6); + *ucp++=lowByte(crc); + *ucp++=highByte(crc); + slen+=4; + } + meter_ss[meter]->write(sbuff,slen); +} +#endif // USE_SCRIPT + +uint16_t MBUS_calculateCRC(uint8_t *frame, uint8_t num) { + uint16_t crc, flag; + crc = 0xFFFF; + for (uint32_t i = 0; i < num; i++) { + crc ^= frame[i]; + for (uint32_t j = 8; j; j--) { + if ((crc & 0x0001) != 0) { // If the LSB is set + crc >>= 1; // Shift right and XOR 0xA001 + crc ^= 0xA001; + } else { // Else LSB is not set + crc >>= 1; // Just shift right + } + } + } + return crc; +} + +/* // for odd parity init with 1 uint8_t CalcEvenParity(uint8_t data) { uint8_t parity=0; @@ -1987,7 +2119,7 @@ uint8_t parity=0; } return parity; } -#endif +*/ // dump to log shows serial data on console @@ -2053,6 +2185,7 @@ void SML_CounterSaveState(void) { + /*********************************************************************************************\ * Interface \*********************************************************************************************/ @@ -2070,11 +2203,11 @@ bool Xsns53(byte function) { if (dump2log) Dump2log(); else SML_Poll(); break; -#ifdef SML_SEND_SEQ - case FUNC_EVERY_SECOND: - SendSeq(); +#ifdef USE_SCRIPT + case FUNC_EVERY_250_MSECOND: + SML_Check_Send(); break; -#endif +#endif // USE_SCRIPT case FUNC_JSON_APPEND: SML_Show(1); break;