Merge branch 'FuelGauge'

This commit is contained in:
Ray Jones 2019-07-22 21:10:15 +10:00
commit 672645c59a
55 changed files with 1073 additions and 203 deletions

4
.gitignore vendored
View file

@ -21,3 +21,7 @@ Arduino/Afterburner/src/*
/Releases /Releases
/webdev /webdev
/case /case
/DieselHeaterV2.PcbDoc
/StandardResponse.txt
/HeaterHack-Tested.zip
/OTA_COM.txt

View file

@ -99,6 +99,7 @@
#include "src/Utility/helpers.h" #include "src/Utility/helpers.h"
#include "src/Utility/NVStorage.h" #include "src/Utility/NVStorage.h"
#include "src/Utility/DebugPort.h" #include "src/Utility/DebugPort.h"
#include "src/Utility/macros.h"
#include "src/Utility/UtilClasses.h" #include "src/Utility/UtilClasses.h"
#include "src/Utility/BTC_JSON.h" #include "src/Utility/BTC_JSON.h"
#include "src/Utility/BTC_GPIO.h" #include "src/Utility/BTC_GPIO.h"
@ -446,6 +447,10 @@ void setup() {
FilteredSamples.Fan.setRounding(10); FilteredSamples.Fan.setRounding(10);
FilteredSamples.Fan.setAlpha(0.7); FilteredSamples.Fan.setAlpha(0.7);
FilteredSamples.AmbientTemp.reset(-100.0); FilteredSamples.AmbientTemp.reset(-100.0);
FilteredSamples.FastipVolts.setRounding(0.1);
FilteredSamples.FastipVolts.setAlpha(0.7);
FilteredSamples.FastGlowAmps.setRounding(0.01);
FilteredSamples.FastGlowAmps.setAlpha(0.7);
RTC_Store.begin(); RTC_Store.begin();
FuelGauge.init(RTC_Store.getFuelGauge()); FuelGauge.init(RTC_Store.getFuelGauge());
@ -792,9 +797,24 @@ void loop()
ScreenManager.reqUpdate(); ScreenManager.reqUpdate();
} }
if(bHasHtrData) { if(bHasHtrData) {
// apply exponential mean to the anlogue readings for some smoothing
updateFilteredData(); updateFilteredData();
FuelGauge.Integrate(HeaterFrame2.getPump_Actual());
// integrate fuel pump activity for fuel gauge
FuelGauge.Integrate(getHeaterInfo().getPump_Actual());
// test for low volts shutdown during normal run
if(INBOUNDS(getHeaterInfo().getRunState(), 1, 5)) { // check for Low Voltage Cutout
SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue());
}
// trap being in state 0 with a heater error - cancel user on memory to avoid unexpected cyclic restarts
if(RTC_Store.getCyclicEngaged() && (getHeaterInfo().getRunState() == 0) && (getHeaterInfo().getErrState() > 1)) {
DebugPort.println("Forcing cyclic cancel due to error induced shutdown");
RTC_Store.setCyclicEngaged(false);
}
} }
updateJSONclients(bReportJSONData); updateJSONclients(bReportJSONData);
CommState.set(CommStates::Idle); CommState.set(CommStates::Idle);
@ -822,7 +842,7 @@ void manageCyclicMode()
const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic; const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic;
if(cyclic.Stop && RTC_Store.getCyclicEngaged()) { // cyclic mode enabled, and user has started heater if(cyclic.Stop && RTC_Store.getCyclicEngaged()) { // 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! int stopDeltaT = cyclic.Stop + 1; // bump up by 1 degree - no point invoking at 1 deg over!
float deltaT = FilteredSamples.AmbientTemp.getValue() - getDemandDegC(); float deltaT = getTemperatureSensor() - getDemandDegC();
// DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT); // DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT);
// ensure we cancel user ON mode if heater throws an error // ensure we cancel user ON mode if heater throws an error
@ -883,9 +903,11 @@ bool validateFrame(const CProtocol& frame, const char* name)
void requestOn() void requestOn()
{ {
if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) {
heaterOn(); heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode RTC_Store.setCyclicEngaged(true); // for cyclic mode
} }
}
void requestOff() void requestOff()
{ {
@ -1041,7 +1063,7 @@ float getTemperatureDesired()
float getTemperatureSensor() float getTemperatureSensor()
{ {
return FilteredSamples.AmbientTemp.getValue(); return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempOfs;
} }
void setPumpMin(float val) void setPumpMin(float val)
@ -1449,11 +1471,14 @@ void simulateGPIOin(uint8_t newKey)
GPIOin.simulateKey(newKey); GPIOin.simulateKey(newKey);
} }
float getBatteryVoltage() float getBatteryVoltage(bool fast)
{ {
#ifdef RAW_SAMPLES #ifdef RAW_SAMPLES
return getHeaterInfo().getBattVoltage(); return getHeaterInfo().getBattVoltage();
#else #else
if(fast)
return FilteredSamples.FastipVolts.getValue();
else
return FilteredSamples.ipVolts.getValue(); return FilteredSamples.ipVolts.getValue();
#endif #endif
} }
@ -1487,13 +1512,16 @@ float getFanSpeed()
void updateFilteredData() void updateFilteredData()
{ {
FilteredSamples.ipVolts.update(HeaterFrame2.getVoltage_Supply()); FilteredSamples.ipVolts.update(getHeaterInfo().getBattVoltage());
FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage()); FilteredSamples.GlowVolts.update(getHeaterInfo().getGlow_Voltage());
FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current()); FilteredSamples.GlowAmps.update(getHeaterInfo().getGlow_Current());
FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual()); FilteredSamples.Fan.update(getHeaterInfo().getFan_Actual());
FilteredSamples.FastipVolts.update(getHeaterInfo().getBattVoltage());
FilteredSamples.FastGlowAmps.update(getHeaterInfo().getGlow_Current());
} }
int sysUptime() int sysUptime()
{ {
return Clock.get().secondstime() - BootTime; return Clock.get().secondstime() - BootTime;
} }

10
Partitions.txt Normal file
View file

@ -0,0 +1,10 @@
PLATFORMIO MIN_SPIFFS PARTITION ARDUINO MIN_SPIFFS PARTITION
# Name, Type, SubType, Offset, Size, Flags # Name, Type, SubType, Offset, Size, Flags
Same nvs, data, nvs, 0x9000, 0x5000, nvs, data, nvs, 0x9000, 0x5000,
Same otadata, data, ota, 0xe000, 0x2000, otadata, data, ota, 0xe000, 0x2000,
Same app0, app, ota_0, 0x10000, 0x1E0000, app0, app, ota_0, 0x10000, 0x1E0000,
Same app1, app, ota_1, 0x1F0000,0x1E0000, app1, app, ota_1, 0x1F0000,0x1E0000,
Diff eeprom, data, 0x99, 0x3D0000,0x1000, spiffs, data, spiffs, 0x3D0000,0x30000,
Diff spiffs, data, spiffs, 0x3D1000,0x2F000,

View file

@ -51,15 +51,15 @@ Working so far:
Web browser upload new binary to controller (AP or STA mode) Web browser upload new binary to controller (AP or STA mode)
Direct discovery and download of updates from internet server (STA mode) Direct discovery and download of updates from internet server (STA mode)
* Factory default menu option * Factory default menu option
* "Fuel gauge" - Integrates pump frequency, assumes a repeatable dose of fuel per pump stroke.
* Low voltage cut out, definable threshold - auto adjusts for cable voltage drop during start
* Temperature probe offset to correct adverse readings.
To be implemented To be implemented
-------------------------- --------------------------
* 433MHz Rx stream, 433MHz Tx stream connections. This would allow external timer units for example, or analogue temperature demand (which is still only 1 degree resolution with standard heater thermostat). * 433MHz Rx stream, 433MHz Tx stream connections. This would allow external timer units for example, or analogue temperature demand (which is still only 1 degree resolution with standard heater thermostat).
* Low voltage cut out
* Temperature probe offset or mapping to correct adverse readings.
* MQTT pub/sub * MQTT pub/sub
* "fuel gauge" - Integrate pump frequency, assuming a repeatable dose of fuel per pump cycle...
* Regular Hot Burn cycle (DPF mode!) * Regular Hot Burn cycle (DPF mode!)
* Hour meter - run time, glow time * Hour meter - run time, glow time
* list under construction..... * list under construction.....

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 B

After

Width:  |  Height:  |  Size: 198 B

BIN
icons/DegC.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

BIN
icons/DegF.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 126 B

After

Width:  |  Height:  |  Size: 110 B

BIN
icons/FuelIconSmall.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 B

BIN
icons/Reset.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

BIN
icons/ThermostatC.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

BIN
icons/ThermostatF.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

BIN
icons/ThermostatHz.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

View file

@ -11,6 +11,7 @@
[env:esp32dev] [env:esp32dev]
platform = espressif32 platform = espressif32
lib_extra_dirs = ~/Documents/Arduino/libraries lib_extra_dirs = ~/Documents/Arduino/libraries
;lib_dir = src/Afterburner/src
board = esp32dev board = esp32dev
framework = arduino framework = arduino
board_build.partitions = min_spiffs.csv board_build.partitions = min_spiffs.csv
@ -22,5 +23,6 @@ upload_flags =
monitor_speed = 115200 monitor_speed = 115200
extra_scripts = post:add_CRC.py extra_scripts = post:add_CRC.py
; replace shitty Arduino millis with a linear time version ; replace shitty Arduino millis with a linear time version
build_flags = -Wl,--wrap,millis build_flags =
-Wl,--wrap,millis

View file

@ -99,6 +99,7 @@
#include "src/Utility/helpers.h" #include "src/Utility/helpers.h"
#include "src/Utility/NVStorage.h" #include "src/Utility/NVStorage.h"
#include "src/Utility/DebugPort.h" #include "src/Utility/DebugPort.h"
#include "src/Utility/macros.h"
#include "src/Utility/UtilClasses.h" #include "src/Utility/UtilClasses.h"
#include "src/Utility/BTC_JSON.h" #include "src/Utility/BTC_JSON.h"
#include "src/Utility/BTC_GPIO.h" #include "src/Utility/BTC_GPIO.h"
@ -446,6 +447,10 @@ void setup() {
FilteredSamples.Fan.setRounding(10); FilteredSamples.Fan.setRounding(10);
FilteredSamples.Fan.setAlpha(0.7); FilteredSamples.Fan.setAlpha(0.7);
FilteredSamples.AmbientTemp.reset(-100.0); FilteredSamples.AmbientTemp.reset(-100.0);
FilteredSamples.FastipVolts.setRounding(0.1);
FilteredSamples.FastipVolts.setAlpha(0.7);
FilteredSamples.FastGlowAmps.setRounding(0.01);
FilteredSamples.FastGlowAmps.setAlpha(0.7);
RTC_Store.begin(); RTC_Store.begin();
FuelGauge.init(RTC_Store.getFuelGauge()); FuelGauge.init(RTC_Store.getFuelGauge());
@ -792,9 +797,24 @@ void loop()
ScreenManager.reqUpdate(); ScreenManager.reqUpdate();
} }
if(bHasHtrData) { if(bHasHtrData) {
// apply exponential mean to the anlogue readings for some smoothing
updateFilteredData(); updateFilteredData();
FuelGauge.Integrate(HeaterFrame2.getPump_Actual());
// integrate fuel pump activity for fuel gauge
FuelGauge.Integrate(getHeaterInfo().getPump_Actual());
// test for low volts shutdown during normal run
if(INBOUNDS(getHeaterInfo().getRunState(), 1, 5)) { // check for Low Voltage Cutout
SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue());
}
// trap being in state 0 with a heater error - cancel user on memory to avoid unexpected cyclic restarts
if(RTC_Store.getCyclicEngaged() && (getHeaterInfo().getRunState() == 0) && (getHeaterInfo().getErrState() > 1)) {
DebugPort.println("Forcing cyclic cancel due to error induced shutdown");
RTC_Store.setCyclicEngaged(false);
}
} }
updateJSONclients(bReportJSONData); updateJSONclients(bReportJSONData);
CommState.set(CommStates::Idle); CommState.set(CommStates::Idle);
@ -822,7 +842,7 @@ void manageCyclicMode()
const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic; const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic;
if(cyclic.Stop && RTC_Store.getCyclicEngaged()) { // cyclic mode enabled, and user has started heater if(cyclic.Stop && RTC_Store.getCyclicEngaged()) { // 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! int stopDeltaT = cyclic.Stop + 1; // bump up by 1 degree - no point invoking at 1 deg over!
float deltaT = FilteredSamples.AmbientTemp.getValue() - getDemandDegC(); float deltaT = getTemperatureSensor() - getDemandDegC();
// DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT); // DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT);
// ensure we cancel user ON mode if heater throws an error // ensure we cancel user ON mode if heater throws an error
@ -883,9 +903,11 @@ bool validateFrame(const CProtocol& frame, const char* name)
void requestOn() void requestOn()
{ {
if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) {
heaterOn(); heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode RTC_Store.setCyclicEngaged(true); // for cyclic mode
} }
}
void requestOff() void requestOff()
{ {
@ -1041,7 +1063,7 @@ float getTemperatureDesired()
float getTemperatureSensor() float getTemperatureSensor()
{ {
return FilteredSamples.AmbientTemp.getValue(); return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempOfs;
} }
void setPumpMin(float val) void setPumpMin(float val)
@ -1449,11 +1471,14 @@ void simulateGPIOin(uint8_t newKey)
GPIOin.simulateKey(newKey); GPIOin.simulateKey(newKey);
} }
float getBatteryVoltage() float getBatteryVoltage(bool fast)
{ {
#ifdef RAW_SAMPLES #ifdef RAW_SAMPLES
return getHeaterInfo().getBattVoltage(); return getHeaterInfo().getBattVoltage();
#else #else
if(fast)
return FilteredSamples.FastipVolts.getValue();
else
return FilteredSamples.ipVolts.getValue(); return FilteredSamples.ipVolts.getValue();
#endif #endif
} }
@ -1487,13 +1512,16 @@ float getFanSpeed()
void updateFilteredData() void updateFilteredData()
{ {
FilteredSamples.ipVolts.update(HeaterFrame2.getVoltage_Supply()); FilteredSamples.ipVolts.update(getHeaterInfo().getBattVoltage());
FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage()); FilteredSamples.GlowVolts.update(getHeaterInfo().getGlow_Voltage());
FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current()); FilteredSamples.GlowAmps.update(getHeaterInfo().getGlow_Current());
FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual()); FilteredSamples.Fan.update(getHeaterInfo().getFan_Actual());
FilteredSamples.FastipVolts.update(getHeaterInfo().getBattVoltage());
FilteredSamples.FastGlowAmps.update(getHeaterInfo().getGlow_Current());
} }
int sysUptime() int sysUptime()
{ {
return Clock.get().secondstime() - BootTime; return Clock.get().secondstime() - BootTime;
} }

View file

@ -50,7 +50,7 @@ CBasicScreen::CBasicScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen
bool bool
CBasicScreen::show() CBasicScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
char msg[20]; char msg[20];
int xPos, yPos; int xPos, yPos;

View file

@ -43,10 +43,11 @@ CClockScreen::CClockScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen
} }
bool bool
CClockScreen::show() CClockScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
const BTCDateTime& now = Clock.get(); const BTCDateTime& now = Clock.get();

View file

@ -29,8 +29,6 @@
#include "../Utility/NVStorage.h" #include "../Utility/NVStorage.h"
#include "../Utility/FuelGauge.h" #include "../Utility/FuelGauge.h"
extern CFuelGauge FuelGauge;
#define MINIFONT miniFontInfo #define MINIFONT miniFontInfo
@ -84,7 +82,7 @@ CDetailedScreen::CDetailedScreen(C128x64_OLED& display, CScreenManager& mgr) : C
bool bool
CDetailedScreen::show() CDetailedScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
int runstate = getHeaterInfo().getRunStateEx(); int runstate = getHeaterInfo().getRunStateEx();
int errstate = getHeaterInfo().getErrState(); int errstate = getHeaterInfo().getErrState();

View file

@ -0,0 +1,48 @@
/*
* This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
*
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef __FUELCALSCREEN_H__
#define __FUELCALSCREEN_H__
#include <stdint.h>
#include "PasswordScreen.h"
class C128x64_OLED;
class CScreenManager;
class CFuelCalScreen : public CPasswordScreen
{
int _rowSel;
void _adjust(int dir);
float _mlPerStroke;
float _tOfs;
uint8_t _LVC;
int _animateCount;
void _initUI();
public:
CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);
void onSelect();
};
#endif

View file

@ -34,6 +34,7 @@
#include "../Utility/DebugPort.h" #include "../Utility/DebugPort.h"
#include "../Utility/macros.h" #include "../Utility/macros.h"
#include "../Protocol/Protocol.h" #include "../Protocol/Protocol.h"
#include "fonts/Icons.h"
CFuelMixtureScreen::CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr) CFuelMixtureScreen::CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
@ -47,6 +48,12 @@ CFuelMixtureScreen::onSelect()
CPasswordScreen::onSelect(); CPasswordScreen::onSelect();
_initUI(); _initUI();
_load();
}
void
CFuelMixtureScreen::_load()
{
adjPump[0] = getHeaterInfo().getPump_Min(); adjPump[0] = getHeaterInfo().getPump_Min();
adjPump[1] = getHeaterInfo().getPump_Max(); adjPump[1] = getHeaterInfo().getPump_Max();
adjFan[0] = getHeaterInfo().getFan_Min(); adjFan[0] = getHeaterInfo().getFan_Min();
@ -58,6 +65,7 @@ CFuelMixtureScreen::_initUI()
{ {
_rowSel = 0; _rowSel = 0;
_colSel = 0; _colSel = 0;
_animateCount = 0;
} }
bool bool
@ -67,34 +75,40 @@ CFuelMixtureScreen::show()
int xPos, yPos; int xPos, yPos;
const int col3 = _display.width() - border; const int col3 = _display.width() - border;
_display.clearDisplay(); _display.fillRect(70, 0, 58, 64, BLACK); // scrub variables
_display.fillRect(0, 50, 128, 14, BLACK); // scrub footer
if(!CPasswordScreen::show()) { if(!CPasswordScreen::show()) {
switch(_rowSel) { switch(_rowSel) {
case 0: case 0:
case 1: case 1:
case 2: case 2:
case 3: case 3:
case 4: case 4:
if(_animateCount == -1) {
_animateCount = 0;
_display.clearDisplay();
}
// Pump Minimum adjustment // Pump Minimum adjustment
yPos = border + 36; yPos = border + 36;
_printMenuText(80, yPos, "Min", false, eRightJustify); _printMenuText(65, yPos, "Min", false, eRightJustify);
sprintf(str, "%.1f", adjPump[0]); sprintf(str, "%.1f Hz", adjPump[0]);
_printMenuText(col3, yPos, str, _rowSel == 1, eRightJustify); _printMenuText(col3, yPos, str, _rowSel == 1, eRightJustify);
// Pump Maximum adjustment // Pump Maximum adjustment
yPos = border + 24; yPos = border + 24;
_printMenuText(80, yPos, "Pump Hz Max", false, eRightJustify); _printMenuText(65, yPos, "Max", false, eRightJustify);
sprintf(str, "%.1f", adjPump[1]); sprintf(str, "%.1f Hz", adjPump[1]);
_printMenuText(col3, yPos, str, _rowSel == 2, eRightJustify); _printMenuText(col3, yPos, str, _rowSel == 2, eRightJustify);
// Fan Minimum adjustment // Fan Minimum adjustment
yPos = border + 12; yPos = border + 12;
_printMenuText(80, yPos, "Min", false, eRightJustify); _printMenuText(65, yPos, "Min", false, eRightJustify);
sprintf(str, "%d", adjFan[0]); sprintf(str, "%d RPM", adjFan[0]);
_printMenuText(col3, yPos, str, _rowSel == 3, eRightJustify); _printMenuText(col3, yPos, str, _rowSel == 3, eRightJustify);
// Fan Maximum adjustment // Fan Maximum adjustment
yPos = border; yPos = border;
_printMenuText(80, yPos, "Fan RPM Max", false, eRightJustify); _printMenuText(65, yPos, "Max", false, eRightJustify);
sprintf(str, "%d", adjFan[1]); sprintf(str, "%d RPM", adjFan[1]);
_printMenuText(col3, yPos, str, _rowSel == 4, eRightJustify); _printMenuText(col3, yPos, str, _rowSel == 4, eRightJustify);
// navigation line // navigation line
yPos = 53; yPos = 53;
@ -128,6 +142,29 @@ CFuelMixtureScreen::show()
return true; return true;
} }
bool
CFuelMixtureScreen::animate()
{
if(_animateCount >= 0) {
int xPos = 20;
int yPos = 5;
int yFuel = 30;
_display.fillRect(xPos, yPos, FanIcon1Info.width, FanIcon1Info.height, BLACK);
_display.fillRect(xPos+5, yFuel, FuelIconInfo.width, FuelIconInfo.height + 4, BLACK);
_drawBitmap(xPos+5, yFuel+_animateCount, FuelIconInfo);
switch(_animateCount) {
case 0: _drawBitmap(xPos, yPos, FanIcon1Info); break;
case 1: _drawBitmap(xPos, yPos, FanIcon2Info); break;
case 2: _drawBitmap(xPos, yPos, FanIcon3Info); break;
case 3: _drawBitmap(xPos, yPos, FanIcon4Info); break;
}
_animateCount++;
WRAPUPPERLIMIT(_animateCount, 3, 0);
}
return true;
}
bool bool
CFuelMixtureScreen::keyHandler(uint8_t event) CFuelMixtureScreen::keyHandler(uint8_t event)
@ -143,6 +180,8 @@ CFuelMixtureScreen::keyHandler(uint8_t event)
case 2: case 2:
case 3: case 3:
case 4: case 4:
_animateCount = -1;
_display.clearDisplay();
_rowSel = 5; // enter save confirm mode _rowSel = 5; // enter save confirm mode
break; break;
case 5: case 5:
@ -204,6 +243,8 @@ CFuelMixtureScreen::keyHandler(uint8_t event)
UPPERLIMIT(_rowSel, 4); UPPERLIMIT(_rowSel, 4);
break; break;
case 5: case 5:
_display.clearDisplay();
_animateCount = -1;
_showStoringMessage(); _showStoringMessage();
setPumpMin(adjPump[0]); setPumpMin(adjPump[0]);
setPumpMax(adjPump[1]); setPumpMax(adjPump[1]);
@ -233,6 +274,9 @@ CFuelMixtureScreen::keyHandler(uint8_t event)
_ScreenManager.reqUpdate(); _ScreenManager.reqUpdate();
} }
if(_rowSel == 0) {
_load(); // dispose of any changes, re-obtain current settings
}
if(event & keyRepeat) { if(event & keyRepeat) {
switch(_rowSel) { switch(_rowSel) {

View file

@ -33,12 +33,15 @@ class CFuelMixtureScreen : public CPasswordScreen {
uint16_t adjFan[2]; uint16_t adjFan[2];
int _rowSel; int _rowSel;
int _colSel; int _colSel;
int _animateCount;
void _adjustSetting(int dir); void _adjustSetting(int dir);
void _initUI(); void _initUI();
void _load();
public: public:
CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr); CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show(); bool show();
bool animate();
bool keyHandler(uint8_t event); bool keyHandler(uint8_t event);
void onSelect(); void onSelect();
}; };

View file

@ -291,12 +291,6 @@ CGPIOInfoScreen::CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr) : C
_keyRepeatCount = -1; _keyRepeatCount = -1;
} }
void
CGPIOInfoScreen::onSelect()
{
CScreenHeader::onSelect();
}
void void
CGPIOInfoScreen::_initUI() CGPIOInfoScreen::_initUI()
{ {
@ -305,7 +299,7 @@ CGPIOInfoScreen::_initUI()
bool bool
CGPIOInfoScreen::show() CGPIOInfoScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
char msg[16]; char msg[16];
_display.writeFillRect(49, 18, 30, 12, WHITE); _display.writeFillRect(49, 18, 30, 12, WHITE);

View file

@ -53,7 +53,6 @@ public:
CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr); CGPIOInfoScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show(); bool show();
bool keyHandler(uint8_t event); bool keyHandler(uint8_t event);
void onSelect();
}; };
#endif #endif

View file

@ -21,10 +21,13 @@
#include "128x64OLED.h" #include "128x64OLED.h"
#include "HeaterSettingsScreen.h" #include "HeaterSettingsScreen.h"
#include "FuelCalScreen.h"
#include "KeyPad.h" #include "KeyPad.h"
#include "../Utility/helpers.h" #include "../Utility/helpers.h"
#include "../Utility/macros.h" #include "../Utility/macros.h"
#include "../Utility/NVStorage.h"
#include "../Protocol/Protocol.h" #include "../Protocol/Protocol.h"
#include "fonts/Icons.h"
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// //
@ -246,3 +249,280 @@ CHeaterSettingsScreen::_adjust(int dir)
break; break;
} }
} }
CFuelCalScreen::CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
_mlPerStroke = 0.02;
_LVC = 115;
_tOfs = 0;
}
void
CFuelCalScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
_mlPerStroke = NVstore.getHeaterTuning().pumpCal;
_LVC = NVstore.getHeaterTuning().lowVolts;
_tOfs = NVstore.getHeaterTuning().tempOfs;
}
void
CFuelCalScreen::_initUI()
{
_rowSel = 0;
_animateCount = 0;
}
bool
CFuelCalScreen::show()
{
char msg[20];
const int col = 90;
_display.fillRect(0, 50, 128, 14, BLACK);
_display.fillRect(col-border, Line3-border, 128-(col-1), 64-Line3-border, BLACK);
if(!CPasswordScreen::show()) { // for showing "saving settings"
if(_rowSel == 4) {
_printInverted(_display.xCentre(), 0, " Saving Settings ", true, eCentreJustify);
_printMenuText(_display.xCentre(), 35, "Press UP to", false, eCentreJustify);
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
}
else {
if(_animateCount < 0) {
_display.clearDisplay();
_animateCount = 0;
}
_printInverted(_display.xCentre(), 0, " Special Features ", true, eCentreJustify);
// fuel calibration
int yPos = Line1;
_printMenuText(col, yPos, "mL/stroke : ", false, eRightJustify);
sprintf(msg, "%.03f", _mlPerStroke);
_printMenuText(col, yPos, msg, _rowSel == 1);
// low voltage cutout
yPos = Line2;
_printMenuText(col, yPos, "L.V.C. < ", false, eRightJustify);
if(_LVC)
sprintf(msg, "%.1fV", float(_LVC) * 0.1);
else
strcpy(msg, "OFF");
_printMenuText(col, yPos, msg, _rowSel == 2);
// temp offset
yPos = Line3;
_printMenuText(col, yPos, "\367C offset : ", false, eRightJustify);
sprintf(msg, "%+.1f", _tOfs);
_printMenuText(col, yPos, msg, _rowSel == 3);
// navigation line
yPos = 53;
int xPos = _display.xCentre();
switch(_rowSel) {
case 0:
_printMenuText(xPos, yPos, " \021 Exit \020 ", true, eCentreJustify);
break;
default:
_display.drawFastHLine(0, 52, 128, WHITE);
_printMenuText(xPos, 56, "\030\031Sel \033\032 Adj", false, eCentreJustify);
_printMenuText(xPos, 56, "Save", false, eCentreJustify);
break;
}
}
}
return true;
}
bool
CFuelCalScreen::animate()
{
if(_animateCount >= 0) {
switch(_animateCount) {
case 0:
_display.fillRect(0, Line3-4, BatteryIconInfo.width, 40, BLACK);
_drawBitmap(6, Line1-3, FuelIconSmallInfo);
_drawBitmap(0, Line2-1 , BatteryIconInfo);
_drawBitmap(5, Line3-4, miniThermoIconInfo);
break;
case 2:
_display.fillRect(6, Line1-3, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
_drawBitmap(6, Line1-2, FuelIconSmallInfo); // drip fuel
_display.fillRect(BatteryIconInfo.width - 4, Line2+2, 2, 5, BLACK); // deplete battery
_display.fillRect(7, Line3+2, 2, 2, WHITE); // grow thermometer
break;
case 4:
_display.fillRect(6, Line1-2, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
_drawBitmap(6, Line1-1, FuelIconSmallInfo); // drip fuel
_display.fillRect(BatteryIconInfo.width - 7, Line2+2, 2, 5, BLACK); // deplete battery
_display.fillRect(7, Line3+1, 2, 1, WHITE); // grow thermometer
break;
case 6:
_display.fillRect(6, Line1-1, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
_drawBitmap(6, Line1, FuelIconSmallInfo); // drip fuel
_display.fillRect(BatteryIconInfo.width - 10, Line2+2, 2, 5, BLACK); // deplete battery
_display.fillRect(7, Line3, 2, 1, WHITE); // grow thermometer
break;
case 8:
_display.fillRect(6, Line1, FuelIconSmallInfo.width, FuelIconSmallInfo.height, BLACK); // scrub prior drip
_drawBitmap(6, Line1+1, FuelIconSmallInfo); // drip fuel
_display.fillRect(BatteryIconInfo.width - 13, Line2+2, 2, 5, BLACK); // deplete battery
_display.fillRect(7, Line3-1, 2, 1, WHITE); // grow thermometer
break;
}
_animateCount++;
WRAPUPPERLIMIT(_animateCount, 9, 0);
}
return true;
}
bool
CFuelCalScreen::keyHandler(uint8_t event)
{
sHeaterTuning tuning;
if(event & keyRepeat) {
if(event & key_Left) {
_adjust(-1);
}
if(event & key_Right) {
_adjust(+1);
}
}
if(event & keyPressed) {
// press LEFT to select previous screen
if(event & key_Left) {
switch(_rowSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 1:
case 2:
case 3:
_adjust(-1);
break;
case 4:
_rowSel = 0; // abort save
break;
}
}
// press RIGHT to select next screen
if(event & key_Right) {
switch(_rowSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 1:
case 2:
case 3:
_adjust(+1);
break;
case 4:
_rowSel = 0; // abort save
break;
}
}
if(event & key_Down) {
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
// UP press
if(event & key_Up) {
switch(_rowSel) {
case 0:
case 1:
case 2:
case 3:
_rowSel++;
UPPERLIMIT(_rowSel, 3);
break;
case 4: // confirmed save
_display.clearDisplay();
_animateCount = -1;
_showStoringMessage();
tuning = NVstore.getHeaterTuning();
tuning.pumpCal = _mlPerStroke;
tuning.lowVolts = _LVC;
tuning.tempOfs = _tOfs;
NVstore.setHeaterTuning(tuning);
saveNV();
_rowSel = 0;
break;
}
}
// CENTRE press
if(event & key_Centre) {
switch(_rowSel) {
case 0:
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
break;
case 1:
case 2:
case 3:
_animateCount = -1;
_display.clearDisplay();
_rowSel = 4;
break;
}
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CFuelCalScreen::_adjust(int dir)
{
switch(_rowSel) {
case 1:
_mlPerStroke += dir * 0.001;
BOUNDSLIMIT(_mlPerStroke, 0.001, 1);
break;
case 2:
if(_LVC == 0) {
if(NVstore.getHeaterTuning().sysVoltage == 120)
_LVC = dir > 0 ? 115 : 0;
else
_LVC = dir > 0 ? 230 : 0;
}
else {
_LVC += dir;
if(NVstore.getHeaterTuning().sysVoltage == 120) {
if(_LVC < 100)
_LVC = 0;
else
UPPERLIMIT(_LVC, 125);
}
else {
if(_LVC < 200)
_LVC = 0;
else
UPPERLIMIT(_LVC, 250);
}
}
break;
case 3:
_tOfs += dir * 0.1;
BOUNDSLIMIT(_tOfs, -10, 10);
break;
}
}

View file

@ -57,7 +57,7 @@ CInheritSettingsScreen::_initUI()
bool bool
CInheritSettingsScreen::show() CInheritSettingsScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
_display.writeFillRect(0, 16, 96, 12, WHITE); _display.writeFillRect(0, 16, 96, 12, WHITE);
_printInverted(3, 18, "Inherit Settings", true); _printInverted(3, 18, "Inherit Settings", true);

View file

@ -41,6 +41,7 @@ CPasswordScreen::CPasswordScreen(C128x64_OLED& display, CScreenManager& mgr) : C
void void
CPasswordScreen::onSelect() CPasswordScreen::onSelect()
{ {
CScreenHeader::onSelect();
_initUI(); _initUI();
} }

View file

@ -23,6 +23,10 @@
#include "KeyPad.h" #include "KeyPad.h"
#include "../Utility/NVStorage.h" #include "../Utility/NVStorage.h"
#include "../Protocol/Protocol.h" #include "../Protocol/Protocol.h"
#include "fonts/Icons.h"
#include "../RTC/Clock.h"
#include "../Utility/FuelGauge.h"
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// //
@ -42,6 +46,7 @@ CPrimingScreen::CPrimingScreen(C128x64_OLED& display, CScreenManager& mgr) : CSc
void void
CPrimingScreen::onSelect() CPrimingScreen::onSelect()
{ {
CScreenHeader::onSelect();
_stopPump(); _stopPump();
_initUI(); _initUI();
} }
@ -58,93 +63,147 @@ CPrimingScreen::_initUI()
{ {
_PrimeStop = 0; _PrimeStop = 0;
_PrimeCheck = 0; _PrimeCheck = 0;
_rowSel = 0; _paramSel = 0;
_colSel = 0; _colSel = 0;
} }
bool bool
CPrimingScreen::show() CPrimingScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
_display.fillRect(0, 15, 100, 3, BLACK);
CRect extents; CRect extents;
int yPos = 53; int yPos = 53;
// show next/prev menu navigation line // show next/prev menu navigation line
switch(_rowSel) { switch(_paramSel) {
case 0: case 0:
_printMenuText(_display.xCentre(), yPos, " \021 \030Edit \020 ", _rowSel == 0, eCentreJustify); _printMenuText(_display.xCentre(), yPos, " \021 \030Edit \020 ", _paramSel == 0, eCentreJustify);
break; break;
case 1: case 1:
case 2: case 2:
_display.drawFastHLine(0, 53, 128, WHITE); _display.drawFastHLine(0, 53, 128, WHITE);
_printMenuText(_display.xCentre(), 57, "\030\031 Sel \033\032 Adj", false, eCentreJustify); _printMenuText(_display.xCentre(), 57, "\030\031 Sel \033\032 Param", false, eCentreJustify);
break; break;
case 3: case 3:
_display.drawFastHLine(0, 53, 128, WHITE); _display.drawFastHLine(0, 53, 128, WHITE);
if(_colSel == 2) { switch(_colSel) {
_printMenuText(_display.xCentre(), 57, "\033\030\031 Stop", false, eCentreJustify); case 1:
} _printMenuText(_display.xCentre(), 57, "\033\030\031\032 Stop", false, eCentreJustify);
else { break;
_printMenuText(_display.xCentre(), 57, "\032 Start \031 Sel", false, eCentreJustify); case 0:
_printMenuText(_display.xCentre(), 57, "\030 Start \031 Sel", false, eCentreJustify);
break;
case -1:
_printMenuText(_display.xCentre(), 57, "\030 Sel Zero", false, eCentreJustify);
break;
} }
break; break;
} }
yPos = 40; int topline = 19;
if(_rowSel == 1) { int midline = 29;
int botline = 35;
CRect loc;
loc.height = ThermostatDegCIconInfo.height;
loc.width = ThermostatDegCIconInfo.width;
loc.xPos = border;
if(_paramSel == 1) {
// follow user desired setting, heater info is laggy // follow user desired setting, heater info is laggy
_printMenuText(border, yPos, "Thermostat", _colSel == 0); if(NVstore.getUserSettings().degF)
_printMenuText(_display.width()-border, yPos, "Fixed Hz", _colSel == 1, eRightJustify); _drawBitmap(loc.xPos, topline-1, ThermostatDegFIconInfo);
else
_drawBitmap(loc.xPos, topline-1, ThermostatDegCIconInfo);
_drawBitmap(loc.xPos, botline+1, ThermostatHzIconInfo);
loc.yPos = (_colSel == 0) ? topline-1 : botline+1;
_drawMenuSelection(loc, border, radius);
} }
else { else {
// follow actual heater settings // follow actual heater settings
// int col = getHeaterInfo().isThermostat() ? 0 : 1; if(getThermostatModeActive()) {
int col = getThermostatModeActive() ? 0 : 1; _drawBitmap(loc.xPos, midline, NVstore.getUserSettings().degF ? ThermostatDegFIconInfo : ThermostatDegCIconInfo);
_printInverted(border, yPos, "Thermostat", col == 0);
_printInverted(_display.width()-border, yPos, "Fixed Hz", col == 1, eRightJustify);
}
yPos = 28;
if(_rowSel == 2) {
_printMenuText(border, yPos, "degC", _colSel == 0);
_printMenuText(_display.width()-border, yPos, "degF", _colSel == 1, eRightJustify);
} }
else { else {
int col = NVstore.getUserSettings().degF ? 1 : 0; _drawBitmap(loc.xPos, midline, ThermostatHzIconInfo);
_printInverted(border, yPos, "degC", col == 0); }
_printInverted(_display.width()-border, yPos, "degF", col == 1, eRightJustify); }
loc.height = DegCIconInfo.height;
loc.width = DegCIconInfo.width;
loc.xPos = 35;
if(_paramSel == 2) {
loc.yPos = (_colSel == 0) ? topline : botline;
_drawMenuSelection(loc, border, radius);
_drawBitmap(loc.xPos, topline, DegCIconInfo);
_drawBitmap(loc.xPos, botline, DegFIconInfo);
}
else {
_drawBitmap(loc.xPos, midline, NVstore.getUserSettings().degF ? DegFIconInfo : DegCIconInfo);
} }
// fuel pump priming menu // fuel pump priming menu
yPos = 16; loc.xPos = 66;
_printMenuText(border, yPos, "Pump"); loc.width = BowserIconInfo.width;
if(_rowSel == 3) { loc.height = BowserIconInfo.height;
_printMenuText(40, yPos, "OFF", _colSel == 1); _drawBitmap(loc.xPos, midline, BowserIconInfo);
if(_colSel != 2) { loc.xPos = 81;
if(!getHeaterInfo().getRunState()) { // prevent option if heater is running if(_paramSel == 3) {
_printMenuText(70, yPos, "ON"); // becomes Hz when actually priming _drawBitmap(loc.xPos, topline, FuelIconInfo);
_drawBitmap(loc.xPos, botline, resetIconInfo);
if(_colSel == -1) {
loc.yPos = botline;
loc.width = resetIconInfo.width;
loc.height = resetIconInfo.height;
_drawMenuSelection(loc, border, radius);
} }
loc.yPos = _colSel == -1 ? botline : topline;
loc.width = FuelIconInfo.width + StartIconInfo.width + 2;
loc.height = FuelIconInfo.height;
if(_colSel == 0) {
_drawMenuSelection(loc, border, radius);
}
loc.xPos += FuelIconInfo.width + 2;
if(_colSel != 1) { // only show start options if not priming already
if(getHeaterInfo().getRunState() == 0) { // prevent priming option if heater is running
_drawBitmap(loc.xPos, topline+2, StartIconInfo); // becomes Hz when actually priming
} }
else { else {
_drawBitmap(loc.xPos, topline, CrossIconInfo);
}
}
if(_colSel == 1) {
float pumpHz = getHeaterInfo().getPump_Actual(); float pumpHz = getHeaterInfo().getPump_Actual();
// recognise if heater has stopped pump, after an initial holdoff upon first starting // recognise if heater has stopped pump, after an initial holdoff upon first starting
long tDelta = millis() - _PrimeCheck; long tDelta = millis() - _PrimeCheck;
if(_PrimeCheck && tDelta > 0 && pumpHz < 0.1) { if(_PrimeCheck && tDelta > 0 && pumpHz < 0.1) {
_stopPump(); _stopPump();
_paramSel = _colSel = 0;
} }
// test if time is up, stop priming if so // test if time is up, stop priming if so
tDelta = millis() - _PrimeStop; tDelta = millis() - _PrimeStop;
if(_PrimeStop && tDelta > 0) { if(_PrimeStop && tDelta > 0) {
_stopPump(); _stopPump();
_paramSel = _colSel = 0;
} }
if(_PrimeStop) { if(_PrimeStop) {
char msg[16]; char msg[16];
sprintf(msg, "%.1fHz", pumpHz); sprintf(msg, "%.1fHz", pumpHz);
_printMenuText(70, yPos, msg, true); _printMenuText(loc.xPos+1+border, topline+3, msg, true);
_ScreenManager.bumpTimeout(); // don't allow menu timeouts whilst priming is active
} }
} }
} }
else {
char msg[16];
sprintf(msg, "%.02fL", FuelGauge.Used_mL() * 0.001);
_printMenuText(loc.xPos+1, midline+3, msg);
}
return true; return true;
} }
@ -157,47 +216,46 @@ CPrimingScreen::keyHandler(uint8_t event)
if(event & keyPressed) { if(event & keyPressed) {
// press LEFT // press LEFT
if(event & key_Left) { if(event & key_Left) {
switch(_rowSel) { switch(_paramSel) {
case 0: case 0:
_ScreenManager.prevMenu(); _ScreenManager.prevMenu();
break; break;
case 1: default:
_paramSel--;
LOWERLIMIT(_paramSel, 0);
_colSel = 0; _colSel = 0;
setThermostatMode(1); switch(_paramSel) {
saveNV(); case 1:
_colSel = getThermostatModeActive() ? 0 : 1;
break; break;
case 2: case 2:
_colSel = 0; _colSel = NVstore.getUserSettings().degF ? 1 : 0;
setDegFMode(false);
saveNV();
break; break;
case 3: }
_colSel = 1;
break; break;
case 4: break;
} }
} }
// press RIGHT // press RIGHT
if(event & key_Right) { if(event & key_Right) {
switch(_rowSel) { switch(_paramSel) {
case 0: case 0:
_ScreenManager.nextMenu(); _ScreenManager.nextMenu();
break; break;
case 1: default:
_colSel = 1; _paramSel++;
setThermostatMode(0); UPPERLIMIT(_paramSel, 3);
saveNV(); switch(_paramSel) {
case 3:
_colSel = 0; // select OFF upon entry to priming menu
break; break;
case 2: case 2:
_colSel = 1; _colSel = NVstore.getUserSettings().degF ? 1 : 0;
setDegFMode(true);
saveNV();
break; break;
case 3: case 1:
if(!getHeaterInfo().getRunState()) _colSel = getThermostatModeActive() ? 0 : 1;
_colSel = 2; break;
}
break; break;
case 4: break;
} }
} }
// press UP // press UP
@ -205,35 +263,90 @@ CPrimingScreen::keyHandler(uint8_t event)
if(hasOEMcontroller()) if(hasOEMcontroller())
_reqOEMWarning(); _reqOEMWarning();
else { else {
_rowSel++; switch(_paramSel) {
UPPERLIMIT(_rowSel, 3); case 0:
if(_rowSel == 3) _paramSel = 1;
_colSel = 1; // select OFF upon entry to priming menu
if(_rowSel == 2)
_colSel = NVstore.getUserSettings().degF ? 1 : 0;
if(_rowSel == 1)
_colSel = getThermostatModeActive() ? 0 : 1; _colSel = getThermostatModeActive() ? 0 : 1;
break;
case 1:
_colSel++;
WRAPLIMITS(_colSel, 0, 1);
setThermostatMode(_colSel == 0);
saveNV();
break;
case 2:
_colSel++;
WRAPLIMITS(_colSel, 0, 1);
setDegFMode(_colSel != 0);
saveNV();
break;
case 3:
if(_colSel == 1)
_colSel = 0;
else {
_colSel++;
UPPERLIMIT(_colSel, (getHeaterInfo().getRunState() == 0) ? 1 : 0); // prevent priming if heater is running
}
break;
case 4:
break;
}
} }
} }
// press DOWN // press DOWN
if(event & key_Down) { if(event & key_Down) {
if(_rowSel == 0) { if(_paramSel == 0) {
_ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::VersionUI); // force return to main menu _ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::VersionUI); // force return to main menu
} }
else { else {
_rowSel--; switch(_paramSel) {
LOWERLIMIT(_rowSel, 0); case 0:
break;
case 1:
_colSel--;
WRAPLIMITS(_colSel, 0, 1);
setThermostatMode(_colSel == 0);
saveNV();
break;
case 2:
_colSel--;
WRAPLIMITS(_colSel, 0, 1);
setDegFMode(_colSel != 0);
saveNV();
break;
case 3:
_colSel--;
LOWERLIMIT(_colSel, -1);
break;
case 4:
break;
}
}
}
// press UP
if(event & key_Centre) {
if(_paramSel == 3) {
switch(_colSel) {
case 0:
if(getHeaterInfo().getRunState() == 0)
_colSel = 1;
break;
case 1:
_colSel = 0; _colSel = 0;
if(_rowSel == 1) break;
// _colSel = getHeaterInfo().isThermostat() ? 0 : 1; case -1:
_colSel = getThermostatModeActive() ? 0 : 1; FuelGauge.reset();
if(_rowSel == 2) _paramSel = _colSel = 0;
_colSel = NVstore.getUserSettings().degF ? 1 : 0; break;
}
}
else {
_paramSel = _colSel = 0;
} }
} }
// check if fuel priming was selected // check if fuel priming was selected
if(_rowSel == 3 && _colSel == 2) { if(_paramSel == 3 && _colSel == 1 ) {
reqPumpPrime(true); reqPumpPrime(true);
_PrimeStop = millis() + 150000; // allow 2.5 minutes - much the same as the heater itself cuts out at _PrimeStop = millis() + 150000; // allow 2.5 minutes - much the same as the heater itself cuts out at
_PrimeCheck = millis() + 3000; // holdoff upon start before testing for heater shutting off pump _PrimeCheck = millis() + 3000; // holdoff upon start before testing for heater shutting off pump
@ -253,6 +366,7 @@ CPrimingScreen::_stopPump()
reqPumpPrime(false); reqPumpPrime(false);
_PrimeCheck = 0; _PrimeCheck = 0;
_PrimeStop = 0; _PrimeStop = 0;
if(_colSel == 2) if(_paramSel == 3 && _colSel == 1) {
_colSel = 1; _colSel = 0;
}
} }

View file

@ -31,7 +31,7 @@ class CScreenManager;
class CPrimingScreen : public CScreenHeader { class CPrimingScreen : public CScreenHeader {
unsigned long _PrimeStop; unsigned long _PrimeStop;
unsigned long _PrimeCheck; unsigned long _PrimeCheck;
int _rowSel; int _paramSel;
int _colSel; int _colSel;
void _stopPump(); void _stopPump();
void _initUI(); void _initUI();

View file

@ -63,6 +63,7 @@ CScreen::show()
void void
CScreen::onSelect() CScreen::onSelect()
{ {
_display.clearDisplay();
} }
void void
@ -91,9 +92,19 @@ CScreen::_printMenuText(int x, int y, const char* str, bool selected, eJUSTIFY j
void void
CScreen::_drawMenuSelection(CRect extents, const char* str, int border, int radius) CScreen::_drawMenuSelection(CRect extents, const char* str, int border, int radius)
{ {
_display.getTextExtents(str, extents); CRect resize(extents);
extents.Expand(border); _display.getTextExtents(str, resize);
_display.drawRoundRect(extents.xPos, extents.yPos, extents.width, extents.height, radius, WHITE); // resize.Expand(border);
// _display.drawRoundRect(resize.xPos, resize.yPos, resize.width, resize.height, radius, WHITE);
_drawMenuSelection(resize, border, radius);
}
void
CScreen::_drawMenuSelection(const CRect& extents, int border, int radius)
{
CRect resize(extents);
resize.Expand(border);
_display.drawRoundRect(resize.xPos, resize.yPos, resize.width, resize.height, radius, WHITE);
} }
void void

View file

@ -52,6 +52,7 @@ protected:
void _printInverted(int x, int y, const char* str, bool selected, eJUSTIFY justify = eLeftJustify); void _printInverted(int x, int y, const char* str, bool selected, eJUSTIFY justify = eLeftJustify);
void _adjustExtents(CRect& rect, eJUSTIFY justify, const char* str); void _adjustExtents(CRect& rect, eJUSTIFY justify, const char* str);
void _drawMenuSelection(CRect extents, const char* str, int border = 3, int radius = 4); void _drawMenuSelection(CRect extents, const char* str, int border = 3, int radius = 4);
void _drawMenuSelection(const CRect& extents, int border, int radius);
void _scrollMessage(int y, const char* str, int& charOffset); void _scrollMessage(int y, const char* str, int& charOffset);
void _reqOEMWarning(); void _reqOEMWarning();
void _drawBitmap(int x, int y, const BITMAP_INFO& info, uint16_t color = WHITE, uint16_t bg = 0xffff); void _drawBitmap(int x, int y, const BITMAP_INFO& info, uint16_t color = WHITE, uint16_t bg = 0xffff);

View file

@ -31,6 +31,8 @@
#include "fonts/Icons.h" #include "fonts/Icons.h"
#include "fonts/MiniFont.h" #include "fonts/MiniFont.h"
#include "../RTC/TimerManager.h" #include "../RTC/TimerManager.h"
#include "../Protocol/SmartError.h"
#include "../Utility/DataFilter.h"
#define MINIFONT miniFontInfo #define MINIFONT miniFontInfo
@ -65,9 +67,15 @@ CScreenHeader::CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr) : CScreen(
} }
bool bool
CScreenHeader::show() CScreenHeader::show(bool erase)
{ {
_display.clearDisplay(); if(erase)
_display.clearDisplay(); // erase everything
else {
_display.fillRect(0, 17, 128, 47, BLACK); // only erase below the header
_display.fillRect(119, 0, 9, 17, BLACK); // erase top of body thermo
_display.fillRect(0, 0, 9, 17, BLACK); // erase top of ambient thermo
}
// standard header items // standard header items
// Bluetooth // Bluetooth
@ -75,8 +83,7 @@ CScreenHeader::show()
// WiFi icon is updated in animate() // WiFi icon is updated in animate()
// battery // Battery is updated in animate
showBatteryIcon(getBatteryVoltage());
// clock // clock
showTime(); showTime();
@ -104,7 +111,9 @@ CScreenHeader::animate()
// animate timer icon, // animate timer icon,
// inserting an update icon if new firmware available from internet web server // inserting an update icon if new firmware available from internet web server
_animateCount++; _animateCount++;
WRAPUPPERLIMIT(_animateCount, 10, 0); _batteryCount++;
WRAPUPPERLIMIT(_animateCount, 9, 0);
WRAPUPPERLIMIT(_batteryCount, 5, 0);
if(isUpdateAvailable(true)) { if(isUpdateAvailable(true)) {
int xPos = X_TIMER_ICON - 3; int xPos = X_TIMER_ICON - 3;
int yPos = Y_TIMER_ICON; int yPos = Y_TIMER_ICON;
@ -122,7 +131,22 @@ CScreenHeader::animate()
} }
} }
else { else {
int xPos = X_BATT_ICON;
int yPos = Y_BATT_ICON;
showTimers(); showTimers();
switch(_batteryCount) {
case 3:
if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) {
showBatteryIcon(getBatteryVoltage(true));
}
else {
_display.fillRect(xPos, yPos, BatteryIconInfo.width, BatteryIconInfo.height, BLACK);
}
break;
case 0:
showBatteryIcon(getBatteryVoltage(true));
break;
}
} }
showWifiIcon(); showWifiIcon();
@ -285,6 +309,7 @@ CScreenHeader::showTime()
int xPos = X_WIFI_ICON + WifiIconInfo.width + WifiInIconInfo.width; // rhs of wifi conglomeration int xPos = X_WIFI_ICON + WifiIconInfo.width + WifiInIconInfo.width; // rhs of wifi conglomeration
if(isWifiAP()) xPos += 4; // add more if an Access Point if(isWifiAP()) xPos += 4; // add more if an Access Point
_display.fillRect(xPos - 15, Y_CLOCK, 30, arial_8ptFontInfo.nBitsPerLine, BLACK);
_printMenuText(X_CLOCK, Y_CLOCK, msg); _printMenuText(X_CLOCK, Y_CLOCK, msg);
} }
} }

View file

@ -44,7 +44,8 @@ class CScreenHeader : public CScreen {
sScreenholdoff _UpAnnotation; sScreenholdoff _UpAnnotation;
sScreenholdoff _DnAnnotation; sScreenholdoff _DnAnnotation;
bool _colon; bool _colon;
int _animateCount; uint8_t _animateCount;
uint8_t _batteryCount;
protected: protected:
void showBTicon(); void showBTicon();
void showWifiIcon(); void showWifiIcon();
@ -53,7 +54,7 @@ protected:
virtual void showTime(); // x location depends upon how many timers are active virtual void showTime(); // x location depends upon how many timers are active
public: public:
CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr); CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr);
bool show(); bool show(bool erase);
bool animate(); bool animate();
}; };

View file

@ -30,6 +30,7 @@
#include "ClockScreen.h" #include "ClockScreen.h"
#include "RebootScreen.h" #include "RebootScreen.h"
#include "HeaterSettingsScreen.h" #include "HeaterSettingsScreen.h"
#include "FuelCalScreen.h"
#include "SettingsScreen.h" #include "SettingsScreen.h"
#include "ThermostatModeScreen.h" #include "ThermostatModeScreen.h"
#include "FontDumpScreen.h" #include "FontDumpScreen.h"
@ -290,8 +291,9 @@ CScreenManager::begin(bool bNoClock)
// create heater tuning screens loop - password protected // create heater tuning screens loop - password protected
menuloop.clear(); menuloop.clear();
menuloop.push_back(new CFuelMixtureScreen(*_pDisplay, *this)); // tuning menuloop.push_back(new CFuelMixtureScreen(*_pDisplay, *this)); // mixture tuning
menuloop.push_back(new CHeaterSettingsScreen(*_pDisplay, *this)); // tuning menuloop.push_back(new CHeaterSettingsScreen(*_pDisplay, *this)); // heater system tuning
menuloop.push_back(new CFuelCalScreen(*_pDisplay, *this)); // fuel pump calibration
_Screens.push_back(menuloop); _Screens.push_back(menuloop);
// create User Settings screens loop // create User Settings screens loop
@ -514,26 +516,30 @@ CScreenManager::prevMenu()
void void
CScreenManager::keyHandler(uint8_t event) CScreenManager::keyHandler(uint8_t event)
{ {
long dimTime = NVstore.getUserSettings().dimTime;
if(_bDimmed) { if(_bDimmed) {
if(event & keyReleased) { if(event & keyReleased) {
_dim(false); _dim(false);
_DimTime_ms = (millis() + abs(dimTime)) | 1; bumpTimeout();
_MenuTimeout = (millis() + NVstore.getUserSettings().menuTimeout) | 1;
} }
return; // initial press when dimmed is always thrown away return; // initial press when dimmed is always thrown away
} }
// _dim(false); bumpTimeout();
_DimTime_ms = (millis() + abs(dimTime)) | 1;
_MenuTimeout = (millis() + NVstore.getUserSettings().menuTimeout) | 1;
// call key handler for active screen // call key handler for active screen
if(_menu >= 0) if(_menu >= 0)
_Screens[_menu][_subMenu]->keyHandler(event); _Screens[_menu][_subMenu]->keyHandler(event);
} }
void
CScreenManager::bumpTimeout()
{
long dimTime = NVstore.getUserSettings().dimTime;
_DimTime_ms = (millis() + abs(dimTime)) | 1;
_MenuTimeout = (millis() + NVstore.getUserSettings().menuTimeout) | 1;
}
void void
CScreenManager::selectMenu(eUIMenuSets menuSet, int specific) CScreenManager::selectMenu(eUIMenuSets menuSet, int specific)
{ {
@ -572,11 +578,8 @@ void
CScreenManager::showOTAMessage(int percent, eOTAmodes updateType) CScreenManager::showOTAMessage(int percent, eOTAmodes updateType)
{ {
static int prevPercent = -1; static int prevPercent = -1;
static long prevTime = millis();
long tDelta = millis() - prevTime;
if(percent != prevPercent/* && tDelta > 500*/) { if(percent != prevPercent/* && tDelta > 500*/) {
prevTime = millis();
_pDisplay->clearDisplay(); _pDisplay->clearDisplay();
_pDisplay->setCursor(64,22); _pDisplay->setCursor(64,22);
switch(updateType) { switch(updateType) {

View file

@ -49,7 +49,7 @@ public:
enum eUIRootMenus { DetailedControlUI, BasicControlUI, ClockUI, ModeUI, CommsUI, GPIOInfoUI, SettingsUI }; enum eUIRootMenus { DetailedControlUI, BasicControlUI, ClockUI, ModeUI, CommsUI, GPIOInfoUI, SettingsUI };
enum eUITimerMenus { TimerOverviewUI, Timer1UI, Timer2UI, Timer3UI, Timer4UI, Timer5UI, Timer6UI, Timer7UI, enum eUITimerMenus { TimerOverviewUI, Timer1UI, Timer2UI, Timer3UI, Timer4UI, Timer5UI, Timer6UI, Timer7UI,
Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI }; Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI };
enum eUITuningMenus { MixtureUI, HeaterSettingsUI }; enum eUITuningMenus { MixtureUI, HeaterSettingsUI, FuelCalUI };
enum eUIUserSettingsMenus { GPIOUI, ExThermostatUI, VersionUI, HomeMenuUI, TimeIntervalsUI }; enum eUIUserSettingsMenus { GPIOUI, ExThermostatUI, VersionUI, HomeMenuUI, TimeIntervalsUI };
enum eUIBranchMenus { SetClockUI, InheritSettingsUI, FontDumpUI }; enum eUIBranchMenus { SetClockUI, InheritSettingsUI, FontDumpUI };
public: public:
@ -66,6 +66,7 @@ public:
void selectMenu(eUIMenuSets menuset, int specific = -1); // use to select loop menus, including the root or branches void selectMenu(eUIMenuSets menuset, int specific = -1); // use to select loop menus, including the root or branches
void showRebootMsg(const char* content[2], long delayTime); void showRebootMsg(const char* content[2], long delayTime);
void showOTAMessage(int percent, eOTAmodes updateType); void showOTAMessage(int percent, eOTAmodes updateType);
void bumpTimeout();
}; };
#endif // __SCREEN_MANAGER_H__ #endif // __SCREEN_MANAGER_H__

View file

@ -43,6 +43,7 @@ CSetClockScreen::CSetClockScreen(C128x64_OLED& display, CScreenManager& mgr) : C
void void
CSetClockScreen::onSelect() CSetClockScreen::onSelect()
{ {
CScreenHeader::onSelect();
_initUI(); _initUI();
} }
@ -67,7 +68,7 @@ CSetClockScreen::show()
if(deltaT >= 0) { if(deltaT >= 0) {
_nextT += 1000; _nextT += 1000;
CScreenHeader::show(); CScreenHeader::show(false);
char str[16]; char str[16];
int xPos, yPos; int xPos, yPos;

View file

@ -47,6 +47,7 @@ CSetTimerScreen::CSetTimerScreen(C128x64_OLED& display, CScreenManager& mgr, int
void void
CSetTimerScreen::onSelect() CSetTimerScreen::onSelect()
{ {
CScreenHeader::onSelect();
_initUI(); _initUI();
NVstore.getTimerInfo(_timerID, _timerInfo); NVstore.getTimerInfo(_timerID, _timerInfo);
} }
@ -62,7 +63,7 @@ CSetTimerScreen::_initUI()
bool bool
CSetTimerScreen::show() CSetTimerScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
char str[20]; char str[20];
int xPos, yPos; int xPos, yPos;

View file

@ -66,10 +66,10 @@ CSettingsScreen::show()
{ {
char str[16]; char str[16];
CScreenHeader::show(); CScreenHeader::show(false);
_display.writeFillRect(0, 16, 96, 12, WHITE); _display.writeFillRect(0, 16, 84, 12, WHITE);
_printInverted(3, 18, "Heater Settings", true); _printInverted(3, 18, "Heater Tuning", true);
if(!CPasswordScreen::show()) { if(!CPasswordScreen::show()) {

View file

@ -48,6 +48,7 @@ CWiFiScreen::CWiFiScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreenHe
void void
CWiFiScreen::onSelect() CWiFiScreen::onSelect()
{ {
CScreenHeader::onSelect();
_initUI(); _initUI();
} }
@ -87,7 +88,7 @@ CWiFiScreen::_initUI()
bool bool
CWiFiScreen::show() CWiFiScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
int yPos = 18; int yPos = 18;

View file

@ -662,11 +662,19 @@ const uint8_t PROGMEM arial_8ptBitmaps [] =
0x01, 0x00, // # 0x01, 0x00, // #
// @870 '~' (5 pixels wide) // @870 '~' (5 pixels wide)
0x03, 0x00, // ## 0x01, 0x00, // #
0x02, 0x00, // # 0x02, 0x00, // #
0x03, 0x00, // ## 0x03, 0x00, // ##
0x01, 0x00, // # 0x01, 0x00, // #
0x02, 0x00, // # 0x02, 0x00, // #
// @880 '1' (5 pixels wide)
0x00, 0x00, //
0x04, 0x00, // #
0x08, 0x00, // #
0x1F, 0xE0, // ########
0x00, 0x00, //
}; };
// Character descriptors for Arial 8pt // Character descriptors for Arial 8pt
@ -690,7 +698,7 @@ const FONT_CHAR_INFO PROGMEM arial_8ptDescriptors[] =
{1, 14, 100}, // '.' {1, 14, 100}, // '.'
{3, 14, 102}, // '/' {3, 14, 102}, // '/'
{5, 14, 108}, // '0' {5, 14, 108}, // '0'
{3, 14, 118}, // '1' {5, 14, 880}, // '1'
{5, 14, 124}, // '2' {5, 14, 124}, // '2'
{5, 14, 134}, // '3' {5, 14, 134}, // '3'
{5, 14, 144}, // '4' {5, 14, 144}, // '4'

View file

@ -375,6 +375,25 @@ const uint8_t FuelIcon [] PROGMEM = {
}; };
const BITMAP_INFO FuelIconInfo(7, 12, FuelIcon); const BITMAP_INFO FuelIconInfo(7, 12, FuelIcon);
//
// Image data for FuelIconSmall
//
const uint8_t PROGMEM FuelIconSmall[] =
{
0x20, // #
0x20, // #
0x70, // ###
0x70, // ###
0xF8, // #####
0xF8, // #####
0xF8, // #####
0xF8, // #####
0x70, // ###
};
const BITMAP_INFO FuelIconSmallInfo(5, 9, FuelIconSmall);
// 'Target', 13x13px // 'Target', 13x13px
const uint8_t TargetIcon [] PROGMEM = { const uint8_t TargetIcon [] PROGMEM = {
0x0f, 0x80, // ##### 0x0f, 0x80, // #####
@ -578,6 +597,7 @@ const uint8_t PROGMEM CrossIcon[] =
0x50, // # # 0x50, // # #
0x88, // # # 0x88, // # #
}; };
const BITMAP_INFO CrossIconInfo(5, 5, CrossIcon);
const uint8_t PROGMEM TickIcon[] = const uint8_t PROGMEM TickIcon[] =
{ {
@ -961,7 +981,146 @@ const uint8_t PROGMEM bowserIcon[] =
0x7E, 0x00, // ###### 0x7E, 0x00, // ######
0xFF, 0x00, // ######## 0xFF, 0x00, // ########
}; };
const BITMAP_INFO BowserIconInfo(10, 12, bowserIcon); const BITMAP_INFO BowserIconInfo(10, 12, bowserIcon);
//
// Image data for degC
//
const uint8_t PROGMEM degCIcon[] =
{
0x07, 0x00, 0x00, // ###
0x18, 0xC1, 0x8E, // ## ## ## ###
0x27, 0x22, 0x51, // # ### # # # # #
0x4F, 0x92, 0x50, // # ##### # # # #
0x8F, 0x89, 0x90, // # ##### # ## #
0x4F, 0x90, 0x10, // # ##### # #
0x27, 0x20, 0x11, // # ### # # #
0x18, 0xC0, 0x0E, // ## ## ###
0x07, 0x00, 0x00, // ###
};
const BITMAP_INFO DegCIconInfo(23, 9, degCIcon);
const uint8_t PROGMEM degFIcon[] =
{
0x07, 0x00, 0x00, // ###
0x18, 0xC1, 0x9E, // ## ## ## ####
0x27, 0x22, 0x50, // # ### # # # #
0x4F, 0x92, 0x50, // # ##### # # # #
0x8F, 0x89, 0x9C, // # ##### # ## ###
0x4F, 0x90, 0x10, // # ##### # #
0x27, 0x20, 0x10, // # ### # #
0x18, 0xC0, 0x10, // ## ## #
0x07, 0x00, 0x00, // ###
};
const BITMAP_INFO DegFIconInfo(23, 9, degFIcon);
//
// Image data for thermostatC
//
const uint8_t PROGMEM thermostatDegCIcon[] =
{
0x7F, 0xFF, 0xFC, // #####################
0xFF, 0xFF, 0xFE, // #######################
0xE0, 0x07, 0xDE, // ### ##### ####
0xCC, 0x73, 0x8E, // ## ## ### ### ###
0xD2, 0x8B, 0x06, // ## # # # # ## ##
0xD2, 0x83, 0xFE, // ## # # # #########
0xCC, 0x83, 0xFE, // ## ## # #########
0xC0, 0x83, 0x06, // ## # ## ##
0xC0, 0x8B, 0x8E, // ## # # ### ###
0xC0, 0x73, 0xDE, // ## ### #### ####
0xE0, 0x07, 0xFE, // ### ##########
0xFF, 0xFF, 0xFE, // #######################
0x7F, 0xFF, 0xFC, // #####################
};
const BITMAP_INFO ThermostatDegCIconInfo(23, 13, thermostatDegCIcon);
//
// Image data for thermostatDegF
//
const uint8_t PROGMEM thermostatDegFIcon[] =
{
0x7F, 0xFF, 0xFC, // #####################
0xFF, 0xFF, 0xFE, // #######################
0xE0, 0x07, 0xDE, // ### ##### ####
0xCC, 0xF3, 0x8E, // ## ## #### ### ###
0xD2, 0x83, 0x06, // ## # # # ## ##
0xD2, 0x83, 0xFE, // ## # # # #########
0xCC, 0xE3, 0xFE, // ## ## ### #########
0xC0, 0x83, 0x06, // ## # ## ##
0xC0, 0x83, 0x8E, // ## # ### ###
0xC0, 0x83, 0xDE, // ## # #### ####
0xE0, 0x07, 0xFE, // ### ##########
0xFF, 0xFF, 0xFE, // #######################
0x7F, 0xFF, 0xFC, // #####################
};
const BITMAP_INFO ThermostatDegFIconInfo(23, 13, thermostatDegFIcon);
//
// Image data for thermostatHz
//
const uint8_t PROGMEM thermostatHzIcon[] =
{
0x7F, 0xFF, 0xFC, // #####################
0xFF, 0xFF, 0xFE, // #######################
0xE0, 0x07, 0xDE, // ### ##### ####
0xC9, 0x03, 0x8E, // ## # # ### ###
0xC9, 0x03, 0x06, // ## # # ## ##
0xC9, 0x73, 0xFE, // ## # # ### #########
0xCF, 0x13, 0xFE, // ## #### # #########
0xC9, 0x23, 0x06, // ## # # # ## ##
0xC9, 0x43, 0x8E, // ## # # # ### ###
0xC9, 0x73, 0xDE, // ## # # ### #### ####
0xE0, 0x07, 0xFE, // ### ##########
0xFF, 0xFF, 0xFE, // #######################
0x7F, 0xFF, 0xFC, // #####################
};
const BITMAP_INFO ThermostatHzIconInfo(23, 13, thermostatHzIcon);
//
// Image data for reset
//
const uint8_t PROGMEM resetIcon[] =
{
0x9E, 0x00, 0x00, // # ####
0xA1, 0x07, 0x00, // # # # ###
0xC0, 0x88, 0x80, // ## # # #
0xF0, 0x49, 0x80, // #### # # ##
0x00, 0x4A, 0x80, // # # # #
0x00, 0x4C, 0x80, // # ## #
0x00, 0x48, 0x80, // # # #
0x40, 0x87, 0x00, // # # ###
0x21, 0x00, 0x00, // # #
0x1E, 0x00, 0x00, // ####
};
const BITMAP_INFO resetIconInfo(17, 10, resetIcon);
//
// Image data for miniThermo
//
const uint8_t PROGMEM miniThermoIcon[] =
{
0x30, // ##
0x48, // # #
0x48, // # #
0x48, // # #
0x48, // # #
0x48, // # #
0x48, // # #
0x48, // # #
0x78, // ####
0xFC, // ######
0xFC, // ######
0xFC, // ######
0x78, // ####
};
const BITMAP_INFO miniThermoIconInfo(6, 13, miniThermoIcon);

View file

@ -65,8 +65,8 @@ extern const BITMAP_INFO FanIcon4Info;
// 'FuelIcon', 7x12px // 'FuelIcon', 7x12px
extern const BITMAP_INFO FuelIconInfo; extern const BITMAP_INFO FuelIconInfo;
extern const BITMAP_INFO FuelIconSmallInfo;
// 'Target', 13x13px
extern const BITMAP_INFO TargetIconInfo; extern const BITMAP_INFO TargetIconInfo;
extern const BITMAP_INFO RepeatIconInfo; extern const BITMAP_INFO RepeatIconInfo;
@ -77,6 +77,8 @@ extern const BITMAP_INFO LargeTimerIconInfo;
extern const BITMAP_INFO VerticalRepeatIconInfo; extern const BITMAP_INFO VerticalRepeatIconInfo;
extern const BITMAP_INFO CrossLgIconInfo; extern const BITMAP_INFO CrossLgIconInfo;
extern const BITMAP_INFO CrossIconInfo
;
// Bitmap for open // Bitmap for open
extern const BITMAP_INFO OpenIconInfo; extern const BITMAP_INFO OpenIconInfo;
@ -130,3 +132,10 @@ extern const BITMAP_INFO UpdateIconInfo;
extern const BITMAP_INFO WWWIconInfo; extern const BITMAP_INFO WWWIconInfo;
extern const BITMAP_INFO BowserIconInfo; extern const BITMAP_INFO BowserIconInfo;
extern const BITMAP_INFO DegCIconInfo;
extern const BITMAP_INFO DegFIconInfo;
extern const BITMAP_INFO ThermostatDegCIconInfo;
extern const BITMAP_INFO ThermostatDegFIconInfo;
extern const BITMAP_INFO ThermostatHzIconInfo;
extern const BITMAP_INFO resetIconInfo;
extern const BITMAP_INFO miniThermoIconInfo;

View file

@ -368,7 +368,7 @@ const char* Errstates [] PROGMEM = {
"Flame out", // [9] E-08 "Flame out", // [9] E-08
"Temp sense", // [10] E-09 "Temp sense", // [10] E-09
"Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5 "Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5
"Failed 1st ignition attempt", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3 "Failed 1st ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3
"Unknown error?" // mystery code! "Unknown error?" // mystery code!
}; };
@ -385,7 +385,7 @@ const char* ErrstatesEx [] PROGMEM = {
"E-08: Flame out", // [9] E-08 "E-08: Flame out", // [9] E-08
"E-09: Temp sense", // [10] E-09 "E-09: Temp sense", // [10] E-09
"E-10: Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5 "E-10: Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5
"E-11: Failed 1st ignition attempt", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3 "E-11: Failed 1st ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3
"Unknown error?" // mystery code! "Unknown error?" // mystery code!
}; };

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution * This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater) * (https://gitlab.com/mrjones.id.au/bluetoothheater)
* *
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au> * Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -21,6 +21,10 @@
#include "SmartError.h" #include "SmartError.h"
#include "TxManage.h" #include "TxManage.h"
#include "../Utility/helpers.h"
#include "../Utility/macros.h"
#include "../Utility/NVStorage.h"
#include "../Utility/DataFilter.h"
CSmartError::CSmartError() CSmartError::CSmartError()
{ {
@ -83,12 +87,12 @@ CSmartError::monitor(uint8_t newRunState)
else if(newRunState > 5) { else if(newRunState > 5) {
// transitioned from preheat to post glow // transitioned from preheat to post glow
// - second ignition attempt failed, heater is shutting down // - second ignition attempt failed, heater is shutting down
m_Error = 11; m_Error = 11; // +1 over displayed error code
} }
else if(newRunState == 3) { else if(newRunState == 3) {
// transitioned from preheat to retry // transitioned from preheat to retry
// - first ignition attempt failed, heater will retry // - first ignition attempt failed, heater will retry
m_Error = 12; m_Error = 12; // +1 over displayed error code
} }
} }
} }
@ -109,6 +113,23 @@ CSmartError::monitor(uint8_t newRunState)
m_prevRunState = newRunState; m_prevRunState = newRunState;
} }
bool
CSmartError::checkVolts(float ipVolts, float glowI)
{
// check for low voltage
// values here are x10 integers
if(NVstore.getHeaterTuning().lowVolts) { // only if enabled
float cableComp = glowI * 0.1; // allow 1V drop for 10A current (bit naive but better than no compensation)
float Thresh = NVstore.getHeaterTuning().getLVC() - cableComp; // NVstore
if(ipVolts < Thresh) {
m_Error = 2; // +1 over displayed error code
requestOff();
return false;
}
}
return true;
}
// return our smart error, if it exists, as the registered code // return our smart error, if it exists, as the registered code
uint8_t uint8_t
CSmartError::getError() CSmartError::getError()

