Added over temp cycling, based upon Jess Baughan's idea

This commit is contained in:
rljonesau 2019-04-04 21:48:05 +11:00
parent c440498bad
commit cce60328c0
12 changed files with 196 additions and 37 deletions

View file

@ -114,7 +114,6 @@
#define RX_DATA_TIMOUT 50
#ifdef ESP32
#include "src/Bluetooth/BluetoothESP32.h"
#else
@ -135,6 +134,7 @@ void initBlueWireSerial();
bool validateFrame(const CProtocol& frame, const char* name);
void checkDisplayUpdate();
void checkDebugCommands();
void manageCyclicMode();
// DS18B20 temperature sensor support
OneWire ds(15); // on pin 5 (a 4.7K resistor is necessary)
@ -162,6 +162,7 @@ long lastRxTime; // used to observe inter character delays
bool bHasOEMController = false;
bool bHasOEMLCDController = false;
bool bHasHtrData = false;
bool bUserON = false;
bool bReportBlueWireData = REPORT_RAW_DATA;
bool bReportJSONData = REPORT_JSON_TRANSMIT;
@ -768,6 +769,8 @@ void loop()
}
// exponential mean to stabilse readings
fFilteredTemperature = fFilteredTemperature * fAlpha + (1-fAlpha) * fTemperature;
manageCyclicMode();
}
}
else {
@ -775,9 +778,7 @@ void loop()
fFilteredTemperature = -100;
}
// Added DISABLE INTERRUPTS to test for parasitic fix.
// portDISABLE_INTERRUPTS();
TempSensor.requestTemperatures(); // prep sensor for future reading
// portENABLE_INTERRUPTS();
ScreenManager.reqUpdate();
}
@ -801,7 +802,40 @@ void DebugReportFrame(const char* hdr, const CProtocol& Frame, const char* ftr)
DebugPort.print(ftr); // footer
}
void manageCyclicMode()
{
uint8_t cyclic = NVstore.getCyclicMode();
if(cyclic && bUserON) { // cyclic mode enabled, and user has started heater
cyclic += 1; // bump up by 1 degree - no point invoking at 1 deg over!
float deltaT = fFilteredTemperature - getSetTemp();
// DebugPort.print("Cyclic = "); DebugPort.print(cyclic); DebugPort.print(" bUserON = "); DebugPort.print(bUserON);
// DebugPort.print(" deltaT = "); DebugPort.println(deltaT);
// ensure we cancel user ON mode if heater throws an error
int errState = getHeaterInfo().getErrState();
if(errState > 1 && errState < 12) {
// excludes errors 0,1(OK) & 12(Retry)
DebugPort.println("CYCLIC MODE: cancelling user ON status");
requestOff(); // forcibly cancel cyclic operation - pretend user pressed OFF
}
int heaterState = getHeaterInfo().getRunState();
// check if over temp, turn off heater
if(deltaT > cyclic) {
if(heaterState > 0 && heaterState <= 5) {
DebugPort.print("CYCLIC MODE: Stopping heater, deltaT > +"); DebugPort.println(cyclic);
heaterOff(); // over temp - request heater stop
}
}
// check if under temp, turn on heater
if(deltaT < -1) {
// 1 degree below set point - restart heater
if(heaterState == 0) {
DebugPort.println("CYCLIC MODE: Restarting heater, deltaT < -1");
heaterOn();
}
}
}
}
void initBlueWireSerial()
{
@ -837,16 +871,26 @@ bool validateFrame(const CProtocol& frame, const char* name)
void requestOn()
{
TxManage.queueOnRequest();
SmartError.reset();
// HeaterData.setRefTime();
heaterOn();
bUserON = true; // for cyclic mode
}
void requestOff()
{
heaterOff();
bUserON = false; // for cyclic mode
}
void heaterOn()
{
TxManage.queueOnRequest();
SmartError.reset();
}
void heaterOff()
{
TxManage.queueOffRequest();
SmartError.inhibit();
// HeaterData.setRefTime();
}
void ToggleOnOff()
@ -1018,7 +1062,7 @@ void checkDebugCommands()
#ifdef PROTOCOL_INVESTIGATION
bool bSendVal = false;
#endif
if(isControl(rxVal)) { // "End of Line"
if(rxVal == '\n') { // "End of Line"
#ifdef PROTOCOL_INVESTIGATION
String convert(PCline.Line);
val = convert.toInt();
@ -1063,6 +1107,16 @@ void checkDebugCommands()
DebugPort.println("Test fan bytes");
mode = 3;
}
else if(rxVal == 'c') {
DebugPort.println("Test Command Byte... ");
mode = 4;
}
else if(rxVal == 'x') {
DebugPort.println("Special mode cancelled");
val = 0;
mode = 0;
DefaultBTCParams.Controller.Command = 0;
}
else if(rxVal == ']') {
val++;
bSendVal = true;
@ -1110,12 +1164,16 @@ void checkDebugCommands()
DefaultBTCParams.Controller.Prime = val & 0xff; // always 0x32:Thermostat, 0xCD:Fixed
break;
case 2:
DefaultBTCParams.Controller.MinTempRise = val & 0xff; // always 0x05
DefaultBTCParams.Controller.GlowDrive = val & 0xff; // always 0x05
break;
case 3:
DefaultBTCParams.Controller.Unknown2_MSB = (val >> 8) & 0xff; // always 0x0d
DefaultBTCParams.Controller.Unknown2_LSB = (val >> 0) & 0xff; // always 0xac 16bit: "3500" ?? Ignition fan max RPM????
break;
case 4:
DebugPort.print("Forced controller command = "); DebugPort.println(val&0xff);
DefaultBTCParams.Controller.Command = val & 0xff;
break;
}
}
#endif
@ -1158,4 +1216,20 @@ bool hasOEMLCDcontroller()
int getSmartError()
{
return SmartError.getError();
}
}
bool isCyclicActive()
{
return bUserON && (NVstore.getCyclicMode() != 0);
}
int getRunStateEx()
{
int heaterstate = getHeaterInfo().getRunState();
if(heaterstate == 0) {
if(isCyclicActive()) {
heaterstate = 10; // special state for cyclic suspended
}
}
return heaterstate;
}

View file

@ -98,7 +98,7 @@ CBasicScreen::show()
xPos = border;
_printMenuText(xPos, yPos, msg, _nModeSel == 0);
setThermostatMode(_nModeSel == 0 ? 1 : 0); // set the new mode
// setThermostatMode(_nModeSel == 0 ? 1 : 0); // set the new mode
}
else {
// cancel selection mode, apply whatever is boxed
@ -154,11 +154,13 @@ CBasicScreen::keyHandler(uint8_t event)
else {
_showMode = millis() + 5000;
_nModeSel = 0;
setThermostatMode(1); // set the new mode
NVstore.save();
}
_ScreenManager.reqUpdate();
}
}
// press RIGHT to selecxt next screen, or Thermostat mode when in mode select
// press RIGHT to select next screen, or Thermostat mode when in mode select
if(event & key_Right) {
if(!_showMode)
_ScreenManager.nextMenu();
@ -168,6 +170,8 @@ CBasicScreen::keyHandler(uint8_t event)
else {
_showMode = millis() + 5000;
_nModeSel = 1;
setThermostatMode(0); // set the new mode
NVstore.save();
}
_ScreenManager.reqUpdate();
}
@ -215,7 +219,10 @@ CBasicScreen::keyHandler(uint8_t event)
// standby, request ON
if(repeatCount > 3) {
repeatCount = -1;
requestOn();
if(isCyclicActive())
requestOff(); // actually shut off cyclic mode if already in idle
else
requestOn();
}
}
}
@ -288,8 +295,18 @@ CBasicScreen::showRunState()
if(runstate) {
if(runstate < 5) toPrint = "Starting";
else if(runstate == 5) toPrint = "Running";
else if(runstate == 8) toPrint = "Cooling";
else toPrint = "Shutting down";
else if(isCyclicActive()) {
if(runstate > 5) toPrint = "Suspending...";
}
else {
if(runstate == 8) toPrint = "Cooling";
else toPrint = "Shutting down";
}
}
else {
if(isCyclicActive()) {
toPrint = "Suspended";
}
}
}
}

View file

@ -197,7 +197,10 @@ CDetailedScreen::keyHandler(uint8_t event)
else {
if(_keyRepeatCount > 3) {
_keyRepeatCount = -1; // prevent double handling
requestOn();
if(isCyclicActive())
requestOff();
else
requestOn();
}
}
}
@ -396,7 +399,8 @@ CDetailedScreen::showRunState(int runstate, int errstate)
int yPos = 25;
_display.setTextColor(WHITE, BLACK);
if(runstate >= 0 && runstate <= 8) {
if(((runstate == 0) || (runstate > 5)) && errstate) {
if(errstate && ((runstate == 0) || (runstate > 5))) {
// an error is present in idle or states beyond running, show it
// create an "E-XX" message to display
char msg[16];
sprintf(msg, "E-%02d", errstate);
@ -414,7 +418,15 @@ CDetailedScreen::showRunState(int runstate, int errstate)
toPrint = getHeaterInfo().getErrStateStr();
}
else {
toPrint = getHeaterInfo().getRunStateStr();
// no errors, heater normal
if(isCyclicActive()) {
if(runstate == 0) toPrint = "Suspended";
else if(runstate > 5) toPrint = "Suspending...";
else toPrint = getHeaterInfo().getRunStateStr();
}
else {
toPrint = getHeaterInfo().getRunStateStr();
}
}
}
if(toPrint) {

View file

@ -45,6 +45,7 @@ CExperimentalSettingsScreen::CExperimentalSettingsScreen(C128x64_OLED& display,
_initUI();
_window = 10;
_thermoMode = 0;
_cyclicMode = 0;
}
void
@ -54,6 +55,7 @@ CExperimentalSettingsScreen::onSelect()
_initUI();
_window = NVstore.getThermostatMethodWindow();
_thermoMode = NVstore.getThermostatMethodMode();
_cyclicMode = NVstore.getCyclicMode();
}
void
@ -78,6 +80,7 @@ CExperimentalSettingsScreen::show()
}
else {
_printInverted(_display.xCentre(), 0, " Experimental ", true, eCentreJustify);
_printMenuText(65, Line3, "Overtemp:", false, eRightJustify);
_printMenuText(65, Line2, "Thermostat:", false, eRightJustify);
_printMenuText(65, Line1, "Window:", false, eRightJustify);
sprintf(msg, "%.1f\367C", _window); // \367 is octal for Adafruit degree symbol
@ -93,6 +96,13 @@ CExperimentalSettingsScreen::show()
_printMenuText(Column, Line2, "Standard", _rowSel == 2);
break;
}
if(_cyclicMode) {
sprintf(msg, "> %d\367C", _cyclicMode+1); // \367 is octal for Adafruit degree symbol
}
else {
strcpy(msg, "OFF");
}
_printMenuText(Column, Line3, msg, _rowSel == 3);
}
}
@ -132,6 +142,11 @@ CExperimentalSettingsScreen::animate()
if(pMsg)
_scrollMessage(56, pMsg, _startChar);
break;
case 3:
_display.drawFastHLine(0, 52, 128, WHITE);
pMsg = " Controller auto cycles heater if over temperature occurs. ";
_scrollMessage(56, pMsg, _startChar);
break;
}
return true;
}
@ -145,11 +160,11 @@ CExperimentalSettingsScreen::keyHandler(uint8_t event)
// press LEFT to select previous screen
if(event & key_Left) {
switch(_rowSel) {
case 1:
case 2:
_startChar = 0;
case 1:
case 3:
_adjust(-1);
_startChar = 0;
break;
case 4:
_rowSel = 0; // abort save
@ -159,11 +174,11 @@ CExperimentalSettingsScreen::keyHandler(uint8_t event)
// press RIGHT to select next screen
if(event & key_Right) {
switch(_rowSel) {
case 1:
case 2:
_startChar = 0;
case 1:
case 3:
_adjust(+1);
_startChar = 0;
break;
case 4:
_rowSel = 0; // abort save
@ -188,12 +203,13 @@ CExperimentalSettingsScreen::keyHandler(uint8_t event)
case 3:
_startChar = 0;
_rowSel++;
UPPERLIMIT(_rowSel, 2);
UPPERLIMIT(_rowSel, 3);
break;
case 4: // confirmed save
_showStoringMessage();
NVstore.setThermostatMethodMode(_thermoMode);
NVstore.setThermostatMethodWindow(_window);
NVstore.setCyclicMode(_cyclicMode);
saveNV();
_rowSel = 0;
break;
@ -232,5 +248,10 @@ CExperimentalSettingsScreen::_adjust(int dir)
ROLLLOWERLIMIT(_thermoMode, 0, 2);
ROLLUPPERLIMIT(_thermoMode, 2, 0);
break;
case 3:
_cyclicMode += dir;
UPPERLIMIT(_cyclicMode, 10);
LOWERLIMIT(_cyclicMode, 0);
break;
}
}

View file

@ -34,6 +34,7 @@ class CExperimentalSettingsScreen : public CPasswordScreen
void _adjust(int dir);
float _window;
int _thermoMode;
int _cyclicMode;
int _animateCount;
int _startChar;
void _initUI();

View file

@ -324,17 +324,18 @@ CProtocol::setSystemVoltage(float fVal)
}
const char* Runstates [] PROGMEM = {
" Stopped/Ready ",
"Starting...",
"Igniting...",
"Ignition retry pause",
"Ignited",
"Running",
"Stopping",
"Shutting down",
"Cooling",
"Heating glow plug", // interpreted state - actually runstate 2 with no pump action!
"Unknown run state"
" Stopped/Ready ", // 0
"Starting...", // 1
"Igniting...", // 2
"Ignition retry pause", // 3
"Ignited", // 4
"Running", // 5
"Stopping", // 6
"Shutting down", // 7
"Cooling", // 8
"Heating glow plug", // 9 - interpreted state - actually runstate 2 with no pump action!
"Suspended", // 10 - interpreted state - cyclic mode has suspended heater
"Unknown run state"
};
@ -342,7 +343,7 @@ const char* Runstates [] PROGMEM = {
const char*
CProtocolPackage::getRunStateStr() const
{
uint8_t runstate = getRunState();
uint8_t runstate = getRunStateEx();
UPPERLIMIT(runstate, 10);
if(runstate == 2 && getPump_Actual() == 0) { // split runstate 2 - glow, then fuel
runstate = 9;

View file

@ -97,6 +97,7 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
m_TxFrame = basisFrame;
// ALWAYS install on/off commands if required
#ifndef PROTOCOL_INVESTIGATION
m_TxFrame.resetCommand(); // no command upon blue wire initially, unless a request is pending
if(_rawCommand) {
m_TxFrame.setRawCommand(_rawCommand);
@ -112,6 +113,7 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
m_TxFrame.offCommand();
}
}
#endif
// 0x78 prevents the controller showing bum information when we parrot the OEM controller
// heater is happy either way, the OEM controller has set the max/min stuff already

View file

@ -55,6 +55,10 @@ extern bool hasOEMcontroller();
extern bool hasOEMLCDcontroller();
extern int getBlueWireStat();
extern int getSmartError();
extern bool isCyclicActive();
extern int getRunStateEx();
#define LOWERLIMIT(A, B) if((A) < (B)) (A) = (B)
#define UPPERLIMIT(A, B) if((A) > (B)) (A) = (B)

View file

@ -177,7 +177,8 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len)
bSend |= moderator.addJson("TempMin", getHeaterInfo().getTemperature_Min(), root);
bSend |= moderator.addJson("TempMax", getHeaterInfo().getTemperature_Max(), root);
bSend |= moderator.addJson("TempBody", getHeaterInfo().getTemperature_HeatExchg(), root);
bSend |= moderator.addJson("RunState", getHeaterInfo().getRunState(), root);
// bSend |= moderator.addJson("RunState", getHeaterInfo().getRunState(), root);
bSend |= moderator.addJson("RunState", getRunStateEx(), root);
bSend |= moderator.addJson("RunString", getHeaterInfo().getRunStateStr(), root); // verbose it up!
bSend |= moderator.addJson("ErrorState", getHeaterInfo().getErrState(), root );
bSend |= moderator.addJson("ErrorString", getHeaterInfo().getErrStateStrEx(), root); // verbose it up!

View file

@ -271,6 +271,19 @@ CHeaterStorage::setOTAEnabled(unsigned char val)
save();
}
unsigned char
CHeaterStorage::getCyclicMode()
{
return _calValues.Options.cyclicMode;
}
void
CHeaterStorage::setCyclicMode(unsigned char val)
{
_calValues.Options.cyclicMode = val;
save();
}
///////////////////////////////////////////////////////////////////////////////////////
// ESP32
//
@ -389,6 +402,7 @@ CESP32HeaterStorage::loadUI()
validatedLoad("thermoMethod", _calValues.Options.ThermostatMethod, (10 << 2), u8inBounds, 0, 2, 0x03);
validatedLoad("enableWifi", _calValues.Options.enableWifi, 1, u8inBounds, 0, 1);
validatedLoad("enableOTA", _calValues.Options.enableOTA, 1, u8inBounds, 0, 1);
validatedLoad("cyclicMode", _calValues.Options.cyclicMode, 0, u8inBounds, 0, 10);
preferences.end();
}
@ -401,6 +415,7 @@ CESP32HeaterStorage::saveUI()
preferences.putUChar("thermoMethod", _calValues.Options.ThermostatMethod);
preferences.putUChar("enableWifi", _calValues.Options.enableWifi);
preferences.putUChar("enableOTA", _calValues.Options.enableOTA);
preferences.putUChar("cyclicMode", _calValues.Options.cyclicMode);
preferences.end();
}

View file

@ -67,6 +67,7 @@ struct sBTCoptions {
uint8_t ThermostatMethod; // 0: standard heater, 1: Narrow Hysterisis, 2:Managed Hz mode
uint8_t enableWifi;
uint8_t enableOTA;
uint8_t cyclicMode;
bool valid() {
bool retval = true;
retval &= (DimTime >= 0) && (DimTime < 300000); // 5 mins
@ -74,6 +75,7 @@ struct sBTCoptions {
retval &= (ThermostatMethod & 0x03) < 3; // only modes 0, 1 or 2
retval &= (enableWifi == 0) || (enableWifi == 1);
retval &= (enableOTA == 0) || (enableOTA == 1);
retval &= cyclicMode < 10;
return retval;
}
void init() {
@ -82,6 +84,7 @@ struct sBTCoptions {
ThermostatMethod = 0;
enableWifi = 1;
enableOTA = 1;
cyclicMode = 0;
};
};
@ -135,6 +138,7 @@ public:
unsigned char getDegFMode();
unsigned char getWifiEnabled();
unsigned char getOTAEnabled();
unsigned char getCyclicMode();
void setPmin(float);
void setPmax(float);
@ -151,6 +155,7 @@ public:
void setDegFMode(unsigned char val);
void setWifiEnabled(unsigned char val);
void setOTAEnabled(unsigned char val);
void setCyclicMode(unsigned char val);
void getTimerInfo(int idx, sTimer& timerInfo);
void setTimerInfo(int idx, const sTimer& timerInfo);

View file

@ -100,4 +100,10 @@
// Adafruit OLED selection
//
#define USE_ADAFRUIT_SH1106 1
#define USE_ADAFRUIT_SSD1306 0
#define USE_ADAFRUIT_SSD1306 0
///////////////////////////////////////////////////////////////////////////////
// Protocol exploration
//
//#define PROTOCOL_INVESTIGATION