7 Commits

29 changed files with 46452 additions and 45582 deletions

View File

@@ -17,7 +17,7 @@
-DMOTOR_DISABLE -DMOTOR_DISABLE
#-DWiz5100 #-DWiz5100
-DARDUINO_OTA_MDNS_DISABLE -DARDUINO_OTA_MDNS_DISABLE
#-DMDNS_ENABLE -DMDNS_ENABLE
-DRESTART_LAN_ON_MQTT_ERRORS -DRESTART_LAN_ON_MQTT_ERRORS
-D CORS=\"http://lazyhome.ru\" -D CORS=\"http://lazyhome.ru\"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@@ -10,7 +10,7 @@ extern PubSubClient mqttClient;
extern int8_t ethernetIdleCount; extern int8_t ethernetIdleCount;
int abstractCh::publishTopic(const char* topic, long value, const char* subtopic) int abstractCh::publishTopic(const char* topic, long value, const char* subtopic)
{ {
char valstr[16]; char valstr[16];
printUlongValueToStr(valstr, value); printUlongValueToStr(valstr, value);
return publishTopic(topic, valstr,subtopic); return publishTopic(topic, valstr,subtopic);
@@ -19,7 +19,7 @@ int abstractCh::publishTopic(const char* topic, long value, const char* subtopic
int abstractCh::publishTopic(const char* topic, float value, const char* subtopic) int abstractCh::publishTopic(const char* topic, float value, const char* subtopic)
{ {
char valstr[16]; char valstr[16];
printFloatValueToStr(value, valstr); printFloatValueToStr(valstr, value);
return publishTopic(topic, valstr,subtopic); return publishTopic(topic, valstr,subtopic);
}; };

View File

@@ -20,7 +20,7 @@ int abstractIn::publish(long value, const char* subtopic)
int abstractIn::publish(float value, const char* subtopic) int abstractIn::publish(float value, const char* subtopic)
{ {
char valstr[16]; char valstr[16];
printFloatValueToStr(value, valstr); printFloatValueToStr(valstr, value);
return publish(valstr,subtopic); return publish(valstr,subtopic);
}; };

View File

@@ -39,6 +39,8 @@ extern NRFFlashStorage EEPROM;
#if defined(__SAM3X8E__) #if defined(__SAM3X8E__)
DueFlashStorage EEPROM; DueFlashStorage EEPROM;
static char samBuffer[64];
short samBufferPos = 0;
#endif #endif
#ifdef NRF5 #ifdef NRF5
@@ -129,6 +131,11 @@ NRFFlashStorage EEPROM;
int flashStream::open(short fileNum, char mode) int flashStream::open(short fileNum, char mode)
{ {
#if defined(__SAM3X8E__)
if (samBufferPos) flush();
samBufferPos = 0;
#endif
switch (fileNum) { switch (fileNum) {
case FN_CONFIG_JSON: case FN_CONFIG_JSON:
pos = 0; pos = 0;
@@ -138,6 +145,7 @@ NRFFlashStorage EEPROM;
#ifdef OTA #ifdef OTA
contentType = HTTP_TEXT_JSON; contentType = HTTP_TEXT_JSON;
#endif #endif
openmode = mode;
return 1; return 1;
case FN_CONFIG_BIN: case FN_CONFIG_BIN:
@@ -148,6 +156,7 @@ NRFFlashStorage EEPROM;
#ifdef OTA #ifdef OTA
contentType = HTTP_OCTET_STREAM; contentType = HTTP_OCTET_STREAM;
#endif #endif
openmode = mode;
return 1; return 1;
default: default:
@@ -171,7 +180,13 @@ NRFFlashStorage EEPROM;
}; };
unsigned int flashStream::seek(unsigned int _pos) unsigned int flashStream::seek(unsigned int _pos)
{ pos=min(_pos, streamSize); {
#if defined(__SAM3X8E__)
if (samBufferPos) flush();
#endif
pos=min(_pos, streamSize);
//debugSerial<<F("Seek:")<<pos<<endl; //debugSerial<<F("Seek:")<<pos<<endl;
return pos; return pos;
}; };
@@ -196,21 +211,38 @@ NRFFlashStorage EEPROM;
else return -1; else return -1;
}; };
void flashStream::flush() { void flashStream::flush() {
#if defined(ESP8266) || defined(ESP32) #if defined(ESP8266) || defined(ESP32)
if (EEPROM.commitReset()) if (EEPROM.commitReset())
infoSerial<<"Commited to FLASH"<<endl; infoSerial<<"Commited to FLASH"<<endl;
else errorSerial<<"Commit error. len:"<<EEPROM.length()<<endl; else errorSerial<<"Commit error. len:"<<EEPROM.length()<<endl;
#elif defined(__SAM3X8E__)
if (samBufferPos)
EEPROM.write(startPos+pos-samBufferPos,(byte*)samBuffer,samBufferPos);
samBufferPos=0;
#endif #endif
}; };
size_t flashStream::write(uint8_t ch) size_t flashStream::write(uint8_t ch)
{ {
#if defined(__AVR__) #if defined(__AVR__)
EEPROM.update(startPos+pos++,(char)ch); EEPROM.update(startPos+pos++,(char)ch);
return 1; return 1;
#elif defined(__SAM3X8E__) #elif defined(__SAM3X8E__)
return EEPROM.write(startPos+pos++,(char)ch);
if (samBufferPos==sizeof(samBuffer))
{
samBufferPos = 0;
EEPROM.write(startPos+pos-sizeof(samBuffer),(byte*)samBuffer,sizeof(samBuffer));
}
samBuffer[samBufferPos++]=ch;
pos++;
return 1;
// return EEPROM.write(startPos+pos++,(char)ch);
#else #else
EEPROM.write(startPos+pos++,(char)ch); EEPROM.write(startPos+pos++,(char)ch);
return 1; return 1;
@@ -237,7 +269,10 @@ NRFFlashStorage EEPROM;
void flashStream::close() void flashStream::close()
{ {
putEOF(); if (openmode == 'w') putEOF();
#if defined(__SAM3X8E__)
if (samBufferPos) flush();
#endif
} }

View File

@@ -53,9 +53,10 @@ class flashStream : public seekableStream
protected: protected:
unsigned int pos; unsigned int pos;
unsigned int startPos; unsigned int startPos;
char openmode ;
public: public:
flashStream():seekableStream(MAX_STREAM_SIZE){}; flashStream():seekableStream(MAX_STREAM_SIZE){openmode = '\0';};
void setSize(unsigned int _size); void setSize(unsigned int _size);
int open(short fileNum, char mode='\0') ; int open(short fileNum, char mode='\0') ;
virtual int open(String _filename, char mode='\0') override; virtual int open(String _filename, char mode='\0') override;

View File

@@ -503,11 +503,11 @@ debugSerial << F("IN:") << pin << F(" DHT22 type. T=") << temp << F("°C H=") <<
strncpy(addrstr, emit->valuestring, sizeof(addrstr)); strncpy(addrstr, emit->valuestring, sizeof(addrstr));
if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring); if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring);
strcat(addrstr, "T"); strcat(addrstr, "T");
printFloatValueToStr(temp, valstr); printFloatValueToStr(valstr, temp);
if (mqttClient.connected() && !ethernetIdleCount) if (mqttClient.connected() && !ethernetIdleCount)
mqttClient.publish(addrstr, valstr); mqttClient.publish(addrstr, valstr);
addrstr[strlen(addrstr) - 1] = 'H'; addrstr[strlen(addrstr) - 1] = 'H';
printFloatValueToStr(humidity, valstr); printFloatValueToStr(valstr, humidity);
if (mqttClient.connected() && !ethernetIdleCount) if (mqttClient.connected() && !ethernetIdleCount)
mqttClient.publish(addrstr, valstr); mqttClient.publish(addrstr, valstr);

View File

@@ -1181,6 +1181,7 @@ return false;
i=i->next; i=i->next;
} }
} }
break;
case aJson_String: case aJson_String:
if (strcmp(cmdMapping->valuestring,"fan")==0) if (strcmp(cmdMapping->valuestring,"fan")==0)
switch (getCmd()) switch (getCmd())
@@ -1209,7 +1210,10 @@ return false;
} //switch } //switch
if (matchedCmd) return itemCmd().Int((uint32_t)matchedCmd->valueint); if (matchedCmd && matchedCmd->type != aJson_NULL)
{
return itemCmd().Int((uint32_t)matchedCmd->valueint);
}
aJsonObject *valMapping = aJson.getObjectItem(mappingData, "val"); aJsonObject *valMapping = aJson.getObjectItem(mappingData, "val");
if (isValue() && valMapping && valMapping->type == aJson_Array && aJson.getArraySize(valMapping) == 4) if (isValue() && valMapping && valMapping->type == aJson_Array && aJson.getArraySize(valMapping) == 4)
@@ -1220,6 +1224,7 @@ if (isValue() && valMapping && valMapping->type == aJson_Array && aJson.getArray
aJson.getArrayItem(valMapping,0)->valueint,aJson.getArrayItem(valMapping,1)->valueint, aJson.getArrayItem(valMapping,0)->valueint,aJson.getArrayItem(valMapping,1)->valueint,
aJson.getArrayItem(valMapping,2)->valueint,aJson.getArrayItem(valMapping,3)->valueint)); aJson.getArrayItem(valMapping,2)->valueint,aJson.getArrayItem(valMapping,3)->valueint));
} }
else if (valMapping && valMapping->type == aJson_NULL) return itemCmd(ST_VOID,CMD_VOID);
return *this; return *this;
} }
@@ -1335,7 +1340,10 @@ char * itemCmd::toString(char * Buffer, int bufLen, int sendFlags, bool scale100
snprintf(argPtr, bufLen, "%ld", param.asInt32); snprintf(argPtr, bufLen, "%ld", param.asInt32);
break; break;
case ST_TENS: case ST_TENS:
snprintf(argPtr, bufLen, "%ld.%0"QUOTE(TENS_FRACT_LEN)"d", param.asInt32/TENS_BASE, abs(param.asInt32 % TENS_BASE)); if (param.asInt32<0)
snprintf(argPtr, bufLen, "-%ld.%0"QUOTE(TENS_FRACT_LEN)"d", abs(param.asInt32)/TENS_BASE, abs(param.asInt32 % TENS_BASE));
else
snprintf(argPtr, bufLen, "%ld.%0"QUOTE(TENS_FRACT_LEN)"d", param.asInt32/TENS_BASE, abs(param.asInt32 % TENS_BASE));
break; break;
case ST_HSV255: case ST_HSV255:
colorTemp=getColorTemp(); colorTemp=getColorTemp();

View File

@@ -664,6 +664,8 @@ lan_status lanLoop() {
setTopic(buf,sizeof(buf),T_OUT); setTopic(buf,sizeof(buf),T_OUT);
strncat(buf, "+/+/#", sizeof(buf)); // Subscribing only on separated command/parameters topics strncat(buf, "+/+/#", sizeof(buf)); // Subscribing only on separated command/parameters topics
mqttClient.unsubscribe(buf); mqttClient.unsubscribe(buf);
onMQTTConnect();
lanStatus = OPERATION;//3; lanStatus = OPERATION;//3;
infoSerial<<F("Accepting commands...\n"); infoSerial<<F("Accepting commands...\n");
@@ -1002,7 +1004,7 @@ void ip_ready_config_loaded_connecting_to_broker() {
debugSerialPort.println(buf); debugSerialPort.println(buf);
mqttClient.subscribe(buf); mqttClient.subscribe(buf);
onMQTTConnect(); //onMQTTConnect();
// if (_once) {DMXput(); _once=0;} // if (_once) {DMXput(); _once=0;}
lanStatus = RETAINING_COLLECTING;//4; lanStatus = RETAINING_COLLECTING;//4;
timerLanCheckTime = millis();// + 5000; timerLanCheckTime = millis();// + 5000;
@@ -1497,11 +1499,11 @@ if (arg_cnt>1)
#else #else
sysConfStream.open(FN_CONFIG_JSON,'w'); sysConfStream.open(FN_CONFIG_JSON,'w');
#endif #endif
/*
#if defined(__SAM3X8E__) #if defined(__SAM3X8E__)
long configBufSize = min(MAX_JSON_CONF_SIZE,freeRam()-1024); long configBufSize = min(MAX_JSON_CONF_SIZE,freeRam()-1024);
debugSerial<<"Allocate "<<configBufSize<<" bytes for buffer"<<endl; debugSerial<<"Allocate "<<configBufSize<<" bytes for buffer"<<endl;
char* outBuf = (char*) malloc(configBufSize); /* XXX: Dynamic size. */ char* outBuf = (char*) malloc(configBufSize);
if (!outBuf) if (!outBuf)
{ {
sysConfStream.close(); sysConfStream.close();
@@ -1509,23 +1511,22 @@ if (arg_cnt>1)
return 500; return 500;
} }
infoSerial<<F("Saving config to EEPROM..")<<endl; infoSerial<<F("Saving config to EEPROM..")<<endl;
aJsonStringStream stringStream(NULL, outBuf, configBufSize); aJsonStringStream stringStream(NULL, outBuf, configBufSize-2);
aJson.print(root, &stringStream); aJson.print(root, &stringStream);
int len = strlen(outBuf); int len = strlen(outBuf);
outBuf[len++]= EOFchar; outBuf[len++]= EOFchar;
infoSerial<<len<< F(" bytes collected")<<endl;
size_t res = sysConfStream.write((byte*) outBuf,len); size_t res = sysConfStream.write((byte*) outBuf,len);
free (outBuf); free (outBuf);
infoSerial<<res<< F(" bytes from ")<<len<<F(" are saved to EEPROM")<<endl; infoSerial<<res<< F(" bytes are saved to EEPROM")<<endl;
#else #else */
aJsonStream jsonEEPROMStream = aJsonStream(&sysConfStream); aJsonStream jsonEEPROMStream = aJsonStream(&sysConfStream);
infoSerial<<F("Saving config to EEPROM.."); infoSerial<<F("Saving config to EEPROM..");
aJson.print(root, &jsonEEPROMStream); aJson.print(root, &jsonEEPROMStream);
//sysConfStream.putEOF();
//sysConfStream.flush();
sysConfStream.close(); sysConfStream.close();
infoSerial<<F("Saved to EEPROM")<<endl; infoSerial<<F("Saved to EEPROM")<<endl;
#endif //#endif
sysConf.saveETAG(); sysConf.saveETAG();
return 200; return 200;
} }
@@ -2285,6 +2286,10 @@ infoSerial<<F("\n(+)HUMIDIFIER");
#ifdef ELEVATOR_ENABLE #ifdef ELEVATOR_ENABLE
infoSerial<<F("\n(+)ELEVATOR"); infoSerial<<F("\n(+)ELEVATOR");
#endif #endif
#ifdef IPMODBUS
infoSerial<<F("\n(+)IPMODBUS");
#endif
infoSerial<<endl; infoSerial<<endl;
// WDT_Disable( WDT ) ; // WDT_Disable( WDT ) ;

View File

@@ -317,4 +317,6 @@ void ip_ready_config_loaded_connecting_to_broker();
void printCurentLanConfig(); void printCurentLanConfig();
void onMQTTConnect();
//void printFreeRam(); //void printFreeRam();

View File

@@ -14,7 +14,8 @@ void out_counter::getConfig()
{ {
if (!item) return; if (!item) return;
impulse = item->getFloatArg(0); impulse = item->getFloatArg(0);
period = item->getFloatArg(1)*1000.0; period = item->getFloatArg(1)*1000.0;
//debugSerial<<"CTR: imp:"<<impulse<<" period:"<<period<<endl;
} }
int out_counter::Setup() int out_counter::Setup()
@@ -38,7 +39,7 @@ return driverStatus;
int out_counter::Poll(short cause) int out_counter::Poll(short cause)
{ {
if (cause==POLLING_SLOW) return 0; if (cause==POLLING_SLOW || cause==POLLING_INT) return 0;
if (!item) return 0; if (!item) return 0;
@@ -47,13 +48,18 @@ uint32_t timer = item->getExt();
if (timer && period && isTimeOver(timer,millis(),period)) if (timer && period && isTimeOver(timer,millis(),period))
{ {
item->setExt(millisNZ()); item->setExt(millisNZ());
itemCmd st; itemCmd st;
st.loadItem(item,SEND_PARAMETERS|SEND_COMMAND); st.loadItem(item,SEND_PARAMETERS|SEND_COMMAND);
float val = st.getFloat(); float val = st.getFloat();
//short cmd = st.getCmd(); //short cmd = st.getCmd();
debugSerial<<"CTR: tick val:"<<val<<endl;
val+=impulse; val+=impulse;
st.Float(val); st.Float(val);
st.saveItem(item); st.saveItem(item);
debugSerial<<"CTR: tick saved val:"<<val<<endl;
item->SendStatus(SEND_PARAMETERS);
} }
return 0; return 0;
@@ -82,13 +88,11 @@ case S_SET:
if (!item->getExt()) if (!item->getExt())
{ {
item->setExt(millisNZ()); item->setExt(millisNZ());
//relay(true);
} }
} }
else else
{ {
item->setExt(0); item->setExt(0);
} }
} }
return 1; return 1;
@@ -105,13 +109,11 @@ case S_CMD:
if (!item->getExt()) if (!item->getExt())
{ {
item->setExt(millisNZ()); item->setExt(millisNZ());
//relay(true);
} }
return 1; return 1;
case CMD_OFF: case CMD_OFF:
item->setExt(0); item->setExt(0);
return 1; return 1;
default: default:

