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

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

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,7 +342,13 @@ 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;
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:
@@ -679,6 +704,11 @@ short itemCmd::getPercents(bool inverse)
if (inverse) return 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;
}
@@ -701,6 +731,11 @@ short itemCmd::getPercents255(bool inverse)
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);