View file

@ -31,6 +31,7 @@ public:
void inhibit(); void inhibit();
void monitor(const CProtocol& heaterFrame); void monitor(const CProtocol& heaterFrame);
void monitor(uint8_t runstate); void monitor(uint8_t runstate);
bool checkVolts(float volts, float plugI);
uint8_t getError(); uint8_t getError();
}; };

View file

@ -187,7 +187,7 @@ RTC_DS3231Ex::readData(uint8_t* pData, int len, int ofs) {
Wire.endTransmission(); Wire.endTransmission();
} }
bool void
RTC_DS3231Ex::resetLostPower() RTC_DS3231Ex::resetLostPower()
{ {
Wire.beginTransmission(DS3231_ADDRESS); Wire.beginTransmission(DS3231_ADDRESS);

View file

@ -30,7 +30,7 @@ class RTC_DS3231Ex : public RTC_DS3231 {
public: public:
void writeData(uint8_t* pData, int len, int ofs=0); void writeData(uint8_t* pData, int len, int ofs=0);
void readData(uint8_t* pData, int len, int ofs=0); void readData(uint8_t* pData, int len, int ofs=0);
bool resetLostPower(); void resetLostPower();
}; };

View file

@ -277,7 +277,29 @@ void interpretJsonCommand(char* pLine)
sHeaterTuning ht = NVstore.getHeaterTuning(); sHeaterTuning ht = NVstore.getHeaterTuning();
ht.pumpCal = fCal; ht.pumpCal = fCal;
NVstore.setHeaterTuning(ht); NVstore.setHeaterTuning(ht);
NVstore.save(); }
}
else if(strcmp("TempOffset", it->key) == 0) {
float fCal = it->value.as<float>();
if(INBOUNDS(fCal, -10.0, +10.0)) {
sHeaterTuning ht = NVstore.getHeaterTuning();
ht.tempOfs = fCal;
NVstore.setHeaterTuning(ht);
}
}
else if(strcmp("LowVoltCutout", it->key) == 0) {
float fCal = it->value.as<float>();
if(fCal != 0) {
bool bOK = false;
if(NVstore.getHeaterTuning().sysVoltage == 120)
bOK = INBOUNDS(fCal, 10.0, 12.5);
else
bOK = INBOUNDS(fCal, 20.0, 25.0);
if(bOK) {
sHeaterTuning ht = NVstore.getHeaterTuning();
ht.lowVolts = uint8_t(fCal * 10);
NVstore.setHeaterTuning(ht);
}
} }
} }
} }
@ -325,7 +347,7 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len)
bSend |= moderator.addJson("FanRPM", getFanSpeed(), root ); bSend |= moderator.addJson("FanRPM", getFanSpeed(), root );
bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root ); bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root );
bSend |= moderator.addJson("FanSensor", getHeaterInfo().getFan_Sensor(), root ); bSend |= moderator.addJson("FanSensor", getHeaterInfo().getFan_Sensor(), root );
bSend |= moderator.addJson("InputVoltage", getBatteryVoltage(), root ); bSend |= moderator.addJson("InputVoltage", getBatteryVoltage(false), root );
bSend |= moderator.addJson("SystemVoltage", getHeaterInfo().getSystemVoltage(), root ); bSend |= moderator.addJson("SystemVoltage", getHeaterInfo().getSystemVoltage(), root );
bSend |= moderator.addJson("GlowVoltage", getGlowVolts(), root ); bSend |= moderator.addJson("GlowVoltage", getGlowVolts(), root );
bSend |= moderator.addJson("GlowCurrent", getGlowCurrent(), root ); bSend |= moderator.addJson("GlowCurrent", getGlowCurrent(), root );
@ -356,7 +378,9 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
bSend |= moderator.addJson("CyclicOff", stop, root); // threshold of over temp 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 bSend |= moderator.addJson("CyclicOn", NVstore.getUserSettings().cyclic.Start, root); // threshold of under temp for cyclic mode
bSend |= moderator.addJson("PumpCount", RTC_Store.getFuelGauge(), root); // running count of pump strokes bSend |= moderator.addJson("PumpCount", RTC_Store.getFuelGauge(), root); // running count of pump strokes
bSend |= moderator.addJson("PumpCal", NVstore.getHeaterTuning().pumpCal, root); // ml/stroke bSend |= moderator.addJson("PumpCal", NVstore.getHeaterTuning().pumpCal, root); // mL/stroke
bSend |= moderator.addJson("TempOffset", NVstore.getHeaterTuning().tempOfs, root); // degC offset
bSend |= moderator.addJson("LowVoltCutout", NVstore.getHeaterTuning().getLVC(), root); // low volatge cutout
if(bSend) { if(bSend) {
root.printTo(opStr, len); root.printTo(opStr, len);

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution * This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater) * (https://gitlab.com/mrjones.id.au/bluetoothheater)
* *
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au> * Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -44,6 +44,11 @@ struct sFilteredData {
CExpMean GlowAmps; CExpMean GlowAmps;
CExpMean Fan; CExpMean Fan;
CExpMean AmbientTemp; CExpMean AmbientTemp;
CExpMean FastipVolts;
CExpMean FastGlowAmps;
}; };
extern sFilteredData FilteredSamples;
#endif #endif

View file

@ -43,6 +43,13 @@ CFuelGauge::init(float fuelUsed)
_lastStoredVal = _pumpStrokes; _lastStoredVal = _pumpStrokes;
} }
void
CFuelGauge::reset()
{
_pumpStrokes = 0;
_lastStoredVal = _pumpStrokes;
RTC_Store.setFuelGauge(_pumpStrokes); // uses RTC registers to store this
}
void void
CFuelGauge::Integrate(float Hz) CFuelGauge::Integrate(float Hz)
@ -66,5 +73,11 @@ CFuelGauge::Integrate(float Hz)
float float
CFuelGauge::Used_mL() CFuelGauge::Used_mL()
{ {
return _pumpStrokes * _pumpCal; // strokes * mL / stroke return _pumpStrokes * _pumpCal; // strokes * millilitre / stroke
}
float
CFuelGauge::Used_strokes()
{
return _pumpStrokes;
} }

