Modbus mapping, AC swing, vent, pwm relay fix

This commit is contained in:
2022-10-02 19:31:18 +03:00
parent a17ea0bad7
commit 891701cee1
9 changed files with 279 additions and 71 deletions

View File

@@ -1122,12 +1122,14 @@ int Item::Ctrl(itemCmd cmd, char* subItem, bool allowRecursion)
toExecute=true;
break;
}
if (chActive)
{
debugSerial<<F("ON:Already Active\n");
setCmd(CMD_ON);
SendStatus(SEND_COMMAND | SEND_DEFFERED);
return 3;
}
//newly added. For climate commands need to restore previous temperature
case CMD_AUTO:
case CMD_COOL:
@@ -1433,9 +1435,10 @@ int Item::SendStatus(int sendFlags) {
int Item::SendStatusImmediate(itemCmd st, int sendFlags, char * subItem) {
{
char addrstr[48];
char addrstr[64];
char valstr[20] = "";
char cmdstr[9] = "";
//debugSerial<<"SSI "<<subItem<<endl;
st.debugOut();
if (sendFlags & SEND_COMMAND)
{
@@ -1469,9 +1472,10 @@ int Item::SendStatus(int sendFlags) {
// myhome/s_out/item - mix: value and command
if (mqttClient.connected() && !ethernetIdleCount && !subItem)
if (mqttClient.connected() && !ethernetIdleCount)
{
if (!subItem)
{
setTopic(addrstr,sizeof(addrstr),T_OUT);
strncat(addrstr, itemArr->name, sizeof(addrstr)-1);
@@ -1490,6 +1494,7 @@ int Item::SendStatus(int sendFlags) {
debugSerial<<F("Pub: ")<<addrstr<<F("->")<<cmdstr<<endl;
}
} //!subItem
}
else
{

View File

@@ -23,10 +23,10 @@ e-mail anklimov@gmail.com
#include "itemCmd.h"
#define S_NOTFOUND 0
//#define S_SETnCMD 0
#define S_CMD 1
#define S_SET 2
//#define S_ESET 4
#define S_VAL 3
#define S_DELAYED 4
#define S_HSV 5
#define S_RGB 6
#define S_FAN 7
@@ -34,10 +34,8 @@ e-mail anklimov@gmail.com
#define S_HUE 9
#define S_SAT 10
#define S_TEMP 11
#define S_VAL 12
#define S_DELAYED 13
#define S_RAW 14
#define S_ADDITIONAL 14
#define S_RAW 12
#define S_ADDITIONAL 12
#define CH_DIMMER 0 //DMX 1-4 ch
#define CH_RGBW 1 //DMX 4 ch

View File

@@ -1128,52 +1128,177 @@ bool itemCmd::saveItem(Item * item, uint16_t optionsFlag)
return false;
}
int replaceCmdToInt(aJsonObject* verb)
{
if (verb && verb->type == aJson_String)
{
int cmd = txt2cmd(verb->valuestring);
if (cmd>0)
{
free(verb->valuestring);
verb->valueint=cmd;
verb->type=aJson_Int;
return verb->valueint;
}
} else if (verb && verb->type == aJson_Int) return verb->valueint;
return 0;
}
// Mapping from unified itemCmd object to some specific device-depended value
itemCmd itemCmd::doMapping(aJsonObject *mappingData)
{
if (isCommand())
if (!mappingData) return *this;
aJsonObject *cmdMapping = aJson.getObjectItem(mappingData, "cmd");
aJsonObject *matchedCmd = NULL;
if (isCommand() && cmdMapping)
switch (cmdMapping->type)
{
case aJson_Array:
{
debugSerial<<"Array mapping"<<endl;
aJsonObject *i = cmdMapping->child;
//if first array element is not array - this is default mapping value
if (i && i->type==aJson_Int)
{
matchedCmd = i;
i=i->next;
}
while (i)
{
if (i->type == aJson_Array && aJson.getArraySize(i) == 2)
{
int cmdFrom = replaceCmdToInt(aJson.getArrayItem(i,0));
aJsonObject *to = aJson.getArrayItem(i,1);
if (getCmd()==cmdFrom && to->type == aJson_Int)
{
matchedCmd=to;
break;
}
}
i=i->next;
}
}
case aJson_String:
if (strcmp(cmdMapping->valuestring,"fan")==0)
switch (getCmd())
{
/*
case CMD_AUTO:
case CMD_ON:
return itemCmd().Int((uint32_t)3);
case CMD_OFF:
return itemCmd().Int((uint32_t)0);
case CMD_FAN:
return itemCmd().Int((uint32_t)1);
case CMD_HEAT:
return itemCmd().Int((uint32_t)2);
*/
case CMD_OFF:
return itemCmd().Int((uint32_t)0);
case CMD_LOW:
return itemCmd().Int((uint32_t)10);
return itemCmd().Int((uint32_t)20);
case CMD_MED:
return itemCmd().Int((uint32_t)128);
case CMD_HIGH:
return itemCmd().Int((uint32_t)255);
default:
return itemCmd().Int((uint32_t)0);
return *this;
}
} //switch
if (matchedCmd) return itemCmd().Int((uint32_t)matchedCmd->valueint);
aJsonObject *valMapping = aJson.getObjectItem(mappingData, "val");
if (isValue() && valMapping && valMapping->type == aJson_Array && aJson.getArraySize(valMapping) == 4)
{
if (getInt()<aJson.getArrayItem(valMapping,0)->valueint) return itemCmd().Int((uint32_t) 0);
return itemCmd().Int((uint32_t)
map(getInt(),
aJson.getArrayItem(valMapping,0)->valueint,aJson.getArrayItem(valMapping,1)->valueint,
aJson.getArrayItem(valMapping,2)->valueint,aJson.getArrayItem(valMapping,3)->valueint));
}
return *this;
}
// Mapping from some device specific value back to unified itemcmd
itemCmd itemCmd::doReverseMapping (aJsonObject *mappingData)
{
if (!mappingData) return *this;
aJsonObject *cmdMapping = aJson.getObjectItem(mappingData, "cmd");
aJsonObject *matchedCmd = NULL;
if (cmdMapping)
switch (cmdMapping->type )
{
case aJson_Array:
{
aJsonObject *i = cmdMapping->child;
//if first array element is not array - this is default mapping value
if (i && i->type==aJson_Int)
{
matchedCmd = i;
i=i->next;
}
while (i)
{
if (i->type == aJson_Array && aJson.getArraySize(i) == 2)
{
aJsonObject *from =aJson.getArrayItem(i,0);
int cmdFrom = replaceCmdToInt(from);
aJsonObject *to = aJson.getArrayItem(i,1);
if (to->type == aJson_Int && getInt()==to->valueint)
{
matchedCmd=from;
break;
}
}
i=i->next;
}
}
break;
case aJson_String:
{
if (strcmp(cmdMapping->valuestring,"fan")==0)
{
if (getInt())
switch (constrain(map(getInt(),0,255,1,3),1,3))
{
case 1:
return itemCmd().setSuffix(S_FAN).Cmd(CMD_LOW);
case 2:
return itemCmd().setSuffix(S_FAN).Cmd(CMD_MED);
case 3:
return itemCmd().setSuffix(S_FAN).Cmd(CMD_HIGH);
}
else return itemCmd().setSuffix(S_FAN).Cmd(CMD_OFF);
}
}
}//switch
if (matchedCmd) return itemCmd().Cmd(matchedCmd->valueint);
aJsonObject *valMapping = aJson.getObjectItem(mappingData, "val");
if (valMapping && valMapping->type == aJson_Array && aJson.getArraySize(valMapping) == 4)
{
int a = aJson.getArrayItem(valMapping,0)->valueint;
int b = aJson.getArrayItem(valMapping,1)->valueint;
int c = aJson.getArrayItem(valMapping,2)->valueint;
int d = aJson.getArrayItem(valMapping,3)->valueint;
if (getInt()<aJson.getArrayItem(valMapping,2)->valueint) return itemCmd().Int((uint32_t) 0);
int diff = ((b-a)/(d-c))/2;
return itemCmd().Int((uint32_t) constrain(map(getInt(),c,d,a,b)+diff,0,255));
}
return *this;
}
int itemCmd::doMappingCmd(aJsonObject *mappingData)
{
return 0;
}
int itemCmd::doReverseMappingCmd (aJsonObject *mappingData)
{
return 0;
}
char * itemCmd::toString(char * Buffer, int bufLen, int sendFlags, bool scale100 )
{

View File

@@ -26,8 +26,8 @@ typedef char cmdstr[9];
const cmdstr commands_P[] PROGMEM =
{
"","ON","OFF","REST","TOGGLE","HALT","XON","XOFF","INCREASE","DECREASE",
"HEAT","COOL","AUTO","FAN_ONLY","DRY","STOP","HIGH","MEDIUM","LOW",
"TRUE","FALSE","ENABLED","DISABLED","RGB","HSV"
"HEAT","COOL","AUTO","FAN_ONLY","DRY","STOP","HIGH","MEDIUM","LOW","ENABLE","DISABLE",
"TRUE","FALSE","RGB","HSV"
};
#define commandsNum sizeof(commands_P)/sizeof(cmdstr)
@@ -50,8 +50,8 @@ const cmdstr commands_P[] PROGMEM =
#define CMD_HIGH 0x10 /// AC/Vent fan level HIGH
#define CMD_MED 0x11 /// AC/Vent fan level MEDIUM
#define CMD_LOW 0x12 /// AC/Vent fan level LOW
#define CMD_ENABLED 0x13 /// Aliase for ON
#define CMD_DISABLED 0x14 /// Aliase for OFF
#define CMD_ENABLE 0x13 /// for PID regulator
#define CMD_DISABLE 0x14 /// for PID regulator
#define CMD_TRUE 0x15 /// Aliase for ON
#define CMD_FALSE 0x16 /// Aliase for OFF
#define CMD_RGB 0x17
@@ -222,8 +222,6 @@ public:
itemCmd doMapping(aJsonObject *mappingData);
itemCmd doReverseMapping (aJsonObject *mappingData);
int doMappingCmd(aJsonObject *mappingData);
int doReverseMappingCmd (aJsonObject *mappingData);
bool scale100();
};

View File

@@ -38,17 +38,7 @@ const char LOCK_P[] PROGMEM = "lock";
const char QUIET_P[] PROGMEM = "queit";
const char SWING_P[] PROGMEM = "swing";
const char RAW_P[] PROGMEM = "raw";
//const char IDLE_P[] PROGMEM = "IDLE";
/*
extern const char HEAT_P[] PROGMEM;
extern const char COOL_P[] PROGMEM;
extern const char AUTO_P[] PROGMEM;
extern const char FAN_ONLY_P[] PROGMEM;
extern const char DRY_P[] PROGMEM;
extern const char HIGH_P[] PROGMEM;
extern const char MED_P[] PROGMEM;
extern const char LOW_P[] PROGMEM;
*/
void out_AC::InsertData(byte data[], size_t size){
char s_mode[10];
@@ -405,11 +395,11 @@ int out_AC::Ctrl(itemCmd cmd, char* subItem , bool toExecute)
switch (cmd.getCmd())
{
case CMD_ON:
data[B_LOCK_REM] = 3;
data[B_SWING] = 3;
publishTopic(item->itemArr->name,"ON","/swing");
break;
case CMD_OFF:
data[B_LOCK_REM] = 0;
data[B_SWING] = 0;
publishTopic(item->itemArr->name,"OFF","/swing");
break;
default:

View File

@@ -301,11 +301,14 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
mappedParam.Float((int32_t) data/100.);
}
if (mapObj && (mapObj->type==aJson_Array || mapObj->type==aJson_Object))
mappedParam.doMapping(mapObj);
debugSerial << F("MB got ")<<mappedParam.toString(buf,sizeof(buf))<< F(" from ")<<regType<<F(":")<<paramObj->name<<endl;
if (mapObj && (mapObj->type==aJson_Array || mapObj->type==aJson_Object))
{
mappedParam=mappedParam.doReverseMapping(mapObj);
debugSerial << F("Mapped:")<<mappedParam.toString(buf,sizeof(buf))<<endl;
}
if (itemParametersObj && itemParametersObj->type ==aJson_Object)
{
aJsonObject *execObj = aJson.getObjectItem(itemParametersObj,paramObj->name);
@@ -329,13 +332,16 @@ int out_Modbus::findRegister(int registerNum, int posInBuffer, int regType)
aJson.addNumberToObject(execObj, "@S", (long) param);
}
if (submitParam)
{ // Compare with last submitted val
{
//#ifdef MB_SUPPRESS_OUT_EQ_IN
// Compare with last submitted val (if @V NOT marked as NULL in config)
aJsonObject *settedValue = aJson.getObjectItem(execObj,"@V");
if (settedValue && (settedValue->valueint == param))
if (settedValue && settedValue->type==aJson_Int && (settedValue->valueint == param))
{
debugSerial<<F("Ignored - equal with setted val")<<endl;
}
else executeCommand(execObj, -1, mappedParam);
//#endif
}
}
}
@@ -598,18 +604,19 @@ if (itemParametersObj && itemParametersObj->type ==aJson_Object)
execObj->subtype |= MB_NEED_SEND;
aJsonObject *outValue = aJson.getObjectItem(execObj,"@V");
if (outValue)
if (outValue) // Existant. Preserve original @type
{
outValue->valueint=Value;
outValue->subtype =regType;
polledValue->valueint=Value; //to pevent suppressing to change back to previously polled value if this occurs before next polling
outValue->subtype =regType & 0xF;
if (outValue->type == aJson_Int) polledValue->valueint=Value; //to pevent suppressing to change back to previously polled value if this occurs before next polling
}
else //No container to store value yet
// If no @V in config - creating with INT type - normal behavior - no supress in-to-out
{
debugSerial<<F("Add @V: ")<<execObj->name<<endl;
aJson.addNumberToObject(execObj, "@V", Value);
outValue = aJson.getObjectItem(execObj,"@V");
if (outValue) outValue->subtype =regType;
if (outValue) outValue->subtype =regType & 0xF;
}
}
}

View File

@@ -102,6 +102,24 @@ if (cmd.isCommand() && !suffixCode) suffixCode=S_CMD; //if some known command fi
aJsonObject * i = NULL;
if (cmd.isCommand() && cmd.getSuffix()==S_FAN)
switch (cmd.getCmd())
{
case CMD_HIGH:
cmd.Percents255(255);
break;
case CMD_MED:
cmd.Percents255(128);
break;
case CMD_LOW:
cmd.setPercents(10);
break;
} //switch cmd
if (gatesObj) i = gatesObj->child; // Pass 1 - calculate summ air value, max value etc
int activeV = 0;
@@ -116,6 +134,7 @@ while (i)
aJsonObject * setObj=aJson.getObjectItem(i, "set");
aJsonObject * cmdObj=aJson.getObjectItem(i, "cmd");
aJsonObject * cascadeObj=aJson.getObjectItem(i, "cas");
if (setObj && cmdObj && setObj->type==aJson_Int && cmdObj->type==aJson_Int)
{
@@ -128,31 +147,78 @@ while (i)
{
cmdObj->valueint = cmd.getCmd();
//publishTopic(i->name,cmdObj->valueint,"/set");
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_COMMAND,i->name);
switch (cmd.getCmd())
{
case CMD_ON:
cmd.Percents255(setObj->valueint);
break;
case CMD_OFF:
cmd.Percents255(0);
}
if (setObj && cmd.isValue())
if (cmdObj->valueint == CMD_ON && setObj->valueint<20)
{
setObj->valueint=30;
cmd.Percents255(30);
//if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_PARAMETERS,i->name);
}
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_COMMAND|SEND_PARAMETERS,i->name);
}
else if (setObj && cmdObj && suffixCode == S_FAN && cmd.isValue())
{
if (cmd.getInt())
{
if (cmdObj->valueint == CMD_OFF || cmdObj->valueint == -1)
{
debugSerial<<"Turning ON"<<endl;
cmdObj->valueint = CMD_ON;
cmd.Cmd(CMD_ON);
//if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_ON),SEND_COMMAND,i->name);
}
setObj->valueint = cmd.getInt();
}
else
{
if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1)
{ debugSerial<<"Turning OFF"<<endl;
cmdObj->valueint = CMD_OFF;
cmd.Cmd(CMD_OFF);
//if (isNotRetainingStatus()) item->SendStatusImmediate(itemCmd().Cmd(CMD_OFF),SEND_COMMAND,i->name);
}
setObj->valueint = 0;
}
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_PARAMETERS|SEND_COMMAND,i->name);
}
else if (setObj && cmd.isValue())
{
setObj->valueint = cmd.getPercents255();
//publishTopic(i->name,setObj->valueint,"/set");
if (isNotRetainingStatus()) item->SendStatusImmediate(cmd,SEND_PARAMETERS,i->name);
}
if (cascadeObj) executeCommand(cascadeObj,-1,cmd);
}
if (cmdObj->valueint != CMD_OFF)
if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1)
{
requestedV=V*setObj->valueint;
activeV+=requestedV;
}
totalV+=V;
//if(requestedV>maxRequestedV)
if (setObj->valueint>maxPercent)
if (setObj->valueint>maxPercent )
{
maxRequestedV=requestedV;
maxV=V;
maxPercent=setObj->valueint;
}
}
totalV+=V;
}
i=i->next;
}
@@ -161,7 +227,7 @@ if (!totalV) return 0;
int fanV=activeV/totalV;
debugSerial << F("Total V:")<<totalV<<F(" active V:")<<activeV/255<< F(" fan%:")<<fanV<< F(" Max request:")<<maxRequestedV/255 <<F(" from ")<<maxV<<F(" m3")<< endl;
executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV));
executeCommand(aJson.getObjectItem(gatesObj, ""),-1,itemCmd().Percents255(fanV).Cmd((fanV)?CMD_ON:CMD_OFF));
i=NULL;
if (gatesObj) i = gatesObj->child; //Pass 2: re-distribute airflow
@@ -177,7 +243,7 @@ while (i)
if (outObj && setObj && cmdObj && outObj->type==aJson_Int && setObj->type==aJson_Int && cmdObj->type==aJson_Int && V)
{
long int out = 0;
if (cmdObj->valueint != CMD_OFF && maxRequestedV)
if (cmdObj->valueint != CMD_OFF && cmdObj->valueint != -1 && maxRequestedV)
{
int requestedV=V*setObj->valueint;
out = (( long)requestedV*255L)/(( long)V)*( long)maxV/( long)maxRequestedV;

View File

@@ -167,7 +167,7 @@ if (store && store->pid && (Status() == CST_INITIALIZED) && item && (item->getCm
//itemCmd st;
//st.loadItem(item);
//short cmd = st.getCmd();
if (item->getCmd() != CMD_OFF)
if (item->getCmd() != CMD_OFF && item->getCmd() != CMD_DISABLE)
{
if(store->pid->Compute() )
{
@@ -337,7 +337,15 @@ case S_CMD:
executeCommand(oCmd,-1,value);
return 1;
case CMD_ENABLE:
item->setCmd(CMD_ENABLE);
item->SendStatus(SEND_COMMAND);
return 1;
case CMD_DISABLE:
item->setCmd(CMD_DISABLE);
item->SendStatus(SEND_COMMAND);
return 1;
/*
case CMD_OFF:
{

View File

@@ -173,6 +173,17 @@ case S_SET:
item->setExt(0);
relay(false);
}
} else //not execute
{
switch (item->getCmd())
{
case CMD_AUTO:
case CMD_ON:
case CMD_COOL:
case CMD_DRY:
case CMD_HEAT:
if (cmd.getPercents255() && !item->getExt()) item->setExt(millisNZ());
}
}
return 1;
case S_CMD: