MBUS refactoring,

AC Haier tolerance for comm errors(CRC check),
MERCURY - not blocking MBUS if failed (delay added if login fail)
Kernel fixes (flags, Locks)
Multivent to multichannel virtual AC converted (interim)
PID library forked and changed
This commit is contained in:
2025-01-22 02:18:25 +03:00
parent 891b029501
commit 6019aa41bb
19 changed files with 702 additions and 222 deletions

View File

@@ -3,6 +3,9 @@
#include "item.h" #include "item.h"
#include "abstractout.h" #include "abstractout.h"
#include "itemCmd.h" #include "itemCmd.h"
#include "Arduino.h"
#include "textconst.h"
int abstractOut::isActive() int abstractOut::isActive()
{itemCmd st; {itemCmd st;
@@ -37,4 +40,39 @@ int abstractOut::Status()
void abstractOut::setStatus(uint8_t status) void abstractOut::setStatus(uint8_t status)
{ {
if (item && item->itemArr) item->itemArr->subtype = status & 0xF; if (item && item->itemArr) item->itemArr->subtype = status & 0xF;
}
int abstractOut::pubAction(bool state)
{
char subtopic[10]="/";
char val[10];
strcat_P(subtopic,action_P);
short cmd=item->getCmd();
if (state)
switch(cmd)
{
case CMD_COOL:
strcpy_P(val,cooling_P);
break;
//case CMD_AUTO:
//case CMD_HEAT:
//case CMD_ON:
//
// break;
case CMD_DRY:
strcpy_P(val,drying_P);
break;
case CMD_FAN:
strcpy_P(val,fan_P);
break;
default:
strcpy_P(val,heating_P);
}
else //turned off
if (cmd==CMD_OFF) strcpy_P(val,off_P);
else strcpy_P(val,idle_P);
return publishTopic(item->itemArr->name,val,subtopic);
} }

View File

@@ -16,7 +16,9 @@ public:
// virtual int getDefaultStorageType(){return 0;} /// Remove?? Now getChanType used instead // virtual int getDefaultStorageType(){return 0;} /// Remove?? Now getChanType used instead
virtual int Status() override; virtual int Status() override;
virtual void setStatus(uint8_t status) override; virtual void setStatus(uint8_t status) override;
int Setup() override; int Setup() override;
protected: protected:
int pubAction(bool state);
Item * item; Item * item;
}; };

View File

@@ -953,11 +953,11 @@ int Item::scheduleOppositeCommand(itemCmd cmd,bool isActiveNow,bool authorized)
nextCmd.Cmd(CMD_ENABLE); nextCmd.Cmd(CMD_ENABLE);
break; break;
case CMD_FREEZE: case CMD_FREEZE:
if (getFlag(FLAG_FREEZED) && !isScheduled()) return 0; if ((getFlag(FLAG_FREEZED) == FLAG_FREEZED) && !isScheduled()) return 0;
nextCmd.Cmd(CMD_UNFREEZE); nextCmd.Cmd(CMD_UNFREEZE);
break; break;
case CMD_UNFREEZE: case CMD_UNFREEZE:
if (!getFlag(FLAG_FREEZED) && !isScheduled()) return 0; if (!(getFlag(FLAG_FREEZED) == FLAG_FREEZED) && !isScheduled()) return 0;
nextCmd.Cmd(CMD_FREEZE); nextCmd.Cmd(CMD_FREEZE);
break; break;
case CMD_HALT: case CMD_HALT:
@@ -1014,6 +1014,7 @@ int Item::scheduleCommand(itemCmd cmd,bool authorized)
// -1 system error // -1 system error
// -4 invalid argument // -4 invalid argument
// -5 unauthorized // -5 unauthorized
// -6 disabled
int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized) int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized)
{ {
int fr = freeRam(); int fr = freeRam();
@@ -1050,6 +1051,31 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized
//debugSerial<<endl; //debugSerial<<endl;
if (subItem && subItem[0] == '$') {debugSerial<<F("Skipped homie stuff")<<endl;return -4; } if (subItem && subItem[0] == '$') {debugSerial<<F("Skipped homie stuff")<<endl;return -4; }
if (!itemArr) return -1; if (!itemArr) return -1;
if (!suffixCode && cmd.isCommand()) suffixCode=S_CMD;
switch (suffixCode)
{
case S_CMD:
case S_CTRL:
case S_DELAYED:
if (cmd.isCommand() && getFlag(FLAG_LOCKED_CMD) && cmd.getCmd()!=CMD_UNFREEZE)
{
errorSerial<<F("CTRL: channel frozen")<<endl;
return -6;
}
break;
case S_VAL:
break;
default:
if (cmd.isValue() && getFlag(FLAG_LOCKED_SET))
{
errorSerial<<F("CTRL: channel frozen")<<endl;
return -6;
}
}
/// DELAYED COMMANDS processing /// DELAYED COMMANDS processing
if (suffixCode == S_DELAYED) if (suffixCode == S_DELAYED)
@@ -1062,7 +1088,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized
bool scale100 = false; bool scale100 = false;
bool invalidArgument = false; bool invalidArgument = false;
int res = -1; int res = -1;
uint16_t status2Send = 0; long status2Send = 0;
uint8_t command2Set = 0; uint8_t command2Set = 0;
itemCmd originalCmd = cmd; itemCmd originalCmd = cmd;
@@ -1565,7 +1591,14 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized
} // NO GROUP } // NO GROUP
if (invalidArgument) return -4; if (invalidArgument) return -4;
if ((!driver || driver->isAllowed(cmd)) && (!getFlag(FLAG_FREEZED))) if ((!driver || driver->isAllowed(cmd))
// && (
// //!getFlag(FLAG_FREEZED)
// (suffixCode == S_VAL)
// || (cmd.isCommand() && !getFlag(FLAG_LOCKED_CMD))
// || (cmd.isValue() && !getFlag(FLAG_LOCKED_SET))
// )
)
{ {
if (driver) //New style modular code if (driver) //New style modular code
@@ -1714,7 +1747,7 @@ if ((!driver || driver->isAllowed(cmd)) && (!getFlag(FLAG_FREEZED)))
} //alowed cmd } //alowed cmd
else else
{ {
errorSerial<<F("CTRL: Command blocked by driver or channel frozen")<<endl; errorSerial<<F("CTRL: Command blocked by driver")<<endl;
if ((status2Send & FLAG_FLAGS) && operation) if ((status2Send & FLAG_FLAGS) && operation)
{ {
cmd.saveItem(this,FLAG_FLAGS); cmd.saveItem(this,FLAG_FLAGS);
@@ -1888,7 +1921,7 @@ void Item::sendDelayedStatus()
} }
int Item::SendStatus(int sendFlags, char * subItem) { int Item::SendStatus(long sendFlags, char * subItem) {
if (sendFlags & FLAG_SEND_IMMEDIATE) sendFlags &= ~ (FLAG_SEND_IMMEDIATE | FLAG_SEND_DEFFERED); if (sendFlags & FLAG_SEND_IMMEDIATE) sendFlags &= ~ (FLAG_SEND_IMMEDIATE | FLAG_SEND_DEFFERED);
if ((sendFlags & FLAG_SEND_DEFFERED) || freeRam()<150 || (!isNotRetainingStatus() )) { if ((sendFlags & FLAG_SEND_DEFFERED) || freeRam()<150 || (!isNotRetainingStatus() )) {
setFlag(sendFlags & (FLAG_COMMAND | FLAG_PARAMETERS | FLAG_FLAGS)); setFlag(sendFlags & (FLAG_COMMAND | FLAG_PARAMETERS | FLAG_FLAGS));
@@ -1904,13 +1937,13 @@ int Item::SendStatus(int sendFlags, char * subItem) {
} }
} }
int Item::SendStatusImmediate(itemCmd st, int sendFlags, char * subItem) { int Item::SendStatusImmediate(itemCmd st, long sendFlags, char * subItem) {
{ {
char addrstr[64]; char addrstr[64];
char valstr[20] = ""; char valstr[20] = "";
char cmdstr[9] = ""; char cmdstr[9] = "";
debugSerial<<"SENDSTATUS: "<<subItem; debugSerial<<"SENDSTATUS: "<<subItem<<" ";
st.debugOut(); st.debugOut();
#ifdef CANDRV #ifdef CANDRV
@@ -2007,7 +2040,15 @@ int Item::SendStatus(int sendFlags, char * subItem) {
if (sendFlags & FLAG_SEND_DELAYED) if (sendFlags & FLAG_SEND_DELAYED)
strncat_P(addrstr, suffix_P[S_DELAYED], sizeof(addrstr)-1); strncat_P(addrstr, suffix_P[S_DELAYED], sizeof(addrstr)-1);
else strncat_P(addrstr, suffix_P[S_SET], sizeof(addrstr)-1); else
switch (st.getSuffix())
{
case S_FAN:
strncat_P(addrstr, suffix_P[S_FAN], sizeof(addrstr)-1);
break;
default:
strncat_P(addrstr, suffix_P[S_SET], sizeof(addrstr)-1);
}
// Preparing parameters payload ////////// // Preparing parameters payload //////////
@@ -2102,7 +2143,7 @@ int Item::SendStatus(int sendFlags, char * subItem) {
if (getFlag(FLAG_DISABLED)) if (getFlag(FLAG_DISABLED))
strcpy_P(cmdstr, DISABLE_P); strcpy_P(cmdstr, DISABLE_P);
else if (getFlag(FLAG_FREEZED)) else if (getFlag(FLAG_FREEZED) == FLAG_FREEZED)
strcpy_P(cmdstr, FREEZE_P); strcpy_P(cmdstr, FREEZE_P);
else strcpy_P(cmdstr, ENABLE_P); else strcpy_P(cmdstr, ENABLE_P);

View File

@@ -138,8 +138,8 @@ class Item
void setFloatVal(float par); void setFloatVal(float par);
void setSubtype(uint8_t par); void setSubtype(uint8_t par);
int Poll(int cause); int Poll(int cause);
int SendStatus(int sendFlags, char * subItem=NULL); int SendStatus(long sendFlags, char * subItem=NULL);
int SendStatusImmediate(itemCmd st, int sendFlags, char * subItem=NULL); int SendStatusImmediate(itemCmd st, long sendFlags, char * subItem=NULL);
int isActive(); int isActive();
int getChanType(); int getChanType();
inline int On (){return Ctrl(itemCmd(ST_VOID,CMD_ON));}; inline int On (){return Ctrl(itemCmd(ST_VOID,CMD_ON));};

View File

@@ -1211,7 +1211,7 @@ bool itemCmd::saveItem(Item * item, uint16_t optionsFlag)
case CMD_ENABLE: case CMD_ENABLE:
item->clearFlag(FLAG_DISABLED); item->clearFlag(FLAG_DISABLED);
item->clearFlag(FLAG_FREEZED); //? item->clearFlag(FLAG_FREEZED); //?
break; break;
case CMD_FREEZE: case CMD_FREEZE:
item->setFlag(FLAG_FREEZED); item->setFlag(FLAG_FREEZED);

View File

@@ -104,21 +104,40 @@ const ch_type ch_type_P[] PROGMEM =
#define CMD_JSON -2 #define CMD_JSON -2
//FLAGS //FLAGS
#define FLAG_SEND_IMMEDIATE 0x1UL
#define FLAG_COMMAND 0x100UL
#define FLAG_PARAMETERS 0x200UL
#define FLAG_FLAGS 0x400UL
#define FLAG_SEND_RETRY 0x800UL
#define FLAG_SEND_DEFFERED 0x1000UL
#define FLAG_SEND_DELAYED 0x2000UL
#define FLAG_ACTION_NEEDED 0x4000UL
#define FLAG_ACTION_IN_PROCESS 0x8000UL
#define FLAG_DISABLED 0x10000UL //#define FLAG_COMMAND 0x100UL
#define FLAG_FREEZED 0x20000UL //#define FLAG_PARAMETERS 0x200UL
//#define FLAG_FLAGS 0x400UL
//#define FLAG_SEND_RETRY 0x800UL
//#define FLAG_SEND_DEFFERED 0x1000UL
//#define FLAG_SEND_DELAYED 0x2000UL
//#define FLAG_ACTION_NEEDED 0x4000UL
//#define FLAG_ACTION_IN_PROCESS 0x8000UL
//#define FLAG_DISABLED 0x10000UL
//#define FLAG_FREEZED 0x20000UL
//#define FLAG_HALTED 0x40000UL
//#define FLAG_XON 0x80000UL
#define FLAG_DISABLED 0x100UL
#define FLAG_LOCKED_CMD 0x200UL
#define FLAG_LOCKED_SET 0x400UL
#define FLAG_FREEZED 0x600UL
#define FLAG_SEND_DEFFERED 0x800UL
#define FLAG_COMMAND 0x1000UL
#define FLAG_PARAMETERS 0x2000UL
#define FLAG_FLAGS 0x4000UL
#define FLAG_SEND_RETRY 0x8000UL
#define FLAG_ACTION_NEEDED 0x10000UL
#define FLAG_ACTION_IN_PROCESS 0x20000UL
#define FLAG_HALTED 0x40000UL #define FLAG_HALTED 0x40000UL
#define FLAG_XON 0x80000UL #define FLAG_XON 0x80000UL
#define FLAG_SEND_DELAYED 0x100000UL
#define FLAG_SEND_IMMEDIATE 0x1UL
#define FLAG_NOT_SEND_CAN 0x2UL #define FLAG_NOT_SEND_CAN 0x2UL
int txt2cmd (char * payload); int txt2cmd (char * payload);

View File

@@ -551,28 +551,6 @@ void printMACAddress() {
char* getStringFromConfig(aJsonObject * a, int i)
{
aJsonObject * element = NULL;
if (!a) return NULL;
if (a->type == aJson_Array)
element = aJson.getArrayItem(a, i);
// TODO - human readable JSON objects as alias
if (element && element->type == aJson_String) return element->valuestring;
return NULL;
}
char* getStringFromConfig(aJsonObject * a, char * name)
{
aJsonObject * element = NULL;
if (!a) return NULL;
if (a->type == aJson_Object)
element = aJson.getObjectItem(a, name);
if (element && element->type == aJson_String) return element->valuestring;
return NULL;
}
#ifdef OTA #ifdef OTA
const char defaultPassword[] PROGMEM = QUOTE(DEFAULT_OTA_PASSWORD); const char defaultPassword[] PROGMEM = QUOTE(DEFAULT_OTA_PASSWORD);
void setupOTA(void) void setupOTA(void)
@@ -608,7 +586,7 @@ void setupSyslog()
udpSyslogArr = aJson.getObjectItem(root, "syslog"); udpSyslogArr = aJson.getObjectItem(root, "syslog");
if (udpSyslogArr && (n = aJson.getArraySize(udpSyslogArr))) { if (udpSyslogArr && (n = aJson.getArraySize(udpSyslogArr))) {
char *syslogServer = getStringFromConfig(udpSyslogArr, 0); char *syslogServer = getStringFromJson(udpSyslogArr, 0);
if (n>1) syslogPort = aJson.getArrayItem(udpSyslogArr, 1)->valueint; if (n>1) syslogPort = aJson.getArrayItem(udpSyslogArr, 1)->valueint;
@@ -619,7 +597,7 @@ void setupSyslog()
udpSyslog.server(syslogServer, syslogPort); udpSyslog.server(syslogServer, syslogPort);
udpSyslog.deviceHostname(syslogDeviceHostname); udpSyslog.deviceHostname(syslogDeviceHostname);
if (mqttArr) deviceName = getStringFromConfig(mqttArr, 0); if (mqttArr) deviceName = getStringFromJson(mqttArr, 0);
if (deviceName) udpSyslog.appName(deviceName); if (deviceName) udpSyslog.appName(deviceName);
else udpSyslog.appName(lighthub); else udpSyslog.appName(lighthub);
udpSyslog.defaultPriority(LOG_KERN); udpSyslog.defaultPriority(LOG_KERN);
@@ -1119,7 +1097,7 @@ void ip_ready_config_loaded_connecting_to_broker() {
} }
deviceName = getStringFromConfig(mqttArr, 0); deviceName = getStringFromJson(mqttArr, 0);
if (!deviceName) deviceName = (char*) lighthub; if (!deviceName) deviceName = (char*) lighthub;
infoSerial<<F("Device Name:")<<deviceName<<endl; infoSerial<<F("Device Name:")<<deviceName<<endl;
@@ -1132,13 +1110,13 @@ void ip_ready_config_loaded_connecting_to_broker() {
//debugSerial<<F("N:")<<n<<endl; //debugSerial<<F("N:")<<n<<endl;
char *servername = getStringFromConfig(mqttArr, 1); char *servername = getStringFromJson(mqttArr, 1);
if (n >= 3) port = aJson.getArrayItem(mqttArr, 2)->valueint; if (n >= 3) port = aJson.getArrayItem(mqttArr, 2)->valueint;
if (n >= 4) user = getStringFromConfig(mqttArr, 3); if (n >= 4) user = getStringFromJson(mqttArr, 3);
//if (!loadFlash(OFFSET_MQTT_PWD, passwordBuf, sizeof(passwordBuf)) && (n >= 5)) //if (!loadFlash(OFFSET_MQTT_PWD, passwordBuf, sizeof(passwordBuf)) && (n >= 5))
if (!sysConf.getMQTTpwd(passwordBuf, sizeof(passwordBuf)) && (n >= 5)) if (!sysConf.getMQTTpwd(passwordBuf, sizeof(passwordBuf)) && (n >= 5))
{ {
password = getStringFromConfig(mqttArr, 4); password = getStringFromJson(mqttArr, 4);
infoSerial<<F("Using MQTT password from config")<<endl; infoSerial<<F("Using MQTT password from config")<<endl;
} }

View File

@@ -455,12 +455,15 @@ debugSerial<<F("AC: ")<<portNum<<F(" >> ");
debugSerial.print(store->data[i], HEX); debugSerial.print(store->data[i], HEX);
} }
} }
if (store->data[36] == getCRC(store->data,36))
if (store->data[36] != store->inCheck){ {
store->inCheck = store->data[36]; if (store->data[36] != store->inCheck){
InsertData(store->data, 37); store->inCheck = store->data[36];
debugSerial<<F("AC: OK"); InsertData(store->data, 37);
debugSerial<<F("AC: OK");
}
else debugSerial<<F("AC: Bad CRC");
} }
debugSerial.println(); debugSerial.println();

View File

@@ -346,6 +346,7 @@ if (!getConfig()) return 0;
break; break;
default: default:
store->timestamp = millisNZ();
setStatus(CST_INITIALIZED); setStatus(CST_INITIALIZED);
} }

View File

@@ -70,6 +70,47 @@ int str2regSize(char * str)
return (int) PAR_I16; return (int) PAR_I16;
} }
//TODO irs etc
char * getParamNameByReg(aJsonObject * parameters, int regnum)
{
if (!parameters) return NULL;
aJsonObject * i = parameters->child;
while (i)
{
aJsonObject * regObj = aJson.getObjectItem(i, "reg");
if (regObj && regObj->type == aJson_Int && regObj->valueint == regnum)
{
debugSerial<<F("MBUS: ")<<i->name<<F(" added by num ")<<regnum<<endl;
return i->name;
}
i=i->next;
}
return NULL;
}
bool haveAction(aJsonObject * execObj)
{
aJsonObject * j = execObj->child;
switch (execObj->type)
{
case aJson_Object:
while (j)
{
if (j->name && *j->name && (*j->name != '@')) return true;
j=j->next;
}
break;
case aJson_Array:
while (j)
{
if (haveAction(j)) return true;
j=j->next;
}
}
return false;
}
bool out_Modbus::getConfig() bool out_Modbus::getConfig()
{ {
// Retrieve and store template values from global modbus settings // Retrieve and store template values from global modbus settings
@@ -124,11 +165,112 @@ bool out_Modbus::getConfig()
else {store->pollingRegisters=NULL;store->pollingInterval = 1000;store->pollingIrs=NULL;} else {store->pollingRegisters=NULL;store->pollingInterval = 1000;store->pollingIrs=NULL;}
store->parameters=aJson.getObjectItem(templateObj, "par"); store->parameters=aJson.getObjectItem(templateObj, "par");
// initializing @S where needed
if (store->parameters)
{
// Creating for parameters where prefetch required
debugSerial<<F("Adding prefetch regs:")<<endl;
aJsonObject * i = store->parameters->child;
while (i)
{
aJsonObject * prefetchObj = aJson.getObjectItem(i, "prefetch");
if (prefetchObj && prefetchObj->type == aJson_Boolean && prefetchObj->valuebool)
{
createLastMeasured(i->name);
}
i=i->next;
}
debugSerial<<F("Adding referred regs:")<<endl;
i = store->parameters->child;
// Creating for parameters used in references from another parameters
while (i)
{
aJsonObject * mapObj = aJson.getObjectItem(i, "map");
if (mapObj)
{
aJsonObject * defObj = aJson.getObjectItem(mapObj, "def");
if (defObj && defObj->type == aJson_Int)
{
createLastMeasured(getParamNameByReg(store->parameters,defObj->valueint));
}
if (defObj && defObj->type == aJson_String)
{
createLastMeasured(defObj->valuestring);
}
}
i=i->next;
}
debugSerial<<F("Adding regs with actions:")<<endl;
// Check - if action configured for object and create
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
if (itemParametersObj)
{
i = itemParametersObj->child;
while (i)
{
if (haveAction(i)) createLastMeasured(i);
i=i->next;
}
}
}
return true; return true;
//store->addr=item->getArg(0); //store->addr=item->getArg(0);
} }
int out_Modbus::createLastMeasured(char * name)
{
if (!name) return false;
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
return createLastMeasured(aJson.getObjectItem(itemParametersObj,name));
}
int out_Modbus::createLastMeasured(aJsonObject * execObj)
{
if (!execObj) return false;
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array)
{
markObj = execObj->child;
//storeLastValue = true;
}
if (!markObj) return false;
aJsonObject *lastMeasured = aJson.getObjectItem(markObj,"@S");
if (lastMeasured) return false;
debugSerial<<F("MBUS: Add @S: ")<<execObj->name<<endl;
aJson.addNumberToObject(markObj, "@S", (long) 0);
lastMeasured = aJson.getObjectItem(markObj,"@S");
if (!lastMeasured) return false;
lastMeasured->subtype |= MB_VALUE_OUTDATED;
return true;
}
aJsonObject * out_Modbus::getLastMeasured(char * name)
{
if (!name) return NULL;
aJsonObject * itemParametersObj = aJson.getArrayItem(item->itemArg, 2);
return getLastMeasured (aJson.getObjectItem(itemParametersObj,name));
}
aJsonObject * out_Modbus::getLastMeasured(aJsonObject * execObj)
{
if (!execObj) return NULL;
if (execObj->type == aJson_Array) execObj = execObj->child;
aJsonObject *lastMeasured = aJson.getObjectItem(execObj,"@S");
if (lastMeasured && lastMeasured->type == aJson_Int) return lastMeasured;
return NULL;
}
int out_Modbus::Setup() int out_Modbus::Setup()
{ {
abstractOut::Setup(); abstractOut::Setup();
@@ -330,12 +472,9 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
if (itemParametersObj && itemParametersObj->type ==aJson_Object) if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{ {
//Searching item param for nested mapping //Searching item param for nested mapping
aJsonObject *itemParObj = aJson.getObjectItem(itemParametersObj,defMappingObj->valuestring); //Retrive previous data
if (itemParObj) aJsonObject *lastMeasured = getLastMeasured(defMappingObj->valuestring);
{ if (lastMeasured)
//Retrive previous data
aJsonObject *lastMeasured = aJson.getObjectItem(itemParObj,"@S");
if (lastMeasured && lastMeasured->type ==aJson_Int)
{ {
traceSerial<<F("LastKnown value: ")<<lastMeasured->valueint<<endl; traceSerial<<F("LastKnown value: ")<<lastMeasured->valueint<<endl;
//Searching template param for nested mapping //Searching template param for nested mapping
@@ -384,8 +523,7 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
} }
} }
} } //nested have lastMeasured
}
} }
break; break;
} }
@@ -411,52 +549,31 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramObj->name); aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramObj->name);
if (execObj) if (execObj)
{ {
// if (!doExecution || haveAction(execObj)) //if no action in execObj - do not save last value to avoid confuse further recurrent check
bool storeLastValue = true; // {
if (doExecution)
{
storeLastValue=false;
// Check - if no action configured for object - not need to store last value - let requrent process do it
aJsonObject * i = execObj->child;
while (i && !storeLastValue)
{
if (i->name && *i->name && (*i->name != '@')) storeLastValue = true;
i=i->next;
}
}
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array)
{
markObj = execObj->child;
storeLastValue = true;
}
if (storeLastValue)
{
//Retrive previous data //Retrive previous data
aJsonObject *lastMeasured = aJson.getObjectItem(markObj,"@S"); aJsonObject *lastMeasured = getLastMeasured(execObj);
if (lastMeasured) if (lastMeasured)
{ {
if (lastMeasured->type == aJson_Int)
{
if (lastMeasured->valueint == param) if (lastMeasured->valueint == param)
*submitParam=false; //supress repeating execution for same val {
//if recurrent call but value was readed before
if (!doExecution && !(lastMeasured->subtype & MB_VALUE_OUTDATED))
{
*submitParam=true; //never used
lastMeasured->subtype|=MB_VALUE_OUTDATED;
return mappedParam;
}
*submitParam=false; //supress repeating execution for same val
}
else else
{ {
lastMeasured->valueint=param; lastMeasured->valueint=param;
traceSerial<<"MBUS: Stored "<<param<<" to @S of "<<paramObj->name<<endl; traceSerial<<"MBUS: Stored "<<param<<" to @S of "<<paramObj->name<<endl;
lastMeasured->subtype&=~MB_VALUE_OUTDATED; lastMeasured->subtype&=~MB_VALUE_OUTDATED;
} }
}
} }
else //No container to store value yet // }
{
debugSerial<<F("MBUS: Add @S: ")<<paramObj->name<<endl;
aJson.addNumberToObject(markObj, "@S", (long) param);
}
}
if (executeWithoutCheck) if (executeWithoutCheck)
{ {
@@ -474,6 +591,12 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
if (*submitParam && doExecution) if (*submitParam && doExecution)
{ {
// Compare with last submitted val (if @V NOT marked as NULL in config) // Compare with last submitted val (if @V NOT marked as NULL in config)
aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array)
{
markObj = execObj->child;
//storeLastValue = true;
}
aJsonObject *settedValue = aJson.getObjectItem(markObj,"@V"); aJsonObject *settedValue = aJson.getObjectItem(markObj,"@V");
if (settedValue && settedValue->type==aJson_Int && (settedValue->valueint == param)) if (settedValue && settedValue->type==aJson_Int && (settedValue->valueint == param))
{ {
@@ -491,14 +614,14 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
if (settedValue && !(execObj->subtype & MB_NEED_SEND)) if (settedValue && !(execObj->subtype & MB_NEED_SEND))
settedValue->valueint=param; settedValue->valueint=param;
} }
} } //to be executed
} } //ExecObj
} } //item Parameters
//if (submitRecurrentOut) *submitParam=true; //if requrrent check has submit smth - report it.
return mappedParam; return mappedParam;
} } //reg == regNum
paramObj=paramObj->next; paramObj=paramObj->next;
} } //while
return itemCmd(); return itemCmd();
} }
@@ -618,14 +741,14 @@ if (prefetchObj && (prefetchObj->type == aJson_Boolean) && prefetchObj->valueboo
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramName); aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramName);
if (execObj) if (execObj)
{ {
aJsonObject * markObj = execObj; //aJsonObject * markObj = execObj;
if (execObj->type == aJson_Array) markObj = execObj->child; //if (execObj->type == aJson_Array) markObj = execObj->child;
//Retrive previous data //Retrive previous data
lastMeasured = aJson.getObjectItem(markObj,"@S"); lastMeasured = getLastMeasured(execObj);// aJson.getObjectItem(markObj,"@S");
if (lastMeasured) if (lastMeasured)
{ {
if (lastMeasured->type == aJson_Int) //if (lastMeasured->type == aJson_Int)
{ // {
traceSerial<<F(" Last:")<<lastMeasured->valueint<< F(" Now:") << localBuffer<<endl; traceSerial<<F(" Last:")<<lastMeasured->valueint<< F(" Now:") << localBuffer<<endl;
if (lastMeasured->valueint != localBuffer) if (lastMeasured->valueint != localBuffer)
@@ -645,7 +768,7 @@ if (prefetchObj && (prefetchObj->type == aJson_Boolean) && prefetchObj->valueboo
debugSerial << F("MBUS:")<<paramName<< F(" val not changed. Continue")<<endl; debugSerial << F("MBUS:")<<paramName<< F(" val not changed. Continue")<<endl;
} }
} //}
} }
} }
} }