View file

@ -32,9 +32,12 @@ class CFuelGauge {
public: public:
CFuelGauge(); CFuelGauge();
void init(float fuelUsed = 0); void init(float fuelUsed = 0);
void reset();
void Integrate(float Hz); void Integrate(float Hz);
float Used_mL(); float Used_mL();
float Used_strokes();
}; };
extern CFuelGauge FuelGauge;
#endif #endif

View file

@ -97,6 +97,11 @@ sHeaterTuning::setSysVoltage(float fVal)
} }
} }
float
sHeaterTuning::getLVC() const
{
return lowVolts * 0.1;
}
void void
CHeaterStorage::getTimerInfo(int idx, sTimer& timerInfo) CHeaterStorage::getTimerInfo(int idx, sTimer& timerInfo)
@ -235,7 +240,12 @@ sHeaterTuning::load()
validatedLoad("systemVoltage", sysVoltage, 120, u8Match2, 120, 240); validatedLoad("systemVoltage", sysVoltage, 120, u8Match2, 120, 240);
validatedLoad("fanSensor", fanSensor, 1, u8inBounds, 1, 2); validatedLoad("fanSensor", fanSensor, 1, u8inBounds, 1, 2);
validatedLoad("glowDrive", glowDrive, 5, u8inBounds, 1, 6); validatedLoad("glowDrive", glowDrive, 5, u8inBounds, 1, 6);
if(sysVoltage == 120)
validatedLoad("lowVolts", lowVolts, 115, u8inBounds, 100, 125);
else
validatedLoad("lowVolts", lowVolts, 230, u8inBounds, 200, 250);
validatedLoad("pumpCal", pumpCal, 0.02, 0.001, 1); validatedLoad("pumpCal", pumpCal, 0.02, 0.001, 1);
validatedLoad("tempOfs", tempOfs, 0.0, -10.0, +10.0);
preferences.end(); preferences.end();
} }
@ -252,7 +262,9 @@ sHeaterTuning::save()
preferences.putUChar("systemVoltage", sysVoltage); preferences.putUChar("systemVoltage", sysVoltage);
preferences.putUChar("fanSensor", fanSensor); preferences.putUChar("fanSensor", fanSensor);
preferences.putUChar("glowDrive", glowDrive); preferences.putUChar("glowDrive", glowDrive);
preferences.putUChar("lowVolts", lowVolts);
preferences.putFloat("pumpCal", pumpCal); preferences.putFloat("pumpCal", pumpCal);
preferences.putFloat("tempOfs", tempOfs);
preferences.end(); preferences.end();
} }

