mirror of https://github.com/arendst/Tasmota.git
sml, median filter, mutiple modbus, pzem
This commit is contained in:
parent
7d768905cd
commit
37f6fc6bac
|
@ -22,7 +22,6 @@
|
|||
*/
|
||||
|
||||
#ifdef USE_SML_M
|
||||
//
|
||||
|
||||
#define XSNS_53 53
|
||||
|
||||
|
@ -30,13 +29,14 @@
|
|||
#define SML_BAUDRATE 9600
|
||||
|
||||
// send this every N seconds (for meters that only send data on demand)
|
||||
// not longer supported, use scripting instead
|
||||
//#define SML_SEND_SEQ
|
||||
|
||||
// debug counter input to led for counter1 and 2
|
||||
//#define DEBUG_CNT_LED1 2
|
||||
//#define DEBUG_CNT_LED1 2
|
||||
|
||||
// use analog optical counter sensor with AD Converter ADS1115 (not yet)
|
||||
// use analog optical counter sensor with AD Converter ADS1115 (not yet functional)
|
||||
//#define ANALOG_OPTO_SENSOR
|
||||
// fototransistor with pullup at A0, A1 of ADS1115 A3 and +3.3V
|
||||
// level and amplification are automatically set
|
||||
|
@ -44,7 +44,7 @@
|
|||
|
||||
#include <TasmotaSerial.h>
|
||||
|
||||
// use special no wait serial driver
|
||||
// use special no wait serial driver, should be always on
|
||||
#define SPECIAL_SS
|
||||
|
||||
// addresses a bug in meter DWS74
|
||||
|
@ -147,6 +147,9 @@ struct METER_DESC {
|
|||
uint8_t max_index;
|
||||
};
|
||||
|
||||
// this descriptor method is no longer supported
|
||||
// but still functional for simple meters
|
||||
// use scripting method instead
|
||||
// meter list , enter new meters here
|
||||
//=====================================================
|
||||
#define EHZ161_0 1
|
||||
|
@ -391,7 +394,7 @@ const uint8_t meter[]=
|
|||
#define METERS_USED 1
|
||||
struct METER_DESC const meter_desc[METERS_USED]={
|
||||
[0]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}};
|
||||
// 2 Richtungszähler EHZ SML 8 bit 9600 baud, binär
|
||||
// 2 direction meter EHZ SML 8 bit 9600 baud, binary
|
||||
const uint8_t meter[]=
|
||||
//0x77,0x07,0x01,0x00,0x01,0x08,0x00,0xff
|
||||
"1,77070100010800ff@1000," D_TPWRIN ",KWh," DJ_TPWRIN ",4|"
|
||||
|
@ -407,7 +410,7 @@ const uint8_t meter[]=
|
|||
"1,77070100000009ff@#," D_METERNR ",," DJ_METERNR ",0";
|
||||
#endif
|
||||
|
||||
// Beispiel für einen OBIS Stromzähler und einen Gaszähler + Wasserzähler
|
||||
// example OBIS power meter + gas and water counter
|
||||
#if METER==COMBO3b
|
||||
#undef METERS_USED
|
||||
#define METERS_USED 3
|
||||
|
@ -416,14 +419,14 @@ struct METER_DESC const meter_desc[METERS_USED]={
|
|||
[1]={14,'c',0,50,"Gas"}, // GPIO14 gas counter
|
||||
[2]={1,'c',0,10,"Wasser"}}; // water counter
|
||||
|
||||
// 3 Zähler definiert
|
||||
// 3 meters defined
|
||||
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|"
|
||||
"1,=d 2 10 @1," D_TPWRCURR ",W," DJ_TPWRCURR ",0|"
|
||||
"1,1-0:0.0.0*255(@#)," D_METERNR ",," DJ_METERNR ",0|"
|
||||
|
||||
// bei gaszählern (countern) muss der Vergleichsstring so aussehen wie hier
|
||||
// with counters the comparison string must be exactly this string
|
||||
"2,1-0:1.8.0*255(@100," D_GasIN ",cbm," DJ_COUNTER ",2|"
|
||||
|
||||
"3,1-0:1.8.0*255(@100," D_H2oIN ",cbm," DJ_COUNTER ",2";
|
||||
|
@ -435,8 +438,8 @@ const uint8_t meter[]=
|
|||
#define METERS_USED 3
|
||||
|
||||
struct METER_DESC const meter_desc[METERS_USED]={
|
||||
[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
|
||||
[0]={1,'c',0,10,"H20",-1,1,0}, // GPIO1 water counter
|
||||
[1]={4,'c',0,50,"GAS",-1,1,0}, // GPIO4 gas counter
|
||||
[2]={3,'s',0,SML_BAUDRATE,"SML",-1,1,0}}; // SML harware serial RX pin
|
||||
|
||||
const uint8_t meter[]=
|
||||
|
@ -491,10 +494,12 @@ const uint8_t meter[]=
|
|||
|
||||
// median filter eliminates outliers, but uses much RAM and CPU cycles
|
||||
// 672 bytes extra RAM with MAX_VARS = 16
|
||||
//#define USE_MEDIAN_FILTER
|
||||
// default compile on, but must be enabled by descriptor flag 16
|
||||
// may be undefined if RAM must be saved
|
||||
#define USE_SML_MEDIAN_FILTER
|
||||
|
||||
// max number of vars , may be adjusted
|
||||
#define MAX_VARS 16
|
||||
#define MAX_VARS 20
|
||||
// max number of meters , may be adjusted
|
||||
#define MAX_METERS 5
|
||||
double meter_vars[MAX_VARS];
|
||||
|
@ -506,6 +511,7 @@ uint8_t meters_used;
|
|||
|
||||
struct METER_DESC const *meter_desc_p;
|
||||
const uint8_t *meter_p;
|
||||
uint8_t meter_spos[MAX_METERS];
|
||||
|
||||
// software serial pointers
|
||||
TasmotaSerial *meter_ss[MAX_METERS];
|
||||
|
@ -520,24 +526,58 @@ 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
|
||||
uint8_t sml_send_blocks;
|
||||
uint8_t sml_100ms_cnt;
|
||||
uint8_t sml_desc_cnt;
|
||||
|
||||
#ifdef USE_SML_MEDIAN_FILTER
|
||||
// median filter, should be odd size
|
||||
#define MEDIAN_SIZE 5
|
||||
struct MEDIAN_FILTER {
|
||||
struct SML_MEDIAN_FILTER {
|
||||
double buffer[MEDIAN_SIZE];
|
||||
int8_t index;
|
||||
} sml_mf[MAX_VARS];
|
||||
|
||||
|
||||
double sml_median_array(double *array,uint8_t len) {
|
||||
uint8_t ind[len];
|
||||
uint8_t mind=0,index=0,flg;
|
||||
double 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]];
|
||||
}
|
||||
|
||||
|
||||
// calc median
|
||||
double median(struct MEDIAN_FILTER* mf, double in) {
|
||||
double tbuff[MEDIAN_SIZE],tmp;
|
||||
uint8_t flag;
|
||||
double sml_median(struct SML_MEDIAN_FILTER* mf, double in) {
|
||||
//double tbuff[MEDIAN_SIZE],tmp;
|
||||
//uint8_t flag;
|
||||
mf->buffer[mf->index]=in;
|
||||
mf->index++;
|
||||
if (mf->index>=MEDIAN_SIZE) mf->index=0;
|
||||
|
||||
return sml_median_array(mf->buffer,MEDIAN_SIZE);
|
||||
/*
|
||||
// sort list and take median
|
||||
memmove(tbuff,mf->buffer,sizeof(tbuff));
|
||||
for (byte ocnt=0; ocnt<MEDIAN_SIZE; ocnt++) {
|
||||
|
@ -553,6 +593,7 @@ double median(struct MEDIAN_FILTER* mf, double in) {
|
|||
if (!flag) break;
|
||||
}
|
||||
return tbuff[MEDIAN_SIZE/2];
|
||||
*/
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -714,8 +755,7 @@ uint16_t ADS1115::read_register(uint8_t reg)
|
|||
|
||||
uint8_t result = Wire.requestFrom((int)m_address, 2, 1);
|
||||
if (result != 2) {
|
||||
Wire.flush();
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint16_t val;
|
||||
|
@ -1056,9 +1096,8 @@ uint8_t hexnibble(char chr) {
|
|||
|
||||
uint8_t sb_counter;
|
||||
|
||||
// because orig CharToDouble was defective
|
||||
// fixed in Tasmota 6.4.1.19 20190222
|
||||
double xCharToDouble(const char *str)
|
||||
// need double precision in this driver
|
||||
double CharToDouble(const char *str)
|
||||
{
|
||||
// simple ascii to double, because atof or strtod are too large
|
||||
char strbuf[24];
|
||||
|
@ -1145,9 +1184,16 @@ uint8_t ebus_CalculateCRC( uint8_t *Data, uint16_t DataLen ) {
|
|||
return Crc;
|
||||
}
|
||||
|
||||
void sml_empty_receiver(uint32_t meters) {
|
||||
while (meter_ss[meters]->available()) {
|
||||
meter_ss[meters]->read();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sml_shift_in(uint32_t meters,uint32_t shard) {
|
||||
uint32_t count;
|
||||
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m') {
|
||||
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='p') {
|
||||
// shift in
|
||||
for (count=0; count<SML_BSIZ-1; count++) {
|
||||
smltbuf[meters][count]=smltbuf[meters][count+1];
|
||||
|
@ -1162,43 +1208,48 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
|
|||
} 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) {
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters]>=9) {
|
||||
SML_Decode(meters);
|
||||
mbus_pos=0;
|
||||
sml_empty_receiver(meters);
|
||||
meter_spos[meters]=0;
|
||||
}
|
||||
} else if (meter_desc_p[meters].type=='p') {
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters]>=7) {
|
||||
SML_Decode(meters);
|
||||
sml_empty_receiver(meters);
|
||||
meter_spos[meters]=0;
|
||||
}
|
||||
} else {
|
||||
if (iob==EBUS_SYNC) {
|
||||
// should be end of telegramm
|
||||
// QQ,ZZ,PB,SB,NN ..... CRC, ACK SYNC
|
||||
if (ebus_pos>4+5) {
|
||||
if (meter_spos[meters]>4+5) {
|
||||
// get telegramm lenght
|
||||
uint8_t tlen=smltbuf[meters][4]+5;
|
||||
// test crc
|
||||
if (smltbuf[meters][tlen]=ebus_CalculateCRC(smltbuf[meters],tlen)) {
|
||||
ebus_esc(smltbuf[meters],tlen);
|
||||
//eBus_analyze();
|
||||
// XX0204UUSS@
|
||||
SML_Decode(meters);
|
||||
//AddLog_P(LOG_LEVEL_INFO, PSTR("ebus block found"));
|
||||
//ebus_set_timeout();
|
||||
} else {
|
||||
// crc error
|
||||
//AddLog_P(LOG_LEVEL_INFO, PSTR("ebus crc error"));
|
||||
}
|
||||
}
|
||||
ebus_pos=0;
|
||||
meter_spos[meters]=0;
|
||||
return;
|
||||
}
|
||||
smltbuf[meters][ebus_pos] = iob;
|
||||
ebus_pos++;
|
||||
if (ebus_pos>=SML_BSIZ) {
|
||||
ebus_pos=0;
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters]>=SML_BSIZ) {
|
||||
meter_spos[meters]=0;
|
||||
}
|
||||
}
|
||||
sb_counter++;
|
||||
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m') SML_Decode(meters);
|
||||
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='p') SML_Decode(meters);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1356,14 +1407,22 @@ void SML_Decode(uint8_t index) {
|
|||
found=0;
|
||||
}
|
||||
} else {
|
||||
// ebus mbus or raw
|
||||
// ebus mbus pzem or raw
|
||||
// XXHHHHSSUU
|
||||
if (*mp=='x' && *(mp+1)=='x') {
|
||||
//ignore
|
||||
mp+=2;
|
||||
cp++;
|
||||
} else if (*mp=='u' && *(mp+1)=='u' && *(mp+2)=='u' && *(mp+3)=='u'){
|
||||
uint16_t val = *cp|(*(cp+1)<<8);
|
||||
} else if (!strncmp(mp,"uuuuuuuu",8)) {
|
||||
uint32_t val= (cp[0]<<24)|(cp[1]<<16)|(cp[2]<<8)|(cp[3]<<0);
|
||||
ebus_dval=val;
|
||||
mbus_dval=val;
|
||||
mp+=8;
|
||||
cp+=4;
|
||||
}
|
||||
else if (*mp=='u' && *(mp+1)=='u' && *(mp+2)=='u' && *(mp+3)=='u'){
|
||||
uint16_t val = cp[0]|(cp[1]<<8);
|
||||
mbus_dval=val;
|
||||
ebus_dval=val;
|
||||
mp+=4;
|
||||
cp+=2;
|
||||
|
@ -1383,13 +1442,44 @@ void SML_Decode(uint8_t index) {
|
|||
ebus_dval=val;
|
||||
mp+=2;
|
||||
}
|
||||
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);
|
||||
else if (!strncmp(mp,"ffffffff",8)) {
|
||||
uint32_t val= (cp[0]<<24)|(cp[1]<<16)|(cp[2]<<8)|(cp[3]<<0);
|
||||
float *fp=(float*)&val;
|
||||
ebus_dval=*fp;
|
||||
mbus_dval=*fp;
|
||||
mp+=8;
|
||||
cp+=4;
|
||||
}
|
||||
else if (!strncmp(mp,"FFffFFff",8)) {
|
||||
// reverse word float
|
||||
uint32_t val= (cp[1]<<0)|(cp[0]<<8)|(cp[3]<<16)|(cp[2]<<24);
|
||||
float *fp=(float*)&val;
|
||||
ebus_dval=*fp;
|
||||
mbus_dval=*fp;
|
||||
mp+=8;
|
||||
cp+=4;
|
||||
}
|
||||
else if (!strncmp(mp,"eeeeee",6)) {
|
||||
uint32_t val=(cp[0]<<16)|(cp[1]<<8)|(cp[2]<<0);
|
||||
mbus_dval=val;
|
||||
mp+=6;
|
||||
cp+=3;
|
||||
}
|
||||
else if (!strncmp(mp,"vvvvvv",6)) {
|
||||
mbus_dval=(float)((cp[0]<<8)|(cp[1])) + ((float)cp[2]/10.0);
|
||||
mp+=6;
|
||||
cp+=3;
|
||||
}
|
||||
else if (!strncmp(mp,"cccccc",6)) {
|
||||
mbus_dval=(float)((cp[0]<<8)|(cp[1])) + ((float)cp[2]/100.0);
|
||||
mp+=6;
|
||||
cp+=3;
|
||||
}
|
||||
else if (!strncmp(mp,"pppp",4)) {
|
||||
mbus_dval=(float)((cp[0]<<8)|cp[1]);
|
||||
mp+=4;
|
||||
cp+=2;
|
||||
}
|
||||
else {
|
||||
uint8_t val = hexnibble(*mp++) << 4;
|
||||
val |= hexnibble(*mp++);
|
||||
|
@ -1419,15 +1509,15 @@ void SML_Decode(uint8_t index) {
|
|||
}
|
||||
} else {
|
||||
double dval;
|
||||
if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r' && meter_desc_p[mindex].type!='m') {
|
||||
if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r' && meter_desc_p[mindex].type!='m' && meter_desc_p[mindex].type!='p') {
|
||||
// get numeric values
|
||||
if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') {
|
||||
dval=xCharToDouble((char*)cp);
|
||||
dval=CharToDouble((char*)cp);
|
||||
} else {
|
||||
dval=sml_getvalue(cp,mindex);
|
||||
}
|
||||
} else {
|
||||
// ebus or mbus
|
||||
// ebus pzem or mbus or raw
|
||||
if (*mp=='b') {
|
||||
mp++;
|
||||
uint8_t shift=*mp&7;
|
||||
|
@ -1449,17 +1539,28 @@ void SML_Decode(uint8_t index) {
|
|||
//AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %s"),mp);
|
||||
mp++;
|
||||
} else {
|
||||
dval=ebus_dval;
|
||||
if (meter_desc_p[mindex].type=='p') {
|
||||
uint8_t crc = SML_PzemCrc(&smltbuf[mindex][0],6);
|
||||
if (crc!=smltbuf[mindex][6]) goto nextsect;
|
||||
dval=mbus_dval;
|
||||
} else {
|
||||
dval=ebus_dval;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
#ifdef USE_MEDIAN_FILTER
|
||||
meter_vars[vindex]=median(&sml_mf[vindex],dval);
|
||||
#ifdef USE_SML_MEDIAN_FILTER
|
||||
if (meter_desc_p[mindex].flag&16) {
|
||||
meter_vars[vindex]=sml_median(&sml_mf[vindex],dval);
|
||||
} else {
|
||||
meter_vars[vindex]=dval;
|
||||
}
|
||||
#else
|
||||
meter_vars[vindex]=dval;
|
||||
#endif
|
||||
//AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %s"),mp);
|
||||
// get scaling factor
|
||||
double fac=xCharToDouble((char*)mp);
|
||||
double fac=CharToDouble((char*)mp);
|
||||
meter_vars[vindex]/=fac;
|
||||
SML_Immediate_MQTT((const char*)mp,vindex,mindex);
|
||||
}
|
||||
|
@ -1616,7 +1717,7 @@ void SML_Show(boolean json) {
|
|||
if (lastmind!=mindex) {
|
||||
// meter changed, close mqtt
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s}", b_mqtt_data);
|
||||
ResponseJsonEnd();
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
// and open new
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s,\"%s\":{\"%s\":%s", b_mqtt_data,meter_desc_p[mindex].prefix,jname,tpowstr);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"),meter_desc_p[mindex].prefix,jname,tpowstr);
|
||||
|
@ -1643,7 +1744,7 @@ void SML_Show(boolean json) {
|
|||
if (json) {
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s}", b_mqtt_data);
|
||||
//ResponseAppend_P(PSTR("%s"),b_mqtt_data);
|
||||
ResponseJsonEnd();
|
||||
ResponseAppend_P(PSTR("}"));
|
||||
} else {
|
||||
//WSContentSend_PD(PSTR("%s"),b_mqtt_data);
|
||||
}
|
||||
|
@ -1733,10 +1834,15 @@ void SML_Init(void) {
|
|||
meter_desc_p=meter_desc;
|
||||
meter_p=meter;
|
||||
|
||||
sml_desc_cnt=0;
|
||||
|
||||
for (uint32_t cnt=0;cnt<MAX_VARS;cnt++) {
|
||||
meter_vars[cnt]=0;
|
||||
}
|
||||
|
||||
for (uint32_t cnt=0;cnt<MAX_METERS;cnt++) {
|
||||
meter_spos[cnt]=0;
|
||||
}
|
||||
|
||||
#ifdef USE_SCRIPT
|
||||
|
||||
|
@ -1744,17 +1850,20 @@ void SML_Init(void) {
|
|||
if (script_meter_desc[cnt].txmem) {
|
||||
free(script_meter_desc[cnt].txmem);
|
||||
script_meter_desc[cnt].txmem=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t meter_script=Run_Scripter(">M",-2,0);
|
||||
if (meter_script==99) {
|
||||
// use script definition
|
||||
if (script_meter) free(script_meter);
|
||||
script_meter=0;
|
||||
uint8_t *tp=0;
|
||||
uint16_t index=0;
|
||||
uint8_t section=0;
|
||||
uint8_t srcpin=0;
|
||||
char *lp=glob_script_mem.scriptptr;
|
||||
sml_send_blocks=0;
|
||||
while (lp) {
|
||||
if (!section) {
|
||||
if (*lp=='>' && *(lp+1)=='M') {
|
||||
|
@ -1770,7 +1879,9 @@ void SML_Init(void) {
|
|||
}
|
||||
if (mlen==0) return; // missing end #
|
||||
script_meter=(uint8_t*)calloc(mlen,1);
|
||||
if (!script_meter) return;
|
||||
if (!script_meter) {
|
||||
goto dddef_exit;
|
||||
}
|
||||
tp=script_meter;
|
||||
goto next_line;
|
||||
}
|
||||
|
@ -1784,14 +1895,18 @@ void SML_Init(void) {
|
|||
// add descriptor +1,1,c,0,10,H20
|
||||
//toLogEOL(">>",lp);
|
||||
lp++;
|
||||
uint8_t index=*lp&7;
|
||||
index=*lp&7;
|
||||
lp+=2;
|
||||
if (index<1 || index>meters_used) goto next_line;
|
||||
index--;
|
||||
uint8_t srcpin=strtol(lp,&lp,10);
|
||||
srcpin=strtol(lp,&lp,10);
|
||||
if (Gpio_used(srcpin)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("gpio double define!"));
|
||||
return;
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("gpio rx double define!"));
|
||||
dddef_exit:
|
||||
if (script_meter) free(script_meter);
|
||||
script_meter=0;
|
||||
meters_used=METERS_USED;
|
||||
goto init10;
|
||||
}
|
||||
script_meter_desc[index].srcpin=srcpin;
|
||||
if (*lp!=',') goto next_line;
|
||||
|
@ -1815,6 +1930,10 @@ void SML_Init(void) {
|
|||
if (*lp==',') {
|
||||
lp++;
|
||||
script_meter_desc[index].trxpin=strtol(lp,&lp,10);
|
||||
if (Gpio_used(script_meter_desc[index].trxpin)) {
|
||||
AddLog_P(LOG_LEVEL_INFO, PSTR("gpio tx double define!"));
|
||||
goto dddef_exit;
|
||||
}
|
||||
if (*lp!=',') goto next_line;
|
||||
lp++;
|
||||
script_meter_desc[index].tsecs=strtol(lp,&lp,10);
|
||||
|
@ -1838,6 +1957,7 @@ void SML_Init(void) {
|
|||
}
|
||||
script_meter_desc[index].index=0;
|
||||
script_meter_desc[index].max_index=tx_entries;
|
||||
sml_send_blocks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1879,6 +1999,7 @@ next_line:
|
|||
}
|
||||
#endif
|
||||
|
||||
init10:
|
||||
typedef void (*function)();
|
||||
function counter_callbacks[] = {SML_CounterUpd1,SML_CounterUpd2,SML_CounterUpd3,SML_CounterUpd4};
|
||||
uint8_t cindex=0;
|
||||
|
@ -1916,7 +2037,7 @@ next_line:
|
|||
} else {
|
||||
// serial input, init
|
||||
#ifdef SPECIAL_SS
|
||||
if (meter_desc_p[meters].type=='m') {
|
||||
if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='p') {
|
||||
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1);
|
||||
} else {
|
||||
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,1);
|
||||
|
@ -2028,26 +2149,38 @@ char *SML_Get_Sequence(char *cp,uint32_t index) {
|
|||
}
|
||||
}
|
||||
|
||||
uint8_t sml_250ms_cnt;
|
||||
|
||||
|
||||
void SML_Check_Send(void) {
|
||||
sml_250ms_cnt++;
|
||||
for (uint32_t cnt=0; cnt<meters_used; cnt++) {
|
||||
sml_100ms_cnt++;
|
||||
char *cp;
|
||||
for (uint32_t cnt=sml_desc_cnt; cnt<meters_used; cnt++) {
|
||||
if (script_meter_desc[cnt].trxpin>=0 && script_meter_desc[cnt].txmem) {
|
||||
if ((sml_250ms_cnt%script_meter_desc[cnt].tsecs)==0) {
|
||||
if ((sml_100ms_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;
|
||||
sml_desc_cnt++;
|
||||
}
|
||||
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);
|
||||
cp=SML_Get_Sequence(script_meter_desc[cnt].txmem,script_meter_desc[cnt].index);
|
||||
//SML_Send_Seq(cnt,cp);
|
||||
} else {
|
||||
SML_Send_Seq(cnt,script_meter_desc[cnt].txmem);
|
||||
cp=script_meter_desc[cnt].txmem;
|
||||
//SML_Send_Seq(cnt,cp);
|
||||
sml_desc_cnt++;
|
||||
}
|
||||
//AddLog_P2(LOG_LEVEL_INFO, PSTR(">> %s"),cp);
|
||||
SML_Send_Seq(cnt,cp);
|
||||
if (sml_desc_cnt>=meters_used) {
|
||||
sml_desc_cnt=0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
sml_desc_cnt++;
|
||||
}
|
||||
|
||||
if (sml_desc_cnt>=meters_used) {
|
||||
sml_desc_cnt=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2066,7 +2199,7 @@ uint8_t sml_hexnibble(char chr) {
|
|||
// send sequence every N Seconds
|
||||
void SML_Send_Seq(uint32_t meter,char *seq) {
|
||||
uint8_t sbuff[32];
|
||||
uint8_t *ucp=sbuff,slen;
|
||||
uint8_t *ucp=sbuff,slen=0;
|
||||
char *cp=seq;
|
||||
while (*cp) {
|
||||
if (!*cp || !*(cp+1)) break;
|
||||
|
@ -2086,6 +2219,15 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
|
|||
*ucp++=highByte(crc);
|
||||
slen+=4;
|
||||
}
|
||||
if (script_meter_desc[meter].type=='p') {
|
||||
*ucp++=0xc0;
|
||||
*ucp++=0xa8;
|
||||
*ucp++=1;
|
||||
*ucp++=1;
|
||||
*ucp++=0;
|
||||
*ucp++=SML_PzemCrc(sbuff,6);
|
||||
slen+=6;
|
||||
}
|
||||
meter_ss[meter]->write(sbuff,slen);
|
||||
}
|
||||
#endif // USE_SCRIPT
|
||||
|
@ -2107,6 +2249,11 @@ uint16_t MBUS_calculateCRC(uint8_t *frame, uint8_t num) {
|
|||
return crc;
|
||||
}
|
||||
|
||||
uint8_t SML_PzemCrc(uint8_t *data, uint8_t len) {
|
||||
uint16_t crc = 0;
|
||||
for (uint32_t i = 0; i < len; i++) crc += *data++;
|
||||
return (uint8_t)(crc & 0xFF);
|
||||
}
|
||||
/*
|
||||
// for odd parity init with 1
|
||||
uint8_t CalcEvenParity(uint8_t data) {
|
||||
|
@ -2200,7 +2347,7 @@ bool Xsns53(byte function) {
|
|||
else SML_Poll();
|
||||
break;
|
||||
#ifdef USE_SCRIPT
|
||||
case FUNC_EVERY_250_MSECOND:
|
||||
case FUNC_EVERY_100_MSECOND:
|
||||
SML_Check_Send();
|
||||
break;
|
||||
#endif // USE_SCRIPT
|
||||
|
|
Loading…
Reference in New Issue