View File

@@ -15,6 +15,7 @@ extern aJsonObject *modbusObj;
extern ModbusMaster node; extern ModbusMaster node;
extern short modbusBusy; extern short modbusBusy;
extern void modbusIdle(void) ; extern void modbusIdle(void) ;
static uint32_t mbusSlenceTimer = 0;
struct reg_t struct reg_t
{ {
@@ -116,13 +117,13 @@ bool out_Modbus::getConfig()
aJsonObject * templateIdObj = aJson.getArrayItem(item->itemArg, 1); aJsonObject * templateIdObj = aJson.getArrayItem(item->itemArg, 1);
if (templateIdObj->type != aJson_String || !templateIdObj->valuestring) if (templateIdObj->type != aJson_String || !templateIdObj->valuestring)
{ {
errorSerial<<F("Invalid template.")<<endl; errorSerial<<F("MBUS: Invalid template.")<<endl;
return false; return false;
} }
aJsonObject * templateObj = aJson.getObjectItem(modbusObj, templateIdObj->valuestring); aJsonObject * templateObj = aJson.getObjectItem(modbusObj, templateIdObj->valuestring);
if (! templateObj) if (! templateObj)
{ {
errorSerial<<F("Modbus template not found: ")<<templateIdObj->valuestring<<endl; errorSerial<<F("MBUS: Modbus template not found: ")<<templateIdObj->valuestring<<endl;
return false; return false;
} }
@@ -173,12 +174,12 @@ if (!store)
store->timestamp=millisNZ(); store->timestamp=millisNZ();
if (getConfig()) if (getConfig())
{ {
infoSerial<<F("Modbus config loaded ")<< item->itemArr->name<<endl; infoSerial<<F("MBUS: config loaded ")<< item->itemArr->name<<endl;
store->driverStatus = CST_INITIALIZED; store->driverStatus = CST_INITIALIZED;
return 1; return 1;
} }
else else
{ errorSerial<<F("Modbus config error")<<endl; { errorSerial<<F("MBUS: config error")<<endl;
store->driverStatus = CST_FAILED; store->driverStatus = CST_FAILED;
return 0; return 0;
} }
@@ -187,7 +188,7 @@ else
int out_Modbus::Stop() int out_Modbus::Stop()
{ {
debugSerial.println("Modbus De-Init"); debugSerial.println("MBUS: De-Init");
delete store; delete store;
item->setPersistent(NULL); item->setPersistent(NULL);
@@ -221,8 +222,9 @@ switch (regType) {
result = node.readInputRegisters(reg, count); result = node.readInputRegisters(reg, count);
break; break;
default: default:
debugSerial<<F("Not supported reg type\n"); debugSerial<<F("MBUS: Not supported reg type\n");
} }
mbusSlenceTimer = millisNZ();
if (result != node.ku8MBSuccess) errorSerial<<F("MBUS: Polling error ")<<_HEX(result)<<endl; if (result != node.ku8MBSuccess) errorSerial<<F("MBUS: Polling error ")<<_HEX(result)<<endl;
return (result == node.ku8MBSuccess); return (result == node.ku8MBSuccess);
} }
@@ -260,7 +262,7 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
case PAR_I16: case PAR_I16:
//isSigned=true; //isSigned=true;
param=data; param=data;
mappedParam.Int((int32_t)data); mappedParam.Int((int32_t)(int16_t)data);
break; break;
case PAR_U16: case PAR_U16:
@@ -292,21 +294,21 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
case PAR_TENS: case PAR_TENS:
param=data; param=data;
mappedParam.Tens((int32_t) data); mappedParam.Tens((int16_t) data);
break; break;
case PAR_100: case PAR_100:
param=data; param=data;
mappedParam.Tens_raw(data * (TENS_BASE/100)); mappedParam.Tens_raw((int16_t) data * (TENS_BASE/100));
mappedParam.Float((int32_t) data/100.); mappedParam.Float((int32_t) (int16_t) data/100.);
} }
debugSerial << F("MB got ")<<mappedParam.toString(buf,sizeof(buf))<< F(" from ")<<regType<<F(":")<<paramObj->name<<endl; debugSerial << F("MBUSD: got ")<<mappedParam.toString(buf,sizeof(buf))<< F(" from ")<<regType<<F(":")<<paramObj->name<<endl;
if (mapObj && (mapObj->type==aJson_Array || mapObj->type==aJson_Object)) if (mapObj && (mapObj->type==aJson_Array || mapObj->type==aJson_Object))
{ {
mappedParam=mappedParam.doReverseMapping(mapObj); mappedParam=mappedParam.doReverseMapping(mapObj);
debugSerial << F("Mapped:")<<mappedParam.toString(buf,sizeof(buf))<<endl; debugSerial << F("MBUSD: Mapped:")<<mappedParam.toString(buf,sizeof(buf))<<endl;
} }
if (itemParametersObj && itemParametersObj->type ==aJson_Object) if (itemParametersObj && itemParametersObj->type ==aJson_Object)
@@ -328,7 +330,7 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
} }
else //No container to store value yet else //No container to store value yet
{ {
debugSerial<<F("Add @S: ")<<paramObj->name<<endl; debugSerial<<F("MBUS: Add @S: ")<<paramObj->name<<endl;
aJson.addNumberToObject(execObj, "@S", (long) param); aJson.addNumberToObject(execObj, "@S", (long) param);
} }
if (submitParam) if (submitParam)
@@ -338,9 +340,15 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
aJsonObject *settedValue = aJson.getObjectItem(execObj,"@V"); aJsonObject *settedValue = aJson.getObjectItem(execObj,"@V");
if (settedValue && settedValue->type==aJson_Int && (settedValue->valueint == param)) if (settedValue && settedValue->type==aJson_Int && (settedValue->valueint == param))
{ {
debugSerial<<F("Ignored - equal with setted val")<<endl; debugSerial<<F("MBUSD: Ignored - equal with setted val")<<endl;
} }
else executeCommand(execObj, -1, mappedParam); else
{
executeCommand(execObj, -1, mappedParam);
// if param updated by device and no new value queued to send - update @V to avoid "Ignored - equal with setted val"
if (settedValue && !(execObj->subtype & MB_NEED_SEND))
settedValue->valueint=param;
}
//#endif //#endif
} }
} }
@@ -410,7 +418,7 @@ void out_Modbus::initLine()
#else #else
modbusSerial.begin(store->baud, (store->serialParam)); modbusSerial.begin(store->baud, (store->serialParam));
#endif #endif
debugSerial<< store->baud << F("---")<< store->serialParam<<endl; //debugSerial<< store->baud << F("---")<< store->serialParam<<endl;
node.begin(item->getArg(0), modbusSerial); node.begin(item->getArg(0), modbusSerial);
} }
@@ -452,7 +460,8 @@ int out_Modbus::sendModbus(char * paramName, int32_t value, uint8_t regType)
res = node.writeSingleRegister(regObj->valueint,(value & 0xFFFF)>> 8); res = node.writeSingleRegister(regObj->valueint,(value & 0xFFFF)>> 8);
break; break;
} }
debugSerial<<F("MB_SEND Res: ")<<res<<F(" ")<<paramName<<" reg:"<<regObj->valueint<<F(" val:")<<value<<F(" ival:")<<(int32_t) value<<endl; mbusSlenceTimer = millisNZ();
debugSerial<<F("Res: ")<<res<<F(" ")<<paramName<<" reg:"<<regObj->valueint<<F(" val:")<<value<<endl;
return ( res == 0); return ( res == 0);
} }
@@ -461,7 +470,7 @@ int out_Modbus::Poll(short cause)
if (cause==POLLING_SLOW) return 0; if (cause==POLLING_SLOW) return 0;
bool lineInitialized = false; bool lineInitialized = false;
if (modbusBusy || (Status() != CST_INITIALIZED)) return 0; if (modbusBusy || (Status() != CST_INITIALIZED) || ( mbusSlenceTimer && !isTimeOver(mbusSlenceTimer,millis(),100))) return 0;
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2); aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
if (itemParametersObj && itemParametersObj->type ==aJson_Object) if (itemParametersObj && itemParametersObj->type ==aJson_Object)
@@ -480,18 +489,22 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
lineInitialized=true; lineInitialized=true;
initLine(); initLine();
} }
debugSerial<<"MBUS: SEND "<<item->itemArr->name<<" ";
switch (sendModbus(execObj->name,outValue->valueint,outValue->subtype)) switch (sendModbus(execObj->name,outValue->valueint,outValue->subtype))
{ {
case 1: //success case 1: //success
execObj->subtype&=~ MB_NEED_SEND; execObj->subtype&=~ MB_NEED_SEND;
///return 1; //relax
break; break;
case 0: //fault case 0: //fault
execObj->subtype |= MB_SEND_ERROR; execObj->subtype |= MB_SEND_ERROR;
errorSerial<<F("MBus ")<<execObj->name<<F(" send error")<<endl; errorSerial<<F("MBUS: ")<<execObj->name<<F(" send error. ");
if ((execObj->subtype & 3) != MB_SEND_ATTEMPTS) execObj->subtype++; if ((execObj->subtype & 3) != MB_SEND_ATTEMPTS) execObj->subtype++;
errorSerial<<"Attempt: "<< (execObj->subtype & 3) <<endl;
break; break;
default: //param not found default: //param not found
errorSerial<<F("MBus param ")<<execObj->name<<F(" not found")<<endl; errorSerial<<F("MBUS: param ")<<execObj->name<<F(" not found")<<endl;
execObj->subtype&=~ MB_NEED_SEND; execObj->subtype&=~ MB_NEED_SEND;
} }
} }
@@ -502,7 +515,7 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
} }
if (isTimeOver(store->timestamp,millis(),store->pollingInterval)) if (isTimeOver(store->timestamp,millis(),store->pollingInterval) && ( !mbusSlenceTimer || isTimeOver(mbusSlenceTimer,millis(),100)))
{ {
// Clean_up SEND_ERROR flag // Clean_up SEND_ERROR flag
@@ -512,7 +525,14 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
while (execObj && execObj->type == aJson_Object) while (execObj && execObj->type == aJson_Object)
{ {
if (execObj->subtype & MB_SEND_ERROR) execObj->subtype&=~ MB_SEND_ERROR; if (execObj->subtype & MB_SEND_ERROR) execObj->subtype&=~ MB_SEND_ERROR;
if ((execObj->subtype & 0x3) >= MB_SEND_ATTEMPTS) execObj->subtype&=~ MB_NEED_SEND; if ((execObj->subtype & 0x3) >= MB_SEND_ATTEMPTS)
{
//execObj->subtype&=~ MB_NEED_SEND;
//Clean ERROR, NEED, Attempts
errorSerial<<"MBUS: send failed "<<item->itemArr->name<<endl;
execObj->subtype = 0;
}
execObj=execObj->next; execObj=execObj->next;
} }
} }
@@ -520,7 +540,7 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
// if some polling configured // if some polling configured
if (store->pollingRegisters || store->pollingIrs) if (store->pollingRegisters || store->pollingIrs)
{ {
debugSerial<<F("Poll ")<< item->itemArr->name << endl; debugSerial<<F("MBUSD: Poll ")<< item->itemArr->name << endl;
modbusBusy=1; modbusBusy=1;
if (!lineInitialized) if (!lineInitialized)
@@ -531,7 +551,7 @@ if (store->pollingRegisters || store->pollingIrs)
pollModbus(store->pollingRegisters,MODBUS_HOLDING_REG_TYPE); pollModbus(store->pollingRegisters,MODBUS_HOLDING_REG_TYPE);
pollModbus(store->pollingIrs,MODBUS_INPUT_REG_TYPE); pollModbus(store->pollingIrs,MODBUS_INPUT_REG_TYPE);
debugSerial<<F("endPoll ")<< item->itemArr->name << endl; debugSerial<<F("MBUSD: endPoll ")<< item->itemArr->name << endl;
//Non blocking waiting to release line //Non blocking waiting to release line
uint32_t time = millis(); uint32_t time = millis();
@@ -561,7 +581,8 @@ if (!suffixCode) return 0;
char *suffixStr =templateParamObj->name; char *suffixStr =templateParamObj->name;
// We have find template for suffix or suffixCode // We have find template for suffix or suffixCode
long Value = 0; itemCmd cmdValue = itemCmd(ST_VOID,CMD_VOID);
long Value = 0;
int8_t regType = PAR_I16; int8_t regType = PAR_I16;
aJsonObject * typeObj = aJson.getObjectItem(templateParamObj, "type"); aJsonObject * typeObj = aJson.getObjectItem(templateParamObj, "type");
aJsonObject * mapObj = aJson.getObjectItem(templateParamObj, "map"); aJsonObject * mapObj = aJson.getObjectItem(templateParamObj, "map");
@@ -577,29 +598,36 @@ aJsonObject * mapObj = aJson.getObjectItem(templateParamObj, "map");
case PAR_I8H: case PAR_I8H:
case PAR_I8L: case PAR_I8L:
Value=cmd.doMapping(mapObj).getInt(); cmdValue=cmd.doMapping(mapObj);
if (!cmdValue.isValue())return 0;
Value=cmdValue.getInt();
break; break;
case PAR_TENS: case PAR_TENS:
Value=cmd.doMapping(mapObj).getTens(); cmdValue=cmd.doMapping(mapObj);
if (!cmdValue.isValue())return 0;
Value=cmdValue.getTens();
break; break;
case PAR_100: case PAR_100:
Value=cmd.doMapping(mapObj).getTens_raw()*(100/TENS_BASE); cmdValue=cmd.doMapping(mapObj);
if (!cmdValue.isValue())return 0;
Value=cmdValue.getTens_raw()*(100/TENS_BASE);
} }
debugSerial<<F("MB suffix:")<<suffixStr<< F(" Val: ")<<Value<<endl; debugSerial<<F("MBUSD: suffix:")<<suffixStr<< F(" Val: ")<<Value<<endl;
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2); aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
if (itemParametersObj && itemParametersObj->type ==aJson_Object) if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{ {
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,suffixStr); aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,suffixStr);
if (execObj && execObj->type == aJson_Object) if (execObj && execObj->type == aJson_Object)
{ {
/*
aJsonObject *polledValue = aJson.getObjectItem(execObj,"@S"); aJsonObject *polledValue = aJson.getObjectItem(execObj,"@S");
if (polledValue && polledValue->type == aJson_Int && (polledValue->valueint == Value)) if (polledValue && polledValue->type == aJson_Int && (polledValue->valueint == Value))
{ {
debugSerial<<F("Ignored - not changed")<<endl; debugSerial<<F("Ignored - not changed")<<endl;
} }
else else */
{ //Schedule update { //Schedule update
execObj->subtype |= MB_NEED_SEND; execObj->subtype |= MB_NEED_SEND;
@@ -608,7 +636,6 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{ {
outValue->valueint=Value; outValue->valueint=Value;
outValue->subtype =regType & 0xF; outValue->subtype =regType & 0xF;
if (outValue->type == aJson_Int) polledValue->valueint=Value; //to pevent suppressing to change back to previously polled value if this occurs before next polling
} }
else //No container to store value yet else //No container to store value yet
// If no @V in config - creating with INT type - normal behavior - no supress in-to-out // If no @V in config - creating with INT type - normal behavior - no supress in-to-out
@@ -618,6 +645,10 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
outValue = aJson.getObjectItem(execObj,"@V"); outValue = aJson.getObjectItem(execObj,"@V");
if (outValue) outValue->subtype =regType & 0xF; if (outValue) outValue->subtype =regType & 0xF;
} }
aJsonObject *polledValue = aJson.getObjectItem(execObj,"@S");
if (polledValue && outValue->type == aJson_Int) polledValue->valueint=Value; //to pevent suppressing to change back to previously polled value if this occurs before next polling
} }
} }
} }
@@ -663,7 +694,7 @@ else
} }
templateParamObj=templateParamObj->next; templateParamObj=templateParamObj->next;
} }
if (!suffixFinded) errorSerial<<F("No template for ")<<subItem<<F(" or suffix ")<<suffixCode<<endl; if (!suffixFinded) errorSerial<<F("MBUS: No template for ")<<subItem<<F(" or suffix ")<<suffixCode<<endl;
} }
return res; return res;
} }