View file

@ -37,10 +37,12 @@ struct sHeaterTuning : public CESP32_NVStorage {
uint8_t Pmax; uint8_t Pmax;
uint16_t Fmin; uint16_t Fmin;
uint16_t Fmax; uint16_t Fmax;
uint8_t sysVoltage; uint8_t sysVoltage; // x10
uint8_t fanSensor; uint8_t fanSensor;
uint8_t glowDrive; uint8_t glowDrive;
uint8_t lowVolts; // x10
float pumpCal; float pumpCal;
float tempOfs;
bool valid() { bool valid() {
bool retval = true; bool retval = true;
@ -52,6 +54,11 @@ struct sHeaterTuning : public CESP32_NVStorage {
retval &= fanSensor == 1 || fanSensor == 2; retval &= fanSensor == 1 || fanSensor == 2;
retval &= INBOUNDS(glowDrive, 1, 6); retval &= INBOUNDS(glowDrive, 1, 6);
retval &= INBOUNDS(pumpCal, 0.001, 1.0); retval &= INBOUNDS(pumpCal, 0.001, 1.0);
if(sysVoltage == 120)
retval &= INBOUNDS(lowVolts, 100, 125);
else
retval &= INBOUNDS(lowVolts, 200, 250);
retval &= INBOUNDS(tempOfs, -10, +10);
return retval; return retval;
}; };
void init() { void init() {
@ -63,6 +70,8 @@ struct sHeaterTuning : public CESP32_NVStorage {
fanSensor = 1; fanSensor = 1;
glowDrive = 5; glowDrive = 5;
pumpCal = 0.02; pumpCal = 0.02;
lowVolts = 115;
tempOfs = 0;
}; };
void load(); void load();
void save(); void save();
@ -75,6 +84,8 @@ struct sHeaterTuning : public CESP32_NVStorage {
fanSensor = rhs.fanSensor; fanSensor = rhs.fanSensor;
glowDrive = rhs.glowDrive; glowDrive = rhs.glowDrive;
pumpCal = rhs.pumpCal; pumpCal = rhs.pumpCal;
lowVolts = rhs.lowVolts;
tempOfs = rhs.tempOfs;
return *this; return *this;
} }
float getPmin() const; float getPmin() const;
@ -82,6 +93,7 @@ struct sHeaterTuning : public CESP32_NVStorage {
void setPmin(float val); void setPmin(float val);
void setPmax(float val); void setPmax(float val);
void setSysVoltage(float val); void setSysVoltage(float val);
float getLVC() const;
}; };
struct sHomeMenuActions { struct sHomeMenuActions {
@ -108,6 +120,11 @@ struct sHomeMenuActions {
} }
}; };
struct sHourMeter {
unsigned long RunTime;
unsigned long GlowTime;
};
struct sCyclicThermostat { struct sCyclicThermostat {
int8_t Stop; int8_t Stop;
int8_t Start; int8_t Start;

View file

@ -152,6 +152,12 @@ struct CRect {
CRect() { CRect() {
xPos = yPos = width = height = 0; xPos = yPos = width = height = 0;
} }
CRect(const CRect& a) {
xPos = a.xPos;
yPos = a.yPos;
width = a.width;
height = a.height;
}
void Expand(int val) { void Expand(int val) {
xPos -= val; xPos -= val;
yPos -= val; yPos -= val;

View file

@ -78,19 +78,12 @@ extern void setUploadSize(long val);
extern void getGPIOinfo(sGPIO& info); extern void getGPIOinfo(sGPIO& info);
extern void simulateGPIOin(uint8_t newKey); extern void simulateGPIOin(uint8_t newKey);
extern void setDegFMode(bool state); extern void setDegFMode(bool state);
extern float getBatteryVoltage(); extern float getBatteryVoltage(bool fast);
extern float getGlowVolts(); extern float getGlowVolts();
extern float getGlowCurrent(); extern float getGlowCurrent();
extern float getFanSpeed(); extern float getFanSpeed();
extern int sysUptime(); extern int sysUptime();
/* extern void setFuelGauge_RTC(float val);
extern void getFuelGauge_RTC(float& val);
extern void setDesiredTemp_RTC(uint8_t val);
extern void getDesiredTemp_RTC(uint8_t& val);
extern void setDesiredPump_RTC(uint8_t val);
extern void getDesiredPump_RTC(uint8_t& val);*/
extern void ShowOTAScreen(int percent=0, eOTAmodes updateType=eOTAnormal); extern void ShowOTAScreen(int percent=0, eOTAmodes updateType=eOTAnormal);

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution * This file is part of the "bluetoothheater" distribution
* (https://gitlab.com/mrjones.id.au/bluetoothheater) * (https://gitlab.com/mrjones.id.au/bluetoothheater)
* *
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au> * Copyright (C) 2019 Ray Jones <ray@mrjones.id.au>
* Copyright (C) 2018 James Clark * Copyright (C) 2018 James Clark
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
@ -23,12 +23,12 @@
#ifndef __MACROS_H__ #ifndef __MACROS_H__
#define __MACROS_H__ #define __MACROS_H__
#define LOWERLIMIT(A, B) if((A) < (B)) (A) = (B) #define LOWERLIMIT(A, B) { if((A) < (B)) (A) = (B); }
#define UPPERLIMIT(A, B) if((A) > (B)) (A) = (B) #define UPPERLIMIT(A, B) { if((A) > (B)) (A) = (B); }
#define WRAPUPPERLIMIT(A, B, C) if((A) > (B)) (A) = (C) #define WRAPUPPERLIMIT(A, B, C) { if((A) > (B)) (A) = (C); }
#define WRAPLOWERLIMIT(A, B, C) if((A) < (B)) (A) = (C) #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 WRAPLIMITS(A, B, C) { if((A) < (B)) (A) = (C) ; if((A) > (C)) (A) = (B); }
#define INBOUNDS(TST, MIN, MAX) (((TST) >= (MIN)) && ((TST) <= (MAX))) #define INBOUNDS(TST, MIN, MAX) (((TST) >= (MIN)) && ((TST) <= (MAX)))
#define BOUNDSLIMIT(A, B, C) if((A) < (B)) (A) = (B); if((A) > (C)) (A) = (C) #define BOUNDSLIMIT(A, B, C) { if((A) < (B)) (A) = (B); if((A) > (C)) (A) = (C); }
#endif #endif