Added excess fuel usage shutdown feature

This commit is contained in:
Ray Jones 2020-03-30 16:17:54 +11:00
parent 8b8aaf0024
commit 8ec438e02a
19 changed files with 546 additions and 101 deletions

View File

@ -128,7 +128,7 @@
const int FirmwareRevision = 32;
const int FirmwareSubRevision = 0;
const int FirmwareMinorRevision = 0;
const char* FirmwareDate = "21 Mar 2020";
const char* FirmwareDate = "30 Mar 2020";
#ifdef ESP32
@ -907,6 +907,7 @@ void loop()
// 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());
SmartError.checkfuelUsage();
}
// trap being in state 0 with a heater error - cancel user on memory to avoid unexpected cyclic restarts
@ -1072,7 +1073,11 @@ bool validateFrame(const CProtocol& frame, const char* name)
int requestOn(bool checkTemp)
{
bool LVCOK = SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue()) != 2;
bool fuelOK = 2 != SmartError.checkfuelUsage();
if(!fuelOK) {
return -4;
}
bool LVCOK = 2 != SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue());
if(bHasHtrData && LVCOK) {
RTC_Store.setCyclicEngaged(true); // for cyclic mode
RTC_Store.setFrostOn(false); // cancel frost mode
@ -1129,7 +1134,6 @@ bool reqDemand(uint8_t newDemand, bool save)
// set and save the demand to NV storage
// note that we now maintain fixed Hz and Thermostat set points seperately
if(getThermostatModeActive()) {
// RTC_Store.setDesiredTemp(newDemand);
CTimerManager::setWorkingTemperature(newDemand);
}
else {
@ -1144,7 +1148,6 @@ bool reqDemandDelta(int delta)
{
uint8_t newDemand;
if(getThermostatModeActive()) {
// newDemand = RTC_Store.getDesiredTemp() + delta;
newDemand = CTimerManager::getWorkingTemperature() + delta;
}
else {
@ -1251,7 +1254,6 @@ void forceBootInit()
uint8_t getDemandDegC()
{
return CTimerManager::getWorkingTemperature();
// return RTC_Store.getDesiredTemp();
}
void setDemandDegC(uint8_t val)
@ -1259,7 +1261,6 @@ void setDemandDegC(uint8_t val)
uint8_t max = DefaultBTCParams.getTemperature_Max();
uint8_t min = DefaultBTCParams.getTemperature_Min();
BOUNDSLIMIT(val, min, max);
// RTC_Store.setDesiredTemp(val);
CTimerManager::setWorkingTemperature(val);
}
@ -1276,7 +1277,6 @@ float getTemperatureDesired()
}
else {
if(getThermostatModeActive())
// return RTC_Store.getDesiredTemp();
return CTimerManager::getWorkingTemperature();
else
return RTC_Store.getDesiredPump();

View File

@ -73,6 +73,7 @@ CBasicScreen::show()
case -1: strcpy(msg, "Ignored - too warm!"); break;
case -2: strcpy(msg, "Suspended - too warm!"); break;
case -3: strcpy(msg, "Ignored - low voltage!"); break;
case -4: strcpy(msg, "Ignored - fuel empty!"); break;
}
// centre message at bottom of screen
_printMenuText(_display.xCentre(), _display.height() - _display.textHeight(), msg, false, eCentreJustify);

View File

@ -29,15 +29,14 @@
#include "fonts/Icons.h"
static const int Line3 = 14;
static const int Line2 = 20;
static const int Line1 = 36;
static const int Line2 = 26;
static const int Line1 = 38;
CFuelCalScreen::CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
_mlPerStroke = 0.02;
_LVC = 115;
}
void
@ -46,14 +45,15 @@ CFuelCalScreen::onSelect()
CPasswordScreen::onSelect();
_initUI();
_mlPerStroke = NVstore.getHeaterTuning().pumpCal;
_LVC = NVstore.getHeaterTuning().lowVolts;
_maxUsage = NVstore.getHeaterTuning().maxFuelUsage;
_warnUsage = NVstore.getHeaterTuning().warnFuelUsage;
}
bool
CFuelCalScreen::show()
{
char msg[20];
const int col = 90;
const int col = 86;
_display.fillRect(0, 50, 128, 14, BLACK);
_display.fillRect(col-border, Line3-border, 128-(col-1), 64-Line3-border, BLACK);
@ -65,20 +65,33 @@ CFuelCalScreen::show()
_animateCount = 0;
}
_showTitle("Special Features");
_showTitle("Fuel usage");
// fuel calibration
int yPos = Line1;
_printMenuText(col, yPos, "mL/stroke : ", false, eRightJustify);
_printMenuText(col, yPos, ":", false, eRightJustify);
_printMenuText(col-7, 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);
_printMenuText(col+2, yPos, msg, _rowSel == 1);
// tank calibration
_drawBitmap(6, Line3+3, BowserIconInfo);
yPos = Line3;
_printMenuText(col, yPos, ":", false, eRightJustify);
_printMenuText(col-7, yPos, "Maximum", false, eRightJustify);
if(_maxUsage != 0)
sprintf(msg, "%.1fL", float(_maxUsage) * 0.1f);
else
strcpy(msg, "OFF");
_printMenuText(col, yPos, msg, _rowSel == 2);
strcpy(msg, "Off");
_printMenuText(col+2, yPos, msg, _rowSel == 3);
yPos = Line2;
_printMenuText(col, yPos, ":", false, eRightJustify);
_printMenuText(col-7, yPos, "Warning", false, eRightJustify);
if(_maxUsage != 0)
sprintf(msg, "%.1fL", float(_warnUsage) * 0.1f);
else
strcpy(msg, "n/a");
_printMenuText(col+2, yPos, msg, _rowSel == 2);
// navigation line
yPos = 53;
int xPos = _display.xCentre();
@ -109,29 +122,24 @@ CFuelCalScreen::animate()
if(_animateCount >= 0) {
switch(_animateCount) {
case 0:
_display.fillRect(0, Line3-3, BatteryIconInfo.width, 35, BLACK);
_display.fillRect(6, Line1-3, FuelIconSmallInfo.width, FuelIconSmallInfo.height+4, BLACK); // scrub prior drip
_drawBitmap(6, Line1-3, FuelIconSmallInfo);
_drawBitmap(0, Line2-1 , BatteryIconInfo);
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
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
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
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
break;
}
@ -198,7 +206,7 @@ CFuelCalScreen::keyHandler(uint8_t event)
case 2:
case 3:
_rowSel++;
UPPERLIMIT(_rowSel, 2);
UPPERLIMIT(_rowSel, 3);
break;
}
}
@ -233,27 +241,12 @@ CFuelCalScreen::_adjust(int dir)
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);
}
}
_warnUsage += dir;
BOUNDSLIMIT(_warnUsage, 0, 100);
break;
case 3:
_maxUsage += dir;
BOUNDSLIMIT(_maxUsage, 0, 10000);
break;
}
}
@ -263,8 +256,8 @@ CFuelCalScreen::_saveNV()
{
sHeaterTuning tuning = NVstore.getHeaterTuning();
tuning.pumpCal = _mlPerStroke;
tuning.lowVolts = _LVC;
// tuning.DS18B20probe[0].offset = _tOfs;
tuning.maxFuelUsage = _maxUsage;
tuning.warnFuelUsage = _warnUsage;
NVstore.setHeaterTuning(tuning);
NVstore.save();
}

