Added CyclicOn, CyclicOff, CyclicTemp JSON Removed UserSettings subset setters/getters

BOUNDS checking on JSON inputs
This commit is contained in:
Ray Jones 2019-07-03 23:01:36 +10:00
parent 6d7af0e010
commit c20b309184
12 changed files with 104 additions and 112 deletions

View file

@ -116,8 +116,8 @@
#define RX_DATA_TIMOUT 50
const int FirmwareRevision = 23;
const int FirmwareSubRevision = 5;
const char* FirmwareDate = "30 Jun 2019";
const int FirmwareSubRevision = 6;
const char* FirmwareDate = "3 Jul 2019";
#ifdef ESP32
@ -766,7 +766,7 @@ void DebugReportFrame(const char* hdr, const CProtocol& Frame, const char* ftr)
void manageCyclicMode()
{
const sCyclicThermostat& cyclic = NVstore.getCyclicMode();
const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic;
if(cyclic.Stop && bUserON) { // cyclic mode enabled, and user has started heater
int stopDeltaT = cyclic.Stop + 1; // bump up by 1 degree - no point invoking at 1 deg over!
float deltaT = fFilteredTemperature - getDemandDegC();
@ -898,7 +898,8 @@ bool setThermostatMode(unsigned char val)
return false;
sUserSettings settings = NVstore.getUserSettings();
settings.useThermostat = val;
if(INBOUNDS(val, 0, 1))
settings.useThermostat = val;
NVstore.setUserSettings(settings);
return true;
}
@ -954,6 +955,14 @@ uint8_t getDemandDegC()
return demandDegC;
}
void setDemandDegC(uint8_t val)
{
unsigned char max = DefaultBTCParams.getTemperature_Max();
unsigned char min = DefaultBTCParams.getTemperature_Min();
BOUNDSLIMIT(val, min, max);
demandDegC = val;
}
uint8_t getDemandPump()
{
return demandPump;
@ -995,21 +1004,24 @@ void setPumpMax(float val)
void setFanMin(short cVal)
{
sHeaterTuning tuning = NVstore.getHeaterTuning();
tuning.Fmin = cVal;
if(INBOUNDS(cVal, 500, 5000))
tuning.Fmin = cVal;
NVstore.setHeaterTuning(tuning);
}
void setFanMax(short cVal)
{
sHeaterTuning tuning = NVstore.getHeaterTuning();
tuning.Fmax = cVal;
if(INBOUNDS(cVal, 500, 5000))
tuning.Fmax = cVal;
NVstore.setHeaterTuning(tuning);
}
void setFanSensor(unsigned char cVal)
{
sHeaterTuning tuning = NVstore.getHeaterTuning();
tuning.fanSensor = cVal;
if(INBOUNDS(cVal, 1, 2))
tuning.fanSensor = cVal;
NVstore.setHeaterTuning(tuning);
}
@ -1021,7 +1033,8 @@ void setSystemVoltage(float val) {
void setGlowDrive(unsigned char val) {
sHeaterTuning tuning = NVstore.getHeaterTuning();
tuning.glowDrive = val;
if(INBOUNDS(val, 1, 6))
tuning.glowDrive = val;
NVstore.setHeaterTuning(tuning);
}
@ -1215,7 +1228,7 @@ int getSmartError()
bool isCyclicActive()
{
return bUserON && NVstore.getCyclicMode().isEnabled();
return bUserON && NVstore.getUserSettings().cyclic.isEnabled();
}
void setupGPIO()
@ -1226,12 +1239,12 @@ void setupGPIO()
// V2.0+ PCBs use an input transistor buffer. Active state into ESP32 is HIGH (inverted).
int activePinState = (BoardRevision == 10) ? LOW : HIGH;
int Input1 = BoardRevision == 20 ? GPIOin1_pinV20 : GPIOin1_pinV21V10;
GPIOin.begin(Input1, GPIOin2_pin, NVstore.getGPIOparams().inMode, activePinState);
GPIOin.begin(Input1, GPIOin2_pin, NVstore.getUserSettings().GPIO.inMode, activePinState);
// GPIO out is always active high from ESP32
// V1.0 PCBs only expose the bare pins
// V2.0+ PCBs provide an open collector output that conducts when active
GPIOout.begin(GPIOout1_pin, GPIOout2_pin, NVstore.getGPIOparams().outMode);
GPIOout.begin(GPIOout1_pin, GPIOout2_pin, NVstore.getUserSettings().GPIO.outMode);
// ### MAJOR ISSUE WITH ADC INPUTS ###
//
@ -1247,7 +1260,7 @@ void setupGPIO()
// This will be properly fixed in V2.1 PCBs
//
// As V1.0 PCBS expose the bare pins, the correct GPIO33 input can be readily chosen.
GPIOalgModes algMode = NVstore.getGPIOparams().algMode;
GPIOalgModes algMode = NVstore.getUserSettings().GPIO.algMode;
if(BoardRevision == 20)
algMode = GPIOalgNone; // force off analogue support in V2.0 PCBs
GPIOalg.begin(GPIOalg_pin, algMode);
@ -1262,7 +1275,7 @@ void setupGPIO()
bool toggleGPIOout(int channel)
{
if(NVstore.getGPIOparams().outMode == GPIOoutUser) {
if(NVstore.getUserSettings().GPIO.outMode == GPIOoutUser) {
setGPIOout(channel, !getGPIOout(channel)); // toggle selected GPIO output
return true;
}

View file

@ -59,7 +59,7 @@ CGPIOScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
_GPIOparams = NVstore.getGPIOparams();
_GPIOparams = NVstore.getUserSettings().GPIO;
}
void
@ -176,6 +176,7 @@ CGPIOScreen::animate()
bool
CGPIOScreen::keyHandler(uint8_t event)
{
sUserSettings us;
if(event & keyPressed) {
// press LEFT to select previous screen
if(event & key_Left) {
@ -229,7 +230,9 @@ CGPIOScreen::keyHandler(uint8_t event)
break;
case 4: // confirmed save
_showStoringMessage();
NVstore.setGPIOparams(_GPIOparams);
us = NVstore.getUserSettings();
us.GPIO = _GPIOparams;
NVstore.setUserSettings(us);
saveNV();
setupGPIO();
@ -318,32 +321,32 @@ CGPIOInfoScreen::show()
_printMenuText(55, Line1, "Analogue:", false, eRightJustify);
if(NVstore.getGPIOparams().inMode == GPIOinNone) {
if(NVstore.getUserSettings().GPIO.inMode == GPIOinNone) {
_drawBitmap(7, 28, CrossLgIconInfo);
_drawBitmap(30, 28, CrossLgIconInfo);
}
else {
_drawBitmap(4, 29, GPIOin.getState(0) ? CloseIconInfo : OpenIconInfo);
if(NVstore.getGPIOparams().inMode == GPIOinOn1Off1)
if(NVstore.getUserSettings().GPIO.inMode == GPIOinOn1Off1)
_drawBitmap(30, 28, CrossLgIconInfo);
else
_drawBitmap(27, 29, GPIOin.getState(1) ? CloseIconInfo : OpenIconInfo);
}
if(NVstore.getGPIOparams().outMode == GPIOoutNone) {
if(NVstore.getUserSettings().GPIO.outMode == GPIOoutNone) {
_drawBitmap(87, 28, CrossLgIconInfo);
_drawBitmap(114, 28, CrossLgIconInfo);
}
else {
_drawBitmap(86, 29, GPIOout.getState(0) ? BulbOnIconInfo : BulbOffIconInfo);
if(NVstore.getGPIOparams().outMode == GPIOoutStatus)
if(NVstore.getUserSettings().GPIO.outMode == GPIOoutStatus)
_drawBitmap(114, 28, CrossLgIconInfo);
else
_drawBitmap(113, 29, GPIOout.getState(1) ? BulbOnIconInfo : BulbOffIconInfo);
}
if(NVstore.getGPIOparams().algMode == GPIOalgNone) {
if(NVstore.getUserSettings().GPIO.algMode == GPIOalgNone) {
_drawBitmap(58, Line1, CrossLgIconInfo);
}
else {

View file

@ -237,8 +237,7 @@ CHeaterSettingsScreen::_adjust(int dir)
switch(_rowSel) {
case 1: // glow power
_glowDrive += dir;
UPPERLIMIT(_glowDrive, 6);
LOWERLIMIT(_glowDrive, 1);
BOUNDSLIMIT(_glowDrive, 1, 6);
break;
case 2: // fan sensor
_fanSensor = (_fanSensor == 1) ? 2 : 1;

View file

@ -39,7 +39,7 @@ CHomeMenuSelScreen::onSelect()
{
CScreenHeader::onSelect();
_rowSel = 0;
_action = NVstore.getHomeMenu();
_action = NVstore.getUserSettings().HomeMenu;
}
void
@ -142,12 +142,15 @@ CHomeMenuSelScreen::animate()
bool
CHomeMenuSelScreen::keyHandler(uint8_t event)
{
sUserSettings us;
if(event & keyPressed) {
// UP press
if(event & key_Up) {
if(_rowSel == 4) {
_showStoringMessage();
NVstore.setHomeMenu(_action);
us = NVstore.getUserSettings();
us.HomeMenu = _action;
NVstore.setUserSettings(us);
saveNV();
_rowSel = 0;
}

View file

@ -359,7 +359,7 @@ CScreenManager::checkUpdate()
// Clock
// return to those upon timeout, otherwise return to Basic Control screen
if(_rootMenu > 2) {
uint8_t userHomeMenu = NVstore.getHomeMenu().onTimeout;
uint8_t userHomeMenu = NVstore.getUserSettings().HomeMenu.onTimeout;
if(userHomeMenu) { // allow user to override defualt screen
userHomeMenu--;
DebugPort.print("Screen Manager: Menu timeout, falling back to user preferred screen: ");
@ -384,7 +384,7 @@ CScreenManager::checkUpdate()
if(runState != prevRunState) {
if(runState > 0 && prevRunState == 0) {
// heater has started
uint8_t userStartMenu = NVstore.getHomeMenu().onStart;
uint8_t userStartMenu = NVstore.getUserSettings().HomeMenu.onStart;
if(userStartMenu && userStartMenu <= 3) { // allow user to override defualt screen
userStartMenu--;
DebugPort.print("Screen Manager: Heater start detected, switching to user preferred screen: ");
@ -399,7 +399,7 @@ CScreenManager::checkUpdate()
}
if(runState == 0 && prevRunState != 0) {
// heater has stopped
uint8_t userStopMenu = NVstore.getHomeMenu().onStop;
uint8_t userStopMenu = NVstore.getUserSettings().HomeMenu.onStop;
if(userStopMenu && userStopMenu <= 3) { // allow user to override defualt screen
userStopMenu--;
DebugPort.print("Screen Manager: Heater stop detected, switching to user preferred screen: ");

View file

@ -56,7 +56,7 @@ CThermostatModeScreen::onSelect()
_initUI();
_window = NVstore.getUserSettings().ThermostatWindow;
_thermoMode = NVstore.getUserSettings().ThermostatMethod;
_cyclicMode = NVstore.getCyclicMode();
_cyclicMode = NVstore.getUserSettings().cyclic;
}
void
@ -255,8 +255,8 @@ CThermostatModeScreen::keyHandler(uint8_t event)
settings = NVstore.getUserSettings();
settings.ThermostatMethod = _thermoMode;
settings.ThermostatWindow = _window;
settings.cyclic = _cyclicMode;
NVstore.setUserSettings(settings);
NVstore.setCyclicMode(_cyclicMode);
saveNV();
_rowSel = 0;
break;
@ -310,18 +310,15 @@ CThermostatModeScreen::_adjust(int dir)
switch(_rowSel) {
case 1:
_cyclicMode.Stop += dir;
LOWERLIMIT(_cyclicMode.Stop, 0);
UPPERLIMIT(_cyclicMode.Stop, 10);
BOUNDSLIMIT(_cyclicMode.Stop, 0, 9);
break;
case 2:
_cyclicMode.Start += dir;
LOWERLIMIT(_cyclicMode.Start, -20);
UPPERLIMIT(_cyclicMode.Start, 0);
BOUNDSLIMIT(_cyclicMode.Start, -20, 0);
break;
case 3: // window
_window += (dir * 0.1);
UPPERLIMIT(_window, 10.0);
LOWERLIMIT(_window, 0.2);
BOUNDSLIMIT(_window, 0.2, 10.0);
break;
case 4: // thermostat mode
_thermoMode += dir;

View file

@ -657,57 +657,58 @@ const uint8_t PROGMEM segoeUI_Italic_7ptBitmaps [] =
0x80, // #
// @34 '6' (4 pixels wide)
0x7E, // ######
0xA2, // # # #
0xBE, // # #####
0x1C, // ###
0x72, // ### #
0x92, // # # #
0x9C, // # ###
0x80, // #
// @38 '7' (4 pixels wide)
// @39 '7' (4 pixels wide)
0x86, // # ##
0x98, // # ##
0xA0, // # #
0xC0, // ##
// @42 '8' (5 pixels wide)
// @43 '8' (5 pixels wide)
0x0C, // ##
0x6A, // ## # #
0x72, // ### #
0x92, // # # #
0x9E, // # ####
0x9C, // # ###
0x60, // ##
// @47 '9' (5 pixels wide)
// @48 '9' (5 pixels wide)
0x02, // #
0x72, // ### #
0x92, // # # #
0x9C, // # ###
0x70, // ###
// @52 ':' (2 pixels wide)
// @53 ':' (2 pixels wide)
0x08, // #
0x80, // #
// @54 'C' (5 pixels wide)
// @55 'C' (5 pixels wide)
0x7C, // #####
0xC2, // ## #
0x82, // # #
0x82, // # #
0x80, // #
// @59 'F' (5 pixels wide)
// @60 'F' (5 pixels wide)
0x06, // ##
0x78, // ####
0x90, // # #
0x90, // # #
0x80, // #
// @64 'V' (5 pixels wide)
// @65 'V' (5 pixels wide)
0xFC, // ######
0x06, // ##
0x18, // ##
0x20, // #
0xC0, // ##
// @69 '`' (2 pixels wide)
// @70 '`' (2 pixels wide)
0x80, // #
0x40, // #
};
@ -739,10 +740,10 @@ const FONT_CHAR_INFO PROGMEM segoeUI_Italic_7ptDescriptors[] =
{5, 6, 24}, // '4'
{5, 7, 29}, // '5'
{4, 7, 34}, // '6'
{4, 7, 38}, // '7'
{5, 7, 42}, // '8'
{5, 7, 47}, // '9'
{2, 5, 52}, // ':'
{4, 7, 39}, // '7'
{5, 7, 43}, // '8'
{5, 7, 48}, // '9'
{2, 5, 53}, // ':'
{0, 0, 0}, // ';'
{0, 0, 0}, // '<'
{0, 0, 0}, // '='
@ -751,10 +752,10 @@ const FONT_CHAR_INFO PROGMEM segoeUI_Italic_7ptDescriptors[] =
{0, 0, 0}, // '@'
{0, 0, 0}, // 'A'
{0, 0, 0}, // 'B'
{5, 7, 54}, // 'C'
{5, 7, 55}, // 'C'
{0, 0, 0}, // 'D'
{0, 0, 0}, // 'E'
{5, 7, 59}, // 'F'
{5, 7, 60}, // 'F'
{0, 0, 0}, // 'G'
{0, 0, 0}, // 'H'
{0, 0, 0}, // 'I'
@ -770,7 +771,7 @@ const FONT_CHAR_INFO PROGMEM segoeUI_Italic_7ptDescriptors[] =
{0, 0, 0}, // 'S'
{0, 0, 0}, // 'T'
{0, 0, 0}, // 'U'
{5, 7, 64}, // 'V'
{5, 7, 65}, // 'V'
{0, 0, 0}, // 'W'
{0, 0, 0}, // 'X'
{0, 0, 0}, // 'Y'
@ -780,7 +781,7 @@ const FONT_CHAR_INFO PROGMEM segoeUI_Italic_7ptDescriptors[] =
{0, 0, 0}, // ']'
{0, 0, 0}, // '^'
{0, 0, 0}, // '_'
{2, 2, 69}, // '`'
{2, 2, 70}, // '`'
};
// Font information for Segoe UI 7pt

View file

@ -85,21 +85,28 @@ void interpretJsonCommand(char* pLine)
else if(strcmp("FanMax", it->key) == 0) {
setFanMax(it->value.as<short>());
}
else if(strcmp("ThermostatOvertemp", it->key) == 0) {
sCyclicThermostat cyclic = NVstore.getCyclicMode();
cyclic.Stop = it->value.as<char>();
if(cyclic.Stop > 1) cyclic.Stop--; // internal uses a 1 offset
NVstore.setCyclicMode(cyclic);
else if(strcmp("CyclicTemp", it->key) == 0) {
setDemandDegC(it->value.as<unsigned char>()); // directly set demandDegC
}
else if((strcmp("CyclicOff", it->key) == 0) || (strcmp("ThermostatOvertemp", it->key) == 0)) {
sUserSettings us = NVstore.getUserSettings();
char val = it->value.as<char>();
if(val > 1) val--; // internal uses a 1 offset
if(INBOUNDS(val, 0, 10))
us.cyclic.Stop = val;
NVstore.setUserSettings(us);
}
else if(strcmp("ThermostatUndertemp", it->key) == 0) {
sCyclicThermostat cyclic = NVstore.getCyclicMode();
cyclic.Start = it->value.as<char>();
NVstore.setCyclicMode(cyclic);
else if((strcmp("CyclicOn", it->key) == 0) || (strcmp("ThermostatUndertemp", it->key) == 0)) {
sUserSettings us = NVstore.getUserSettings();
char val = it->value.as<char>();
if(INBOUNDS(val, -20, 0))
us.cyclic.Start = val;
NVstore.setUserSettings(us);
}
else if(strcmp("ThermostatMethod", it->key) == 0) {
sUserSettings settings = NVstore.getUserSettings();
uint8_t val = it->value.as<uint8_t>();
if(val <= 2)
if(INBOUNDS(val, 0, 2))
settings.ThermostatMethod = val;
NVstore.setUserSettings(settings);
}
@ -227,6 +234,12 @@ void interpretJsonCommand(char* pLine)
NVstore.save();
resetJSONmoderator();
}
else if(strcmp("TempMode", it->key) == 0) {
sUserSettings us = NVstore.getUserSettings();
us.degF = it->value.as<unsigned char>() ? 0x01 : 0x00;
NVstore.setUserSettings(us);
NVstore.save();
}
}
}
@ -295,10 +308,13 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
bSend |= moderator.addJson("ThermostatMethod", NVstore.getUserSettings().ThermostatMethod, root);
bSend |= moderator.addJson("ThermostatWindow", NVstore.getUserSettings().ThermostatWindow, root);
int stop = NVstore.getCyclicMode().Stop;
int stop = NVstore.getUserSettings().cyclic.Stop;
if(stop) stop++; // deliver effective threshold, not internal working value
bSend |= moderator.addJson("ThermostatOvertemp", stop, root);
bSend |= moderator.addJson("ThermostatUndertemp", NVstore.getCyclicMode().Start, root);
bSend |= moderator.addJson("ThermostatUndertemp", NVstore.getUserSettings().cyclic.Start, root);
bSend |= moderator.addJson("CyclicTemp", getDemandDegC(), root); // actual pivot point for cyclic mode
bSend |= moderator.addJson("CyclicOff", stop, root); // threshold of over temp for cyclic mode
bSend |= moderator.addJson("CyclicOn", NVstore.getUserSettings().cyclic.Start, root); // threshold of under temp for cyclic mode
if(bSend) {
root.printTo(opStr, len);

View file

@ -74,6 +74,7 @@ sHeaterTuning::getPmax() const
void
sHeaterTuning::setPmin(float val)
{
BOUNDSLIMIT(val, 0.4, 5.0);
uint8_t cVal = (uint8_t)(val * 10.f + 0.5f);
Pmin = cVal;
}
@ -81,6 +82,7 @@ sHeaterTuning::setPmin(float val)
void
sHeaterTuning::setPmax(float val)
{
BOUNDSLIMIT(val, 1.0, 10.0);
uint8_t cVal = (uint8_t)(val * 10.f + 0.5f);
Pmax = cVal;
}
@ -112,43 +114,6 @@ CHeaterStorage::setTimerInfo(int idx, const sTimer& timerInfo)
}
}
const sCyclicThermostat&
CHeaterStorage::getCyclicMode() const
{
return _calValues.userSettings.cyclic;
}
void
CHeaterStorage::setCyclicMode(const sCyclicThermostat& val)
{
_calValues.userSettings.cyclic = val;
save();
}
const sGPIOparams&
CHeaterStorage::getGPIOparams() const
{
return _calValues.userSettings.GPIO;
}
void
CHeaterStorage::setGPIOparams(const sGPIOparams& params)
{
_calValues.userSettings.GPIO = params;
}
const sHomeMenuActions&
CHeaterStorage::getHomeMenu() const
{
return _calValues.userSettings.HomeMenu;
}
void
CHeaterStorage::setHomeMenu(const sHomeMenuActions& val)
{
_calValues.userSettings.HomeMenu = val;
}
// MQTT parameter read/save
const sMQTTparams&

View file

@ -314,18 +314,11 @@ public:
virtual void doSave() {}
const sCyclicThermostat& getCyclicMode() const;
const sMQTTparams& getMQTTinfo() const;
const sGPIOparams& getGPIOparams() const;
const sHomeMenuActions& getHomeMenu() const;
const sCredentials& getCredentials() const;
const sUserSettings& getUserSettings() const;
const sHeaterTuning& getHeaterTuning() const;
void setCyclicMode(const sCyclicThermostat& val);
void setGPIOparams(const sGPIOparams& params);
void setHomeMenu(const sHomeMenuActions& val);
void getTimerInfo(int idx, sTimer& timerInfo);
void setTimerInfo(int idx, const sTimer& timerInfo);
void setMQTTinfo(const sMQTTparams& info);

View file

@ -39,6 +39,7 @@ extern bool getThermostatModeActive(); // OEM: actual mode from blue wire, BTC
extern void reqPumpPrime(bool on);
extern float getTemperatureDesired(); // OEM: the advertised value, BTC our setpoint
extern uint8_t getDemandDegC();
extern void setDemandDegC(uint8_t val);
extern uint8_t getDemandPump();
extern float getTemperatureSensor();

View file

@ -29,5 +29,6 @@
#define WRAPLOWERLIMIT(A, B, C) if((A) < (B)) (A) = (C)
#define WRAPLIMITS(A, B, C) if((A) < (B)) (A) = (C) ; if((A) > (C)) (A) = (B)
#define INBOUNDS(TST, MIN, MAX) (((TST) >= (MIN)) && ((TST) <= (MAX)))
#define BOUNDSLIMIT(A, B, C) if((A) < (B)) (A) = (B); if((A) > (C)) (A) = (C)
#endif