mirror of
https://github.com/anklimov/lighthub
synced 2025-12-06 03:39:49 +03:00
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:
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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<<endl;
|
||||
if (subItem && subItem[0] == '$') {debugSerial<<F("Skipped homie stuff")<<endl;return -4; }
|
||||
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
|
||||
if (suffixCode == S_DELAYED)
|
||||
@@ -1062,7 +1088,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized
|
||||
bool scale100 = false;
|
||||
bool invalidArgument = false;
|
||||
int res = -1;
|
||||
uint16_t status2Send = 0;
|
||||
long status2Send = 0;
|
||||
uint8_t command2Set = 0;
|
||||
itemCmd originalCmd = cmd;
|
||||
|
||||
@@ -1565,7 +1591,14 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion, bool authorized
|
||||
} // NO GROUP
|
||||
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
|
||||
@@ -1714,7 +1747,7 @@ if ((!driver || driver->isAllowed(cmd)) && (!getFlag(FLAG_FREEZED)))
|
||||
} //alowed cmd
|
||||
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)
|
||||
{
|
||||
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_DEFFERED) || freeRam()<150 || (!isNotRetainingStatus() )) {
|
||||
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 valstr[20] = "";
|
||||
char cmdstr[9] = "";
|
||||
|
||||
debugSerial<<"SENDSTATUS: "<<subItem;
|
||||
debugSerial<<"SENDSTATUS: "<<subItem<<" ";
|
||||
st.debugOut();
|
||||
|
||||
#ifdef CANDRV
|
||||
@@ -2007,7 +2040,15 @@ int Item::SendStatus(int sendFlags, char * subItem) {
|
||||
|
||||
if (sendFlags & FLAG_SEND_DELAYED)
|
||||
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 //////////
|
||||
@@ -2102,7 +2143,7 @@ int Item::SendStatus(int sendFlags, char * subItem) {
|
||||
if (getFlag(FLAG_DISABLED))
|
||||
strcpy_P(cmdstr, DISABLE_P);
|
||||
|
||||
else if (getFlag(FLAG_FREEZED))
|
||||
else if (getFlag(FLAG_FREEZED) == FLAG_FREEZED)
|
||||
strcpy_P(cmdstr, FREEZE_P);
|
||||
|
||||
else strcpy_P(cmdstr, ENABLE_P);
|
||||
|
||||
@@ -138,8 +138,8 @@ class Item
|
||||
void setFloatVal(float par);
|
||||
void setSubtype(uint8_t par);
|
||||
int Poll(int cause);
|
||||
int SendStatus(int sendFlags, char * subItem=NULL);
|
||||
int SendStatusImmediate(itemCmd st, int sendFlags, char * subItem=NULL);
|
||||
int SendStatus(long sendFlags, char * subItem=NULL);
|
||||
int SendStatusImmediate(itemCmd st, long sendFlags, char * subItem=NULL);
|
||||
int isActive();
|
||||
int getChanType();
|
||||
inline int On (){return Ctrl(itemCmd(ST_VOID,CMD_ON));};
|
||||
|
||||
@@ -1211,7 +1211,7 @@ bool itemCmd::saveItem(Item * item, uint16_t optionsFlag)
|
||||
|
||||
case CMD_ENABLE:
|
||||
item->clearFlag(FLAG_DISABLED);
|
||||
item->clearFlag(FLAG_FREEZED);
|
||||
//? item->clearFlag(FLAG_FREEZED); //?
|
||||
break;
|
||||
case CMD_FREEZE:
|
||||
item->setFlag(FLAG_FREEZED);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<<F("Device Name:")<<deviceName<<endl;
|
||||
@@ -1132,13 +1110,13 @@ void ip_ready_config_loaded_connecting_to_broker() {
|
||||
|
||||
//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 >= 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<<F("Using MQTT password from config")<<endl;
|
||||
}
|
||||
|
||||
|
||||
@@ -455,12 +455,15 @@ debugSerial<<F("AC: ")<<portNum<<F(" >> ");
|
||||
debugSerial.print(store->data[i], HEX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (store->data[36] != store->inCheck){
|
||||
store->inCheck = store->data[36];
|
||||
InsertData(store->data, 37);
|
||||
debugSerial<<F("AC: OK");
|
||||
|
||||
if (store->data[36] == getCRC(store->data,36))
|
||||
{
|
||||
if (store->data[36] != store->inCheck){
|
||||
store->inCheck = store->data[36];
|
||||
InsertData(store->data, 37);
|
||||
debugSerial<<F("AC: OK");
|
||||
}
|
||||
else debugSerial<<F("AC: Bad CRC");
|
||||
}
|
||||
|
||||
debugSerial.println();
|
||||
|
||||
@@ -346,6 +346,7 @@ if (!getConfig()) return 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
store->timestamp = millisNZ();
|
||||
setStatus(CST_INITIALIZED);
|
||||
|
||||
}
|
||||
|
||||
@@ -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<<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()
|
||||
{
|
||||
// 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<<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;
|
||||
//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()
|
||||
{
|
||||
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<<F("LastKnown value: ")<<lastMeasured->valueint<<endl;
|
||||
//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;
|
||||
}
|
||||
@@ -411,52 +549,31 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
|
||||
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramObj->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 "<<param<<" to @S of "<<paramObj->name<<endl;
|
||||
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)
|
||||
{
|
||||
@@ -474,6 +591,12 @@ itemCmd out_Modbus::findRegister(uint16_t registerNum, uint16_t posInBuffer, uin
|
||||
if (*submitParam && doExecution)
|
||||
{
|
||||
// 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");
|
||||
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<<F(" Last:")<<lastMeasured->valueint<< F(" Now:") << localBuffer<<endl;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,5 +49,9 @@ protected:
|
||||
void initLine();
|
||||
int sendModbus(char * paramName, aJsonObject * outValue);
|
||||
int sendItemCmd(aJsonObject *templateParamObj, itemCmd cmd);
|
||||
int createLastMeasured(char * name);
|
||||
int createLastMeasured(aJsonObject * execObj);
|
||||
aJsonObject * getLastMeasured(char * name);
|
||||
aJsonObject * getLastMeasured(aJsonObject * execObj);
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "item.h"
|
||||
#include "main.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
||||
void out_Multivent::getConfig()
|
||||
@@ -14,6 +15,7 @@ void out_Multivent::getConfig()
|
||||
gatesObj = NULL;
|
||||
if (!item || !item->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<<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;
|
||||
}
|
||||
debugSerial << F ("VENT: init")<< endl;
|
||||
item->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<<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()
|
||||
@@ -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:")<<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;
|
||||
|
||||
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"<<endl;
|
||||
cmdObj->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"<<endl;
|
||||
cmdObj->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:")<<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).setSuffix(S_FAN));
|
||||
/*
|
||||
if (fanV)
|
||||
executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).Cmd(CMD_ON));
|
||||
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
|
||||
if (!fanV) return 1;
|
||||
|
||||
@@ -219,18 +423,20 @@ if (gatesObj) i = gatesObj->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<<F("VENT: ")<<i->name<<F(" Req:")<<requestedV/255<<F(" Out:")<<out<<endl;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <abstractout.h>
|
||||
#include <item.h>
|
||||
#include "itemCmd.h"
|
||||
#include <PID_v1.h>
|
||||
|
||||
|
||||
//static int8_t motorQuote = 0;
|
||||
@@ -22,5 +23,6 @@ public:
|
||||
protected:
|
||||
void getConfig();
|
||||
aJsonObject * gatesObj;
|
||||
//float acTemp;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -35,8 +35,8 @@ int out_relay::Setup()
|
||||
{
|
||||
abstractOut::Setup();
|
||||
|
||||
debugSerial<<F("Relay-Out #")<<pin<<F(" init")<<endl;
|
||||
if (isProtectedPin(pin)) {errorSerial<<F("pin disabled")<<endl;return 0;}
|
||||
debugSerial<<F("relayCtr: ")<<F("pin#")<<pin<<F(" init")<<endl;
|
||||
if (isProtectedPin(pin)) {errorSerial<<F("relayCtr: ")<<F("pin disabled")<<endl;return 0;}
|
||||
pinMode(pin, OUTPUT);
|
||||
digitalWrite(pin,INACTIVE);
|
||||
if (item) item->setExt(0);
|
||||
@@ -52,7 +52,7 @@ return 1;
|
||||
|
||||
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);
|
||||
setStatus(CST_UNKNOWN);
|
||||
return 1;
|
||||
@@ -60,39 +60,12 @@ return 1;
|
||||
|
||||
void out_relay::relay(bool state)
|
||||
{
|
||||
char subtopic[10]="/";
|
||||
char val[10];
|
||||
digitalWrite(pin,(state)?ACTIVE:INACTIVE);
|
||||
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;
|
||||
|
||||
default:
|
||||
debugSerial<<F("Unknown cmd ")<<cmd.getCmd()<<endl;
|
||||
debugSerial<<F("relayCtr: ")<<F("Unknown cmd ")<<cmd.getCmd()<<endl;
|
||||
} //switch cmd
|
||||
|
||||
default:
|
||||
debugSerial<<F("Unknown suffix ")<<suffixCode<<endl;
|
||||
debugSerial<<F("relayCtr: ")<<F("Unknown suffix ")<<suffixCode<<endl;
|
||||
} //switch suffix
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -991,5 +991,76 @@ return crcStream.getCRC16();
|
||||
}
|
||||
#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(SERIAL_BAUD))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user