Implemented mechanism for thermostat hysteresis. Need to build UI.
This commit is contained in:
parent
220657956f
commit
2fc020ae6c
|
@ -770,7 +770,6 @@ void loop()
|
||||||
DS18B20holdoff = 2;
|
DS18B20holdoff = 2;
|
||||||
fFilteredTemperature = -100;
|
fFilteredTemperature = -100;
|
||||||
}
|
}
|
||||||
DefaultBTCParams.setTemperature_Actual((unsigned char)(fFilteredTemperature + 0.5)); // update [BTC] frame to send
|
|
||||||
// Added DISABLE INTERRUPTS to test for parasitic fix.
|
// Added DISABLE INTERRUPTS to test for parasitic fix.
|
||||||
// portDISABLE_INTERRUPTS();
|
// portDISABLE_INTERRUPTS();
|
||||||
TempSensor.requestTemperatures(); // prep sensor for future reading
|
TempSensor.requestTemperatures(); // prep sensor for future reading
|
||||||
|
@ -891,7 +890,7 @@ int getSetTemp()
|
||||||
|
|
||||||
bool reqThermoToggle()
|
bool reqThermoToggle()
|
||||||
{
|
{
|
||||||
return setThermostatMode(getThermostatMode() ? 0 : 1);
|
return setThermostatMode(getThermostatModeActive() ? 0 : 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setThermostatMode(unsigned char val)
|
bool setThermostatMode(unsigned char val)
|
||||||
|
@ -904,9 +903,14 @@ bool setThermostatMode(unsigned char val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool getThermostatMode()
|
bool getThermostatModeActive()
|
||||||
{
|
{
|
||||||
|
if(bHasOEMController) {
|
||||||
|
return getHeaterInfo().isThermostat();
|
||||||
|
}
|
||||||
|
else {
|
||||||
return NVstore.getThermostatMode() != 0;
|
return NVstore.getThermostatMode() != 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void checkDisplayUpdate()
|
void checkDisplayUpdate()
|
||||||
|
@ -932,7 +936,17 @@ void reqPumpPrime(bool on)
|
||||||
DefaultBTCParams.setPump_Prime(on);
|
DefaultBTCParams.setPump_Prime(on);
|
||||||
}
|
}
|
||||||
|
|
||||||
float getActualTemperature()
|
float getTemperatureDesired()
|
||||||
|
{
|
||||||
|
if(bHasOEMController) {
|
||||||
|
return getHeaterInfo().getTemperature_Desired();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return NVstore.getDesiredTemperature();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float getTemperatureSensor()
|
||||||
{
|
{
|
||||||
return fFilteredTemperature;
|
return fFilteredTemperature;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ CBasicScreen::show()
|
||||||
char msg[20];
|
char msg[20];
|
||||||
int xPos, yPos;
|
int xPos, yPos;
|
||||||
|
|
||||||
float fTemp = getActualTemperature();
|
float fTemp = getTemperatureSensor();
|
||||||
if(fTemp > -80) {
|
if(fTemp > -80) {
|
||||||
if(NVstore.getDegFMode()) {
|
if(NVstore.getDegFMode()) {
|
||||||
fTemp = fTemp * 9 / 5 + 32;
|
fTemp = fTemp * 9 / 5 + 32;
|
||||||
|
@ -110,8 +110,8 @@ CBasicScreen::show()
|
||||||
long tDelta = millis() - _showSetMode;
|
long tDelta = millis() - _showSetMode;
|
||||||
if(tDelta < 0) {
|
if(tDelta < 0) {
|
||||||
// Show current heat demand setting
|
// Show current heat demand setting
|
||||||
if(getHeaterInfo().isThermostat()) {
|
if(getThermostatModeActive()) {
|
||||||
float fTemp = getHeaterInfo().getTemperature_Desired();
|
float fTemp = getTemperatureDesired();
|
||||||
if(NVstore.getDegFMode()) {
|
if(NVstore.getDegFMode()) {
|
||||||
fTemp = fTemp * 9 / 5 + 32;
|
fTemp = fTemp * 9 / 5 + 32;
|
||||||
sprintf(msg, "Setpoint = %.0f`F", fTemp);
|
sprintf(msg, "Setpoint = %.0f`F", fTemp);
|
||||||
|
@ -191,7 +191,7 @@ CBasicScreen::keyHandler(uint8_t event)
|
||||||
if(repeatCount > 2) {
|
if(repeatCount > 2) {
|
||||||
repeatCount = -1; // prevent double handling
|
repeatCount = -1; // prevent double handling
|
||||||
_showMode = millis() + 5000;
|
_showMode = millis() + 5000;
|
||||||
_nModeSel = getHeaterInfo().isThermostat() ? 0 : 1;
|
_nModeSel = getThermostatModeActive() ? 0 : 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// hold UP to toggle degC/degF mode selection
|
// hold UP to toggle degC/degF mode selection
|
||||||
|
|
|
@ -79,7 +79,7 @@ CDetailedScreen::show()
|
||||||
{
|
{
|
||||||
CScreenHeader::show();
|
CScreenHeader::show();
|
||||||
|
|
||||||
const char* c = String(getActualTemperature()).c_str();
|
const char* c = String(getTemperatureSensor()).c_str();
|
||||||
|
|
||||||
int runstate = getHeaterInfo().getRunState();//HtrFrame.getRunState();
|
int runstate = getHeaterInfo().getRunState();//HtrFrame.getRunState();
|
||||||
int errstate = getHeaterInfo().getErrState(); //HtrFrame.getErrState();
|
int errstate = getHeaterInfo().getErrState(); //HtrFrame.getErrState();
|
||||||
|
@ -92,13 +92,13 @@ CDetailedScreen::show()
|
||||||
|
|
||||||
float desiredT = 0;
|
float desiredT = 0;
|
||||||
if((runstate && (runstate <= 5)) || _showTarget) {
|
if((runstate && (runstate <= 5)) || _showTarget) {
|
||||||
if(getHeaterInfo().isThermostat())
|
if(getThermostatModeActive())
|
||||||
desiredT = getHeaterInfo().getTemperature_Desired();
|
desiredT = getHeaterInfo().getTemperature_Desired();
|
||||||
else
|
else
|
||||||
desiredT = -getHeaterInfo().getPump_Fixed();
|
desiredT = -getHeaterInfo().getPump_Fixed();
|
||||||
}
|
}
|
||||||
|
|
||||||
float fTemp = getActualTemperature();
|
float fTemp = getTemperatureSensor();
|
||||||
showThermometer(desiredT, // read values from most recently sent [BTC] frame
|
showThermometer(desiredT, // read values from most recently sent [BTC] frame
|
||||||
fTemp);
|
fTemp);
|
||||||
|
|
||||||
|
|
|
@ -310,11 +310,9 @@ CProtocol::DebugReport(const char* hdr, const char* ftr)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CProtocol::setThermostatMode(unsigned on)
|
CProtocol::setThermostatModeProtocol(unsigned on)
|
||||||
{
|
{
|
||||||
Controller.OperatingMode = on ? 0x32 : 0xCD;
|
Controller.OperatingMode = on ? 0x32 : 0xCD;
|
||||||
if(!on)
|
|
||||||
setTemperature_Actual(0); // if using fixed mode, actual must be reported as 0
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -183,7 +183,7 @@ public:
|
||||||
unsigned char getTemperature_Min() const { return Controller.MinTemperature; };
|
unsigned char getTemperature_Min() const { return Controller.MinTemperature; };
|
||||||
unsigned char getTemperature_Max() const { return Controller.MaxTemperature; };
|
unsigned char getTemperature_Max() const { return Controller.MaxTemperature; };
|
||||||
unsigned char getTemperature_Actual() const { return Controller.ActualTemperature; };
|
unsigned char getTemperature_Actual() const { return Controller.ActualTemperature; };
|
||||||
void setThermostatMode(unsigned on);
|
void setThermostatModeProtocol(unsigned on);
|
||||||
bool isThermostat() const { return Controller.OperatingMode == 0x32; };
|
bool isThermostat() const { return Controller.OperatingMode == 0x32; };
|
||||||
// glow plug
|
// glow plug
|
||||||
float getGlowPlug_Current() const; // glow plug current
|
float getGlowPlug_Current() const; // glow plug current
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "TxManage.h"
|
#include "TxManage.h"
|
||||||
#include "../Utility/NVStorage.h"
|
#include "../Utility/NVStorage.h"
|
||||||
|
#include "../Protocol/helpers.h"
|
||||||
|
|
||||||
extern void DebugReportFrame(const char* hdr, const CProtocol&, const char* ftr);
|
extern void DebugReportFrame(const char* hdr, const CProtocol&, const char* ftr);
|
||||||
|
|
||||||
|
@ -117,8 +118,77 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
|
||||||
m_TxFrame.setFan_Max(NVstore.getFmax());
|
m_TxFrame.setFan_Max(NVstore.getFmax());
|
||||||
m_TxFrame.setPump_Min(NVstore.getPmin());
|
m_TxFrame.setPump_Min(NVstore.getPmin());
|
||||||
m_TxFrame.setPump_Max(NVstore.getPmax());
|
m_TxFrame.setPump_Max(NVstore.getPmax());
|
||||||
m_TxFrame.setThermostatMode(NVstore.getThermostatMode());
|
|
||||||
|
float tActual = getTemperatureSensor();
|
||||||
|
uint8_t u8Temp = (uint8_t)(tActual);
|
||||||
|
m_TxFrame.setTemperature_Actual(u8Temp); // use current temp, for now
|
||||||
m_TxFrame.setTemperature_Desired(NVstore.getDesiredTemperature());
|
m_TxFrame.setTemperature_Desired(NVstore.getDesiredTemperature());
|
||||||
|
|
||||||
|
if(NVstore.getThermostatMode()) {
|
||||||
|
uint8_t ThermoMode = NVstore.getThermostatMethodMode(); // get the METHOD of thermostat control
|
||||||
|
float Hysteresis = NVstore.getThermostatMethodHysteresis();
|
||||||
|
float tCurrent = getTemperatureSensor();
|
||||||
|
float tDesired = float(NVstore.getDesiredTemperature());
|
||||||
|
float tDelta = tCurrent - tDesired;
|
||||||
|
#ifdef DEBUG_THERMOSTAT
|
||||||
|
DebugPort.print("Hysteresis = "); DebugPort.print(Hysteresis); DebugPort.print(" tCurrent = "); DebugPort.print(tCurrent); DebugPort.print(" tDesired = "); DebugPort.print(tDesired); DebugPort.print(" tDelta = "); DebugPort.println(tDelta);
|
||||||
|
#endif
|
||||||
|
switch(ThermoMode) {
|
||||||
|
case 0: // conventional heater controlled thermostat mode
|
||||||
|
m_TxFrame.setThermostatModeProtocol(1); // using heater thermostat control
|
||||||
|
u8Temp = (uint8_t)(tActual + 0.5);
|
||||||
|
m_TxFrame.setTemperature_Actual(u8Temp);
|
||||||
|
#ifdef DEBUG_THERMOSTAT
|
||||||
|
DebugPort.print("Conventional thermostat mode: tActual = "); DebugPort.println(u8Temp);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case 1: // heater controlled thermostat mode - BUT actual temp is tweaked via a changed hysteresis
|
||||||
|
m_TxFrame.setThermostatModeProtocol(1); // using heater thermostat control
|
||||||
|
u8Temp = (uint8_t)(tActual + 0.5); // use rounded actual unless within hysteresis window
|
||||||
|
if(fabs(tDelta) < Hysteresis) {
|
||||||
|
// hold at desired if inside hysteresis
|
||||||
|
u8Temp = NVstore.getDesiredTemperature();
|
||||||
|
}
|
||||||
|
else if(fabs(tDelta) <= 1.0) {
|
||||||
|
// force outside if delta is <= 1 but greater than hysteresis
|
||||||
|
u8Temp = NVstore.getDesiredTemperature() + ((tDelta > 0) ? 1 : -1);
|
||||||
|
}
|
||||||
|
m_TxFrame.setTemperature_Actual(u8Temp);
|
||||||
|
#ifdef DEBUG_THERMOSTAT
|
||||||
|
DebugPort.print("Heater hysteresis thermostat mode: tActual = "); DebugPort.println(u8Temp);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case 2: // BTC controlled thermostat mode
|
||||||
|
// map Hysteresis to a Hz value,
|
||||||
|
// Hz mode however uses the desired temperature field, somewhere between 8 - 35 for min/max
|
||||||
|
// so create a desired "temp" according the the current hystersis
|
||||||
|
tDelta /= Hysteresis; // convert tDelta to fraction of hysteresis (CAUTION - may be > +-1 !)
|
||||||
|
#ifdef DEBUG_THERMOSTAT
|
||||||
|
DebugPort.print("Controller hysteresis thermostat mode: Fraction = "); DebugPort.print(tDelta);
|
||||||
|
#endif
|
||||||
|
Hysteresis = (m_TxFrame.getTemperature_Max() + m_TxFrame.getTemperature_Min()) * 0.5; // midpoint - tDelta = 0 hinges here
|
||||||
|
tDelta *= (m_TxFrame.getTemperature_Max() - Hysteresis); // linear offset from setpoint
|
||||||
|
Hysteresis -= tDelta; // lower Hz when over temp, higher Hz when under!
|
||||||
|
// bounds limit - recall original tDelta was NOT managed prior!
|
||||||
|
LOWERLIMIT(Hysteresis, m_TxFrame.getTemperature_Min());
|
||||||
|
UPPERLIMIT(Hysteresis, m_TxFrame.getTemperature_Max());
|
||||||
|
// apply modifed desired temperature (works in conjunction with thermostatmode = 0!)
|
||||||
|
u8Temp = (uint8_t)(Hysteresis + 0.5);
|
||||||
|
m_TxFrame.setTemperature_Desired(u8Temp);
|
||||||
|
m_TxFrame.setThermostatModeProtocol(0); // direct heater to use Hz Mode
|
||||||
|
m_TxFrame.setTemperature_Actual(0); // must force actual to 0 for Hz mode
|
||||||
|
#ifdef DEBUG_THERMOSTAT
|
||||||
|
DebugPort.print(" tDesired (pseudo Hz demand) = "); DebugPort.println(u8Temp);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_TxFrame.setThermostatModeProtocol(0); // not using any form of thermostat control
|
||||||
|
m_TxFrame.setTemperature_Actual(0); // must force actual to 0 for Hz mode
|
||||||
|
}
|
||||||
|
// m_TxFrame.setThermostatMode(NVstore.getThermostatMode());
|
||||||
|
|
||||||
m_TxFrame.Controller.OperatingVoltage = NVstore.getSysVoltage();
|
m_TxFrame.Controller.OperatingVoltage = NVstore.getSysVoltage();
|
||||||
m_TxFrame.Controller.FanSensor = NVstore.getFanSensor();
|
m_TxFrame.Controller.FanSensor = NVstore.getFanSensor();
|
||||||
m_TxFrame.Controller.GlowDrive = NVstore.getGlowDrive();
|
m_TxFrame.Controller.GlowDrive = NVstore.getGlowDrive();
|
||||||
|
|
|
@ -30,8 +30,10 @@ extern bool reqTempDelta(int delta);
|
||||||
extern bool reqTemp(unsigned char newTemp);
|
extern bool reqTemp(unsigned char newTemp);
|
||||||
extern bool reqThermoToggle();
|
extern bool reqThermoToggle();
|
||||||
extern bool setThermostatMode(unsigned char);
|
extern bool setThermostatMode(unsigned char);
|
||||||
|
extern bool getThermostatModeActive(); // OEM: actual mode from blue wire, BTC: or our NV
|
||||||
extern void reqPumpPrime(bool on);
|
extern void reqPumpPrime(bool on);
|
||||||
extern float getActualTemperature();
|
float getTemperatureDesired(); // OEM: the advertised value, BTC our setpoint
|
||||||
|
extern float getTemperatureSensor();
|
||||||
extern int getSetTemp();
|
extern int getSetTemp();
|
||||||
extern void setPumpMin(float);
|
extern void setPumpMin(float);
|
||||||
extern void setPumpMax(float);
|
extern void setPumpMax(float);
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include "BTCDateTime.h"
|
#include "BTCDateTime.h"
|
||||||
|
|
||||||
|
|
||||||
void decodeTimerDays(const char* ipStr)
|
void decodeJSONTimerDays(const char* ipStr)
|
||||||
{
|
{
|
||||||
char dayInfo[32];
|
char dayInfo[32];
|
||||||
int timerIdx;
|
int timerIdx;
|
||||||
|
@ -53,7 +53,7 @@ void decodeTimerDays(const char* ipStr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void decodeTimerTime(int stop, const char* ipStr)
|
void decodeJSONTimerTime(int stop, const char* ipStr)
|
||||||
{
|
{
|
||||||
int hour, min;
|
int hour, min;
|
||||||
int timerIdx;
|
int timerIdx;
|
||||||
|
@ -75,7 +75,7 @@ void decodeTimerTime(int stop, const char* ipStr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decodeTimerNumeric(int valID, const char* ipStr)
|
void decodeJSONTimerNumeric(int valID, const char* ipStr)
|
||||||
{
|
{
|
||||||
int value;
|
int value;
|
||||||
int timerIdx;
|
int timerIdx;
|
||||||
|
|
|
@ -81,8 +81,8 @@ struct sTimer {
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* getTimerJSONStr(int timer, int param);
|
const char* getTimerJSONStr(int timer, int param);
|
||||||
void decodeTimerDays(const char* str);
|
void decodeJSONTimerDays(const char* str);
|
||||||
void decodeTimerTime(int stop, const char*);
|
void decodeJSONTimerTime(int stop, const char*);
|
||||||
void decodeTimerNumeric(int repeat, const char*);
|
void decodeJSONTimerNumeric(int repeat, const char*);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -115,22 +115,22 @@ void interpretJsonCommand(char* pLine)
|
||||||
}
|
}
|
||||||
else if(strcmp("TimerDays", it->key) == 0) {
|
else if(strcmp("TimerDays", it->key) == 0) {
|
||||||
// value encoded as "ID Days,Days"
|
// value encoded as "ID Days,Days"
|
||||||
decodeTimerDays(it->value.as<const char*>());
|
decodeJSONTimerDays(it->value.as<const char*>());
|
||||||
}
|
}
|
||||||
else if(strcmp("TimerStart", it->key) == 0) {
|
else if(strcmp("TimerStart", it->key) == 0) {
|
||||||
// value encoded as "ID HH:MM"
|
// value encoded as "ID HH:MM"
|
||||||
decodeTimerTime(0, it->value.as<const char*>());
|
decodeJSONTimerTime(0, it->value.as<const char*>());
|
||||||
}
|
}
|
||||||
else if(strcmp("TimerStop", it->key) == 0) {
|
else if(strcmp("TimerStop", it->key) == 0) {
|
||||||
// value encoded as "ID HH:MM"
|
// value encoded as "ID HH:MM"
|
||||||
decodeTimerTime(1, it->value.as<const char*>());
|
decodeJSONTimerTime(1, it->value.as<const char*>());
|
||||||
}
|
}
|
||||||
else if(strcmp("TimerRepeat", it->key) == 0) {
|
else if(strcmp("TimerRepeat", it->key) == 0) {
|
||||||
// value encoded as "ID val"
|
// value encoded as "ID val"
|
||||||
decodeTimerNumeric(0, it->value.as<const char*>());
|
decodeJSONTimerNumeric(0, it->value.as<const char*>());
|
||||||
}
|
}
|
||||||
else if(strcmp("TimerTemp", it->key) == 0) {
|
else if(strcmp("TimerTemp", it->key) == 0) {
|
||||||
decodeTimerNumeric(1, it->value.as<const char*>());
|
decodeJSONTimerNumeric(1, it->value.as<const char*>());
|
||||||
}
|
}
|
||||||
else if(strcmp("TimerConflict", it->key) == 0) {
|
else if(strcmp("TimerConflict", it->key) == 0) {
|
||||||
validateTimer(it->value.as<int>());
|
validateTimer(it->value.as<int>());
|
||||||
|
@ -152,22 +152,22 @@ void validateTimer(int ID)
|
||||||
|
|
||||||
timerConflict = CTimerManager::conflictTest(ID); // check targeted timer against other timers
|
timerConflict = CTimerManager::conflictTest(ID); // check targeted timer against other timers
|
||||||
|
|
||||||
TimerModerator.reset(ID); // ensure we fully update client with our understanding of selected timer
|
TimerModerator.reset(ID); // ensure we update client with our (real) version of the selected timer
|
||||||
}
|
}
|
||||||
|
|
||||||
bool makeJsonString(CModerator& moderator, char* opStr, int len)
|
bool makeJSONString(CModerator& moderator, char* opStr, int len)
|
||||||
{
|
{
|
||||||
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
||||||
|
|
||||||
bool bSend = false; // reset should send flag
|
bool bSend = false; // reset should send flag
|
||||||
|
|
||||||
float tidyTemp = getActualTemperature();
|
float tidyTemp = getTemperatureSensor();
|
||||||
tidyTemp = int(tidyTemp * 10) * 0.1f; // round to 0.1 resolution
|
tidyTemp = int(tidyTemp * 10) * 0.1f; // round to 0.1 resolution
|
||||||
if(tidyTemp > -80) {
|
if(tidyTemp > -80) {
|
||||||
bSend |= moderator.addJson("TempCurrent", tidyTemp, root);
|
bSend |= moderator.addJson("TempCurrent", tidyTemp, root);
|
||||||
}
|
}
|
||||||
bSend |= moderator.addJson("TempDesired", getHeaterInfo().getTemperature_Desired(), root);
|
bSend |= moderator.addJson("TempDesired", getTemperatureDesired(), root);
|
||||||
bSend |= moderator.addJson("TempMin", getHeaterInfo().getTemperature_Min(), root);
|
bSend |= moderator.addJson("TempMin", getHeaterInfo().getTemperature_Min(), root);
|
||||||
bSend |= moderator.addJson("TempMax", getHeaterInfo().getTemperature_Max(), root);
|
bSend |= moderator.addJson("TempMax", getHeaterInfo().getTemperature_Max(), root);
|
||||||
bSend |= moderator.addJson("TempBody", getHeaterInfo().getTemperature_HeatExchg(), root);
|
bSend |= moderator.addJson("TempBody", getHeaterInfo().getTemperature_HeatExchg(), root);
|
||||||
|
@ -175,7 +175,7 @@ bool makeJsonString(CModerator& moderator, char* opStr, int len)
|
||||||
bSend |= moderator.addJson("RunString", getHeaterInfo().getRunStateStr(), root); // verbose it up!
|
bSend |= moderator.addJson("RunString", getHeaterInfo().getRunStateStr(), root); // verbose it up!
|
||||||
bSend |= moderator.addJson("ErrorState", getHeaterInfo().getErrState(), root );
|
bSend |= moderator.addJson("ErrorState", getHeaterInfo().getErrState(), root );
|
||||||
bSend |= moderator.addJson("ErrorString", getHeaterInfo().getErrStateStrEx(), root); // verbose it up!
|
bSend |= moderator.addJson("ErrorString", getHeaterInfo().getErrStateStrEx(), root); // verbose it up!
|
||||||
bSend |= moderator.addJson("Thermostat", getHeaterInfo().isThermostat(), root );
|
bSend |= moderator.addJson("Thermostat", getThermostatModeActive(), root );
|
||||||
bSend |= moderator.addJson("PumpFixed", getHeaterInfo().getPump_Fixed(), root );
|
bSend |= moderator.addJson("PumpFixed", getHeaterInfo().getPump_Fixed(), root );
|
||||||
bSend |= moderator.addJson("PumpMin", getHeaterInfo().getPump_Min(), root );
|
bSend |= moderator.addJson("PumpMin", getHeaterInfo().getPump_Min(), root );
|
||||||
bSend |= moderator.addJson("PumpMax", getHeaterInfo().getPump_Max(), root );
|
bSend |= moderator.addJson("PumpMax", getHeaterInfo().getPump_Max(), root );
|
||||||
|
@ -204,7 +204,7 @@ bool makeJsonString(CModerator& moderator, char* opStr, int len)
|
||||||
// timer
|
// timer
|
||||||
// Only timer parameters that have changed will be sent, after reset the typical string will be
|
// Only timer parameters that have changed will be sent, after reset the typical string will be
|
||||||
// {"TimerStart":XX:XX,"TimerStop":XX:XX,"TimerDays":XX,"TimerRepeat":X}
|
// {"TimerStart":XX:XX,"TimerStop":XX:XX,"TimerDays":XX,"TimerRepeat":X}
|
||||||
bool makeJsonTimerString(int channel, char* opStr, int len)
|
bool makeJSONTimerString(int channel, char* opStr, int len)
|
||||||
{
|
{
|
||||||
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
|
||||||
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
|
||||||
|
@ -229,7 +229,7 @@ void updateJSONclients(bool report)
|
||||||
// update general parameters
|
// update general parameters
|
||||||
char jsonStr[800];
|
char jsonStr[800];
|
||||||
{
|
{
|
||||||
if(makeJsonString(JSONmoderator, jsonStr, sizeof(jsonStr))) {
|
if(makeJSONString(JSONmoderator, jsonStr, sizeof(jsonStr))) {
|
||||||
if (report) {
|
if (report) {
|
||||||
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
|
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ void updateJSONclients(bool report)
|
||||||
bool bNewTimerInfo = false;
|
bool bNewTimerInfo = false;
|
||||||
for(int tmr=0; tmr<14; tmr++)
|
for(int tmr=0; tmr<14; tmr++)
|
||||||
{
|
{
|
||||||
if(makeJsonTimerString(tmr, jsonStr, sizeof(jsonStr))) {
|
if(makeJSONTimerString(tmr, jsonStr, sizeof(jsonStr))) {
|
||||||
if (report) {
|
if (report) {
|
||||||
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
|
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
|
|
||||||
extern char defaultJSONstr[64];
|
extern char defaultJSONstr[64];
|
||||||
|
|
||||||
bool makeJsonString(CModerator& moderator, char* opStr, int len);
|
bool makeJSONString(CModerator& moderator, char* opStr, int len);
|
||||||
bool makeJsonTimerString(int channel, char* opStr, int len);
|
bool makeJSONTimerString(int channel, char* opStr, int len);
|
||||||
void updateJSONclients(bool report);
|
void updateJSONclients(bool report);
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
|
|
|
@ -28,12 +28,14 @@ bool s8inBounds(int8_t test, int8_t minLim, int8_t maxLim);
|
||||||
bool u8Match2(uint8_t test, uint8_t test1, uint8_t test2);
|
bool u8Match2(uint8_t test, uint8_t test1, uint8_t test2);
|
||||||
bool u16inBounds(uint16_t test, uint16_t minLim, uint16_t maxLim);
|
bool u16inBounds(uint16_t test, uint16_t minLim, uint16_t maxLim);
|
||||||
bool s32inBounds(long test, long minLim, long maxLim);
|
bool s32inBounds(long test, long minLim, long maxLim);
|
||||||
|
bool thermoMethodinBounds(uint8_t test, uint8_t minLim, uint8_t maxLim);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sNVStore::valid()
|
sNVStore::valid()
|
||||||
{
|
{
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
retval &= (DimTime >= 0) && (DimTime < 300000); // 5 mins
|
retval &= (DimTime >= 0) && (DimTime < 300000); // 5 mins
|
||||||
|
retval &= (ThermostatMethod & 0x03) < 3; // only modes 0, 1 or 2
|
||||||
for(int i=0; i<2; i++) {
|
for(int i=0; i<2; i++) {
|
||||||
retval &= timer[i].valid();
|
retval &= timer[i].valid();
|
||||||
}
|
}
|
||||||
|
@ -48,6 +50,7 @@ sNVStore::init()
|
||||||
timer[i].init();
|
timer[i].init();
|
||||||
}
|
}
|
||||||
DimTime = 60000; // 1 minute
|
DimTime = 60000; // 1 minute
|
||||||
|
ThermostatMethod = 10 << 2; // 1 degree hysteresis, normal thermostat
|
||||||
Heater.init();
|
Heater.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,6 +95,18 @@ CHeaterStorage::getThermostatMode()
|
||||||
return _calValues.Heater.ThermostatMode;
|
return _calValues.Heater.ThermostatMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char
|
||||||
|
CHeaterStorage::getThermostatMethodMode()
|
||||||
|
{
|
||||||
|
return _calValues.ThermostatMethod & 0x03;
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
CHeaterStorage::getThermostatMethodHysteresis()
|
||||||
|
{
|
||||||
|
return float((_calValues.ThermostatMethod >> 2) & 0x3f) * 0.05f; // top 5 bits / 10, then / 2
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CHeaterStorage::setPmin(float val)
|
CHeaterStorage::setPmin(float val)
|
||||||
{
|
{
|
||||||
|
@ -130,6 +145,22 @@ CHeaterStorage::setThermostatMode(unsigned char val)
|
||||||
_calValues.Heater.ThermostatMode = val;
|
_calValues.Heater.ThermostatMode = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CHeaterStorage::setThermostatMethodMode(unsigned char val)
|
||||||
|
{
|
||||||
|
_calValues.ThermostatMethod &= 0xF3;
|
||||||
|
_calValues.ThermostatMethod |= (val & 0x03);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CHeaterStorage::setThermostatMethodHysteresis(float val)
|
||||||
|
{
|
||||||
|
_calValues.ThermostatMethod &= 0x03;
|
||||||
|
int nVal = int(val * 10 + 0.5);
|
||||||
|
_calValues.ThermostatMethod |= ((nVal & 0x3F) << 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CHeaterStorage::setSystemVoltage(float fVal)
|
CHeaterStorage::setSystemVoltage(float fVal)
|
||||||
{
|
{
|
||||||
|
@ -331,6 +362,8 @@ CESP32HeaterStorage::loadUI()
|
||||||
preferences.begin("user", false);
|
preferences.begin("user", false);
|
||||||
validatedLoad("dimTime", _calValues.DimTime, 60000, s32inBounds, 0, 600000);
|
validatedLoad("dimTime", _calValues.DimTime, 60000, s32inBounds, 0, 600000);
|
||||||
validatedLoad("degF", _calValues.degF, 0, u8inBounds, 0, 1);
|
validatedLoad("degF", _calValues.degF, 0, u8inBounds, 0, 1);
|
||||||
|
validatedLoad("thermoMethod", _calValues.ThermostatMethod, (10 << 2), u8inBounds, 0, 2, 0x03);
|
||||||
|
// validatedLoad("thermoMethod", _calValues.ThermostatMethod, (10 << 2) + 0, u8inBounds, 0, 2); // TESTO!!!!
|
||||||
preferences.end();
|
preferences.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,14 +373,15 @@ CESP32HeaterStorage::saveUI()
|
||||||
preferences.begin("user", false);
|
preferences.begin("user", false);
|
||||||
preferences.putULong("dimTime", _calValues.DimTime);
|
preferences.putULong("dimTime", _calValues.DimTime);
|
||||||
preferences.putUChar("degF", _calValues.degF);
|
preferences.putUChar("degF", _calValues.degF);
|
||||||
|
preferences.putUChar("thermoMethod", _calValues.ThermostatMethod);
|
||||||
preferences.end();
|
preferences.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CESP32HeaterStorage::validatedLoad(const char* key, uint8_t& val, int defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, int min, int max)
|
CESP32HeaterStorage::validatedLoad(const char* key, uint8_t& val, int defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, int min, int max, uint8_t mask)
|
||||||
{
|
{
|
||||||
val = preferences.getUChar(key, defVal);
|
val = preferences.getUChar(key, defVal);
|
||||||
if(!validator(val, min, max)) {
|
if(!validator(val & mask, min, max)) {
|
||||||
|
|
||||||
DebugPort.print("CESP32HeaterStorage::validatedLoad<uint8_t> invalid read ");
|
DebugPort.print("CESP32HeaterStorage::validatedLoad<uint8_t> invalid read ");
|
||||||
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
|
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
|
||||||
|
|
|
@ -67,6 +67,7 @@ struct sNVStore {
|
||||||
sHeater Heater;
|
sHeater Heater;
|
||||||
long DimTime;
|
long DimTime;
|
||||||
uint8_t degF;
|
uint8_t degF;
|
||||||
|
uint8_t ThermostatMethod; // 0: standard heater, 1: Narrow Hysterisis, 2:Managed Hz mode
|
||||||
sTimer timer[14];
|
sTimer timer[14];
|
||||||
bool valid();
|
bool valid();
|
||||||
void init();
|
void init();
|
||||||
|
@ -103,6 +104,8 @@ public:
|
||||||
unsigned short getFmax();
|
unsigned short getFmax();
|
||||||
unsigned char getDesiredTemperature();
|
unsigned char getDesiredTemperature();
|
||||||
unsigned char getThermostatMode();
|
unsigned char getThermostatMode();
|
||||||
|
unsigned char getThermostatMethodMode();
|
||||||
|
float getThermostatMethodHysteresis();
|
||||||
unsigned char getSysVoltage();
|
unsigned char getSysVoltage();
|
||||||
unsigned char getFanSensor();
|
unsigned char getFanSensor();
|
||||||
unsigned char getGlowDrive();
|
unsigned char getGlowDrive();
|
||||||
|
@ -115,6 +118,8 @@ public:
|
||||||
void setFmax(unsigned short val);
|
void setFmax(unsigned short val);
|
||||||
void setDesiredTemperature(unsigned char val);
|
void setDesiredTemperature(unsigned char val);
|
||||||
void setThermostatMode(unsigned char val);
|
void setThermostatMode(unsigned char val);
|
||||||
|
void setThermostatMethodMode(unsigned char val);
|
||||||
|
void setThermostatMethodHysteresis(float val);
|
||||||
void setSystemVoltage(float fVal);
|
void setSystemVoltage(float fVal);
|
||||||
void setFanSensor(unsigned char val);
|
void setFanSensor(unsigned char val);
|
||||||
void setGlowDrive(unsigned char val);
|
void setGlowDrive(unsigned char val);
|
||||||
|
@ -146,7 +151,7 @@ public:
|
||||||
void loadUI();
|
void loadUI();
|
||||||
void saveUI();
|
void saveUI();
|
||||||
bool validatedLoad(const char* key, int8_t& val, int defVal, std::function<bool(int8_t, int8_t, int8_t)> validator, int min, int max);
|
bool validatedLoad(const char* key, int8_t& val, int defVal, std::function<bool(int8_t, int8_t, int8_t)> validator, int min, int max);
|
||||||
bool validatedLoad(const char* key, uint8_t& val, int defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, int min, int max);
|
bool validatedLoad(const char* key, uint8_t& val, int defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, int min, int max, uint8_t mask=0xff);
|
||||||
bool validatedLoad(const char* key, uint16_t& val, int defVal, std::function<bool(uint16_t, uint16_t, uint16_t)> validator, int min, int max);
|
bool validatedLoad(const char* key, uint16_t& val, int defVal, std::function<bool(uint16_t, uint16_t, uint16_t)> validator, int min, int max);
|
||||||
bool validatedLoad(const char* key, long& val, long defVal, std::function<bool(long, long, long)> validator, long min, long max);
|
bool validatedLoad(const char* key, long& val, long defVal, std::function<bool(long, long, long)> validator, long min, long max);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue