diff --git a/Bootload/AfterburnerV3.0.3.bin b/Bootload/AfterburnerV3.0.3.bin deleted file mode 100644 index 26c395b..0000000 Binary files a/Bootload/AfterburnerV3.0.3.bin and /dev/null differ diff --git a/Bootload/COM.bat b/Bootload/COM.bat index f958d0d..fe273d4 100644 --- a/Bootload/COM.bat +++ b/Bootload/COM.bat @@ -1,5 +1,5 @@ REM Firmware -esptool.exe --chip esp32 --port COM16 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader_qio_80m.bin 0x10000 AfterburnerV3.0.3.bin 0x8000 Afterburner.partitions.bin +esptool.exe --chip esp32 --port COM16 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 80m --flash_size detect 0xe000 boot_app0.bin 0x1000 bootloader_qio_80m.bin 0x10000 AfterburnerV3.0.4.bin 0x8000 Afterburner.partitions.bin REM SPIFFS esptool.exe --chip esp32 --port COM16 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_size detect 0x3d0000 spiffs.bin diff --git a/platformio.ini b/platformio.ini index 57d9c08..558768a 100644 --- a/platformio.ini +++ b/platformio.ini @@ -15,10 +15,10 @@ board = esp32dev framework = arduino board_build.partitions = min_spiffs.csv upload_speed = 921600 -upload_port = 192.168.20.40 -upload_protocol = espota -;upload_port = COM16 -;upload_protocol = esptool +;upload_port = 192.168.20.40 +;upload_protocol = espota +upload_port = COM16 +upload_protocol = esptool upload_flags = --port=3232 monitor_speed = 115200 diff --git a/src/OLED/ScreenHeader.cpp b/src/OLED/ScreenHeader.cpp index 7fb9cc2..c5043b6 100644 --- a/src/OLED/ScreenHeader.cpp +++ b/src/OLED/ScreenHeader.cpp @@ -218,6 +218,9 @@ CScreenHeader::showBTicon() if(getBluetoothClient().isConnected()) { _drawBitmap(X_BT_ICON, Y_BT_ICON, BluetoothIconInfo, WHITE); } + else { + _display.fillRect(X_BT_ICON, Y_BT_ICON, BluetoothIconInfo.width, BluetoothIconInfo.height, BLACK); + } } void diff --git a/src/OLED/ThermostatModeScreen.cpp b/src/OLED/ThermostatModeScreen.cpp index efb05f2..4fb95e1 100644 --- a/src/OLED/ThermostatModeScreen.cpp +++ b/src/OLED/ThermostatModeScreen.cpp @@ -56,6 +56,7 @@ CThermostatModeScreen::onSelect() _window = NVstore.getUserSettings().ThermostatWindow; _thermoMode = NVstore.getUserSettings().ThermostatMethod; _cyclicMode = NVstore.getUserSettings().cyclic; + _ExtHold = NVstore.getUserSettings().ExtThermoTimeout; } void @@ -98,6 +99,21 @@ CThermostatModeScreen::show() } if(modeStr) _printMenuText(Column, Line3, modeStr, _rowSel == 4); + modeStr = "??"; + if(_thermoMode == 3) { + switch(_ExtHold) { + case 0: modeStr = "Psv"; break; + case 60000: modeStr = "1 min"; break; + case 120000: modeStr = "2 min"; break; + case 300000: modeStr = "5 min"; break; + case 600000: modeStr = "10 min"; break; + case 900000: modeStr = "15 min"; break; + case 1200000: modeStr = "20 min"; break; + case 1800000: modeStr = "30 min"; break; + case 3600000: modeStr = "1 hour"; break; + } + _printMenuText(_display.width()-border, Line2, modeStr, _rowSel == 5, eRightJustify); + } if(_cyclicMode.isEnabled()) { float fTemp = _cyclicMode.Stop+1; if(NVstore.getUserSettings().degF) { @@ -178,6 +194,10 @@ CThermostatModeScreen::animate() if(pMsg) _scrollMessage(56, pMsg, _scrollChar); break; + case 5: + _display.drawFastHLine(0, 52, 128, WHITE); + pMsg = " External thermostat handling - start upon initial closure, stop the heater after the nominated period. "; + break; } return true; } @@ -202,6 +222,7 @@ CThermostatModeScreen::keyHandler(uint8_t event) case 1: case 2: case 3: + case 5: _adjust(-1); break; case 10: @@ -220,6 +241,7 @@ CThermostatModeScreen::keyHandler(uint8_t event) case 1: case 2: case 3: + case 5: _adjust(+1); break; case 10: @@ -252,12 +274,17 @@ CThermostatModeScreen::keyHandler(uint8_t event) _rowSel++; UPPERLIMIT(_rowSel, 4); break; + case 4: + if(_thermoMode == 3) + _rowSel++; + break; case 10: // confirmed save _enableStoringMessage(); settings = NVstore.getUserSettings(); settings.ThermostatMethod = _thermoMode; settings.ThermostatWindow = _window; settings.cyclic = _cyclicMode; + settings.ExtThermoTimeout = _ExtHold; NVstore.setUserSettings(settings); saveNV(); _rowSel = 0; @@ -275,6 +302,7 @@ CThermostatModeScreen::keyHandler(uint8_t event) case 2: case 3: case 4: + case 5: _rowSel = 10; break; } @@ -329,5 +357,19 @@ CThermostatModeScreen::_adjust(int dir) wrap = getExternalThermostatModeActive() ? 3 : 2; WRAPLIMITS(_thermoMode, 0, wrap); break; + case 5: + switch(_ExtHold) { + case 0: _ExtHold = (dir > 0) ? 60000 : 0; break; + case 60000: _ExtHold = (dir > 0) ? 120000 : 0; break; + case 120000: _ExtHold = (dir > 0) ? 300000 : 60000; break; + case 300000: _ExtHold = (dir > 0) ? 600000 : 120000; break; + case 600000: _ExtHold = (dir > 0) ? 900000 : 300000; break; + case 900000: _ExtHold = (dir > 0) ? 1200000 : 600000; break; + case 1200000: _ExtHold = (dir > 0) ? 1800000 : 900000; break; + case 1800000: _ExtHold = (dir > 0) ? 3600000 : 1200000; break; + case 3600000: _ExtHold = (dir > 0) ? 3600000 : 1800000; break; + default: _ExtHold = 0; break; + } + break; } } diff --git a/src/OLED/ThermostatModeScreen.h b/src/OLED/ThermostatModeScreen.h index 4c62b29..34be291 100644 --- a/src/OLED/ThermostatModeScreen.h +++ b/src/OLED/ThermostatModeScreen.h @@ -36,6 +36,7 @@ class CThermostatModeScreen : public CPasswordScreen void _adjust(int dir); float _window; int _thermoMode; + unsigned long _ExtHold; sCyclicThermostat _cyclicMode; int _animateCount; int _scrollChar; diff --git a/src/Utility/BTC_GPIO.cpp b/src/Utility/BTC_GPIO.cpp index 8436c01..08e1dd4 100644 --- a/src/Utility/BTC_GPIO.cpp +++ b/src/Utility/BTC_GPIO.cpp @@ -24,6 +24,7 @@ #include #include "DebugPort.h" #include "../Protocol/Protocol.h" +#include "../Utility/NVStorage.h" const int BREATHINTERVAL = 45; const int FADEAMOUNT = 3; @@ -61,6 +62,7 @@ const char* GPIOalgNames[] = { CGPIOin1::CGPIOin1() { _Mode = Disabled; + _prevActive = false; } void @@ -77,11 +79,14 @@ CGPIOin1::Modes CGPIOin1::getMode() const void CGPIOin1::manage(bool active) { - switch (_Mode) { - case Disabled: break; - case Start: _doStart(active); break; - case Run: _doRun(active); break; - case StartStop: _doStartStop(active); break; + if(_prevActive ^ active) { + switch (_Mode) { + case Disabled: break; + case Start: _doStart(active); break; + case Run: _doRun(active); break; + case StartStop: _doStartStop(active); break; + } + _prevActive = active; } } @@ -122,6 +127,8 @@ CGPIOin1::_doStartStop(bool active) CGPIOin2::CGPIOin2() { _Mode = Disabled; + _prevActive = false; + _OffHoldoff = 0; } void @@ -148,8 +155,11 @@ CGPIOin2::manage(bool active) void CGPIOin2::_doStop(bool active) { - if(active) { - requestOff(); + if(_prevActive ^ active) { + if(active) { + requestOff(); + } + _prevActive = active; } } @@ -158,6 +168,28 @@ CGPIOin2::_doStop(bool active) void CGPIOin2::_doThermostat(bool active) { + // only if actually using thermostat input, and a timeout is defined do we perform heater start / stop functions + if((NVstore.getUserSettings().ThermostatMethod == 3) && NVstore.getUserSettings().ExtThermoTimeout) { + if(active && !_prevActive) { // initial switch on of thermostat input + DebugPort.println("starting heater due to thermostat contact closure"); + requestOn(); // request heater to start upon closure of thermostat input + } + if(!active && _prevActive) { // initial switch off of thermostat input + _OffHoldoff = (millis() + NVstore.getUserSettings().ExtThermoTimeout) | 1; + DebugPort.printf("thermostat contact opened - will stop in %ldms\r\n", NVstore.getUserSettings().ExtThermoTimeout); + } + if(!active) { + if(_OffHoldoff) { + long tDelta = millis() - _OffHoldoff; + if(tDelta >= 0) { + DebugPort.println("stopping heater due to thermostat contact being open for required dwell"); + requestOff(); // request heater to stop after thermostat input has stayed open for interval + _OffHoldoff = 0; + } + } + } + _prevActive = active; + } // handling actually performed at Tx Manage for setting the fuel rate } @@ -222,7 +254,6 @@ CGPIOin::manage() _lastKey = newKey; if(keyChange) { - simulateKey(newKey); // record possible sub sample transients - JSON usage especially if(keyChange & 0x01) @@ -230,6 +261,7 @@ CGPIOin::manage() if(keyChange & 0x02) _eventList[1].push_back(newKey & 0x02); // mask the channel bit } + simulateKey(newKey); } void diff --git a/src/Utility/BTC_GPIO.h b/src/Utility/BTC_GPIO.h index a05a7a9..a81cd83 100644 --- a/src/Utility/BTC_GPIO.h +++ b/src/Utility/BTC_GPIO.h @@ -50,6 +50,7 @@ public: Modes getMode() const; private: Modes _Mode; + bool _prevActive; void _doStart(bool active); void _doRun(bool active); void _doStartStop(bool active); @@ -69,6 +70,8 @@ public: Modes getMode() const; private: Modes _Mode; + bool _prevActive; + unsigned long _OffHoldoff; void _doStop(bool active); void _doThermostat(bool active); }; diff --git a/src/Utility/NVStorage.cpp b/src/Utility/NVStorage.cpp index cd2581b..a6c7f83 100644 --- a/src/Utility/NVStorage.cpp +++ b/src/Utility/NVStorage.cpp @@ -329,6 +329,7 @@ sUserSettings::load() preferences.begin("user", false); validatedLoad("dimTime", dimTime, 60000, -600000, 600000); validatedLoad("menuTimeout", menuTimeout, 60000, 0, 300000); + validatedLoad("thermoTimeout", ExtThermoTimeout, 0, 0, 3600000); validatedLoad("degF", degF, 0, u8inBounds, 0, 1); validatedLoad("thermostat", useThermostat, 1, u8inBounds, 0, 1); validatedLoad("thermoMethod", ThermostatMethod, 0, u8inBounds, 0, 255); @@ -395,6 +396,7 @@ sUserSettings::save() preferences.begin("user", false); preferences.putLong("dimTime", dimTime); preferences.putLong("menuTimeout", menuTimeout); + preferences.putLong("thermoTimeout", ExtThermoTimeout); preferences.putUChar("thermostat", useThermostat); preferences.putUChar("degF", degF); preferences.putUChar("thermoMethod", ThermostatMethod); diff --git a/src/Utility/NVStorage.h b/src/Utility/NVStorage.h index d3c7557..117277b 100644 --- a/src/Utility/NVStorage.h +++ b/src/Utility/NVStorage.h @@ -245,6 +245,7 @@ struct sMQTTparams : public CESP32_NVStorage { struct sUserSettings : public CESP32_NVStorage { long dimTime; long menuTimeout; + long ExtThermoTimeout; uint8_t degF; uint8_t ThermostatMethod; // 0: standard heater, 1: Narrow Hysterisis, 2:Managed Hz mode float ThermostatWindow; @@ -261,6 +262,7 @@ struct sUserSettings : public CESP32_NVStorage { bool retval = true; retval &= INBOUNDS(dimTime, -600000, 600000); // +/- 10 mins retval &= INBOUNDS(menuTimeout, 0, 300000); // 5 mins + retval &= INBOUNDS(ExtThermoTimeout, 0, 3600000); // 1 hour retval &= (degF == 0) || (degF == 1); retval &= ThermostatMethod <= 3; // only modes 0, 1 or 2, 3 retval &= INBOUNDS(ThermostatWindow, 0.2f, 10.f); @@ -280,6 +282,7 @@ struct sUserSettings : public CESP32_NVStorage { void init() { dimTime = 60000; menuTimeout = 60000; + ExtThermoTimeout = 0; degF = 0; ThermostatMethod = 0; ThermostatWindow = 1.0; @@ -301,6 +304,7 @@ struct sUserSettings : public CESP32_NVStorage { sUserSettings& operator=(const sUserSettings& rhs) { dimTime = rhs.dimTime; menuTimeout = rhs.menuTimeout; + ExtThermoTimeout = rhs.ExtThermoTimeout; degF = rhs.degF; ThermostatMethod = rhs.ThermostatMethod; ThermostatWindow = rhs.ThermostatWindow;