mirror of
https://github.com/anklimov/lighthub
synced 2025-12-06 11:49:51 +03:00
Termostat refactoring
All Sensors (1-w, DHT, HDC, CCS):unified transfer measurements to mqtt/local items
This commit is contained in:
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.
@@ -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");
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -156,3 +156,13 @@ class Item
|
||||
int defaultSuffixCode;
|
||||
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int16_t tempX100;
|
||||
uint16_t timestamp16;
|
||||
};
|
||||
int32_t asint;
|
||||
} thermostatStore;
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;}
|
||||
*/
|
||||
@@ -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");}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user