mirror of https://github.com/arendst/Tasmota.git
Merge pull request #16538 from gemu2015/sml_update
add kamstrup, fix mbus u32
This commit is contained in:
commit
9c7e536618
|
@ -53,6 +53,8 @@
|
|||
#define TMSBSIZ 256
|
||||
#endif
|
||||
|
||||
#define MODBUS_DEBUG
|
||||
|
||||
// addresses a bug in meter DWS74
|
||||
//#define DWS74_BUG
|
||||
|
||||
|
@ -1609,16 +1611,16 @@ void sml_empty_receiver(uint32_t meters) {
|
|||
void sml_shift_in(uint32_t meters,uint32_t shard) {
|
||||
uint32_t count;
|
||||
#ifndef SML_OBIS_LINE
|
||||
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p' && meter_desc_p[meters].type!='R' && meter_desc_p[meters].type!='v') {
|
||||
if (meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') {
|
||||
#else
|
||||
if (meter_desc_p[meters].type!='o' && meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p' && meter_desc_p[meters].type!='R' && meter_desc_p[meters].type!='v') {
|
||||
if (meter_desc_p[meters].type!= 'o' && meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') {
|
||||
#endif
|
||||
// shift in
|
||||
for (count=0; count<SML_BSIZ-1; count++) {
|
||||
smltbuf[meters][count]=smltbuf[meters][count+1];
|
||||
for (count = 0; count < SML_BSIZ - 1; count++) {
|
||||
smltbuf[meters][count] = smltbuf[meters][count + 1];
|
||||
}
|
||||
}
|
||||
uint8_t iob=(uint8_t)meter_ss[meters]->read();
|
||||
uint8_t iob = (uint8_t)meter_ss[meters]->read();
|
||||
|
||||
if (meter_desc_p[meters].type == 'o') {
|
||||
#ifndef SML_OBIS_LINE
|
||||
|
@ -1639,37 +1641,73 @@ 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' || meter_desc_p[meters].type=='M') {
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters]>=SML_BSIZ) {
|
||||
meter_spos[meters]=0;
|
||||
}
|
||||
if (meter_spos[meters]>=8) {
|
||||
uint32_t mlen=smltbuf[meters][2]+5;
|
||||
if (mlen>SML_BSIZ) mlen=SML_BSIZ;
|
||||
if (meter_spos[meters]>=mlen) {
|
||||
SML_Decode(meters);
|
||||
} else if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M' || meter_desc_p[meters].type=='k') {
|
||||
|
||||
if (meter_desc_p[meters].type=='k') {
|
||||
// Kamstrup
|
||||
if (iob == 0x40) {
|
||||
meter_spos[meters] = 0;
|
||||
} else if (iob == 0x0d) {
|
||||
uint16_t crc = KS_calculateCRC(&smltbuf[meters][0], meter_spos[meters]);
|
||||
if (!crc) {
|
||||
uint8_t *ucp = &smltbuf[meters][0];
|
||||
for (uint16_t cnt = 0; cnt < meter_spos[meters]; cnt++) {
|
||||
uint8_t iob = smltbuf[meters][cnt];
|
||||
if (iob == 0x1b) {
|
||||
*ucp++ = smltbuf[meters][cnt + 1] ^ 0xff;
|
||||
cnt++;
|
||||
} else {
|
||||
*ucp++ = iob;
|
||||
}
|
||||
}
|
||||
SML_Decode(meters);
|
||||
}
|
||||
sml_empty_receiver(meters);
|
||||
meter_spos[meters]=0;
|
||||
meter_spos[meters] = 0;
|
||||
} else {
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters] >= SML_BSIZ) {
|
||||
meter_spos[meters] = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters] >= SML_BSIZ) {
|
||||
meter_spos[meters] = 0;
|
||||
}
|
||||
// modbus
|
||||
if (meter_spos[meters] >= 8) {
|
||||
uint32_t mlen = smltbuf[meters][2] + 5;
|
||||
if (mlen > SML_BSIZ) mlen = SML_BSIZ;
|
||||
if (meter_spos[meters] >= mlen) {
|
||||
#ifdef MODBUS_DEBUG
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("receive index >> %d"),meter_desc_p[meters].index);
|
||||
Hexdump(smltbuf[meters], 10);
|
||||
#endif
|
||||
SML_Decode(meters);
|
||||
sml_empty_receiver(meters);
|
||||
meter_spos[meters] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (meter_desc_p[meters].type=='p') {
|
||||
} else if (meter_desc_p[meters].type == 'p') {
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters]>=7) {
|
||||
if (meter_spos[meters] >= 7) {
|
||||
SML_Decode(meters);
|
||||
sml_empty_receiver(meters);
|
||||
meter_spos[meters]=0;
|
||||
meter_spos[meters] = 0;
|
||||
}
|
||||
} else if (meter_desc_p[meters].type=='R') {
|
||||
} else if (meter_desc_p[meters].type == 'R') {
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters]>=SML_BSIZ) {
|
||||
meter_spos[meters]=0;
|
||||
if (meter_spos[meters] >= SML_BSIZ) {
|
||||
meter_spos[meters] = 0;
|
||||
}
|
||||
} else if (meter_desc_p[meters].type=='v') {
|
||||
if (iob==EBUS_SYNC) {
|
||||
} else if (meter_desc_p[meters].type == 'v') {
|
||||
if (iob == EBUS_SYNC) {
|
||||
sb_counter = 0;
|
||||
SML_Decode(meters);
|
||||
smltbuf[meters][0] = iob;
|
||||
|
@ -1682,15 +1720,15 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
|
|||
}
|
||||
}
|
||||
else {
|
||||
if (iob==EBUS_SYNC) {
|
||||
if (iob == EBUS_SYNC) {
|
||||
// should be end of telegramm
|
||||
// QQ,ZZ,PB,SB,NN ..... CRC, ACK SYNC
|
||||
if (meter_spos[meters]>4+5) {
|
||||
if (meter_spos[meters] > 4 + 5) {
|
||||
// get telegramm lenght
|
||||
uint16_t tlen=smltbuf[meters][4]+5;
|
||||
uint16_t tlen = smltbuf[meters][4] + 5;
|
||||
// test crc
|
||||
if (smltbuf[meters][tlen]=ebus_CalculateCRC(smltbuf[meters],tlen)) {
|
||||
ebus_esc(smltbuf[meters],tlen);
|
||||
if (smltbuf[meters][tlen] = ebus_CalculateCRC(smltbuf[meters], tlen)) {
|
||||
ebus_esc(smltbuf[meters], tlen);
|
||||
SML_Decode(meters);
|
||||
} else {
|
||||
// crc error
|
||||
|
@ -1702,15 +1740,15 @@ void sml_shift_in(uint32_t meters,uint32_t shard) {
|
|||
}
|
||||
smltbuf[meters][meter_spos[meters]] = iob;
|
||||
meter_spos[meters]++;
|
||||
if (meter_spos[meters]>=SML_BSIZ) {
|
||||
meter_spos[meters]=0;
|
||||
if (meter_spos[meters] >= SML_BSIZ) {
|
||||
meter_spos[meters] = 0;
|
||||
}
|
||||
}
|
||||
sb_counter++;
|
||||
#ifndef SML_OBIS_LINE
|
||||
if (meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p' && meter_desc_p[meters].type!='R' && meter_desc_p[meters].type!='v') SML_Decode(meters);
|
||||
if (meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') SML_Decode(meters);
|
||||
#else
|
||||
if (meter_desc_p[meters].type!='o' && meter_desc_p[meters].type!='e' && meter_desc_p[meters].type!='m' && meter_desc_p[meters].type!='M' && meter_desc_p[meters].type!='p' && meter_desc_p[meters].type!='R' && meter_desc_p[meters].type!='v') SML_Decode(meters);
|
||||
if (meter_desc_p[meters].type != 'o' && meter_desc_p[meters].type != 'e' && meter_desc_p[meters].type != 'm' && meter_desc_p[meters].type != 'M' && meter_desc_p[meters].type != 'k' && meter_desc_p[meters].type != 'p' && meter_desc_p[meters].type != 'R' && meter_desc_p[meters].type != 'v') SML_Decode(meters);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1723,7 +1761,7 @@ uint32_t meters;
|
|||
if (meter_desc_p[meters].type != 'c') {
|
||||
// poll for serial input
|
||||
if (!meter_ss[meters]) continue;
|
||||
if (ser_act_LED_pin!=255 && (ser_act_meter_num==0 || ser_act_meter_num-1==meters)) {
|
||||
if (ser_act_LED_pin != 255 && (ser_act_meter_num == 0 || ser_act_meter_num - 1 == meters)) {
|
||||
digitalWrite(ser_act_LED_pin, meter_ss[meters]->available() && !digitalRead(ser_act_LED_pin)); // Invert LED, if queue is continuously full
|
||||
}
|
||||
while (meter_ss[meters]->available()) {
|
||||
|
@ -1944,7 +1982,7 @@ void SML_Decode(uint8_t index) {
|
|||
// compare value
|
||||
uint8_t found = 1;
|
||||
double ebus_dval = 99;
|
||||
float mbus_dval = 99;
|
||||
double mbus_dval = 99;
|
||||
while (*mp != '@') {
|
||||
if (meter_desc_p[mindex].type == 'o' || meter_desc_p[mindex].type == 'c') {
|
||||
if (*mp++ != *cp++) {
|
||||
|
@ -2083,6 +2121,28 @@ void SML_Decode(uint8_t index) {
|
|||
mbus_dval = (float)((cp[0]<<8) | cp[1]);
|
||||
mp += 4;
|
||||
cp += 2;
|
||||
} else if (!strncmp(mp, "kstr", 4)) {
|
||||
mp += 4;
|
||||
// decode the mantissa
|
||||
uint32_t x = 0;
|
||||
for (uint16_t i = 0; i < cp[5]; i++) {
|
||||
x <<= 8;
|
||||
x |= cp[i + 7];
|
||||
}
|
||||
// decode the exponent
|
||||
int32_t i = cp[6] & 0x3f;
|
||||
if (cp[6] & 0x40) {
|
||||
i = -i;
|
||||
};
|
||||
//float ifl = pow(10, i);
|
||||
float ifl = 1;
|
||||
for (uint16_t x = 1; x <= i; ++x) {
|
||||
ifl *= 10;
|
||||
}
|
||||
if (cp[6] & 0x80) {
|
||||
ifl = -ifl;
|
||||
}
|
||||
mbus_dval = (double )(x * ifl);
|
||||
} else if (!strncmp(mp, "bcd", 3)) {
|
||||
mp += 3;
|
||||
uint8_t digits = strtol((char*)mp, (char**)&mp, 10);
|
||||
|
@ -2229,7 +2289,7 @@ 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' && meter_desc_p[mindex].type!='M' && meter_desc_p[mindex].type!='p' && meter_desc_p[mindex].type!='v') {
|
||||
if (meter_desc_p[mindex].type!='e' && meter_desc_p[mindex].type!='r' && meter_desc_p[mindex].type!='m' && meter_desc_p[mindex].type!='M' && meter_desc_p[mindex].type!='k' && meter_desc_p[mindex].type!='p' && meter_desc_p[mindex].type!='v') {
|
||||
// get numeric values
|
||||
if (meter_desc_p[mindex].type=='o' || meter_desc_p[mindex].type=='c') {
|
||||
if (*mp == '(') {
|
||||
|
@ -2262,47 +2322,53 @@ void SML_Decode(uint8_t index) {
|
|||
}
|
||||
} else {
|
||||
// ebus pzem vbus or mbus or raw
|
||||
if (*mp=='b') {
|
||||
if (*mp == 'b') {
|
||||
mp++;
|
||||
uint8_t shift = *mp&7;
|
||||
ebus_dval = (uint32_t)ebus_dval>>shift;
|
||||
ebus_dval = (uint32_t)ebus_dval&1;
|
||||
mp+=2;
|
||||
}
|
||||
if (*mp=='i') {
|
||||
if (*mp == 'i') {
|
||||
// mbus index
|
||||
mp++;
|
||||
uint8_t mb_index=strtol((char*)mp,(char**)&mp,10);
|
||||
if (mb_index!=meter_desc_p[mindex].index) {
|
||||
uint8_t mb_index = strtol((char*)mp, (char**)&mp, 10);
|
||||
if (mb_index != meter_desc_p[mindex].index) {
|
||||
goto nextsect;
|
||||
}
|
||||
uint16_t pos = smltbuf[mindex][2]+3;
|
||||
if (pos>32) pos=32;
|
||||
uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0],pos,0xFFFF);
|
||||
if (lowByte(crc)!=smltbuf[mindex][pos]) goto nextsect;
|
||||
if (highByte(crc)!=smltbuf[mindex][pos+1]) goto nextsect;
|
||||
dval=mbus_dval;
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),mp);
|
||||
mp++;
|
||||
} else {
|
||||
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;
|
||||
if (meter_desc_p[mindex].type == 'k') {
|
||||
// crc is already checked, get float value
|
||||
dval = mbus_dval;
|
||||
mp++;
|
||||
} else {
|
||||
dval=ebus_dval;
|
||||
uint16_t pos = smltbuf[mindex][2] + 3;
|
||||
if (pos > 32) pos = 32;
|
||||
uint16_t crc = MBUS_calculateCRC(&smltbuf[mindex][0], pos, 0xFFFF);
|
||||
if (lowByte(crc) != smltbuf[mindex][pos]) goto nextsect;
|
||||
if (highByte(crc) != smltbuf[mindex][pos + 1]) goto nextsect;
|
||||
dval = mbus_dval;
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),mp);
|
||||
mp++;
|
||||
}
|
||||
} else {
|
||||
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_SML_MEDIAN_FILTER
|
||||
if (meter_desc_p[mindex].flag&16) {
|
||||
meter_vars[vindex]=sml_median(&sml_mf[vindex],dval);
|
||||
if (meter_desc_p[mindex].flag & 16) {
|
||||
meter_vars[vindex] = sml_median(&sml_mf[vindex], dval);
|
||||
} else {
|
||||
meter_vars[vindex]=dval;
|
||||
meter_vars[vindex] = dval;
|
||||
}
|
||||
#else
|
||||
meter_vars[vindex]=dval;
|
||||
meter_vars[vindex] = dval;
|
||||
#endif
|
||||
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR(">> %s"),mp);
|
||||
|
@ -2356,11 +2422,11 @@ void SML_Immediate_MQTT(const char *mp,uint8_t index,uint8_t mindex) {
|
|||
jname[count]=*cp++;
|
||||
}
|
||||
cp++;
|
||||
uint8_t dp=atoi(cp);
|
||||
if (dp&0x10) {
|
||||
uint8_t dp = atoi(cp);
|
||||
if (dp & 0x10) {
|
||||
// immediate mqtt
|
||||
dtostrfd(meter_vars[index],dp&0xf,tpowstr);
|
||||
ResponseTime_P(PSTR(",\"%s\":{\"%s\":%s}}"),meter_desc_p[mindex].prefix,jname,tpowstr);
|
||||
dtostrfd(meter_vars[index], dp & 0xf, tpowstr);
|
||||
ResponseTime_P(PSTR(",\"%s\":{\"%s\":%s}}"), meter_desc_p[mindex].prefix, jname, tpowstr);
|
||||
MqttPublishTeleSensor();
|
||||
}
|
||||
}
|
||||
|
@ -2383,22 +2449,22 @@ void SML_Show(boolean json) {
|
|||
|
||||
if (!meters_used) return;
|
||||
|
||||
int8_t lastmind=((*mp)&7)-1;
|
||||
if (lastmind<0 || lastmind>=meters_used) lastmind=0;
|
||||
int8_t lastmind = ((*mp) & 7) - 1;
|
||||
if (lastmind < 0 || lastmind >= meters_used) lastmind = 0;
|
||||
while (mp != NULL) {
|
||||
if (*mp==0) break;
|
||||
if (*mp == 0) break;
|
||||
// setup sections
|
||||
mindex=((*mp)&7)-1;
|
||||
mindex = ((*mp) & 7) - 1;
|
||||
|
||||
if (mindex<0 || mindex>=meters_used) mindex=0;
|
||||
if (meter_desc_p[mindex].prefix[0]=='*' && meter_desc_p[mindex].prefix[1]==0) {
|
||||
if (mindex < 0 || mindex >= meters_used) mindex = 0;
|
||||
if (meter_desc_p[mindex].prefix[0] == '*' && meter_desc_p[mindex].prefix[1] == 0) {
|
||||
nojson = 1;
|
||||
} else {
|
||||
nojson = 0;
|
||||
}
|
||||
mp+=2;
|
||||
if (*mp=='=' && *(mp+1)=='h') {
|
||||
mp+=2;
|
||||
mp += 2;
|
||||
if (*mp == '=' && *(mp+1) == 'h') {
|
||||
mp += 2;
|
||||
// html tag
|
||||
if (json) {
|
||||
mp = strchr(mp, '|');
|
||||
|
@ -2407,49 +2473,49 @@ void SML_Show(boolean json) {
|
|||
}
|
||||
// web ui export
|
||||
uint8_t i;
|
||||
for (i=0;i<sizeof(tpowstr)-2;i++) {
|
||||
if (*mp=='|' || *mp==0) break;
|
||||
tpowstr[i]=*mp++;
|
||||
for (i = 0; i < sizeof(tpowstr) - 2; i++) {
|
||||
if (*mp == '|' || *mp == 0) break;
|
||||
tpowstr[i] = *mp++;
|
||||
}
|
||||
tpowstr[i]=0;
|
||||
tpowstr[i] = 0;
|
||||
// export html
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s{s}%s{e}", b_mqtt_data,tpowstr);
|
||||
WSContentSend_PD(PSTR("{s}%s{e}"),tpowstr);
|
||||
WSContentSend_PD(PSTR("{s}%s{e}"), tpowstr);
|
||||
// rewind, to ensure strchr
|
||||
mp--;
|
||||
mp = strchr(mp, '|');
|
||||
if (mp) mp++;
|
||||
continue;
|
||||
}
|
||||
if (*mp=='=' && *(mp+1)=='s') {
|
||||
if (*mp == '=' && *(mp + 1) == 's') {
|
||||
mp = strchr(mp, '|');
|
||||
if (mp) mp++;
|
||||
continue;
|
||||
}
|
||||
// skip compare section
|
||||
cp=strchr(mp,'@');
|
||||
cp=strchr(mp, '@');
|
||||
if (cp) {
|
||||
cp++;
|
||||
tststr:
|
||||
if (*cp=='#') {
|
||||
if (*cp == '#') {
|
||||
// meter id
|
||||
if (*(cp + 1) == 'x') {
|
||||
// convert hex to asci
|
||||
sml_hex_asci(mindex, tpowstr);
|
||||
} else {
|
||||
sprintf(tpowstr,"\"%s\"",&meter_id[mindex][0]);
|
||||
sprintf(tpowstr,"\"%s\"", &meter_id[mindex][0]);
|
||||
}
|
||||
mid=1;
|
||||
} else if (*cp=='(') {
|
||||
if (meter_desc_p[mindex].type=='o') {
|
||||
mid = 1;
|
||||
} else if (*cp == '(') {
|
||||
if (meter_desc_p[mindex].type == 'o') {
|
||||
cp++;
|
||||
strtol((char*)cp,(char**)&cp, 10);
|
||||
cp++;
|
||||
goto tststr;
|
||||
} else {
|
||||
mid=0;
|
||||
mid = 0;
|
||||
}
|
||||
} else if (*cp=='b') {
|
||||
} else if (*cp == 'b') {
|
||||
// bit value
|
||||
#ifdef SML_BIT_TEXT
|
||||
sprintf_P(tpowstr, PSTR("\"%s\""), (uint8_t)meter_vars[index]?D_ON:D_OFF);
|
||||
|
@ -2459,41 +2525,41 @@ void SML_Show(boolean json) {
|
|||
mid = 0;
|
||||
}
|
||||
// skip scaling
|
||||
cp=strchr(cp,',');
|
||||
cp = strchr(cp, ',');
|
||||
if (cp) {
|
||||
// this is the name in web UI
|
||||
cp++;
|
||||
for (count=0;count<sizeof(name);count++) {
|
||||
if (*cp==',') {
|
||||
name[count]=0;
|
||||
for (count = 0; count < sizeof(name); count++) {
|
||||
if (*cp == ',') {
|
||||
name[count] = 0;
|
||||
break;
|
||||
}
|
||||
name[count]=*cp++;
|
||||
name[count] = *cp++;
|
||||
}
|
||||
cp++;
|
||||
|
||||
for (count=0;count<sizeof(unit);count++) {
|
||||
if (*cp==',') {
|
||||
unit[count]=0;
|
||||
for (count = 0; count < sizeof(unit); count++) {
|
||||
if (*cp == ',') {
|
||||
unit[count] = 0;
|
||||
break;
|
||||
}
|
||||
unit[count]=*cp++;
|
||||
unit[count] = *cp++;
|
||||
}
|
||||
cp++;
|
||||
|
||||
for (count=0;count<sizeof(jname);count++) {
|
||||
if (*cp==',') {
|
||||
jname[count]=0;
|
||||
for (count = 0; count < sizeof(jname); count++) {
|
||||
if (*cp == ',') {
|
||||
jname[count] = 0;
|
||||
break;
|
||||
}
|
||||
jname[count]=*cp++;
|
||||
jname[count] = *cp++;
|
||||
}
|
||||
|
||||
cp++;
|
||||
|
||||
if (!mid) {
|
||||
uint8_t dp=atoi(cp)&0xf;
|
||||
dtostrfd(meter_vars[index],dp,tpowstr);
|
||||
uint8_t dp = atoi(cp) & 0xf;
|
||||
dtostrfd(meter_vars[index], dp, tpowstr);
|
||||
}
|
||||
|
||||
if (json) {
|
||||
|
@ -2502,14 +2568,14 @@ void SML_Show(boolean json) {
|
|||
//AddLog(LOG_LEVEL_INFO, PSTR("not yet valid line %d"), index);
|
||||
//}
|
||||
// json export
|
||||
if (index==0) {
|
||||
if (index == 0) {
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s,\"%s\":{\"%s\":%s", b_mqtt_data,meter_desc_p[mindex].prefix,jname,tpowstr);
|
||||
if (!nojson) {
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"),meter_desc_p[mindex].prefix,jname,tpowstr);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"), meter_desc_p[mindex].prefix, jname, tpowstr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (lastmind!=mindex) {
|
||||
if (lastmind != mindex) {
|
||||
// meter changed, close mqtt
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s}", b_mqtt_data);
|
||||
if (!nojson) {
|
||||
|
@ -2518,13 +2584,13 @@ void SML_Show(boolean json) {
|
|||
// 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);
|
||||
if (!nojson) {
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"),meter_desc_p[mindex].prefix,jname,tpowstr);
|
||||
ResponseAppend_P(PSTR(",\"%s\":{\"%s\":%s"), meter_desc_p[mindex].prefix, jname, tpowstr);
|
||||
}
|
||||
lastmind=mindex;
|
||||
lastmind = mindex;
|
||||
} else {
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s,\"%s\":%s", b_mqtt_data,jname,tpowstr);
|
||||
if (!nojson) {
|
||||
ResponseAppend_P(PSTR(",\"%s\":%s"),jname,tpowstr);
|
||||
ResponseAppend_P(PSTR(",\"%s\":%s"), jname, tpowstr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2532,11 +2598,11 @@ void SML_Show(boolean json) {
|
|||
} else {
|
||||
// web ui export
|
||||
//snprintf_P(b_mqtt_data, sizeof(b_mqtt_data), "%s{s}%s %s: {m}%s %s{e}", b_mqtt_data,meter_desc[mindex].prefix,name,tpowstr,unit);
|
||||
if (strcmp(name,"*")) WSContentSend_PD(PSTR("{s}%s %s {m}%s %s{e}"),meter_desc_p[mindex].prefix,name,tpowstr,unit);
|
||||
if (strcmp(name, "*")) WSContentSend_PD(PSTR("{s}%s %s {m}%s %s{e}"), meter_desc_p[mindex].prefix, name,tpowstr, unit);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (index<SML_MAX_VARS-1) {
|
||||
if (index < SML_MAX_VARS - 1) {
|
||||
index++;
|
||||
}
|
||||
// next section
|
||||
|
@ -2631,8 +2697,8 @@ uint32_t debounce_time;
|
|||
|
||||
uint32_t SML_getlinelen(char *lp) {
|
||||
uint32_t cnt;
|
||||
for (cnt=0; cnt<SML_SRCBSIZE-1; cnt++) {
|
||||
if (lp[cnt]==SCRIPT_EOL) {
|
||||
for (cnt = 0; cnt < SML_SRCBSIZE - 1; cnt++) {
|
||||
if (lp[cnt] == SCRIPT_EOL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2640,27 +2706,27 @@ uint32_t cnt;
|
|||
}
|
||||
|
||||
uint32_t SML_getscriptsize(char *lp) {
|
||||
uint32_t mlen=0;
|
||||
char dstbuf[SML_SRCBSIZE*2];
|
||||
uint32_t mlen = 0;
|
||||
char dstbuf[SML_SRCBSIZE * 2];
|
||||
while (1) {
|
||||
Replace_Cmd_Vars(lp,1,dstbuf,sizeof(dstbuf));
|
||||
lp+=SML_getlinelen(lp)+1;
|
||||
uint32_t slen=strlen(dstbuf);
|
||||
Replace_Cmd_Vars(lp, 1, dstbuf, sizeof(dstbuf));
|
||||
lp += SML_getlinelen(lp) + 1;
|
||||
uint32_t slen = strlen(dstbuf);
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR("%d - %s"),slen,dstbuf);
|
||||
mlen+=slen+1;
|
||||
if (*lp=='#') break;
|
||||
if (*lp=='>') break;
|
||||
if (*lp==0) break;
|
||||
mlen += slen + 1;
|
||||
if (*lp == '#') break;
|
||||
if (*lp == '>') break;
|
||||
if (*lp == 0) break;
|
||||
}
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR("len=%d"),mlen);
|
||||
return mlen+32;
|
||||
return mlen + 32;
|
||||
}
|
||||
#else
|
||||
uint32_t SML_getscriptsize(char *lp) {
|
||||
uint32_t mlen=0;
|
||||
for (uint32_t cnt=0;cnt<METER_DEF_SIZE-1;cnt++) {
|
||||
if (lp[cnt]=='\n' && lp[cnt+1]=='#') {
|
||||
mlen=cnt+3;
|
||||
uint32_t mlen = 0;
|
||||
for (uint32_t cnt = 0; cnt < METER_DEF_SIZE - 1; cnt++) {
|
||||
if (lp[cnt] == '\n' && lp[cnt + 1] == '#') {
|
||||
mlen = cnt + 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2711,19 +2777,19 @@ void SML_GetSpecOpt(char *cp, uint32_t mnum) {
|
|||
#endif
|
||||
|
||||
void SML_Init(void) {
|
||||
meters_used=METERS_USED;
|
||||
meter_desc_p=meter_desc;
|
||||
meter_p=meter;
|
||||
meters_used = METERS_USED;
|
||||
meter_desc_p = meter_desc;
|
||||
meter_p = meter;
|
||||
|
||||
sml_desc_cnt=0;
|
||||
sml_desc_cnt = 0;
|
||||
|
||||
for (uint32_t cnt=0;cnt<SML_MAX_VARS;cnt++) {
|
||||
meter_vars[cnt]=0;
|
||||
dvalid[cnt]=0;
|
||||
for (uint32_t cnt = 0; cnt < SML_MAX_VARS; cnt++) {
|
||||
meter_vars[cnt] = 0;
|
||||
dvalid[cnt] = 0;
|
||||
}
|
||||
|
||||
for (uint32_t cnt=0;cnt<MAX_METERS;cnt++) {
|
||||
meter_spos[cnt]=0;
|
||||
for (uint32_t cnt = 0; cnt < MAX_METERS; cnt++) {
|
||||
meter_spos[cnt] = 0;
|
||||
}
|
||||
|
||||
#ifdef USE_SML_SPECOPT
|
||||
|
@ -2735,24 +2801,24 @@ void SML_Init(void) {
|
|||
|
||||
#ifdef USE_SCRIPT
|
||||
|
||||
for (uint32_t cnt=0;cnt<MAX_METERS;cnt++) {
|
||||
for (uint32_t cnt = 0; cnt < MAX_METERS; cnt++) {
|
||||
if (script_meter_desc[cnt].txmem) {
|
||||
free(script_meter_desc[cnt].txmem);
|
||||
}
|
||||
script_meter_desc[cnt].txmem=0;
|
||||
script_meter_desc[cnt].trxpin=-1;
|
||||
script_meter_desc[cnt].txmem = 0;
|
||||
script_meter_desc[cnt].trxpin = -1;
|
||||
|
||||
if (meter_ss[cnt]) {
|
||||
delete meter_ss[cnt];
|
||||
meter_ss[cnt]=NULL;
|
||||
meter_ss[cnt] = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (bitRead(Settings->rule_enabled, 0)) {
|
||||
|
||||
uint8_t meter_script=Run_Scripter(">M",-2,0);
|
||||
if (meter_script==99) {
|
||||
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;
|
||||
|
@ -2781,23 +2847,23 @@ void SML_Init(void) {
|
|||
}
|
||||
else {
|
||||
if (!*lp || *lp == '#' || *lp == '>') {
|
||||
if (*(tp-1) == '|') *(tp-1) = 0;
|
||||
if (*(tp - 1) == '|') *(tp - 1) = 0;
|
||||
break;
|
||||
}
|
||||
if (*lp == '+') {
|
||||
// add descriptor +1,1,c,0,10,H20
|
||||
//toLogEOL(">>",lp);
|
||||
lp++;
|
||||
index = *lp&7;
|
||||
index = *lp & 7;
|
||||
lp += 2;
|
||||
if (index < 1 || index > meters_used) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("illegal meter number!"));
|
||||
goto next_line;
|
||||
}
|
||||
index--;
|
||||
srcpin = strtol(lp,&lp,10);
|
||||
srcpin = strtol(lp, &lp, 10);
|
||||
if (Gpio_used(abs(srcpin))) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for RX in meter number %d"),abs(srcpin),index+1);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for RX in meter number %d"), abs(srcpin), index + 1);
|
||||
dddef_exit:
|
||||
if (script_meter) free(script_meter);
|
||||
script_meter = 0;
|
||||
|
@ -2852,7 +2918,7 @@ dddef_exit:
|
|||
lp++;
|
||||
script_meter_desc[index].trxpin = strtol(lp, &lp, 10);
|
||||
if (Gpio_used(script_meter_desc[index].trxpin)) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"),script_meter_desc[index].trxpin,index+1);
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("SML: Error: Duplicate GPIO %d defined. Not usable for TX in meter number %d"), script_meter_desc[index].trxpin, index + 1);
|
||||
goto dddef_exit;
|
||||
}
|
||||
if (*lp != ',') goto next_line;
|
||||
|
@ -3016,7 +3082,7 @@ dddef_exit:
|
|||
}
|
||||
|
||||
next_line:
|
||||
if (*lp==SCRIPT_EOL) {
|
||||
if (*lp == SCRIPT_EOL) {
|
||||
lp++;
|
||||
} else {
|
||||
lp = strchr(lp, SCRIPT_EOL);
|
||||
|
@ -3024,16 +3090,16 @@ next_line:
|
|||
lp++;
|
||||
}
|
||||
}
|
||||
*tp=0;
|
||||
meter_desc_p=script_meter_desc;
|
||||
meter_p=script_meter;
|
||||
*tp = 0;
|
||||
meter_desc_p = script_meter_desc;
|
||||
meter_p = script_meter;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
init10:
|
||||
typedef void (*function)();
|
||||
uint8_t cindex=0;
|
||||
uint8_t cindex = 0;
|
||||
// preloud counters
|
||||
for (byte i = 0; i < MAX_COUNTERS; i++) {
|
||||
RtcSettings.pulse_counter[i] = Settings->pulse_counter[i];
|
||||
|
@ -3078,7 +3144,7 @@ init10:
|
|||
} else {
|
||||
// serial input, init
|
||||
#ifdef SPECIAL_SS
|
||||
if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M' || meter_desc_p[meters].type=='p' || meter_desc_p[meters].type=='R' || meter_desc_p[meters].type=='v') {
|
||||
if (meter_desc_p[meters].type=='m' || meter_desc_p[meters].type=='M' || meter_desc_p[meters].type=='k' || meter_desc_p[meters].type=='p' || meter_desc_p[meters].type=='R' || meter_desc_p[meters].type=='v') {
|
||||
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,0,TMSBSIZ);
|
||||
} else {
|
||||
meter_ss[meters] = new TasmotaSerial(meter_desc_p[meters].srcpin,meter_desc_p[meters].trxpin,1,1,TMSBSIZ);
|
||||
|
@ -3198,7 +3264,7 @@ uint32_t SML_SetBaud(uint32_t meter, uint32_t br) {
|
|||
}
|
||||
|
||||
uint32_t SML_Status(uint32_t meter) {
|
||||
if (meter<1 || meter>meters_used) return 0;
|
||||
if (meter < 1 || meter > meters_used) return 0;
|
||||
meter--;
|
||||
#if defined(ED300L) || defined(AS2020) || defined(DTZ541) || defined(USE_SML_SPECOPT)
|
||||
return sml_status[meter];
|
||||
|
@ -3210,20 +3276,20 @@ uint32_t SML_Status(uint32_t meter) {
|
|||
|
||||
|
||||
uint32_t SML_Write(uint32_t meter,char *hstr) {
|
||||
if (meter<1 || meter>meters_used) return 0;
|
||||
if (meter < 1 || meter > meters_used) return 0;
|
||||
meter--;
|
||||
if (!meter_ss[meter]) return 0;
|
||||
SML_Send_Seq(meter,hstr);
|
||||
SML_Send_Seq(meter, hstr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t SML_Read(int32_t meter,char *str, uint32_t slen) {
|
||||
uint8_t hflg=0;
|
||||
if (meter<0) {
|
||||
meter=abs(meter);
|
||||
hflg=1;
|
||||
uint8_t hflg = 0;
|
||||
if (meter < 0) {
|
||||
meter = abs(meter);
|
||||
hflg = 1;
|
||||
}
|
||||
if (meter<1 || meter>meters_used) return 0;
|
||||
if (meter < 1 || meter > meters_used) return 0;
|
||||
meter--;
|
||||
if (!meter_ss[meter]) return 0;
|
||||
|
||||
|
@ -3231,26 +3297,26 @@ uint8_t hflg=0;
|
|||
return 0;
|
||||
}
|
||||
|
||||
smltbuf[meter][meter_spos[meter]]=0;
|
||||
smltbuf[meter][meter_spos[meter]] = 0;
|
||||
|
||||
if (!hflg) {
|
||||
strlcpy(str,(char*)&smltbuf[meter][0],slen);
|
||||
strlcpy(str, (char*)&smltbuf[meter][0], slen);
|
||||
} else {
|
||||
uint32_t index=0;
|
||||
for (uint32_t cnt=0; cnt<meter_spos[meter]; cnt++) {
|
||||
sprintf(str,"%02x",smltbuf[meter][cnt]);
|
||||
str+=2;
|
||||
index+=2;
|
||||
if (index>=slen-2) break;
|
||||
uint32_t index = 0;
|
||||
for (uint32_t cnt = 0; cnt < meter_spos[meter]; cnt++) {
|
||||
sprintf(str,"%02x", smltbuf[meter][cnt]);
|
||||
str += 2;
|
||||
index += 2;
|
||||
if (index >= slen - 2) break;
|
||||
}
|
||||
}
|
||||
meter_spos[meter]=0;
|
||||
meter_spos[meter] = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
float SML_GetVal(uint32_t index) {
|
||||
if (index < 1 || index > SML_MAX_VARS) { index = 1;}
|
||||
return meter_vars[index-1];
|
||||
return meter_vars[index - 1];
|
||||
}
|
||||
|
||||
char *SML_GetSVal(uint32_t index) {
|
||||
|
@ -3357,13 +3423,13 @@ uint32_t ctime = millis();
|
|||
#ifdef USE_SCRIPT
|
||||
char *SML_Get_Sequence(char *cp,uint32_t index) {
|
||||
if (!index) return cp;
|
||||
uint32_t cindex=0;
|
||||
uint32_t cindex = 0;
|
||||
while (cp) {
|
||||
cp=strchr(cp,',');
|
||||
cp = strchr(cp, ',');
|
||||
if (cp) {
|
||||
cp++;
|
||||
cindex++;
|
||||
if (cindex==index) {
|
||||
if (cindex == index) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
@ -3385,13 +3451,13 @@ void SML_Check_Send(void) {
|
|||
script_meter_desc[cnt].script_str = 0;
|
||||
} else {
|
||||
//AddLog(LOG_LEVEL_INFO, PSTR("100 ms>> 2"),cp);
|
||||
if (script_meter_desc[cnt].max_index>1) {
|
||||
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++;
|
||||
}
|
||||
cp=SML_Get_Sequence(script_meter_desc[cnt].txmem,script_meter_desc[cnt].index);
|
||||
cp = SML_Get_Sequence(script_meter_desc[cnt].txmem, script_meter_desc[cnt].index);
|
||||
//SML_Send_Seq(cnt,cp);
|
||||
} else {
|
||||
cp = script_meter_desc[cnt].txmem;
|
||||
|
@ -3461,17 +3527,49 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
|
|||
slen++;
|
||||
if (slen >= sizeof(sbuff)-6) break; // leave space for checksum
|
||||
}
|
||||
if (script_meter_desc[meter].type == 'm' || script_meter_desc[meter].type == 'M') {
|
||||
if (!rflg) {
|
||||
if (script_meter_desc[meter].type == 'm' || script_meter_desc[meter].type == 'M' || script_meter_desc[meter].type == 'k') {
|
||||
if (script_meter_desc[meter].type == 'k') {
|
||||
// kamstrup, append crc, cr
|
||||
*ucp++ = 0;
|
||||
*ucp++ = 2;
|
||||
*ucp++ = 0;
|
||||
slen += 2;
|
||||
uint16_t crc = KS_calculateCRC(sbuff, slen);
|
||||
ucp -= 2;
|
||||
*ucp++ = highByte(crc);
|
||||
*ucp++ = lowByte(crc);
|
||||
|
||||
// now check for escapes
|
||||
uint8_t ksbuff[24];
|
||||
ucp = ksbuff;
|
||||
*ucp++ = 0x80;
|
||||
uint8_t klen = 1;
|
||||
for (uint16_t cnt = 0; cnt < slen; cnt++) {
|
||||
uint8_t iob = sbuff[cnt];
|
||||
if ((iob == 0x80) || (iob == 0x40) || (iob == 0x0d) || (iob == 0x06) || (iob == 0x1b)) {
|
||||
*ucp++ = 0x1b;
|
||||
*ucp++ = iob ^= 0xff;
|
||||
klen += 2;
|
||||
} else {
|
||||
*ucp++ = iob;
|
||||
klen++;
|
||||
}
|
||||
}
|
||||
*ucp++ = 0xd;
|
||||
slen = klen + 1;
|
||||
memcpy(sbuff, ksbuff, slen);
|
||||
} else {
|
||||
if (!rflg) {
|
||||
*ucp++ = 0;
|
||||
*ucp++ = 2;
|
||||
slen += 2;
|
||||
}
|
||||
// append crc
|
||||
uint16_t crc = MBUS_calculateCRC(sbuff, slen, 0xFFFF);
|
||||
*ucp++ = lowByte(crc);
|
||||
*ucp++ = highByte(crc);
|
||||
slen += 2;
|
||||
}
|
||||
// append crc
|
||||
uint16_t crc = MBUS_calculateCRC(sbuff, slen, 0xFFFF);
|
||||
*ucp++ = lowByte(crc);
|
||||
*ucp++ = highByte(crc);
|
||||
slen += 2;
|
||||
|
||||
}
|
||||
if (script_meter_desc[meter].type == 'o') {
|
||||
for (uint32_t cnt = 0; cnt < slen; cnt++) {
|
||||
|
@ -3487,18 +3585,28 @@ void SML_Send_Seq(uint32_t meter,char *seq) {
|
|||
*ucp++ = SML_PzemCrc(sbuff, 6);
|
||||
slen += 6;
|
||||
}
|
||||
|
||||
meter_ss[meter]->flush();
|
||||
meter_ss[meter]->write(sbuff, slen);
|
||||
if (dump2log) {
|
||||
#ifdef SML_DUMP_OUT_ALL
|
||||
Hexdump(sbuff, slen);
|
||||
#else
|
||||
uint8_t type = meter_desc_p[(dump2log&7) - 1].type;
|
||||
if (type == 'm' || type == 'M') {
|
||||
if (type == 'm' || type == 'M' || type == 'k') {
|
||||
Hexdump(sbuff, slen);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef MODBUS_DEBUG
|
||||
uint8_t type = script_meter_desc[meter].type;
|
||||
if (!dump2log && (type == 'm' || type == 'M' || type == 'k')) {
|
||||
AddLog(LOG_LEVEL_INFO, PSTR("transmit index >> %d"),meter_desc_p[meter].index);
|
||||
Hexdump(sbuff, slen);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
#endif // USE_SCRIPT
|
||||
|
||||
|
@ -3520,6 +3628,27 @@ uint16_t MBUS_calculateCRC(uint8_t *frame, uint8_t num, uint16_t start) {
|
|||
return crc;
|
||||
}
|
||||
|
||||
|
||||
uint16_t KS_calculateCRC(const uint8_t *frame, uint8_t num) {
|
||||
uint32_t crc = 0;
|
||||
for (uint32_t i = 0; i < num; i++) {
|
||||
uint8_t mask = 0x80;
|
||||
uint8_t iob = frame[i];
|
||||
while (mask) {
|
||||
crc <<= 1;
|
||||
if (iob & mask) {
|
||||
crc |= 1;
|
||||
}
|
||||
mask >>= 1;
|
||||
if (crc & 0x10000) {
|
||||
crc &= 0xffff;
|
||||
crc ^= 0x1021;
|
||||
}
|
||||
}
|
||||
}
|
||||
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++;
|
||||
|
|
Loading…
Reference in New Issue