Termostat refactoring

All Sensors (1-w, DHT, HDC, CCS):unified transfer measurements
to mqtt/local items
This commit is contained in:
2021-03-11 15:08:43 +03:00
parent 8b0ba44445
commit a444ef9b31
22 changed files with 29835 additions and 29580 deletions

View File

@@ -473,12 +473,25 @@ void Input::dht22Poll() {
float temp = dht.readTemperature();
float humidity = dht.readHumidity();
#endif
debugSerial << F("IN:") << pin << F(" DHT22 type. T=") << temp << F("°C H=") << humidity << F("%")<<endl;
// New tyle unified activities
aJsonObject *actT = aJson.getObjectItem(inputObj, "temp");
aJsonObject *actH = aJson.getObjectItem(inputObj, "hum");
executeCommand(actT,-1,itemCmd(temp));
executeCommand(actH,-1,itemCmd(humidity));
//Legacy action conf - TODO - remove in further releases
aJsonObject *emit = aJson.getObjectItem(inputObj, "emit");
aJsonObject *item = aJson.getObjectItem(inputObj, "item");
if (item && item->type == aJson_String) thermoSetCurTemp(item->valuestring, temp);
debugSerial << F("IN:") << pin << F(" DHT22 type. T=") << temp << F("°C H=") << humidity << F("%")<<endl;
//aJsonObject *item = aJson.getObjectItem(inputObj, "item");
//if (item && item->type == aJson_String) thermoSetCurTemp(item->valuestring, temp);
if (emit && emit->type == aJson_String && temp && humidity && temp == temp && humidity == humidity) {
char addrstr[MQTT_TOPIC_LENGTH] = "";
#ifdef WITH_DOMOTICZ
if(getIdxField()){
publishDataToDomoticz(DHT_POLL_DELAY_DEFAULT, emit, "{\"idx\":%s,\"svalue\":\"%.1f;%.0f;0\"}", getIdxField(), temp, humidity);
@@ -498,99 +511,10 @@ void Input::dht22Poll() {
if (mqttClient.connected() && !ethernetIdleCount)
mqttClient.publish(addrstr, valstr);
//setNextPollTime(millis() + DHT_POLL_DELAY_DEFAULT);
// debugSerial << F(" NextPollMillis=") << nextPollTime() << endl;
}
//else
// setNextPollTime(millis() + DHT_POLL_DELAY_DEFAULT / 3);
setNextPollTime(millis());
}
#endif
/*
bool Input::executeCommand(aJsonObject* cmd, int8_t toggle, char* defCmd)
{
if (!cmd) return false;
switch (cmd->type)
{
case aJson_String: //legacy - no action
break;
case aJson_Array: //array - recursive iterate
{
configLocked++;
aJsonObject * command = cmd->child;
while (command)
{
executeCommand(command,toggle,defCmd);
command = command->next;
}
configLocked--;
}
break;
case aJson_Object:
{
aJsonObject *item = aJson.getObjectItem(cmd, "item");
aJsonObject *icmd = aJson.getObjectItem(cmd, "icmd");
aJsonObject *irev = aJson.getObjectItem(cmd, "irev");
aJsonObject *ecmd = aJson.getObjectItem(cmd, "ecmd");
aJsonObject *erev = aJson.getObjectItem(cmd, "erev");
aJsonObject *emit = aJson.getObjectItem(cmd, "emit");
char * itemCommand;
if (irev && toggle && irev->type == aJson_String) itemCommand = irev->valuestring;
else if(icmd && icmd->type == aJson_String) itemCommand = icmd->valuestring;
else itemCommand = defCmd;
char * emitCommand;
if (erev && toggle && erev->type == aJson_String) emitCommand = erev->valuestring;
else if(ecmd && ecmd->type == aJson_String) emitCommand = ecmd->valuestring;
else emitCommand = defCmd;
debugSerial << F("IN:") << (pin) << F(" : ") <<endl;
if (item) debugSerial << item->valuestring<< F(" -> ")<<itemCommand<<endl;
if (emit) debugSerial << emit->valuestring<< F(" -> ")<<emitCommand<<endl;
if (emit && emitCommand && emit->type == aJson_String) {
// *
TODO implement
#ifdef WITH_DOMOTICZ
if (getIdxField())
{ (newValue) ? publishDataToDomoticz(0, emit, "{\"command\":\"switchlight\",\"idx\":%s,\"switchcmd\":\"On\"}",
: publishDataToDomoticz(0,emit,"{\"command\":\"switchlight\",\"idx\":%s,\"switchcmd\":\"Off\"}",getIdxField()); getIdxField())
: publishDataToDomoticz(0, emit,
"{\"command\":\"switchlight\",\"idx\":%s,\"switchcmd\":\"Off\"}",
getIdxField());
} else
#endif
* //
{
char addrstr[MQTT_TOPIC_LENGTH];
strncpy(addrstr,emit->valuestring,sizeof(addrstr));
if (mqttClient.connected() && !ethernetIdleCount)
{
if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring);
mqttClient.publish(addrstr, emitCommand , true);
}
}
} // emit
if (item && itemCommand && item->type == aJson_String) {
//debugSerial <<F("Controlled item:")<< item->valuestring <<endl;
Item it(item->valuestring);
if (it.isValid()) it.Ctrl(itemCommand, true);
}
return true;
}
default:
return false;
} //switch type
return false;
}
*/
// TODO Polling via timed interrupt with CHECK_INTERRUPT cause
bool Input::changeState(uint8_t newState, short cause)
@@ -1032,6 +956,12 @@ if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestri
void Input::onAnalogChanged(float newValue) {
debugSerial << F("IN:") << (pin) << F("=") << newValue << endl;
// New tyle unified activities
aJsonObject *act = aJson.getObjectItem(inputObj, "act");
executeCommand(act,-1,itemCmd(newValue));
// Legacy
aJsonObject *item = aJson.getObjectItem(inputObj, "item");
aJsonObject *emit = aJson.getObjectItem(inputObj, "emit");

View File

@@ -747,7 +747,7 @@ int Item::Ctrl(itemCmd cmd, char* subItem)
break;
case S_VAL:
st.assignFrom(cmd);
st=cmd;
break;
case S_SAT:
@@ -899,7 +899,24 @@ switch (itemType) {
}
case CH_THERMO:
///thermoSet(name,cmd,Par1); all activities done - update temp & cmd
switch (suffixCode)
{
case S_VAL:
//S_NOTFOUND:
{
thermostatStore tStore;
tStore.asint=getExt();
if (!tStore.timestamp16) mqttClient.publish("/alarmoff/snsr", itemArr->name);
tStore.tempX100=st.getFloat()*100.; //Save measurement
tStore.timestamp16=millisNZ(8) & 0xFFFF; //And timestamp
debugSerial<<F(" T:")<<F(":")<<tStore.tempX100<<F(" TS:")<<tStore.timestamp16<<endl;
setExt(tStore.asint);
}
break;
case S_SET:
st.saveItem(this);
break;
}
break;
@@ -941,8 +958,8 @@ return 1;
void printActiveStatus(bool active)
{
if (active) debugSerial<<F(" active\n");
else debugSerial<<F(" inactive\n");
if (active) debugSerial<<F(" active ");
else debugSerial<<F(" inactive ");
}
int Item::isActive() {
@@ -996,13 +1013,13 @@ int Item::isActive() {
Item it(i->valuestring);
if (it.isValid() && it.isActive()>0) {
debugSerial<<F(" active\n");
printActiveStatus(true);
return 1;
}
}
i = i->next;
} //while
debugSerial<<F(" inactive\n");
printActiveStatus(false);
return 0;
} //if
break;
@@ -1033,40 +1050,6 @@ int Item::isActive() {
}
/*
short thermoSet(char * name, short cmd, short t)
{
if (items)
{
aJsonObject *item= aJson.getObjectItem(items, name);
if (item && (item->type==aJson_Array) && (aJson.getArrayItem(item, I_TYPE)->valueint==CH_THERMO))
{
for (int i=aJson.getArraySize(item);i<4;i++) aJson.addItemToArray(item,aJson.createItem(int(0))); //Enlarge item to 4 elements
if (!cmd) aJson.getArrayItem(item, I_VAL)->valueint=t;
aJson.getArrayItem(item, I_CMD)->valueint=cmd;
}
}
}
void PooledItem::Idle()
{
if (PoolingInterval)
{
Pool();
next=millis()+PoolingInterval;
}
};
addr 10d
Снять аварию 42001 (2001=7d1) =>4

View File

@@ -156,3 +156,13 @@ class Item
int defaultSuffixCode;
};
typedef union
{
struct
{
int16_t tempX100;
uint16_t timestamp16;
};
int32_t asint;
} thermostatStore;

View File

@@ -342,8 +342,14 @@ itemCmd itemCmd::assignFrom(itemCmd from)
param.v=map(from.param.v,0,255,0,100);
break;
case ST_FLOAT:
param.v = (int) from.param.asfloat;
break;
if (cmd.itemArgType == ST_HSV)
param.v = constrain(from.param.asfloat,0,100);
else
{
param=from.param;
cmd.itemArgType=from.cmd.itemArgType;
}
break;
default:
debugSerial<<F("Wrong Assignment ")<<from.cmd.itemArgType<<F("->")<<cmd.itemArgType<<endl;
}
@@ -378,6 +384,15 @@ itemCmd itemCmd::assignFrom(itemCmd from)
case ST_PERCENTS255:
param.v=from.param.v;
break;
case ST_FLOAT:
if (cmd.itemArgType == ST_HSV255)
param.v = constrain(map(from.param.asfloat,0,100,0,255),0,255);
else
{
param=from.param;
cmd.itemArgType=from.cmd.itemArgType;
}
break;
default:
debugSerial<<F("Wrong Assignment ")<<from.cmd.itemArgType<<F("->")<<cmd.itemArgType<<endl;
}
@@ -420,6 +435,13 @@ itemCmd itemCmd::assignFrom(itemCmd from)
cmd.itemArgType=from.cmd.itemArgType;
param.asfloat=from.param.asfloat;
break;
case ST_HSV255:
case ST_HSV:
case ST_RGB:
case ST_RGBW:
cmd.itemArgType=from.cmd.itemArgType;
param=from.param;
break;
default:
debugSerial<<F("Wrong Assignment ")<<from.cmd.itemArgType<<F("->")<<cmd.itemArgType<<endl;
}
@@ -605,7 +627,7 @@ long int itemCmd::getInt()
case ST_UINT32:
case ST_RGB:
case ST_RGBW:
case ST_TENS:
return param.aslong;
case ST_PERCENTS:
@@ -618,6 +640,9 @@ long int itemCmd::getInt()
case ST_FLOAT_CELSIUS:
case ST_FLOAT_FARENHEIT:
return param.asfloat;
case ST_TENS:
return param.aslong/10;
default:
@@ -677,7 +702,12 @@ short itemCmd::getPercents(bool inverse)
case ST_FLOAT:
if (inverse) return param.asfloat;
else return 100-param.asfloat;
else return 100-param.asfloat;
case ST_TENS:
if (inverse) return param.asInt32/10;
else return 100-param.asInt32/10;
default:
return 0;
@@ -690,17 +720,22 @@ short itemCmd::getPercents255(bool inverse)
case ST_PERCENTS:
case ST_HSV:
if (inverse) return map(param.v,0,100,255,0);
if (inverse) return map(param.v,0,100,255,0);
else return map(param.v,0,100,0,255);
case ST_PERCENTS255:
case ST_HSV255:
if (inverse) return 255-param.v; else return param.v;
if (inverse) return 255-param.v; else return param.v;
case ST_FLOAT:
if (inverse) return map(param.asfloat,0,100,255,0);
else return map(param.asfloat,0,100,0,255);
case ST_TENS:
if (inverse) return map(param.asInt32,0,1000,255,0);
else return map(param.asInt32,0,1000,0,255);
default:
return 0;
}

View File

@@ -2097,6 +2097,90 @@ configLocked--;
}//if
}
void thermoRelay(int pin, bool on)
{
int thermoPin = abs(pin);
pinMode(thermoPin, OUTPUT);
if (on)
{
digitalWrite(thermoPin, (pin<0)?LOW:HIGH);
debugSerial<<F(" ON")<<endl;
}
else
{
digitalWrite(thermoPin, (pin<0)?HIGH:LOW);
debugSerial<<F(" OFF")<<endl;
}
}
void thermoLoop(void) {
if (!isTimeOver(timerThermostatCheck,millis(),THERMOSTAT_CHECK_PERIOD))
return;
if (!items) return;
bool thermostatCheckPrinted = false;
configLocked++;
for (aJsonObject *thermoItem = items->child; thermoItem; thermoItem = thermoItem->next) {
if ((thermoItem->type == aJson_Array) && (aJson.getArrayItem(thermoItem, I_TYPE)->valueint == CH_THERMO))
{
Item thermostat(thermoItem); //Init Item
if (!thermostat.isValid()) continue;
itemCmd thermostatCmd(&thermostat); // Got itemCmd
thermostatStore tStore;
tStore.asint=thermostat.getExt();
int thermoPin = thermostat.getArg(0);
float thermoSetting = thermostatCmd.getFloat();
int thermoStateCommand = thermostat.getCmd();
float curTemp = (float) tStore.tempX100/100.;
bool active = thermostat.isActive();
debugSerial << F(" Set:") << thermoSetting << F(" Cur:") << curTemp
<< F(" cmd:") << thermoStateCommand;
if (tStore.timestamp16) //Valid temperature
{
if (isTimeOver(tStore.timestamp16,millisNZ(8) & 0xFFFF,PERIOD_THERMOSTAT_FAILED,0xFFFF))
{
errorSerial<<thermoItem->name<<F(" Alarm Expired\n");
mqttClient.publish("/alarm/snsr", thermoItem->name);
tStore.timestamp16=0; //Stop termostat
thermostat.setExt(tStore.asint);
thermoRelay(thermoPin,false);
}
else
{ // Not expired yet
if (curTemp > THERMO_OVERHEAT_CELSIUS) mqttClient.publish("/alarm/ovrht", thermoItem->name);
if (!active) thermoRelay(thermoPin,false);//OFF
else if (curTemp < thermoSetting - THERMO_GIST_CELSIUS) thermoRelay(thermoPin,true);//ON
else if (curTemp >= thermoSetting) thermoRelay(thermoPin,false);//OFF
else debugSerial<<F(" -target zone-")<<endl; // Nothing to do
}
}
else debugSerial<<F(" Expired\n");
thermostatCheckPrinted = true;
} //item is termostat
} //for
configLocked--;
timerThermostatCheck = millis();// + THERMOSTAT_CHECK_PERIOD;
publishStat();
#ifndef DISABLE_FREERAM_PRINT
(thermostatCheckPrinted) ? debugSerial<<F("\nRAM=")<<freeRam()<<" " : debugSerial<<F(" ")<<freeRam()<<F(" ");
#endif
}
/*
bool isThermostatWithMinArraySize(aJsonObject *item, int minimalArraySize) {
return (item->type == aJson_Array) && (aJson.getArrayItem(item, I_TYPE)->valueint == CH_THERMO) &&
(aJson.getArraySize(item) >= minimalArraySize);
@@ -2115,6 +2199,9 @@ bool thermoDisabledOrDisconnected(aJsonObject *thermoExtensionArray, int thermoS
}
//TODO: refactoring
void thermoLoop(void) {
// if (millis() < timerThermostatCheck)
@@ -2215,3 +2302,4 @@ short thermoSetCurTemp(char *name, float t) {
}
return 1;}
return 0;}
*/

View File

@@ -113,6 +113,12 @@ if (reg!=0xff)
M5.Lcd.print("%\n");
#endif
// New tyle unified activities
aJsonObject *actT = aJson.getObjectItem(in->inputObj, "temp");
aJsonObject *actH = aJson.getObjectItem(in->inputObj, "hum");
executeCommand(actT,-1,itemCmd(t));
executeCommand(actH,-1,itemCmd(h));
publish(t,"/T");
publish(h,"/H");
if (CCS811ready) ccs811.setEnvironmentalData(h,t);
@@ -165,6 +171,13 @@ int in_ccs811::Poll(short cause)
if (co2<10000.) //Spontaneous calculation error suppress
{
// New tyle unified activities
aJsonObject *actCO2 = aJson.getObjectItem(in->inputObj, "co2");
aJsonObject *actTVOC = aJson.getObjectItem(in->inputObj, "tvoc");
executeCommand(actCO2,-1,itemCmd(co2));
executeCommand(actTVOC,-1,itemCmd(tvoc));
publish(co2,"/CO2");
publish(tvoc,"/TVOC");
publish(ccs811Baseline,"/base");}

View File

@@ -37,10 +37,11 @@
#define TIMEOUT_REINIT 5000UL
#define TIMEOUT_RETAIN 5000UL
#define INTERVAL_1W 5000UL
#define PERIOD_THERMOSTAT_FAILED (300 * 1000UL)>>8
#define T_ATTEMPTS 200
#define IET_TEMP 0
#define IET_ATTEMPTS 1
//#define T_ATTEMPTS 200
//#define IET_TEMP 0
//#define IET_ATTEMPTS 1
#define THERMO_GIST_CELSIUS 1.
#define THERMO_OVERHEAT_CELSIUS 38.

View File

@@ -642,9 +642,9 @@ itemCmd mapInt(int32_t arg, aJsonObject* map)
return _itemCmd.Int(arg);
}
unsigned long millisNZ()
unsigned long millisNZ(uint8_t shift)
{
unsigned long now = millis();
unsigned long now = millis()>>shift;
if (!now) now=1;
return now;
}

View File

@@ -65,4 +65,4 @@ bool isTimeOver(uint32_t timestamp, uint32_t currTime, uint32_t time, uint32_t m
bool executeCommand(aJsonObject* cmd, int8_t toggle = -1);
bool executeCommand(aJsonObject* cmd, int8_t toggle, itemCmd _itemCmd);
itemCmd mapInt(int32_t arg, aJsonObject* map);
unsigned long millisNZ();
unsigned long millisNZ(uint8_t shift=0);