View File

@@ -49,5 +49,9 @@ protected:
void initLine(); void initLine();
int sendModbus(char * paramName, aJsonObject * outValue); int sendModbus(char * paramName, aJsonObject * outValue);
int sendItemCmd(aJsonObject *templateParamObj, itemCmd cmd); int sendItemCmd(aJsonObject *templateParamObj, itemCmd cmd);
int createLastMeasured(char * name);
int createLastMeasured(aJsonObject * execObj);
aJsonObject * getLastMeasured(char * name);
aJsonObject * getLastMeasured(aJsonObject * execObj);
}; };
#endif #endif

View File

@@ -7,6 +7,7 @@
#include "item.h" #include "item.h"
#include "main.h" #include "main.h"
#include "utils.h"
void out_Multivent::getConfig() void out_Multivent::getConfig()
@@ -14,6 +15,7 @@ void out_Multivent::getConfig()
gatesObj = NULL; gatesObj = NULL;
if (!item || !item->itemArg || item->itemArg->type != aJson_Object) return; if (!item || !item->itemArg || item->itemArg->type != aJson_Object) return;
gatesObj = item->itemArg; gatesObj = item->itemArg;
//acTemp=(float) item->getExt();
} }
int out_Multivent::Setup() int out_Multivent::Setup()
@@ -21,30 +23,81 @@ int out_Multivent::Setup()
abstractOut::Setup(); abstractOut::Setup();
//getConfig(); //getConfig();
//Expand Argument storage to 2
//for (int i = aJson.getArraySize(item->itemArg); i < 2; i++)
// aJson.addItemToArray(item->itemArg, aJson.createItem( (long int) 0));
//Allocate objects to store persistent data in config tree //Allocate objects to store persistent data in config tree
if (gatesObj /*&& aJson.getArraySize(item->itemArg)>=2*/) if (gatesObj)
{ {
aJsonObject * i = gatesObj->child; aJsonObject * i = gatesObj->child;
while (i) while (i)
{ {
if (i->name && *i->name) if (i->name && *i->name)
{ {
aJsonObject * setObj = aJson.getObjectItem(i, "set"); aJsonObject * fanObj = aJson.getObjectItem(i, "fan");
if (!setObj) aJson.addNumberToObject(i, "set", (long int) -1); if (!fanObj) {aJson.addNumberToObject(i, "fan", (long int) -1);fanObj = aJson.getObjectItem(i, "fan");}
aJsonObject * cmdObj = aJson.getObjectItem(i, "cmd"); aJsonObject * cmdObj = aJson.getObjectItem(i, "cmd");
if (!cmdObj) aJson.addNumberToObject(i, "cmd", (long int) -1); if (!cmdObj) {aJson.addNumberToObject(i, "cmd", (long int) -1);cmdObj = aJson.getObjectItem(i, "cmd");}
aJsonObject * outObj = aJson.getObjectItem(i, "out"); aJsonObject * outObj = aJson.getObjectItem(i, "out");
if (!outObj) aJson.addNumberToObject(i, "out", (long int) -1); if (!outObj) {aJson.addNumberToObject(i, "out", (long int) -1);outObj = aJson.getObjectItem(i, "out");}
aJsonObject * pidObj = aJson.getObjectItem(i, "pid");
if (pidObj && pidObj->type == aJson_Array && aJson.getArraySize(pidObj)>=3)
{
aJsonObject * setObj = aJson.getObjectItem(i, "set");
if (!setObj) {aJson.addNumberToObject(i, "set", (float) 20.1);setObj = aJson.getObjectItem(i, "set");}
else if (setObj->type != aJson_Float) {setObj->valuefloat = 20.0;setObj->type= aJson_Float;}
aJsonObject * valObj = aJson.getObjectItem(i, "val");
if (!valObj) {aJson.addNumberToObject(i, "val", (float) 20.1);valObj = aJson.getObjectItem(i, "val");}
else if (valObj->type != aJson_Float) {valObj->valuefloat = 20.0;valObj->type= aJson_Float;}
aJsonObject * poObj = aJson.getObjectItem(i, "po");
if (!poObj) {aJson.addNumberToObject(i, "po", (float) -1.1);poObj = aJson.getObjectItem(i, "po");}
else if (poObj->type != aJson_Float) {poObj->valuefloat = -2.0;valObj->type= aJson_Float;}
float kP = 1.0;
float kI = 0.0;
float kD = 0.0;
int direction = DIRECT;
aJsonObject * param = aJson.getArrayItem(pidObj, 0);
if (param->type == aJson_Float) kP=param->valuefloat;
else if (param->type == aJson_Int) kP=param->valueint;
if (kP<0)
{
kP=-kP;
direction=REVERSE;
}
param = aJson.getArrayItem(pidObj, 1);
if (param->type == aJson_Float) kI=param->valuefloat;
else if (param->type == aJson_Int) kI=param->valueint;
param = aJson.getArrayItem(pidObj, 2);
if (param->type == aJson_Float) kD=param->valuefloat;
else if (param->type == aJson_Int) kD=param->valueint;
float dT=5.0;
if (aJson.getArraySize(pidObj)==4)
{
param = aJson.getArrayItem(pidObj, 3);
if (param->type == aJson_Float) dT=param->valuefloat;
else if (param->type == aJson_Int) dT=param->valueint;
}
debugSerial << "VENT: X:" << (long int) &valObj->valuefloat << "-" << (long int)&poObj->valuefloat <<"="<< (long int)&setObj->valuefloat<<endl;
pidObj->valueint = (long int) new PID (&valObj->valuefloat, &poObj->valuefloat, &setObj->valuefloat, kP, kI, kD, direction);
debugSerial << "VENT: Y:" << (long int)((PID*) pidObj->valueint)->myInput << "-" << (long int)((PID*) pidObj->valueint)->myOutput <<"="<< (long int)((PID*) pidObj->valueint)->mySetpoint<<endl;
((PID*) pidObj->valueint)->SetMode (AUTOMATIC);
((PID*) pidObj->valueint)->SetSampleTime(dT*1000.0);
debugSerial << F ("VENT: PID P=")<<kP<<" I="<<kI<<" D="<<kD<< endl;
}
} }
i=i->next; i=i->next;
} }
debugSerial << F ("VENT: init")<< endl; debugSerial << F ("VENT: init")<< endl;
item->setExt(0);
setStatus(CST_INITIALIZED); setStatus(CST_INITIALIZED);
return 1; return 1;
} }
@@ -57,13 +110,87 @@ return 0;
int out_Multivent::Stop() int out_Multivent::Stop()
{ {
debugSerial << F ("VENT: De-Init") << endl; debugSerial << F ("VENT: De-Init") << endl;
if (gatesObj)
{
aJsonObject * i = gatesObj->child;
while (i)
{
if (i->name && *i->name)
{
aJsonObject * pidObj = aJson.getObjectItem(i, "pid");
if (pidObj && pidObj->valueint)
{
delete ((PID *) pidObj->valueint);
pidObj->valueint = 0;//NULL;
}
}
i=i->next;
}
}
setStatus(CST_UNKNOWN); setStatus(CST_UNKNOWN);
return 1; return 1;
} }
int out_Multivent::Poll(short cause) int out_Multivent::Poll(short cause)
{ {
return 0; if (cause == POLLING_SLOW && item->getExt() && isTimeOver(item->getExt(),millisNZ(),60000L))
{
item->setExt(0);
item->setCmd((isActive())?CMD_ON:CMD_OFF); // if AC temp unknown - change state to ON or OFF instead HEAT|COOL|FAN
}
if (gatesObj)
{
aJsonObject * i = gatesObj->child;
while (i)
{
if (i->name && *i->name)
{
aJsonObject * pidObj = aJson.getObjectItem(i, "pid");
if (pidObj && pidObj->valueint)
{
PID * p = (PID *) pidObj->valueint;
if (p->Compute())
{
aJsonObject * outObj = aJson.getObjectItem(i,"po");
if (outObj && outObj->type == aJson_Float)
{
debugSerial<<F("VENT: ")
<<item->itemArr->name<<"/"<<i->name
<<F(" in:")<<p->GetIn()<<F(" set:")<<p->GetSet()<<F(" out:")<<p->GetOut()
// <<F(" in:")<<getFloatFromJson(i,"val")<<(" set:")<<getFloatFromJson(i,"set")<<F(" out:")<<outObj->valuefloat
<<" P:"<<p->GetKp()<<" I:"<<p->GetKi()<<" D:"<<p->GetKd()<<((p->GetDirection())?" Rev ":" Dir ")<<((p->GetMode())?" A":" M");
debugSerial<<endl;
switch (item->getCmd())
{
case CMD_HEAT:
((PID *) pidObj->valueint)->SetControllerDirection(DIRECT);
debugSerial<<F("VENT: PID: ")<<item->itemArr->name<<"/"<<i->name<<F(" set DIRECT mode")<<endl;
Ctrl(itemCmd().Percents255(outObj->valuefloat).setSuffix(S_FAN),i->name);
break;
case CMD_COOL:
//case CMD_FAN: // if PIB using for vent
//case CMD_ON: // AC temp unknown - assuming that PID used for vent
((PID *) pidObj->valueint)->SetControllerDirection(REVERSE);
debugSerial<<F("VENT: PID: ")<<item->itemArr->name<<"/"<<i->name<<F(" set REVERSE mode")<<endl;
Ctrl(itemCmd().Percents255(outObj->valuefloat).setSuffix(S_FAN),i->name);
break;
// if FAN_ONLY (AC report room temp regularry) - not use internal PID - let be on external control via /fan
}
}
}
}
}
i=i->next;
}
}
return 1;
}; };
int out_Multivent::getChanType() int out_Multivent::getChanType()
@@ -79,6 +206,24 @@ if (cmd.getCmd()==CMD_DISABLE || cmd.getCmd()==CMD_ENABLE) return 0;
int suffixCode = cmd.getSuffix(); int suffixCode = cmd.getSuffix();
if (cmd.isCommand() && !suffixCode) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it if (cmd.isCommand() && !suffixCode) suffixCode=S_CMD; //if some known command find, but w/o correct suffix - got it
if (suffixCode == S_VAL && !subItem && cmd.isValue())
{
//item->setExt((long)cmd.getFloat());
debugSerial << F("VENT:")<<F("AC air temp: ")<< cmd.getFloat()<<endl;
item->setExt(millisNZ());
int mode = CMD_FAN;
int temp = cmd.getInt();
if (temp>30) mode = CMD_HEAT;
else if (temp<17) mode = CMD_COOL;
if (item->getCmd() != mode)
{
item->setCmd(mode);
pubAction(item->isActive());
}
return 1;
}
aJsonObject * i = NULL; aJsonObject * i = NULL;
if (cmd.isCommand() && cmd.getSuffix()==S_FAN) if (cmd.isCommand() && cmd.getSuffix()==S_FAN)
@@ -110,46 +255,33 @@ int maxPercent=0;
while (i) while (i)
{ {
aJsonObject * fanObj=aJson.getObjectItem(i, "fan");
aJsonObject * setObj=aJson.getObjectItem(i, "set");
aJsonObject * cmdObj=aJson.getObjectItem(i, "cmd"); aJsonObject * cmdObj=aJson.getObjectItem(i, "cmd");
aJsonObject * cascadeObj=aJson.getObjectItem(i, "cas"); aJsonObject * cascadeObj=aJson.getObjectItem(i, "cas");
if (setObj && cmdObj && setObj->type==aJson_Int && cmdObj->type==aJson_Int)
aJsonObject * setObj=aJson.getObjectItem(i, "set");
aJsonObject * pidObj=aJson.getObjectItem(i, "pid");
if (fanObj && cmdObj && fanObj->type==aJson_Int && cmdObj->type==aJson_Int)
{ {
int V =aJson.getObjectItem(i,"V")->valueint; int V = getIntFromJson(i,"V",60);
int requestedV=0; int requestedV=0;
if (subItem && !strcmp (i->name,subItem)) if (subItem && !strcmp (i->name,subItem))
{ {
if (cmdObj && cmd.isCommand())
{
cmdObj->valueint = cmd.getCmd();
//publishTopic(i->name,cmdObj->valueint,"/set");
switch (cmd.getCmd())
{
case CMD_ON:
cmd.Percents255(setObj->valueint);
break;
case CMD_OFF:
cmd.Percents255(0);
}
if (isNotRetainingStatus() && (cmdObj->valueint == CMD_ON) && (setObj->valueint<20))
{
setObj->valueint=30;
cmd.Percents255(30);
//if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS,i->name);
}
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_COMMAND|FLAG_PARAMETERS,i->name); switch (suffixCode)
} {
else if (setObj && cmdObj && suffixCode == S_FAN && cmd.isValue()) case S_FAN:
if (cmd.isValue())
{ {
if (cmd.getInt()) if (cmd.getInt())
{ {
if (cmdObj->valueint == CMD_OFF || cmdObj->valueint == -1) if (cmdObj->valueint == CMD_OFF)// || cmdObj->valueint == -1)
{ {
debugSerial<<"VENT: Turning ON"<<endl; debugSerial<<"VENT: Turning ON"<<endl;
cmdObj->valueint = CMD_ON; cmdObj->valueint = CMD_ON;
@@ -157,42 +289,111 @@ while (i)
//if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_ON),FLAG_COMMAND,i->name); //if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_ON),FLAG_COMMAND,i->name);
} }
setObj->valueint = cmd.getInt(); fanObj->valueint = cmd.getInt();
} }
else else
{ {
if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1) if (cmdObj->valueint == CMD_ON)// != CMD_OFF && cmdObj->valueint != -1)
{ debugSerial<<"VENT: Turning OFF"<<endl; { debugSerial<<"VENT: Turning OFF"<<endl;
cmdObj->valueint = CMD_OFF; cmdObj->valueint = CMD_OFF;
cmd.Cmd(CMD_OFF); cmd.Cmd(CMD_OFF);
//if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF),FLAG_COMMAND,i->name); //if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF),FLAG_COMMAND,i->name);
} }
setObj->valueint = 0; fanObj->valueint = 0;
} }
//fanObj->valueint = cmd.getInt();
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS|FLAG_COMMAND,i->name); if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS|FLAG_COMMAND,i->name);
} }
if (!cmd.isCommand()) break; // if have command i FAN suffix - continue processing
else if (setObj && cmd.isValue()) case S_CMD:
if (cmd.isCommand())
{ {
setObj->valueint = cmd.getPercents255(); long sendFlags = 0;
//publishTopic(i->name,setObj->valueint,"/set");
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS,i->name);
switch (cmd.getCmd())
{
case CMD_ON:
cmd.Percents255(fanObj->valueint);
cmd.setSuffix(S_FAN);
sendFlags |= FLAG_COMMAND | FLAG_PARAMETERS;
cmdObj->valueint = cmd.getCmd();
break;
case CMD_OFF:
cmd.Percents255(0);
cmd.setSuffix(S_FAN);
sendFlags |= FLAG_COMMAND | FLAG_PARAMETERS;
cmdObj->valueint = cmd.getCmd();
break;
case CMD_ENABLE:
if (pidObj && pidObj->valueint) ((PID *) pidObj->valueint)->SetMode(AUTOMATIC);
sendFlags |= FLAG_FLAGS;
break;
case CMD_DISABLE:
if (pidObj && pidObj->valueint) ((PID *) pidObj->valueint)->SetMode(MANUAL);
sendFlags |= FLAG_FLAGS;
break;
case CMD_AUTO:
case CMD_COOL:
case CMD_HEAT:
case CMD_FAN:
case CMD_DRY:
sendFlags |= FLAG_COMMAND;
cmdObj->valueint = cmd.getCmd();
break;
//todo - halt-rest-xon-xoff-low-med-hi
} }
if (isNotRetainingStatus() && (cmdObj->valueint == CMD_ON) && (fanObj->valueint<20))
{
fanObj->valueint=30;
cmd.Percents255(30);
//if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS,i->name);
}
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,sendFlags,i->name);
}
break;
case S_SET:
if (cmd.isValue())
{
if (!setObj) {aJson.addNumberToObject(i, "set", (float) cmd.getFloat()); setObj = aJson.getObjectItem(i, "set"); }
else {setObj->valuefloat = cmd.getFloat();setObj->type = aJson_Float;}
//publishTopic(i->name,setObj->valuefloat,"/set");
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS,i->name);
}
break;
case S_VAL:
if (cmd.isValue())
{
aJsonObject * valObj = aJson.getObjectItem(i, "val");
if (!valObj) {aJson.addNumberToObject(i, "val", (float) cmd.getFloat()); setObj = aJson.getObjectItem(i, "val");}
else {valObj->valuefloat = cmd.getFloat();valObj->type= aJson_Float;}
}
return 1;
break;
default:
break;
}
if (cascadeObj) executeCommand(cascadeObj,-1,cmd); if (cascadeObj) executeCommand(cascadeObj,-1,cmd);
} }
if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1) if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1)
{ {
requestedV=V*setObj->valueint; requestedV=V*fanObj->valueint;
activeV+=requestedV; activeV+=requestedV;
if (setObj->valueint>maxPercent ) if (fanObj->valueint>maxPercent )
{ {
maxRequestedV=requestedV; maxRequestedV=requestedV;
maxV=V; maxV=V;
maxPercent=setObj->valueint; maxPercent=fanObj->valueint;
} }
} }
totalV+=V; totalV+=V;
@@ -207,10 +408,13 @@ int fanV=activeV/totalV;
debugSerial << F("VENT: Total V:")<<totalV<<F(" active V:")<<activeV/255<< F(" fan%:")<<fanV<< F(" Max req:")<<maxRequestedV/255 <<F(" from ")<<maxV<<F(" m3")<< endl; debugSerial << F("VENT: Total V:")<<totalV<<F(" active V:")<<activeV/255<< F(" fan%:")<<fanV<< F(" Max req:")<<maxRequestedV/255 <<F(" from ")<<maxV<<F(" m3")<< endl;
//executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).Cmd((fanV)?CMD_ON:CMD_OFF)); //executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).Cmd((fanV)?CMD_ON:CMD_OFF));
executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).setSuffix(S_FAN));
/*
if (fanV) if (fanV)
executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).Cmd(CMD_ON)); executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).Cmd(CMD_ON));
else else
executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV)); executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV)); */
//Move gates only if fan is actually on //Move gates only if fan is actually on
if (!fanV) return 1; if (!fanV) return 1;
@@ -219,18 +423,20 @@ if (gatesObj) i = gatesObj->child; //Pass 2: re-distribute airflow
while (i) while (i)
{ {
int V =aJson.getObjectItem(i,"V")->valueint;
int V = getIntFromJson(i,"V",60);
aJsonObject * outObj=aJson.getObjectItem(i, "out"); aJsonObject * outObj=aJson.getObjectItem(i, "out");
aJsonObject * setObj=aJson.getObjectItem(i, "set"); aJsonObject * fanObj=aJson.getObjectItem(i, "fan");
aJsonObject * cmdObj=aJson.getObjectItem(i, "cmd"); aJsonObject * cmdObj=aJson.getObjectItem(i, "cmd");
if (outObj && setObj && cmdObj && outObj->type==aJson_Int && setObj->type==aJson_Int && cmdObj->type==aJson_Int && V) if (outObj && fanObj && cmdObj && outObj->type==aJson_Int && fanObj->type==aJson_Int && cmdObj->type==aJson_Int && V)
{ {
long int out = 0; long int out = 0;
if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1 && maxRequestedV) if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1 && maxRequestedV)
{ {
int requestedV=V*setObj->valueint; int requestedV=V*fanObj->valueint;
out = (( long)requestedV*255L)/(( long)V)*( long)maxV/( long)maxRequestedV; out = (( long)requestedV*255L)/(( long)V)*( long)maxV/( long)maxRequestedV;
debugSerial<<F("VENT: ")<<i->name<<F(" Req:")<<requestedV/255<<F(" Out:")<<out<<endl; debugSerial<<F("VENT: ")<<i->name<<F(" Req:")<<requestedV/255<<F(" Out:")<<out<<endl;
} }

View File

@@ -4,6 +4,7 @@
#include <abstractout.h> #include <abstractout.h>
#include <item.h> #include <item.h>
#include "itemCmd.h" #include "itemCmd.h"
#include <PID_v1.h>
//static int8_t motorQuote = 0; //static int8_t motorQuote = 0;
@@ -22,5 +23,6 @@ public:
protected: protected:
void getConfig(); void getConfig();
aJsonObject * gatesObj; aJsonObject * gatesObj;
//float acTemp;
}; };
#endif #endif