View File

@@ -14,6 +14,7 @@ bool out_pid::getConfig()
double kI=0.0; double kI=0.0;
double kD=0.0; double kD=0.0;
int direction = DIRECT; int direction = DIRECT;
bool limits = false;
// Retrieve and store // Retrieve and store
if (!store || !item || !item->itemArg || (item->itemArg->type != aJson_Array) || aJson.getArraySize(item->itemArg)<1) if (!store || !item || !item->itemArg || (item->itemArg->type != aJson_Array) || aJson.getArraySize(item->itemArg)<1)
@@ -28,8 +29,8 @@ bool out_pid::getConfig()
errorSerial<<F("Invalid PID param array.")<<endl; errorSerial<<F("Invalid PID param array.")<<endl;
return false; return false;
} }
double outMin=0.; //UNUSED double outMin=0.;
double outMax=255.;//UNUSED double outMax=255.;
float dT=5.; float dT=5.;
uint32_t alarmTO=PERIOD_THERMOSTAT_FAILED; uint32_t alarmTO=PERIOD_THERMOSTAT_FAILED;
@@ -37,13 +38,13 @@ bool out_pid::getConfig()
switch (aJson.getArraySize(kPIDObj)) switch (aJson.getArraySize(kPIDObj))
{ case 8: //kP,kI,kD,dT, alarmTO, alarmVal, outMin, outMax { case 8: //kP,kI,kD,dT, alarmTO, alarmVal, outMin, outMax
param = aJson.getArrayItem(kPIDObj, 7); param = aJson.getArrayItem(kPIDObj, 7);
if (param->type == aJson_Float) outMax=param->valuefloat; if (param->type == aJson_Float) {outMax=param->valuefloat;limits=true;}
else if (param->type == aJson_Int) outMax=param->valueint; else if (param->type == aJson_Int) {outMax=param->valueint;limits=true;}
case 7: //kP,kI,kD,dT alarmTO, alarmVal, outMin case 7: //kP,kI,kD,dT alarmTO, alarmVal, outMin
param = aJson.getArrayItem(kPIDObj, 6); param = aJson.getArrayItem(kPIDObj, 6);
if (param->type == aJson_Float) outMin=param->valuefloat; if (param->type == aJson_Float) {outMin=param->valuefloat;limits=true;}
else if (param->type == aJson_Int) outMin=param->valueint; else if (param->type == aJson_Int) {outMin=param->valueint;limits=true;}
case 6: //kP,kI,kD,dT, alarmTO, alarmVal case 6: //kP,kI,kD,dT, alarmTO, alarmVal
case 5: //kP,kI,kD,dT, alarmTO case 5: //kP,kI,kD,dT, alarmTO
@@ -99,7 +100,7 @@ bool out_pid::getConfig()
{store->pid= new PID (&store->input, &store->output, &store->setpoint, kP, kI, kD, direction); {store->pid= new PID (&store->input, &store->output, &store->setpoint, kP, kI, kD, direction);
if (!store->pid) return false; if (!store->pid) return false;
store->pid->SetMode(AUTOMATIC); store->pid->SetMode(AUTOMATIC);
//store->pid->SetOutputLimits(outMin,outMax); if (limits) store->pid->SetOutputLimits(outMin,outMax);
store->pid->SetSampleTime(dT*1000.0); store->pid->SetSampleTime(dT*1000.0);
return true;} return true;}
else errorSerial<<F("PID already initialized")<<endl; else errorSerial<<F("PID already initialized")<<endl;
@@ -213,16 +214,17 @@ int out_pid::getAlarmVal()
aJsonObject * param; aJsonObject * param;
switch (aJson.getArraySize(kPIDObj)) switch (aJson.getArraySize(kPIDObj))
{ {
case 7: //kP,kI,kD, alarmTO, alarmVal, outMin, outMax case 8: //kP,kI,kD,dT, alarmTO, alarmVal, outMin, outMax
case 6: //kP,kI,kD, alarmTO, alarmVal, outMin case 7: //kP,kI,kD,dT, alarmTO, alarmVal, outMin
case 5: //kP,kI,kD, alarmTO, alarmVal case 6: //kP,kI,kD,dT,alarmTO, alarmVal
param = aJson.getArrayItem(kPIDObj, 4); param = aJson.getArrayItem(kPIDObj, 5);
alarmValDefined=true; alarmValDefined=true;
if (param->type == aJson_Float) outAlarm=param->valuefloat; if (param->type == aJson_Float) outAlarm=param->valuefloat;
else if (param->type == aJson_Int) outAlarm=param->valueint; else if (param->type == aJson_Int) outAlarm=param->valueint;
else alarmValDefined=false; else alarmValDefined=false;
case 4: //kP,kI,kD, alarmTO case 5: //kP,kI,kD,dT, alarmTO
case 4: //kP,kI,kD,dT
case 3: //kP,kI,kD case 3: //kP,kI,kD
case 2: //kP,kI case 2: //kP,kI
case 1: //kP case 1: //kP
@@ -234,7 +236,7 @@ int out_pid::getAlarmVal()
{ {
if (!alarmValDefined) outAlarm = 0.; if (!alarmValDefined) outAlarm = 0.;
} }
else if (!alarmValDefined) outAlarm = .255; else if (!alarmValDefined) outAlarm = 255.;
} }
} }
return outAlarm; return outAlarm;
@@ -339,12 +341,14 @@ case S_CMD:
return 1; return 1;
case CMD_ENABLE: case CMD_ENABLE:
item->setCmd(CMD_ENABLE); item->setCmd(CMD_ENABLE);
item->SendStatus(SEND_COMMAND); item->SendStatus(SEND_COMMAND);
//executeCommand(oCmd,-1,value);
return 1; return 1;
case CMD_DISABLE: case CMD_DISABLE:
item->setCmd(CMD_DISABLE); item->setCmd(CMD_DISABLE);
item->SendStatus(SEND_COMMAND); item->SendStatus(SEND_COMMAND);
//executeCommand(oCmd,-1,value);
return 1; return 1;
/* /*
case CMD_OFF: case CMD_OFF:

View File

@@ -9,7 +9,7 @@
#ifndef MAX_JSON_CONF_SIZE #ifndef MAX_JSON_CONF_SIZE
#if defined(__SAM3X8E__) #if defined(__SAM3X8E__)
#define MAX_JSON_CONF_SIZE 24000 #define MAX_JSON_CONF_SIZE 65535
#elif defined(ARDUINO_ARCH_AVR) #elif defined(ARDUINO_ARCH_AVR)
#define MAX_JSON_CONF_SIZE 4096 #define MAX_JSON_CONF_SIZE 4096
#elif defined(ARDUINO_ARCH_ESP32) #elif defined(ARDUINO_ARCH_ESP32)

View File

@@ -124,9 +124,14 @@ itemCmd getNumber(char **chan) {
long fractnumbers = 0; long fractnumbers = 0;
short fractlen = 0; short fractlen = 0;
short intlen = 0; short intlen = 0;
bool negative = false;
char * intptr = * chan; char * intptr = * chan;
if (*intptr == '-') intptr ++; if (*intptr == '-')
{
negative=true;
intptr ++;
}
while (isDigit(*(intptr+intlen))) intlen++; while (isDigit(*(intptr+intlen))) intlen++;
char * fractptr = strchr(*chan,'.'); char * fractptr = strchr(*chan,'.');
@@ -146,7 +151,7 @@ itemCmd getNumber(char **chan) {
else if (fractlen<=TENS_FRACT_LEN && intlen+TENS_FRACT_LEN<=9) else if (fractlen<=TENS_FRACT_LEN && intlen+TENS_FRACT_LEN<=9)
{ {
long intpart = atol(*chan); long intpart = atol(*chan);
val.Tens_raw(intpart*TENS_BASE+((intpart>=0)?fractnumbers:-fractnumbers)); val.Tens_raw(intpart*TENS_BASE+((negative)?-fractnumbers:fractnumbers));
} }
else else
val.Float(atof(*chan)); val.Float(atof(*chan));
@@ -243,7 +248,7 @@ void parseBytes(const char *str, char separator, byte *bytes, int maxBytes, int
} }
void printFloatValueToStr(float value, char *valstr) { void printFloatValueToStr(char *valstr, float value) {
#if defined(ESP8266) || defined(ARDUINO_ARCH_ESP32) #if defined(ESP8266) || defined(ARDUINO_ARCH_ESP32)
sprintf(valstr, "%2.1f", value); sprintf(valstr, "%2.1f", value);
#endif #endif
@@ -499,6 +504,8 @@ return buf;
void printUlongValueToStr(char *valstr, unsigned long value) { void printUlongValueToStr(char *valstr, unsigned long value) {
ultoa(value,valstr,10);
/*
char buf[11]; char buf[11];
int i=0; int i=0;
for(;value>0;i++){ for(;value>0;i++){
@@ -510,7 +517,7 @@ void printUlongValueToStr(char *valstr, unsigned long value) {
for(int n=0;n<=i;n++){ for(int n=0;n<=i;n++){
valstr[n]=buf[i-n-1]; valstr[n]=buf[i-n-1];
} }
valstr[i]='\0'; valstr[i]='\0';*/
} }
@@ -771,7 +778,7 @@ const serial_st serialModes_P[] PROGMEM =
#define serialModesNum sizeof(serialModes_P)/sizeof(serial_st) #define serialModesNum sizeof(serialModes_P)/sizeof(serial_st)
serialParamType str2SerialParam(char * str) serialParamType str2SerialParam(char * str)
{ debugSerial<<str<<F(" =>"); { //debugSerial<<str<<F(" =>");
for(uint8_t i=0; i<serialModesNum && str;i++) for(uint8_t i=0; i<serialModesNum && str;i++)
if (strcmp_P(str, serialModes_P[i].verb) == 0) if (strcmp_P(str, serialModes_P[i].verb) == 0)
{ {
@@ -782,7 +789,7 @@ serialParamType str2SerialParam(char * str)
else else
return pgm_read_word_near(&serialModes_P[i].mode); return pgm_read_word_near(&serialModes_P[i].mode);
} }
debugSerial<< F("Default serial mode N81 used"); debugSerial<< F("Default serial mode N81 used")<<endl;
return static_cast<serialParamType> (SERIAL_8N1); return static_cast<serialParamType> (SERIAL_8N1);
} }

View File

@@ -58,7 +58,7 @@ itemCmd getNumber(char ** chan);
unsigned long freeRam (); unsigned long freeRam ();
void parseBytes(const char* str, char separator, byte* bytes, int maxBytes, int base); void parseBytes(const char* str, char separator, byte* bytes, int maxBytes, int base);
int log(const char *str, ...); int log(const char *str, ...);
void printFloatValueToStr(float value, char *valstr); void printFloatValueToStr(char *valstr, float value);
void ReadUniqueID( uint32_t * pdwUniqueID ); void ReadUniqueID( uint32_t * pdwUniqueID );
int _inet_aton(const char* aIPAddrString, IPAddress& aResult); int _inet_aton(const char* aIPAddrString, IPAddress& aResult);
char *_inet_ntoa_r(IPAddress addr, char *buf, int buflen); char *_inet_ntoa_r(IPAddress addr, char *buf, int buflen);