View File

@ -32,7 +32,8 @@ class CFuelCalScreen : public CPasswordScreen
{
void _adjust(int dir);
float _mlPerStroke;
uint8_t _LVC;
uint16_t _maxUsage;
uint16_t _warnUsage;
protected:
void _saveNV();
public:

239
src/OLED/LVCScreen.cpp Normal file
View File

@ -0,0 +1,239 @@
/*
* 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/>.
*
*/
#include "128x64OLED.h"
#include "LVCScreen.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../Utility/macros.h"
#include "../Utility/NVStorage.h"
#include "../Protocol/Protocol.h"
#include "fonts/Icons.h"
static const int Line3 = 14;
static const int Line2 = 20;
static const int Line1 = 36;
CLVCScreen::CLVCScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
{
_initUI();
_LVC = 115;
}
void
CLVCScreen::onSelect()
{
CPasswordScreen::onSelect();
_initUI();
_LVC = NVstore.getHeaterTuning().lowVolts;
}
bool
CLVCScreen::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(_animateCount < 0) {
_display.clearDisplay();
_animateCount = 0;
}
_showTitle("Low Volt Cutout");
// low voltage cutout
int yPos = Line2;
_printMenuText(col, yPos, "Shutdown < ", false, eRightJustify);
if(_LVC)
sprintf(msg, "%.1fV", float(_LVC) * 0.1);
else
strcpy(msg, "OFF");
_printMenuText(col, yPos, msg, _rowSel == 1);
// 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
CLVCScreen::animate()
{
if(_saveBusy()) {
return false;
}
if(_animateCount >= 0) {
switch(_animateCount) {
case 0:
_display.fillRect(0, Line3-3, BatteryIconInfo.width, 35, BLACK);
_drawBitmap(0, Line2-1 , BatteryIconInfo);
break;
case 2:
_display.fillRect(BatteryIconInfo.width - 4, Line2+2, 2, 5, BLACK); // deplete battery
break;
case 4:
_display.fillRect(BatteryIconInfo.width - 7, Line2+2, 2, 5, BLACK); // deplete battery
break;
case 6:
_display.fillRect(BatteryIconInfo.width - 10, Line2+2, 2, 5, BLACK); // deplete battery
break;
case 8:
_display.fillRect(BatteryIconInfo.width - 13, Line2+2, 2, 5, BLACK); // deplete battery
break;
}
_animateCount++;
WRAPUPPERLIMIT(_animateCount, 9, 0);
}
return true;
}
bool
CLVCScreen::keyHandler(uint8_t event)
{
if(CUIEditScreen::keyHandler(event)) { // handles save confirm
return true;
}
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:
_adjust(-1);
break;
}
}
// press RIGHT to select next screen
if(event & key_Right) {
switch(_rowSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 1:
_adjust(+1);
break;
}
}
if(event & key_Down) {
_rowSel--;
LOWERLIMIT(_rowSel, 0);
}
// UP press
if(event & key_Up) {
switch(_rowSel) {
case 0:
_rowSel++;
UPPERLIMIT(_rowSel, 1);
break;
}
}
// CENTRE press
if(event & key_Centre) {
switch(_rowSel) {
case 0:
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop);
break;
case 1:
_animateCount = -1;
_display.clearDisplay();
_confirmSave();
_rowSel = 0;
break;
}
}
_ScreenManager.reqUpdate();
}
return true;
}
void
CLVCScreen::_adjust(int dir)
{
switch(_rowSel) {
case 1:
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;
}
}
void
CLVCScreen::_saveNV()
{
sHeaterTuning tuning = NVstore.getHeaterTuning();
tuning.lowVolts = _LVC;
NVstore.setHeaterTuning(tuning);
NVstore.save();
}

