diff --git a/lighthub/abstractout.cpp b/lighthub/abstractout.cpp index 282eb38..e744500 100644 --- a/lighthub/abstractout.cpp +++ b/lighthub/abstractout.cpp @@ -3,6 +3,9 @@ #include "item.h" #include "abstractout.h" #include "itemCmd.h" +#include "Arduino.h" +#include "textconst.h" + int abstractOut::isActive() {itemCmd st; @@ -37,4 +40,39 @@ int abstractOut::Status() void abstractOut::setStatus(uint8_t status) { 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); + } \ No newline at end of file diff --git a/lighthub/abstractout.h b/lighthub/abstractout.h index 7168a2f..5cde9ed 100644 --- a/lighthub/abstractout.h +++ b/lighthub/abstractout.h @@ -16,7 +16,9 @@ public: // virtual int getDefaultStorageType(){return 0;} /// Remove?? Now getChanType used instead virtual int Status() override; virtual void setStatus(uint8_t status) override; - int Setup() override; + int Setup() override; protected: + int pubAction(bool state); + Item * item; }; diff --git a/lighthub/item.cpp b/lighthub/item.cpp index 91dfeba..2f3e91f 100644 --- a/lighthub/item.cpp +++ b/lighthub/item.cpp @@ -953,11 +953,11 @@ int Item::scheduleOppositeCommand(itemCmd cmd,bool isActiveNow,bool authorized) nextCmd.Cmd(CMD_ENABLE); break; case CMD_FREEZE: - if (getFlag(FLAG_FREEZED) && !isScheduled()) return 0; + if ((getFlag(FLAG_FREEZED) == FLAG_FREEZED) && !isScheduled()) return 0; nextCmd.Cmd(CMD_UNFREEZE); break; case CMD_UNFREEZE: - if (!getFlag(FLAG_FREEZED) && !isScheduled()) return 0; + if (!(getFlag(FLAG_FREEZED) == FLAG_FREEZED) && !isScheduled()) return 0; nextCmd.Cmd(CMD_FREEZE); break; case CMD_HALT: @@ -1014,6 +1014,7 @@ int Item::scheduleCommand(itemCmd cmd,bool authorized) // -1 system error // -4 invalid argument // -5 unauthorized +// -6 disabled int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized) { int fr = freeRam(); @@ -1050,6 +1051,31 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized //debugSerial<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 @@ -1714,7 +1747,7 @@ if ((!driver || driver->isAllowed(cmd)) && (!getFlag(FLAG_FREEZED))) } //alowed cmd else { - errorSerial<clearFlag(FLAG_DISABLED); - item->clearFlag(FLAG_FREEZED); + //? item->clearFlag(FLAG_FREEZED); //? break; case CMD_FREEZE: item->setFlag(FLAG_FREEZED); diff --git a/lighthub/itemCmd.h b/lighthub/itemCmd.h index 19efef5..ac86e96 100644 --- a/lighthub/itemCmd.h +++ b/lighthub/itemCmd.h @@ -104,21 +104,40 @@ const ch_type ch_type_P[] PROGMEM = #define CMD_JSON -2 //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_FREEZED 0x20000UL +//#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_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_XON 0x80000UL +#define FLAG_SEND_DELAYED 0x100000UL + +#define FLAG_SEND_IMMEDIATE 0x1UL #define FLAG_NOT_SEND_CAN 0x2UL int txt2cmd (char * payload); diff --git a/lighthub/main.cpp b/lighthub/main.cpp index 8dabe23..f601b63 100644 --- a/lighthub/main.cpp +++ b/lighthub/main.cpp @@ -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 const char defaultPassword[] PROGMEM = QUOTE(DEFAULT_OTA_PASSWORD); void setupOTA(void) @@ -608,7 +586,7 @@ void setupSyslog() udpSyslogArr = aJson.getObjectItem(root, "syslog"); 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; @@ -619,7 +597,7 @@ void setupSyslog() udpSyslog.server(syslogServer, syslogPort); udpSyslog.deviceHostname(syslogDeviceHostname); - if (mqttArr) deviceName = getStringFromConfig(mqttArr, 0); + if (mqttArr) deviceName = getStringFromJson(mqttArr, 0); if (deviceName) udpSyslog.appName(deviceName); else udpSyslog.appName(lighthub); 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; infoSerial<= 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 (!sysConf.getMQTTpwd(passwordBuf, sizeof(passwordBuf)) && (n >= 5)) { - password = getStringFromConfig(mqttArr, 4); + password = getStringFromJson(mqttArr, 4); infoSerial<> "); debugSerial.print(store->data[i], HEX); } } - - - if (store->data[36] != store->inCheck){ - store->inCheck = store->data[36]; - InsertData(store->data, 37); - debugSerial<data[36] == getCRC(store->data,36)) + { + if (store->data[36] != store->inCheck){ + store->inCheck = store->data[36]; + InsertData(store->data, 37); + debugSerial<timestamp = millisNZ(); setStatus(CST_INITIALIZED); } diff --git a/lighthub/modules/out_modbus.cpp b/lighthub/modules/out_modbus.cpp index 3425180..a556cd4 100644 --- a/lighthub/modules/out_modbus.cpp +++ b/lighthub/modules/out_modbus.cpp @@ -70,6 +70,47 @@ int str2regSize(char * str) 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<name<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() { // 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;} store->parameters=aJson.getObjectItem(templateObj, "par"); + + // initializing @S where needed + + if (store->parameters) + { + // Creating for parameters where prefetch required + debugSerial<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<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<itemArg, 2); + if (itemParametersObj) + { + i = itemParametersObj->child; + while (i) + { + if (haveAction(i)) createLastMeasured(i); + i=i->next; + } + } + + } + return true; //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<name<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() { abstractOut::Setup(); @@ -330,12 +472,9 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin if (itemParametersObj && itemParametersObj->type ==aJson_Object) { //Searching item param for nested mapping - aJsonObject *itemParObj = aJson.getObjectItem(itemParametersObj,defMappingObj->valuestring); - if (itemParObj) - { - //Retrive previous data - aJsonObject *lastMeasured = aJson.getObjectItem(itemParObj,"@S"); - if (lastMeasured && lastMeasured->type ==aJson_Int) + //Retrive previous data + aJsonObject *lastMeasured = getLastMeasured(defMappingObj->valuestring); + if (lastMeasured) { traceSerial<valueint<name); if (execObj) { - - 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) - { + // if (!doExecution || haveAction(execObj)) //if no action in execObj - do not save last value to avoid confuse further recurrent check + // { //Retrive previous data - aJsonObject *lastMeasured = aJson.getObjectItem(markObj,"@S"); + aJsonObject *lastMeasured = getLastMeasured(execObj); if (lastMeasured) { - if (lastMeasured->type == aJson_Int) - { 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 { lastMeasured->valueint=param; traceSerial<<"MBUS: Stored "<name<subtype&=~MB_VALUE_OUTDATED; } - } } - else //No container to store value yet - { - debugSerial<name<type == aJson_Array) + { + markObj = execObj->child; + //storeLastValue = true; + } aJsonObject *settedValue = aJson.getObjectItem(markObj,"@V"); 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)) settedValue->valueint=param; } - } - } - } - //if (submitRecurrentOut) *submitParam=true; //if requrrent check has submit smth - report it. + } //to be executed + } //ExecObj + } //item Parameters + return mappedParam; - } + } //reg == regNum paramObj=paramObj->next; - } + } //while return itemCmd(); } @@ -618,14 +741,14 @@ if (prefetchObj && (prefetchObj->type == aJson_Boolean) && prefetchObj->valueboo aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramName); if (execObj) { - aJsonObject * markObj = execObj; - if (execObj->type == aJson_Array) markObj = execObj->child; + //aJsonObject * markObj = execObj; + //if (execObj->type == aJson_Array) markObj = execObj->child; //Retrive previous data - lastMeasured = aJson.getObjectItem(markObj,"@S"); + lastMeasured = getLastMeasured(execObj);// aJson.getObjectItem(markObj,"@S"); if (lastMeasured) { - if (lastMeasured->type == aJson_Int) - { + //if (lastMeasured->type == aJson_Int) + // { traceSerial<valueint<< F(" Now:") << localBuffer<valueint != localBuffer) @@ -645,7 +768,7 @@ if (prefetchObj && (prefetchObj->type == aJson_Boolean) && prefetchObj->valueboo debugSerial << F("MBUS:")<itemArg || item->itemArg->type != aJson_Object) return; gatesObj = item->itemArg; + //acTemp=(float) item->getExt(); } int out_Multivent::Setup() @@ -21,30 +23,81 @@ int out_Multivent::Setup() abstractOut::Setup(); //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 -if (gatesObj /*&& aJson.getArraySize(item->itemArg)>=2*/) +if (gatesObj) { aJsonObject * i = gatesObj->child; while (i) { if (i->name && *i->name) { - aJsonObject * setObj = aJson.getObjectItem(i, "set"); - if (!setObj) aJson.addNumberToObject(i, "set", (long int) -1); + aJsonObject * fanObj = aJson.getObjectItem(i, "fan"); + if (!fanObj) {aJson.addNumberToObject(i, "fan", (long int) -1);fanObj = aJson.getObjectItem(i, "fan");} 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"); - 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<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<valueint)->SetMode (AUTOMATIC); + ((PID*) pidObj->valueint)->SetSampleTime(dT*1000.0); + debugSerial << F ("VENT: PID P=")<setExt(0); setStatus(CST_INITIALIZED); return 1; } @@ -57,13 +110,87 @@ return 0; int out_Multivent::Stop() { 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); return 1; } 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<itemArr->name<<"/"<name + <GetIn()<GetSet()<GetOut() + // <valuefloat + <<" P:"<GetKp()<<" I:"<GetKi()<<" D:"<GetKd()<<((p->GetDirection())?" Rev ":" Dir ")<<((p->GetMode())?" A":" M"); + debugSerial<getCmd()) + { + case CMD_HEAT: + ((PID *) pidObj->valueint)->SetControllerDirection(DIRECT); + debugSerial<itemArr->name<<"/"<name<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<itemArr->name<<"/"<name<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() @@ -79,6 +206,24 @@ if (cmd.getCmd()==CMD_DISABLE || cmd.getCmd()==CMD_ENABLE) return 0; int suffixCode = cmd.getSuffix(); 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:")<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; if (cmd.isCommand() && cmd.getSuffix()==S_FAN) @@ -110,46 +255,33 @@ int maxPercent=0; while (i) { - - aJsonObject * setObj=aJson.getObjectItem(i, "set"); + aJsonObject * fanObj=aJson.getObjectItem(i, "fan"); aJsonObject * cmdObj=aJson.getObjectItem(i, "cmd"); 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; 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); - } - - else if (setObj && cmdObj && suffixCode == S_FAN && cmd.isValue()) + switch (suffixCode) + { + + case S_FAN: + if (cmd.isValue()) { + if (cmd.getInt()) { + - if (cmdObj->valueint == CMD_OFF || cmdObj->valueint == -1) + if (cmdObj->valueint == CMD_OFF)// || cmdObj->valueint == -1) { debugSerial<<"VENT: Turning ON"<valueint = CMD_ON; @@ -157,42 +289,111 @@ while (i) //if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_ON),FLAG_COMMAND,i->name); } - setObj->valueint = cmd.getInt(); + fanObj->valueint = cmd.getInt(); } else { - if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1) + if (cmdObj->valueint == CMD_ON)// != CMD_OFF && cmdObj->valueint != -1) { debugSerial<<"VENT: Turning OFF"<valueint = CMD_OFF; cmd.Cmd(CMD_OFF); //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); } - - else if (setObj && cmd.isValue()) + if (!cmd.isCommand()) break; // if have command i FAN suffix - continue processing + case S_CMD: + if (cmd.isCommand()) { - setObj->valueint = cmd.getPercents255(); - //publishTopic(i->name,setObj->valueint,"/set"); - if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,FLAG_PARAMETERS,i->name); + long sendFlags = 0; + + + 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 (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1) { - requestedV=V*setObj->valueint; + requestedV=V*fanObj->valueint; activeV+=requestedV; - if (setObj->valueint>maxPercent ) + if (fanObj->valueint>maxPercent ) { maxRequestedV=requestedV; maxV=V; - maxPercent=setObj->valueint; + maxPercent=fanObj->valueint; } } totalV+=V; @@ -207,10 +408,13 @@ int fanV=activeV/totalV; debugSerial << F("VENT: Total V:")<child; //Pass 2: re-distribute airflow while (i) { - int V =aJson.getObjectItem(i,"V")->valueint; + + int V = getIntFromJson(i,"V",60); + aJsonObject * outObj=aJson.getObjectItem(i, "out"); - aJsonObject * setObj=aJson.getObjectItem(i, "set"); + aJsonObject * fanObj=aJson.getObjectItem(i, "fan"); 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; 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; debugSerial<name< #include #include "itemCmd.h" +#include //static int8_t motorQuote = 0; @@ -22,5 +23,6 @@ public: protected: void getConfig(); aJsonObject * gatesObj; + //float acTemp; }; #endif diff --git a/lighthub/modules/out_pid.cpp b/lighthub/modules/out_pid.cpp index a26d576..e43ebeb 100644 --- a/lighthub/modules/out_pid.cpp +++ b/lighthub/modules/out_pid.cpp @@ -185,7 +185,7 @@ if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCm item->clearFlag(FLAG_ACTION_NEEDED); itemCmd value((float) (store->output)); - value.setSuffix(S_SET); + //value.setSuffix(S_SET); executeCommand(oCmd,-1,value); store->prevOut=store->output; } diff --git a/lighthub/modules/out_pid.h b/lighthub/modules/out_pid.h index 21eba60..d82ad42 100644 --- a/lighthub/modules/out_pid.h +++ b/lighthub/modules/out_pid.h @@ -11,9 +11,9 @@ class pidPersistent : public chPersistent { public: PID * pid; - double output; - double input; - double setpoint; + iotype output; + iotype input; + iotype setpoint; float prevOut; uint32_t alarmTimer; bool alarmArmed; diff --git a/lighthub/modules/out_relay.cpp b/lighthub/modules/out_relay.cpp index 269fc0b..26c1d49 100644 --- a/lighthub/modules/out_relay.cpp +++ b/lighthub/modules/out_relay.cpp @@ -35,8 +35,8 @@ int out_relay::Setup() { abstractOut::Setup(); -debugSerial<setExt(0); @@ -52,7 +52,7 @@ return 1; int out_relay::Stop() { -debugSerial<itemArr->name<")<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)<itemArr->name<")<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(SERIAL_BAUD)) diff --git a/lighthub/utils.h b/lighthub/utils.h index 370d363..249a734 100644 --- a/lighthub/utils.h +++ b/lighthub/utils.h @@ -82,7 +82,12 @@ bool checkToken(char * token, char * data); bool isProtectedPin(short pin); bool i2cReset(); 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 #include "util/crc16_.h" class CRCStream : public Stream diff --git a/platformio.ini b/platformio.ini index a835bec..940c14f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -114,7 +114,8 @@ lib_deps = Adafruit MCP23017 Arduino Library Adafruit BusIO 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 d00616/arduino-NVM @ ^0.9.1 @@ -183,7 +184,8 @@ lib_deps = Adafruit MCP23017 Arduino Library Adafruit BusIO 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 https://github.com/khoih-prog/TimerInterrupt_Generic.git @@ -255,7 +257,8 @@ lib_deps = Adafruit MCP23017 Arduino Library Adafruit BusIO 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 ;ESPmDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git @@ -323,7 +326,8 @@ lib_deps = https://github.com/anklimov/ArduinoOTA Adafruit MCP23017 Arduino Library Adafruit BusIO - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ArduinoMDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git rweather/Crypto @@ -390,7 +394,8 @@ lib_deps = https://github.com/anklimov/ArduinoOTA Adafruit MCP23017 Arduino Library Adafruit BusIO - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ;ArduinoMDNS ;https://github.com/khoih-prog/TimerInterrupt_Generic.git @@ -464,7 +469,8 @@ lib_deps = https://github.com/anklimov/ArduinoOTA Adafruit MCP23017 Arduino Library Adafruit BusIO - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ArduinoMDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git rweather/Crypto @@ -516,7 +522,8 @@ lib_deps = https://github.com/anklimov/ArduinoOTA Adafruit MCP23017 Arduino Library Adafruit BusIO - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ArduinoMDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git @@ -612,7 +619,8 @@ lib_deps = https://github.com/anklimov/ArduinoOTA.git Adafruit MCP23017 Arduino Library Adafruit BusIO - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ;ArduinoMDNS ;MDNS ESP8266mDNS @@ -665,7 +673,8 @@ lib_deps = https://github.com/anklimov/ArduinoOTA Adafruit MCP23017 Arduino Library Adafruit BusIO - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ArduinoMDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git @@ -731,7 +740,8 @@ lib_deps = https://github.com/anklimov/ArduinoOTA Adafruit MCP23017 Arduino Library Adafruit BusIO - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ArduinoMDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/rlogiacco/CircularBuffer @@ -785,7 +795,8 @@ lib_deps = Adafruit MCP23017 Arduino Library Adafruit BusIO 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 https://github.com/khoih-prog/TimerInterrupt_Generic.git @@ -842,7 +853,8 @@ lib_deps = Adafruit MCP23017 Arduino Library Adafruit BusIO SPI - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ArduinoMDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/anklimov/ModbusMaster @@ -910,7 +922,8 @@ lib_deps = Adafruit MCP23017 Arduino Library Adafruit BusIO SPI - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ArduinoMDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/anklimov/ModbusMaster @@ -979,7 +992,8 @@ lib_deps = Adafruit MCP23017 Arduino Library Adafruit BusIO SPI - br3ttb/PID@^1.2.1 + ;br3ttb/PID@^1.2.1 + https://github.com/anklimov/Arduino-PID-Library.git ; ArduinoMDNS https://github.com/khoih-prog/TimerInterrupt_Generic.git https://github.com/anklimov/ModbusMaster