View File

@@ -185,7 +185,7 @@ if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCm
item->clearFlag(FLAG_ACTION_NEEDED); item->clearFlag(FLAG_ACTION_NEEDED);
itemCmd value((float) (store->output)); itemCmd value((float) (store->output));
value.setSuffix(S_SET); //value.setSuffix(S_SET);
executeCommand(oCmd,-1,value); executeCommand(oCmd,-1,value);
store->prevOut=store->output; store->prevOut=store->output;
} }

View File

@@ -11,9 +11,9 @@
class pidPersistent : public chPersistent { class pidPersistent : public chPersistent {
public: public:
PID * pid; PID * pid;
double output; iotype output;
double input; iotype input;
double setpoint; iotype setpoint;
float prevOut; float prevOut;
uint32_t alarmTimer; uint32_t alarmTimer;
bool alarmArmed; bool alarmArmed;

View File

@@ -35,8 +35,8 @@ int out_relay::Setup()
{ {
abstractOut::Setup(); abstractOut::Setup();
debugSerial<<F("Relay-Out #")<<pin<<F(" init")<<endl; debugSerial<<F("relayCtr: ")<<F("pin#")<<pin<<F(" init")<<endl;
if (isProtectedPin(pin)) {errorSerial<<F("pin disabled")<<endl;return 0;} if (isProtectedPin(pin)) {errorSerial<<F("relayCtr: ")<<F("pin disabled")<<endl;return 0;}
pinMode(pin, OUTPUT); pinMode(pin, OUTPUT);
digitalWrite(pin,INACTIVE); digitalWrite(pin,INACTIVE);
if (item) item->setExt(0); if (item) item->setExt(0);
@@ -52,7 +52,7 @@ return 1;
int out_relay::Stop() int out_relay::Stop()
{ {
debugSerial<<F("Relay-Out #")<<pin<<F(" stop")<<endl; debugSerial<<F("relayCtr: ")<<F("Relay-Out #")<<pin<<F(" stop")<<endl;
pinMode(pin, INPUT); pinMode(pin, INPUT);
setStatus(CST_UNKNOWN); setStatus(CST_UNKNOWN);
return 1; return 1;
@@ -60,39 +60,12 @@ return 1;
void out_relay::relay(bool state) void out_relay::relay(bool state)
{ {
char subtopic[10]="/";
char val[10];
digitalWrite(pin,(state)?ACTIVE:INACTIVE); digitalWrite(pin,(state)?ACTIVE:INACTIVE);
if (period<1000) return; if (period<1000) return;
debugSerial<<F("Out ")<<pin<<F(" is ")<<(state)<<endl; debugSerial<<F("relayCtr: ")<<F("Out ")<<pin<<F(" is ")<<(state)<<endl;
pubAction(state);
//debugSerial << F("OUT: ")<<F("pub action ") << F(":")<<item->itemArr->name<<subtopic<<F("=>")<<val<<endl;
strcat_P(subtopic,action_P);
short cmd=item->getCmd();
if (state)
switch(cmd)
{
case CMD_COOL:
strcpy_P(val,cooling_P);
break;
//case CMD_AUTO:
//case CMD_HEAT:
//case CMD_ON:
//
// break;
case CMD_DRY:
strcpy_P(val,drying_P);
break;
case CMD_FAN:
strcpy_P(val,fan_P);
break;
default:
strcpy_P(val,heating_P);
}
else //turned off
if (cmd==CMD_OFF) strcpy_P(val,off_P);
else strcpy_P(val,idle_P);
debugSerial << F("pub action ") << publishTopic(item->itemArr->name,val,subtopic)<<F(":")<<item->itemArr->name<<subtopic<<F("=>")<<val<<endl;
} }
@@ -197,11 +170,11 @@ case S_CMD:
return 1; return 1;
default: default:
debugSerial<<F("Unknown cmd ")<<cmd.getCmd()<<endl; debugSerial<<F("relayCtr: ")<<F("Unknown cmd ")<<cmd.getCmd()<<endl;
} //switch cmd } //switch cmd
default: default:
debugSerial<<F("Unknown suffix ")<<suffixCode<<endl; debugSerial<<F("relayCtr: ")<<F("Unknown suffix ")<<suffixCode<<endl;
} //switch suffix } //switch suffix
return 0; return 0;

View File

@@ -991,5 +991,76 @@ return crcStream.getCRC16();
} }
#endif #endif
char* getStringFromJson(aJsonObject * a, int i)
{
aJsonObject * element = NULL;
if (!a) return NULL;
if (a->type == aJson_Array)
element = aJson.getArrayItem(a, i);
// TODO - human readable JSON objects as alias
if (element && element->type == aJson_String) return element->valuestring;
return NULL;
}
char* getStringFromJson(aJsonObject * a, char * name)
{
aJsonObject * element = NULL;
if (!a) return NULL;
if (a->type == aJson_Object)
element = aJson.getObjectItem(a, name);
if (element && element->type == aJson_String) return element->valuestring;
return NULL;
}
long getIntFromJson(aJsonObject * a, int i, long def)
{
aJsonObject * element = NULL;
if (!a) return NULL;
if (a->type == aJson_Array)
element = aJson.getArrayItem(a, i);
// TODO - human readable JSON objects as alias
if (element && element->type == aJson_Int) return element->valueint;
if (element && element->type == aJson_Float) return element->valuefloat;
return def;
}
long getIntFromJson(aJsonObject * a, char * name, long def)
{
aJsonObject * element = NULL;
if (!a) return NULL;
if (a->type == aJson_Object)
element = aJson.getObjectItem(a, name);
if (element && element->type == aJson_Int) return element->valueint;
if (element && element->type == aJson_Float) return element->valuefloat;
return def;
}
float getFloatFromJson(aJsonObject * a, int i, float def)
{
aJsonObject * element = NULL;
if (!a) return NULL;
if (a->type == aJson_Array)
element = aJson.getArrayItem(a, i);
// TODO - human readable JSON objects as alias
if (element && element->type == aJson_Float) return element->valuefloat;
if (element && element->type == aJson_Int) return element->valueint;
return def;
}
float getFloatFromJson(aJsonObject * a, char * name, float def)
{
aJsonObject * element = NULL;
if (!a) return NULL;
if (a->type == aJson_Object)
element = aJson.getObjectItem(a, name);
if (element && element->type == aJson_Float) return element->valuefloat;
//if (element && element->type == aJson_Int) return element->valueint;
return def;
}
#pragma message(VAR_NAME_VALUE(debugSerial)) #pragma message(VAR_NAME_VALUE(debugSerial))
#pragma message(VAR_NAME_VALUE(SERIAL_BAUD)) #pragma message(VAR_NAME_VALUE(SERIAL_BAUD))

View File

@@ -82,7 +82,12 @@ bool checkToken(char * token, char * data);
bool isProtectedPin(short pin); bool isProtectedPin(short pin);
bool i2cReset(); bool i2cReset();
uint16_t getCRC(aJsonObject * in); uint16_t getCRC(aJsonObject * in);
char* getStringFromJson(aJsonObject * a, int i);
char* getStringFromJson(aJsonObject * a, char * name);
long getIntFromJson(aJsonObject * a, int i, long def = 0);
long getIntFromJson(aJsonObject * a, char * name, long def = 0);
float getFloatFromJson(aJsonObject * a, int i, float def = 0.0);
float getFloatFromJson(aJsonObject * a, char * name, float def = 0.0);
#ifdef CANDRV #ifdef CANDRV
#include "util/crc16_.h" #include "util/crc16_.h"
class CRCStream : public Stream class CRCStream : public Stream

View File

@@ -114,7 +114,8 @@ lib_deps =
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
https://github.com/arcao/Syslog.git https://github.com/arcao/Syslog.git
br3ttb/PID@^1.2.1 ; br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
TimerInterrupt_Generic TimerInterrupt_Generic
d00616/arduino-NVM @ ^0.9.1 d00616/arduino-NVM @ ^0.9.1
@@ -183,7 +184,8 @@ lib_deps =
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
https://github.com/arcao/Syslog.git https://github.com/arcao/Syslog.git
br3ttb/PID@^1.2.1 ; br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
;ArduinoMDNS ;ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
@@ -255,7 +257,8 @@ lib_deps =
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
https://github.com/arcao/Syslog.git https://github.com/arcao/Syslog.git
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
;ArduinoMDNS ;ArduinoMDNS
;ESPmDNS ;ESPmDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
@@ -323,7 +326,8 @@ lib_deps =
https://github.com/anklimov/ArduinoOTA https://github.com/anklimov/ArduinoOTA
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
ArduinoMDNS ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
rweather/Crypto rweather/Crypto
@@ -390,7 +394,8 @@ lib_deps =
https://github.com/anklimov/ArduinoOTA https://github.com/anklimov/ArduinoOTA
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
;ArduinoMDNS ;ArduinoMDNS
;https://github.com/khoih-prog/TimerInterrupt_Generic.git ;https://github.com/khoih-prog/TimerInterrupt_Generic.git
@@ -464,7 +469,8 @@ lib_deps =
https://github.com/anklimov/ArduinoOTA https://github.com/anklimov/ArduinoOTA
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
ArduinoMDNS ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
rweather/Crypto rweather/Crypto
@@ -516,7 +522,8 @@ lib_deps =
https://github.com/anklimov/ArduinoOTA https://github.com/anklimov/ArduinoOTA
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
ArduinoMDNS ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
@@ -612,7 +619,8 @@ lib_deps =
https://github.com/anklimov/ArduinoOTA.git https://github.com/anklimov/ArduinoOTA.git
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
;ArduinoMDNS ;ArduinoMDNS
;MDNS ;MDNS
ESP8266mDNS ESP8266mDNS
@@ -665,7 +673,8 @@ lib_deps =
https://github.com/anklimov/ArduinoOTA https://github.com/anklimov/ArduinoOTA
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
ArduinoMDNS ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
@@ -731,7 +740,8 @@ lib_deps =
https://github.com/anklimov/ArduinoOTA https://github.com/anklimov/ArduinoOTA
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
ArduinoMDNS ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
https://github.com/rlogiacco/CircularBuffer https://github.com/rlogiacco/CircularBuffer
@@ -785,7 +795,8 @@ lib_deps =
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
https://github.com/arcao/Syslog.git https://github.com/arcao/Syslog.git
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.gitv
ArduinoMDNS ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
@@ -842,7 +853,8 @@ lib_deps =
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
SPI SPI
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
ArduinoMDNS ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
https://github.com/anklimov/ModbusMaster https://github.com/anklimov/ModbusMaster
@@ -910,7 +922,8 @@ lib_deps =
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
SPI SPI
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
ArduinoMDNS ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
https://github.com/anklimov/ModbusMaster https://github.com/anklimov/ModbusMaster
@@ -979,7 +992,8 @@ lib_deps =
Adafruit MCP23017 Arduino Library Adafruit MCP23017 Arduino Library
Adafruit BusIO Adafruit BusIO
SPI SPI
br3ttb/PID@^1.2.1 ;br3ttb/PID@^1.2.1
https://github.com/anklimov/Arduino-PID-Library.git
; ArduinoMDNS ; ArduinoMDNS
https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/khoih-prog/TimerInterrupt_Generic.git
https://github.com/anklimov/ModbusMaster https://github.com/anklimov/ModbusMaster