45
src/OLED/LVCScreen.h Normal file
View File

@ -0,0 +1,45 @@
/*
* 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 __LVCSCREEN_H__
#define __LVCSCREEN_H__
#include <stdint.h>
#include "PasswordScreen.h"
class C128x64_OLED;
class CScreenManager;
class CLVCScreen : public CPasswordScreen
{
void _adjust(int dir);
uint8_t _LVC;
protected:
void _saveNV();
public:
CLVCScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);
void onSelect();
};
#endif

View File

@ -26,6 +26,7 @@
#include "fonts/Icons.h"
#include "../RTC/Clock.h"
#include "../Utility/FuelGauge.h"
#include "fonts/Arial.h"
///////////////////////////////////////////////////////////////////////////
@ -65,6 +66,7 @@ CPrimingScreen::_initUI()
_PrimeCheck = 0;
_paramSel = 0;
_colSel = 0;
_resetConfirm = false;
}
bool
@ -72,10 +74,20 @@ CPrimingScreen::show()
{
CScreenHeader::show(false);
_display.fillRect(0, 15, 100, 3, BLACK);
_display.fillRect(0, 15, 60, 2, BLACK);
_display.fillRect(0, 17, 100, 1, BLACK);
CRect extents;
if(_resetConfirm) {
_display.writeFillRect(12, 24, 104, 30, WHITE);
int x = _display.xCentre();
CTransientFont AF(_display, &arial_8ptBoldFontInfo);
_printInverted(x, 27, "Press Up to", true, eCentreJustify);
_printInverted(x, 39, "confirm reset ", true, eCentreJustify);
return true;
}
int yPos = 53;
// show next/prev menu navigation line
switch(_paramSel) {
@ -146,8 +158,10 @@ CPrimingScreen::show()
}
// fuel pump priming menu
int toplinePump = topline+1;
int botlinePump = botline+1;
// int toplinePump = topline+1;
// int botlinePump = botline+1;
int toplinePump = topline+2;
int botlinePump = botline+2;
loc.xPos = 66;
loc.width = BowserIconInfo.width;
loc.height = BowserIconInfo.height;
@ -237,6 +251,7 @@ CPrimingScreen::keyHandler(uint8_t event)
}
break;
}
_resetConfirm = false;
}
// press RIGHT
if(event & key_Right) {
@ -249,7 +264,7 @@ CPrimingScreen::keyHandler(uint8_t event)
UPPERLIMIT(_paramSel, 3);
switch(_paramSel) {
case 3:
_colSel = 0; // select OFF upon entry to priming menu
_colSel = -1; // select fuel gauge reset // select OFF upon entry to priming menu
break;
case 2:
_colSel = NVstore.getUserSettings().degF ? 1 : 0;
@ -260,6 +275,7 @@ CPrimingScreen::keyHandler(uint8_t event)
}
break;
}
_resetConfirm = false;
}
// press UP
if(event & key_Up) {
@ -284,7 +300,11 @@ CPrimingScreen::keyHandler(uint8_t event)
saveNV();
break;
case 3:
if(_colSel == 1)
if(_resetConfirm) {
FuelGauge.reset();
_paramSel = _colSel = 0;
}
else if(_colSel == 1)
_colSel = 0;
else {
_colSel++;
@ -295,9 +315,11 @@ CPrimingScreen::keyHandler(uint8_t event)
break;
}
}
_resetConfirm = false;
}
// press DOWN
if(event & key_Down) {
_resetConfirm = false;
if(_paramSel == 0) {
_ScreenManager.selectMenu(CScreenManager::SystemSettingsLoop, CScreenManager::SysVerUI); // force return to main menu
}
@ -326,7 +348,7 @@ CPrimingScreen::keyHandler(uint8_t event)
}
}
}
// press UP
// press CENTRE
if(event & key_Centre) {
if(_paramSel == 3) {
switch(_colSel) {
@ -338,13 +360,13 @@ CPrimingScreen::keyHandler(uint8_t event)
_colSel = 0;
break;
case -1:
FuelGauge.reset();
_paramSel = _colSel = 0;
_resetConfirm = !_resetConfirm;
break;
}
}
else {
_paramSel = _colSel = 0;
_resetConfirm = false;
}
}

View File

@ -33,6 +33,7 @@ class CPrimingScreen : public CScreenHeader {
unsigned long _PrimeCheck;
int _paramSel;
int _colSel;
bool _resetConfirm;
void _stopPump();
void _initUI();
public:

View File

@ -141,47 +141,98 @@ CScreenHeader::animate()
// inserting an update icon if new firmware available from internet web server
_animateCount++;
WRAPUPPERLIMIT(_animateCount, 11, 0);
int newVer = isUpdateAvailable(true);
if(newVer) {
int xPos = X_TIMER_ICON - 3;
int yPos = Y_TIMER_ICON;
char msg[16];
CTransientFont AF(_display, &miniFontInfo); // temporarily use a mini font
int xPos = X_TIMER_ICON - 3;
int yPos = Y_TIMER_ICON;
int fuelUsage = SmartError.checkfuelUsage(false);
if(fuelUsage) {
// flash sequence
// LOW _######_____
// EMPTY _###_###_###
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
switch(_animateCount) {
case 0:
_display.fillRect(xPos, yPos, TimerIconInfo.width+3, TimerIconInfo.height, BLACK);
_display.fillRect(xPos-2, yPos+12, 21, 5, BLACK); // erase annotation
break;
_display.fillRect(xPos-4, yPos+12, 25, 5, BLACK); // erase annotation
break;
case 1:
_drawBitmap(xPos+6, yPos, UpdateIconInfo);
crackVer(msg, newVer);
_printMenuText(xPos+19, yPos+12, msg, false, eRightJustify);
_drawBitmap(xPos, yPos, BowserIconInfo);
yPos += BowserIconInfo.height;
_display.fillRect(xPos, yPos-1, BowserIconInfo.width, 1, BLACK); // erase bottom of pump icon
xPos += BowserIconInfo.width/2;
if(fuelUsage == 2)
_printMenuText(xPos, yPos, "EMPTY", false, eCentreJustify);
else
_printMenuText(xPos, yPos, "LOW", false, eCentreJustify);
break;
case 2:
_display.fillRect(xPos, yPos, TimerIconInfo.width+3, TimerIconInfo.height, BLACK);
case 4:
case 8:
if(fuelUsage == 2) {
_display.fillRect(xPos, yPos, BowserIconInfo.width, BowserIconInfo.height, BLACK);
_display.fillRect(xPos-4, yPos+BowserIconInfo.height, 21, 5, BLACK); // erase annotation
}
break;
case 3:
_display.fillRect(xPos-8, yPos+12, 30, 5, BLACK); // erase version annotation
default:
showTimers();
case 7:
if(fuelUsage != 2) {
_display.fillRect(xPos, yPos, BowserIconInfo.width, BowserIconInfo.height, BLACK);
_display.fillRect(xPos-4, yPos+BowserIconInfo.height, 21, 5, BLACK); // erase annotation
}
break;
case 5:
case 9:
if(fuelUsage == 2) {
_drawBitmap(xPos, yPos, BowserIconInfo);
yPos += BowserIconInfo.height;
_display.fillRect(xPos, yPos-1, BowserIconInfo.width, 1, BLACK); // erase bottom of pump icon
xPos += BowserIconInfo.width/2;
_printMenuText(xPos, yPos, "EMPTY", false, eCentreJustify);
}
break;
}
}
else {
showTimers();
int newVer = isUpdateAvailable(true);
if(newVer) {
char msg[16];
CTransientFont AF(_display, &miniFontInfo); // temporarily use a mini font
switch(_animateCount) {
case 0:
_display.fillRect(xPos, yPos, TimerIconInfo.width+3, TimerIconInfo.height, BLACK);
_display.fillRect(xPos-2, yPos+12, 21, 5, BLACK); // erase annotation
break;
case 1:
_drawBitmap(xPos+6, yPos, UpdateIconInfo);
crackVer(msg, newVer);
_printMenuText(xPos+19, yPos+12, msg, false, eRightJustify);
break;
case 2:
_display.fillRect(xPos, yPos, TimerIconInfo.width+3, TimerIconInfo.height, BLACK);
break;
case 3:
_display.fillRect(xPos-8, yPos+12, 30, 5, BLACK); // erase version annotation
default:
showTimers();
break;
}
}
else {
showTimers();
}
}
_batteryCount++;
WRAPUPPERLIMIT(_batteryCount, 5, 0);
int xPos = X_BATT_ICON;
int yPos = Y_BATT_ICON;
xPos = X_BATT_ICON;
yPos = Y_BATT_ICON;
switch(_batteryCount) {
case 0:
// establish battery icon flash pattern
// > 0.5 over LVC - solid
// < 0.5 over LVC - slow flash
// < LVC - fast flash
_batteryWarn = SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue(), false);
_batteryWarn = SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(),
FilteredSamples.FastGlowAmps.getValue(),
false);
showBatteryIcon(getBatteryVoltage(true));
break;
@ -265,7 +316,7 @@ CScreenHeader::showWifiIcon()
_display.fillRect(X_WIFI_ICON+11, Y_WIFI_ICON, 2, 6, BLACK);
CTransientFont AF(_display, &MINIFONT); // temporarily use a mini font
_display.setCursor(X_WIFI_ICON+12, Y_WIFI_ICON);
_display.print("OTA");
_display.print("oTA");
}
}
@ -420,7 +471,7 @@ CScreenHeader::showTime()
CTransientFont AF(_display, &arial_8ptFontInfo);
if(NVstore.getUserSettings().clock12hr)
xPos -= 3;
_display.fillRect(xPos, Y_CLOCK, 30, arial_8ptFontInfo.nBitsPerLine, BLACK);
_display.fillRect(xPos, Y_CLOCK, 30, 8, BLACK);
_printMenuText(xPos, Y_CLOCK-2, msg);
CRect extents;
extents.xPos = 0;

View File

@ -52,6 +52,7 @@
#include "FrostScreen.h"
#include "HumidityScreen.h"
#include "WebPageUpdateScreen.h"
#include "LVCScreen.h"
#include <Wire.h>
#include "../cfg/pins.h"
#include "../cfg/BTCConfig.h"
@ -445,6 +446,7 @@ CScreenManager::_loadScreens()
menuloop.push_back(new CFuelMixtureScreen(*_pDisplay, *this)); // mixture tuning
menuloop.push_back(new CHeaterSettingsScreen(*_pDisplay, *this)); // heater system tuning
menuloop.push_back(new CFuelCalScreen(*_pDisplay, *this)); // fuel pump calibration
menuloop.push_back(new CLVCScreen(*_pDisplay, *this)); // low volt cutout calibration
_Screens.push_back(menuloop);
// create branch screens

View File

@ -120,13 +120,20 @@ CSetTimerScreen::show()
xPos = 18;
yPos = 40;
float fTemp = _timerInfo.temperature;
if(NVstore.getUserSettings().degF) {
fTemp = fTemp * 9 / 5 + 32;
sprintf(str, "%.0f`F", fTemp);
if(fTemp == 0) {
strcpy(str, "Current set ");
}
else {
sprintf(str, "%.0f`C", fTemp);
if(NVstore.getUserSettings().degF) {
fTemp = fTemp * 9 / 5 + 32;
sprintf(str, "%.0f", fTemp);
}
else {
sprintf(str, "%.0f", fTemp);
}
}
bool degF = NVstore.getUserSettings().degF;
strcat(str, degF ? "`F" : "`C");
_printMenuText(_display.xCentre(), yPos, str, _rowSel==1 && _colSel==6, eCentreJustify);
@ -349,8 +356,12 @@ CSetTimerScreen::_adjust(int dir)
_timerInfo.repeat = !_timerInfo.repeat;
break;
case 6:
_timerInfo.temperature += dir;
BOUNDSLIMIT(_timerInfo.temperature, 8, 35);
if(_timerInfo.temperature <= 8 && dir < 0)
_timerInfo.temperature = 0;
else {
_timerInfo.temperature += dir;
BOUNDSLIMIT(_timerInfo.temperature, 8, 35);
}
break;
}
}

View File

@ -160,7 +160,7 @@ const uint8_t miniFontBitmaps[] PROGMEM =
0x40, // #
0xf8, // #####
// @78 'O' (3 pixels wide)
// @78 'o' (3 pixels wide)
0x70, // ###
0x88, // # #
0x70, // ###
@ -182,6 +182,36 @@ const uint8_t miniFontBitmaps[] PROGMEM =
0x20, // #
0x20, // #
0x20, // #
// @91 'N' (3 pixels wide)
0xf8, // #####
0x20, // #
0xf8, // #####
// @94 'Y' (3 pixels wide)
0xc0, // ##
0x38, // ###
0xc0, // ##
// @97 'a' (3 pixels wide)
0x10, // #
0x28, // # #
0x38, // ###
// @100 'n' (3 pixels wide)
0x38, // ###
0x20, // #
0x38, // ###
// @103 'O' (3 pixels wide)
0xF8, // #####
0x88, // # #
0xF8, // #####
// @106 'r' (3 pixels wide)
0x38, // ###
0x20, // #
0x20, // #
};
// Character descriptors for a 3x5 font
@ -221,8 +251,8 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{0, 0, 0}, // 'K'
{3, 5, 48}, // 'L'
{3, 5, 75}, // 'M'
{0, 0, 0}, // 'N'
{3, 5, 78}, // 'O'
{3, 5, 91}, // 'N'
{3, 5, 103}, // 'O'
{3, 5, 51}, // 'P'
{0, 0, 0}, // 'Q'
{3, 5, 66}, // 'R'
@ -232,7 +262,7 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{3, 5, 57}, // 'V'
{3, 5, 60}, // 'W'
{0, 0, 0}, // 'X'
{0, 0, 0}, // 'Y'
{3, 5, 94}, // 'Y'
{0, 0, 0}, // 'Z'
{0, 0, 0}, // '['
{0, 0, 0}, // '\'
@ -240,7 +270,7 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{0, 0, 0}, // '^'
{0, 0, 0}, // '_'
{2, 5, 31}, // '`' use for degree symbol
{0, 0, 0}, // 'a'
{3, 5, 97}, // 'a'
{0, 0, 0}, // 'b'
{0, 0, 0}, // 'c'
{0, 0, 0}, // 'd'
@ -253,11 +283,11 @@ const FONT_CHAR_INFO miniFontDescriptors[] PROGMEM =
{0, 0, 0}, // 'k'
{0, 0, 0}, // 'l'
{0, 0, 0}, // 'm'
{0, 0, 0}, // 'n'
{0, 0, 0}, // 'o'
{3, 5, 100}, // 'n'
{3, 5, 78}, // 'O'
{0, 0, 0}, // 'p'
{0, 0, 0}, // 'q'
{0, 0, 0}, // 'r'
{3, 5, 106}, // 'r'
{0, 0, 0}, // 's'
{0, 0, 0}, // 't'
{0, 0, 0}, // 'u'

View File

@ -384,7 +384,8 @@ const char* Errstates [] PROGMEM = {
"Flame out", // [9] E-08
"Temp sense", // [10] E-09
"Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5
"Failed 1st ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3
"Failed 1st ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3
"Excess fuel usage", // [13] E-12 SmartError manufactured state - excess fuel consumed
"Unknown error?" // mystery code!
};
@ -402,6 +403,7 @@ const char* ErrstatesEx [] PROGMEM = {
"E-09: Temp sense", // [10] E-09
"E-10: Ignition fail", // [11] E-10 SmartError manufactured state - sensing runstate 2 -> >5
"E-11: Failed 1st ignite", // [12] E-11 SmartError manufactured state - sensing runstate 2 -> 3
"E-12 Excess fuel shutdown", // [13] E-12 SmartError manufactured state - excess fuel consumed
"Unknown error?" // mystery code!
};

View File

@ -25,6 +25,7 @@
#include "../Utility/macros.h"
#include "../Utility/NVStorage.h"
#include "../Utility/DataFilter.h"
#include "../Utility/FuelGauge.h"
CSmartError::CSmartError()
{
@ -181,4 +182,30 @@ uint8_t
CSmartError::getError()
{
return _Error;
}
}
int
CSmartError::checkfuelUsage(bool throwfault)
{
int retval = 0;
// const sUserSettings& settings = NVstore.getUserSettings();
if(NVstore.getHeaterTuning().maxFuelUsage) {
// saved as x10 litres (ala decilitres)
uint16_t maxUsage = NVstore.getHeaterTuning().maxFuelUsage;
uint16_t actualUsage = (uint16_t)(FuelGauge.Used_mL() * .01); // convert ml to decilitres
uint16_t warnUsage = maxUsage - NVstore.getHeaterTuning().warnFuelUsage;
if(actualUsage >= warnUsage) {
retval = 1;
}
if(actualUsage >= maxUsage) {
retval = 2;
if(throwfault) {
DebugPort.println("Excess fuel usage shutting heater down");
_Error = 13; // internals error codes are +1 over displayed error code
requestOff(); // shut heater down
}
}
}
return retval;
}

View File

@ -32,6 +32,7 @@ public:
void monitor(const CProtocol& heaterFrame);
void monitor(uint8_t runstate);
int checkVolts(float volts, float plugI, bool throwfault=true); // 0 = OK, 1 = within 0.5V of LVC, 2 = under LVC
int checkfuelUsage(bool throwfault=true);
uint8_t getError();
};

View File

@ -270,7 +270,8 @@ CTimerManager::manageTime(int _hour, int _minute, int _dow)
// get timer settings
int ID = (newID & 0xf) - 1;
NVstore.getTimerInfo(ID, timer);
_workingTemperature = timer.temperature;
if(timer.temperature)
_workingTemperature = timer.temperature;
DebugPort.printf("Start of timer interval, starting heater @ %dC\r\n", _workingTemperature);
requestOn();
_activeDow = dow; // dow when timer interval start was detected

View File

@ -269,6 +269,8 @@ sHeaterTuning::load()
else
validatedLoad("lowVolts", lowVolts, 230, u8inBoundsOrZero, 200, 250);
validatedLoad("pumpCal", pumpCal, 0.02, 0.001, 1);
validatedLoad("maxFuelUsage", maxFuelUsage, 0, u16inBounds, 0, 10000);
validatedLoad("warnFuelUsage", warnFuelUsage, 5, u16inBounds, 0, 100);
validatedLoad("tempOffset0", DS18B20probe[0].offset, 0.0, -10.0, +10.0);
validatedLoad("tempOffset1", DS18B20probe[1].offset, 0.0, -10.0, +10.0);
validatedLoad("tempOffset2", DS18B20probe[2].offset, 0.0, -10.0, +10.0);
@ -326,6 +328,8 @@ sHeaterTuning::save()
preferences.putUChar("glowDrive", glowDrive);
preferences.putUChar("lowVolts", lowVolts);
saveFloat("pumpCal", pumpCal);
preferences.putUShort("maxFuelUsage", maxFuelUsage);
preferences.putUShort("warnFuelUsage", warnFuelUsage);
saveFloat("tempOffset0", DS18B20probe[0].offset);
saveFloat("tempOffset1", DS18B20probe[1].offset);
saveFloat("tempOffset2", DS18B20probe[2].offset);

View File

@ -52,6 +52,8 @@ struct sHeaterTuning : public CESP32_NVStorage {
uint8_t glowDrive;
uint8_t lowVolts; // x10
float pumpCal;
uint16_t maxFuelUsage;
uint16_t warnFuelUsage;
sDS18B20ProbeTuning DS18B20probe[3]; // [0],[1],[2] - Primary, Secondary, Tertiary
sBM280tuning BME280probe;
@ -84,6 +86,8 @@ struct sHeaterTuning : public CESP32_NVStorage {
fanSensor = 1;
glowDrive = 5;
pumpCal = 0.02;
maxFuelUsage = 0;
warnFuelUsage = 0;
lowVolts = 115;
DS18B20probe[0].offset = 0;
DS18B20probe[1].offset = 0;
@ -105,6 +109,8 @@ struct sHeaterTuning : public CESP32_NVStorage {
fanSensor = rhs.fanSensor;
glowDrive = rhs.glowDrive;
pumpCal = rhs.pumpCal;
maxFuelUsage = rhs.maxFuelUsage;
warnFuelUsage = rhs.warnFuelUsage;
lowVolts = rhs.lowVolts;
DS18B20probe[0].offset = rhs.DS18B20probe[0].offset;
DS18B20probe[1].offset = rhs.DS18B20probe[1].offset;

View File

@ -27,6 +27,7 @@
#include "macros.h"
#include "BTC_JSON.h"
#include "../WiFi/BTCWebServer.h"
#include "FuelGauge.h"
// a class to track the blue wire receive / transmit states
@ -104,6 +105,7 @@ CProfile::elapsed(bool reset/* = false*/)
void DecodeCmd(const char* cmd, String& payload)
{
int val;
if(strcmp("TempDesired", cmd) == 0) {
if( !reqDemand(payload.toInt(), false) ) { // this request is blocked if OEM controller active
resetJSONmoderator("TempDesired");
@ -443,6 +445,12 @@ void DecodeCmd(const char* cmd, String& payload)
else if(strcmp("LoadWebContent", cmd) == 0) {
getWebContent(true);
}
/* // TESTO hook - make sure removed for production
else if(strcmp("testo", cmd) == 0) {
val = payload.toInt();
FuelGauge.init(val);
DebugPort.printf("Set Fuel usage to %d => %f\r\n", val, FuelGauge.Used_mL());
}*/
}
void setHoldoff(unsigned long& holdoff, unsigned long period)