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
/webdev
/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/NVStorage.h"
#include "src/Utility/DebugPort.h"
#include "src/Utility/macros.h"
#include "src/Utility/UtilClasses.h"
#include "src/Utility/BTC_JSON.h"
#include "src/Utility/BTC_GPIO.h"
@ -446,7 +447,11 @@ void setup() {
FilteredSamples.Fan.setRounding(10);
FilteredSamples.Fan.setAlpha(0.7);
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();
FuelGauge.init(RTC_Store.getFuelGauge());
// demandDegC = RTC_Store.getDesiredTemp();
@ -792,9 +797,24 @@ void loop()
ScreenManager.reqUpdate();
}
if(bHasHtrData) {
// apply exponential mean to the anlogue readings for some smoothing
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);
CommState.set(CommStates::Idle);
@ -822,7 +842,7 @@ void manageCyclicMode()
const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic;
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!
float deltaT = FilteredSamples.AmbientTemp.getValue() - getDemandDegC();
float deltaT = getTemperatureSensor() - getDemandDegC();
// DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT);
// ensure we cancel user ON mode if heater throws an error
@ -883,8 +903,10 @@ bool validateFrame(const CProtocol& frame, const char* name)
void requestOn()
{
heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode
if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) {
heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode
}
}
void requestOff()
@ -1041,7 +1063,7 @@ float getTemperatureDesired()
float getTemperatureSensor()
{
return FilteredSamples.AmbientTemp.getValue();
return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempOfs;
}
void setPumpMin(float val)
@ -1449,12 +1471,15 @@ void simulateGPIOin(uint8_t newKey)
GPIOin.simulateKey(newKey);
}
float getBatteryVoltage()
float getBatteryVoltage(bool fast)
{
#ifdef RAW_SAMPLES
return getHeaterInfo().getBattVoltage();
#else
return FilteredSamples.ipVolts.getValue();
if(fast)
return FilteredSamples.FastipVolts.getValue();
else
return FilteredSamples.ipVolts.getValue();
#endif
}
@ -1487,13 +1512,16 @@ float getFanSpeed()
void updateFilteredData()
{
FilteredSamples.ipVolts.update(HeaterFrame2.getVoltage_Supply());
FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage());
FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current());
FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual());
FilteredSamples.ipVolts.update(getHeaterInfo().getBattVoltage());
FilteredSamples.GlowVolts.update(getHeaterInfo().getGlow_Voltage());
FilteredSamples.GlowAmps.update(getHeaterInfo().getGlow_Current());
FilteredSamples.Fan.update(getHeaterInfo().getFan_Actual());
FilteredSamples.FastipVolts.update(getHeaterInfo().getBattVoltage());
FilteredSamples.FastGlowAmps.update(getHeaterInfo().getGlow_Current());
}
int sysUptime()
{
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)
Direct discovery and download of updates from internet server (STA mode)
* 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
--------------------------
* 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
* "fuel gauge" - Integrate pump frequency, assuming a repeatable dose of fuel per pump cycle...
* Regular Hot Burn cycle (DPF mode!)
* Hour meter - run time, glow time
* 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]
platform = espressif32
lib_extra_dirs = ~/Documents/Arduino/libraries
;lib_dir = src/Afterburner/src
board = esp32dev
framework = arduino
board_build.partitions = min_spiffs.csv
@ -22,5 +23,6 @@ upload_flags =
monitor_speed = 115200
extra_scripts = post:add_CRC.py
; 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/NVStorage.h"
#include "src/Utility/DebugPort.h"
#include "src/Utility/macros.h"
#include "src/Utility/UtilClasses.h"
#include "src/Utility/BTC_JSON.h"
#include "src/Utility/BTC_GPIO.h"
@ -446,7 +447,11 @@ void setup() {
FilteredSamples.Fan.setRounding(10);
FilteredSamples.Fan.setAlpha(0.7);
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();
FuelGauge.init(RTC_Store.getFuelGauge());
// demandDegC = RTC_Store.getDesiredTemp();
@ -792,9 +797,24 @@ void loop()
ScreenManager.reqUpdate();
}
if(bHasHtrData) {
// apply exponential mean to the anlogue readings for some smoothing
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);
CommState.set(CommStates::Idle);
@ -822,7 +842,7 @@ void manageCyclicMode()
const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic;
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!
float deltaT = FilteredSamples.AmbientTemp.getValue() - getDemandDegC();
float deltaT = getTemperatureSensor() - getDemandDegC();
// DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT);
// ensure we cancel user ON mode if heater throws an error
@ -883,8 +903,10 @@ bool validateFrame(const CProtocol& frame, const char* name)
void requestOn()
{
heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode
if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) {
heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode
}
}
void requestOff()
@ -1041,7 +1063,7 @@ float getTemperatureDesired()
float getTemperatureSensor()
{
return FilteredSamples.AmbientTemp.getValue();
return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().tempOfs;
}
void setPumpMin(float val)
@ -1449,12 +1471,15 @@ void simulateGPIOin(uint8_t newKey)
GPIOin.simulateKey(newKey);
}
float getBatteryVoltage()
float getBatteryVoltage(bool fast)
{
#ifdef RAW_SAMPLES
return getHeaterInfo().getBattVoltage();
#else
return FilteredSamples.ipVolts.getValue();
if(fast)
return FilteredSamples.FastipVolts.getValue();
else
return FilteredSamples.ipVolts.getValue();
#endif
}
@ -1487,13 +1512,16 @@ float getFanSpeed()
void updateFilteredData()
{
FilteredSamples.ipVolts.update(HeaterFrame2.getVoltage_Supply());
FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage());
FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current());
FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual());
FilteredSamples.ipVolts.update(getHeaterInfo().getBattVoltage());
FilteredSamples.GlowVolts.update(getHeaterInfo().getGlow_Voltage());
FilteredSamples.GlowAmps.update(getHeaterInfo().getGlow_Current());
FilteredSamples.Fan.update(getHeaterInfo().getFan_Actual());
FilteredSamples.FastipVolts.update(getHeaterInfo().getBattVoltage());
FilteredSamples.FastGlowAmps.update(getHeaterInfo().getGlow_Current());
}
int sysUptime()
{
return Clock.get().secondstime() - BootTime;
}
}

View file

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

View file

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

View file

@ -29,8 +29,6 @@
#include "../Utility/NVStorage.h"
#include "../Utility/FuelGauge.h"
extern CFuelGauge FuelGauge;
#define MINIFONT miniFontInfo
@ -84,7 +82,7 @@ CDetailedScreen::CDetailedScreen(C128x64_OLED& display, CScreenManager& mgr) : C
bool
CDetailedScreen::show()
{
CScreenHeader::show();
CScreenHeader::show(false);
int runstate = getHeaterInfo().getRunStateEx();
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/macros.h"
#include "../Protocol/Protocol.h"
#include "fonts/Icons.h"
CFuelMixtureScreen::CFuelMixtureScreen(C128x64_OLED& display, CScreenManager& mgr) : CPasswordScreen(display, mgr)
@ -47,6 +48,12 @@ CFuelMixtureScreen::onSelect()
CPasswordScreen::onSelect();
_initUI();
_load();
}
void
CFuelMixtureScreen::_load()
{
adjPump[0] = getHeaterInfo().getPump_Min();
adjPump[1] = getHeaterInfo().getPump_Max();
adjFan[0] = getHeaterInfo().getFan_Min();
@ -58,6 +65,7 @@ CFuelMixtureScreen::_initUI()
{
_rowSel = 0;
_colSel = 0;
_animateCount = 0;
}
bool
@ -67,34 +75,40 @@ CFuelMixtureScreen::show()
int xPos, yPos;
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()) {
switch(_rowSel) {
case 0:
case 1:
case 2:
case 3:
case 4:
if(_animateCount == -1) {
_animateCount = 0;
_display.clearDisplay();
}
// Pump Minimum adjustment
yPos = border + 36;
_printMenuText(80, yPos, "Min", false, eRightJustify);
sprintf(str, "%.1f", adjPump[0]);
_printMenuText(65, yPos, "Min", false, eRightJustify);
sprintf(str, "%.1f Hz", adjPump[0]);
_printMenuText(col3, yPos, str, _rowSel == 1, eRightJustify);
// Pump Maximum adjustment
yPos = border + 24;
_printMenuText(80, yPos, "Pump Hz Max", false, eRightJustify);
sprintf(str, "%.1f", adjPump[1]);
_printMenuText(65, yPos, "Max", false, eRightJustify);
sprintf(str, "%.1f Hz", adjPump[1]);
_printMenuText(col3, yPos, str, _rowSel == 2, eRightJustify);
// Fan Minimum adjustment
yPos = border + 12;
_printMenuText(80, yPos, "Min", false, eRightJustify);
sprintf(str, "%d", adjFan[0]);
_printMenuText(65, yPos, "Min", false, eRightJustify);
sprintf(str, "%d RPM", adjFan[0]);
_printMenuText(col3, yPos, str, _rowSel == 3, eRightJustify);
// Fan Maximum adjustment
yPos = border;
_printMenuText(80, yPos, "Fan RPM Max", false, eRightJustify);
sprintf(str, "%d", adjFan[1]);
_printMenuText(65, yPos, "Max", false, eRightJustify);
sprintf(str, "%d RPM", adjFan[1]);
_printMenuText(col3, yPos, str, _rowSel == 4, eRightJustify);
// navigation line
yPos = 53;
@ -128,6 +142,29 @@ CFuelMixtureScreen::show()
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
CFuelMixtureScreen::keyHandler(uint8_t event)
@ -143,6 +180,8 @@ CFuelMixtureScreen::keyHandler(uint8_t event)
case 2:
case 3:
case 4:
_animateCount = -1;
_display.clearDisplay();
_rowSel = 5; // enter save confirm mode
break;
case 5:
@ -204,6 +243,8 @@ CFuelMixtureScreen::keyHandler(uint8_t event)
UPPERLIMIT(_rowSel, 4);
break;
case 5:
_display.clearDisplay();
_animateCount = -1;
_showStoringMessage();
setPumpMin(adjPump[0]);
setPumpMax(adjPump[1]);
@ -233,7 +274,10 @@ CFuelMixtureScreen::keyHandler(uint8_t event)
_ScreenManager.reqUpdate();
}
if(_rowSel == 0) {
_load(); // dispose of any changes, re-obtain current settings
}
if(event & keyRepeat) {
switch(_rowSel) {
case 1:

View file

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

View file

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

View file

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

View file

@ -21,10 +21,13 @@
#include "128x64OLED.h"
#include "HeaterSettingsScreen.h"
#include "FuelCalScreen.h"
#include "KeyPad.h"
#include "../Utility/helpers.h"
#include "../Utility/macros.h"
#include "../Utility/NVStorage.h"
#include "../Protocol/Protocol.h"
#include "fonts/Icons.h"
///////////////////////////////////////////////////////////////////////////
//
@ -246,3 +249,280 @@ CHeaterSettingsScreen::_adjust(int dir)
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
CInheritSettingsScreen::show()
{
CScreenHeader::show();
CScreenHeader::show(false);
_display.writeFillRect(0, 16, 96, 12, WHITE);
_printInverted(3, 18, "Inherit Settings", true);

View file

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

View file

@ -23,6 +23,10 @@
#include "KeyPad.h"
#include "../Utility/NVStorage.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
CPrimingScreen::onSelect()
{
CScreenHeader::onSelect();
_stopPump();
_initUI();
}
@ -58,93 +63,147 @@ CPrimingScreen::_initUI()
{
_PrimeStop = 0;
_PrimeCheck = 0;
_rowSel = 0;
_paramSel = 0;
_colSel = 0;
}
bool
CPrimingScreen::show()
{
CScreenHeader::show();
CScreenHeader::show(false);
_display.fillRect(0, 15, 100, 3, BLACK);
CRect extents;
int yPos = 53;
// show next/prev menu navigation line
switch(_rowSel) {
switch(_paramSel) {
case 0:
_printMenuText(_display.xCentre(), yPos, " \021 \030Edit \020 ", _rowSel == 0, eCentreJustify);
_printMenuText(_display.xCentre(), yPos, " \021 \030Edit \020 ", _paramSel == 0, eCentreJustify);
break;
case 1:
case 2:
_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;
case 3:
_display.drawFastHLine(0, 53, 128, WHITE);
if(_colSel == 2) {
_printMenuText(_display.xCentre(), 57, "\033\030\031 Stop", false, eCentreJustify);
}
else {
_printMenuText(_display.xCentre(), 57, "\032 Start \031 Sel", false, eCentreJustify);
switch(_colSel) {
case 1:
_printMenuText(_display.xCentre(), 57, "\033\030\031\032 Stop", false, eCentreJustify);
break;
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;
}
yPos = 40;
if(_rowSel == 1) {
int topline = 19;
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
_printMenuText(border, yPos, "Thermostat", _colSel == 0);
_printMenuText(_display.width()-border, yPos, "Fixed Hz", _colSel == 1, eRightJustify);
if(NVstore.getUserSettings().degF)
_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 {
// follow actual heater settings
// int col = getHeaterInfo().isThermostat() ? 0 : 1;
int col = getThermostatModeActive() ? 0 : 1;
_printInverted(border, yPos, "Thermostat", col == 0);
_printInverted(_display.width()-border, yPos, "Fixed Hz", col == 1, eRightJustify);
if(getThermostatModeActive()) {
_drawBitmap(loc.xPos, midline, NVstore.getUserSettings().degF ? ThermostatDegFIconInfo : ThermostatDegCIconInfo);
}
else {
_drawBitmap(loc.xPos, midline, ThermostatHzIconInfo);
}
}
yPos = 28;
if(_rowSel == 2) {
_printMenuText(border, yPos, "degC", _colSel == 0);
_printMenuText(_display.width()-border, yPos, "degF", _colSel == 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 {
int col = NVstore.getUserSettings().degF ? 1 : 0;
_printInverted(border, yPos, "degC", col == 0);
_printInverted(_display.width()-border, yPos, "degF", col == 1, eRightJustify);
_drawBitmap(loc.xPos, midline, NVstore.getUserSettings().degF ? DegFIconInfo : DegCIconInfo);
}
// fuel pump priming menu
yPos = 16;
_printMenuText(border, yPos, "Pump");
if(_rowSel == 3) {
_printMenuText(40, yPos, "OFF", _colSel == 1);
if(_colSel != 2) {
if(!getHeaterInfo().getRunState()) { // prevent option if heater is running
_printMenuText(70, yPos, "ON"); // becomes Hz when actually priming
loc.xPos = 66;
loc.width = BowserIconInfo.width;
loc.height = BowserIconInfo.height;
_drawBitmap(loc.xPos, midline, BowserIconInfo);
loc.xPos = 81;
if(_paramSel == 3) {
_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 {
_drawBitmap(loc.xPos, topline, CrossIconInfo);
}
}
else {
if(_colSel == 1) {
float pumpHz = getHeaterInfo().getPump_Actual();
// recognise if heater has stopped pump, after an initial holdoff upon first starting
long tDelta = millis() - _PrimeCheck;
if(_PrimeCheck && tDelta > 0 && pumpHz < 0.1) {
_stopPump();
_paramSel = _colSel = 0;
}
// test if time is up, stop priming if so
tDelta = millis() - _PrimeStop;
if(_PrimeStop && tDelta > 0) {
_stopPump();
_paramSel = _colSel = 0;
}
if(_PrimeStop) {
char msg[16];
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;
}
@ -157,47 +216,46 @@ CPrimingScreen::keyHandler(uint8_t event)
if(event & keyPressed) {
// press LEFT
if(event & key_Left) {
switch(_rowSel) {
switch(_paramSel) {
case 0:
_ScreenManager.prevMenu();
break;
case 1:
_colSel = 0;
setThermostatMode(1);
saveNV();
default:
_paramSel--;
LOWERLIMIT(_paramSel, 0);
_colSel = 0;
switch(_paramSel) {
case 1:
_colSel = getThermostatModeActive() ? 0 : 1;
break;
case 2:
_colSel = NVstore.getUserSettings().degF ? 1 : 0;
break;
}
break;
case 2:
_colSel = 0;
setDegFMode(false);
saveNV();
break;
case 3:
_colSel = 1;
break;
case 4: break;
}
}
// press RIGHT
if(event & key_Right) {
switch(_rowSel) {
switch(_paramSel) {
case 0:
_ScreenManager.nextMenu();
break;
case 1:
_colSel = 1;
setThermostatMode(0);
saveNV();
default:
_paramSel++;
UPPERLIMIT(_paramSel, 3);
switch(_paramSel) {
case 3:
_colSel = 0; // select OFF upon entry to priming menu
break;
case 2:
_colSel = NVstore.getUserSettings().degF ? 1 : 0;
break;
case 1:
_colSel = getThermostatModeActive() ? 0 : 1;
break;
}
break;
case 2:
_colSel = 1;
setDegFMode(true);
saveNV();
break;
case 3:
if(!getHeaterInfo().getRunState())
_colSel = 2;
break;
case 4: break;
}
}
// press UP
@ -205,35 +263,90 @@ CPrimingScreen::keyHandler(uint8_t event)
if(hasOEMcontroller())
_reqOEMWarning();
else {
_rowSel++;
UPPERLIMIT(_rowSel, 3);
if(_rowSel == 3)
_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;
switch(_paramSel) {
case 0:
_paramSel = 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
if(event & key_Down) {
if(_rowSel == 0) {
if(_paramSel == 0) {
_ScreenManager.selectMenu(CScreenManager::UserSettingsLoop, CScreenManager::VersionUI); // force return to main menu
}
else {
_rowSel--;
LOWERLIMIT(_rowSel, 0);
_colSel = 0;
if(_rowSel == 1)
// _colSel = getHeaterInfo().isThermostat() ? 0 : 1;
_colSel = getThermostatModeActive() ? 0 : 1;
if(_rowSel == 2)
_colSel = NVstore.getUserSettings().degF ? 1 : 0;
switch(_paramSel) {
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;
break;
case -1:
FuelGauge.reset();
_paramSel = _colSel = 0;
break;
}
}
else {
_paramSel = _colSel = 0;
}
}
// check if fuel priming was selected
if(_rowSel == 3 && _colSel == 2) {
if(_paramSel == 3 && _colSel == 1 ) {
reqPumpPrime(true);
_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
@ -253,6 +366,7 @@ CPrimingScreen::_stopPump()
reqPumpPrime(false);
_PrimeCheck = 0;
_PrimeStop = 0;
if(_colSel == 2)
_colSel = 1;
if(_paramSel == 3 && _colSel == 1) {
_colSel = 0;
}
}

View file

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

View file

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

View file

@ -52,6 +52,7 @@ protected:
void _printInverted(int x, int y, const char* str, bool selected, eJUSTIFY justify = eLeftJustify);
void _adjustExtents(CRect& rect, eJUSTIFY justify, const char* str);
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 _reqOEMWarning();
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/MiniFont.h"
#include "../RTC/TimerManager.h"
#include "../Protocol/SmartError.h"
#include "../Utility/DataFilter.h"
#define MINIFONT miniFontInfo
@ -65,9 +67,15 @@ CScreenHeader::CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr) : CScreen(
}
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
// Bluetooth
@ -75,8 +83,7 @@ CScreenHeader::show()
// WiFi icon is updated in animate()
// battery
showBatteryIcon(getBatteryVoltage());
// Battery is updated in animate
// clock
showTime();
@ -104,7 +111,9 @@ CScreenHeader::animate()
// animate timer icon,
// inserting an update icon if new firmware available from internet web server
_animateCount++;
WRAPUPPERLIMIT(_animateCount, 10, 0);
_batteryCount++;
WRAPUPPERLIMIT(_animateCount, 9, 0);
WRAPUPPERLIMIT(_batteryCount, 5, 0);
if(isUpdateAvailable(true)) {
int xPos = X_TIMER_ICON - 3;
int yPos = Y_TIMER_ICON;
@ -122,7 +131,22 @@ CScreenHeader::animate()
}
}
else {
int xPos = X_BATT_ICON;
int yPos = Y_BATT_ICON;
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();
@ -285,6 +309,7 @@ CScreenHeader::showTime()
int xPos = X_WIFI_ICON + WifiIconInfo.width + WifiInIconInfo.width; // rhs of wifi conglomeration
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);
}
}

View file

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

View file

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

View file

@ -49,7 +49,7 @@ public:
enum eUIRootMenus { DetailedControlUI, BasicControlUI, ClockUI, ModeUI, CommsUI, GPIOInfoUI, SettingsUI };
enum eUITimerMenus { TimerOverviewUI, Timer1UI, Timer2UI, Timer3UI, Timer4UI, Timer5UI, Timer6UI, Timer7UI,
Timer8UI, Timer9UI, Timer10UI, Timer11UI, Timer12UI, Timer13UI, Timer14UI };
enum eUITuningMenus { MixtureUI, HeaterSettingsUI };
enum eUITuningMenus { MixtureUI, HeaterSettingsUI, FuelCalUI };
enum eUIUserSettingsMenus { GPIOUI, ExThermostatUI, VersionUI, HomeMenuUI, TimeIntervalsUI };
enum eUIBranchMenus { SetClockUI, InheritSettingsUI, FontDumpUI };
public:
@ -66,6 +66,7 @@ public:
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 showOTAMessage(int percent, eOTAmodes updateType);
void bumpTimeout();
};
#endif // __SCREEN_MANAGER_H__

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -375,6 +375,25 @@ const uint8_t FuelIcon [] PROGMEM = {
};
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
const uint8_t TargetIcon [] PROGMEM = {
0x0f, 0x80, // #####
@ -578,6 +597,7 @@ const uint8_t PROGMEM CrossIcon[] =
0x50, // # #
0x88, // # #
};
const BITMAP_INFO CrossIconInfo(5, 5, CrossIcon);
const uint8_t PROGMEM TickIcon[] =
{
@ -961,7 +981,146 @@ const uint8_t PROGMEM bowserIcon[] =
0x7E, 0x00, // ######
0xFF, 0x00, // ########
};
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
extern const BITMAP_INFO FuelIconInfo;
extern const BITMAP_INFO FuelIconSmallInfo;
// 'Target', 13x13px
extern const BITMAP_INFO TargetIconInfo;
extern const BITMAP_INFO RepeatIconInfo;
@ -77,6 +77,8 @@ extern const BITMAP_INFO LargeTimerIconInfo;
extern const BITMAP_INFO VerticalRepeatIconInfo;
extern const BITMAP_INFO CrossLgIconInfo;
extern const BITMAP_INFO CrossIconInfo
;
// Bitmap for open
extern const BITMAP_INFO OpenIconInfo;
@ -129,4 +131,11 @@ extern const BITMAP_INFO UpdateIconInfo;
// Bitmap sizes for www
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
"Temp sense", // [10] E-09
"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!
};
@ -385,7 +385,7 @@ const char* ErrstatesEx [] PROGMEM = {
"E-08: Flame out", // [9] E-08
"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 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!
};

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (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
* it under the terms of the GNU General Public License as published by
@ -21,6 +21,10 @@
#include "SmartError.h"
#include "TxManage.h"
#include "../Utility/helpers.h"
#include "../Utility/macros.h"
#include "../Utility/NVStorage.h"
#include "../Utility/DataFilter.h"
CSmartError::CSmartError()
{
@ -83,12 +87,12 @@ CSmartError::monitor(uint8_t newRunState)
else if(newRunState > 5) {
// transitioned from preheat to post glow
// - second ignition attempt failed, heater is shutting down
m_Error = 11;
m_Error = 11; // +1 over displayed error code
}
else if(newRunState == 3) {
// transitioned from preheat to retry
// - first ignition attempt failed, heater will retry
m_Error = 12;
m_Error = 12; // +1 over displayed error code
}
}
}
@ -106,7 +110,24 @@ 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

View file

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

View file

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

View file

@ -30,7 +30,7 @@ class RTC_DS3231Ex : public RTC_DS3231 {
public:
void writeData(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();
ht.pumpCal = fCal;
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("FanVoltage", getHeaterInfo().getFan_Voltage(), 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("GlowVoltage", getGlowVolts(), root );
bSend |= moderator.addJson("GlowCurrent", getGlowCurrent(), root );
@ -354,9 +376,11 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
bSend |= moderator.addJson("ThermostatUndertemp", NVstore.getUserSettings().cyclic.Start, root);
bSend |= moderator.addJson("CyclicTemp", getDemandDegC(), root); // actual pivot point for cyclic mode
bSend |= moderator.addJson("CyclicOff", stop, root); // threshold of over temp for cyclic mode
bSend |= moderator.addJson("CyclicOn", NVstore.getUserSettings().cyclic.Start, root); // threshold of under temp for cyclic mode
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("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("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) {
root.printTo(opStr, len);

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (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
* it under the terms of the GNU General Public License as published by
@ -44,6 +44,11 @@ struct sFilteredData {
CExpMean GlowAmps;
CExpMean Fan;
CExpMean AmbientTemp;
CExpMean FastipVolts;
CExpMean FastGlowAmps;
};
extern sFilteredData FilteredSamples;
#endif

View file

@ -43,6 +43,13 @@ CFuelGauge::init(float fuelUsed)
_lastStoredVal = _pumpStrokes;
}
void
CFuelGauge::reset()
{
_pumpStrokes = 0;
_lastStoredVal = _pumpStrokes;
RTC_Store.setFuelGauge(_pumpStrokes); // uses RTC registers to store this
}
void
CFuelGauge::Integrate(float Hz)
@ -66,5 +73,11 @@ CFuelGauge::Integrate(float Hz)
float
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:
CFuelGauge();
void init(float fuelUsed = 0);
void reset();
void Integrate(float Hz);
float Used_mL();
float Used_strokes();
};
extern CFuelGauge FuelGauge;
#endif

View file

@ -97,6 +97,11 @@ sHeaterTuning::setSysVoltage(float fVal)
}
}
float
sHeaterTuning::getLVC() const
{
return lowVolts * 0.1;
}
void
CHeaterStorage::getTimerInfo(int idx, sTimer& timerInfo)
@ -235,7 +240,12 @@ sHeaterTuning::load()
validatedLoad("systemVoltage", sysVoltage, 120, u8Match2, 120, 240);
validatedLoad("fanSensor", fanSensor, 1, u8inBounds, 1, 2);
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("tempOfs", tempOfs, 0.0, -10.0, +10.0);
preferences.end();
}
@ -252,7 +262,9 @@ sHeaterTuning::save()
preferences.putUChar("systemVoltage", sysVoltage);
preferences.putUChar("fanSensor", fanSensor);
preferences.putUChar("glowDrive", glowDrive);
preferences.putUChar("lowVolts", lowVolts);
preferences.putFloat("pumpCal", pumpCal);
preferences.putFloat("tempOfs", tempOfs);
preferences.end();
}

View file

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

View file

@ -152,6 +152,12 @@ struct CRect {
CRect() {
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) {
xPos -= val;
yPos -= val;

View file

@ -78,19 +78,12 @@ extern void setUploadSize(long val);
extern void getGPIOinfo(sGPIO& info);
extern void simulateGPIOin(uint8_t newKey);
extern void setDegFMode(bool state);
extern float getBatteryVoltage();
extern float getBatteryVoltage(bool fast);
extern float getGlowVolts();
extern float getGlowCurrent();
extern float getFanSpeed();
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);

View file

@ -2,7 +2,7 @@
* This file is part of the "bluetoothheater" distribution
* (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
*
* This program is free software: you can redistribute it and/or modify
@ -23,12 +23,12 @@
#ifndef __MACROS_H__
#define __MACROS_H__
#define LOWERLIMIT(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 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 LOWERLIMIT(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 WRAPLOWERLIMIT(A, B, C) { if((A) < (B)) (A) = (C); }
#define WRAPLIMITS(A, B, C) { if((A) < (B)) (A) = (C) ; if((A) > (C)) (A) = (B); }
#define INBOUNDS(TST, MIN, MAX) (((TST) >= (MIN)) && ((TST) <= (MAX)))
#define BOUNDSLIMIT(A, B, C) if((A) < (B)) (A) = (B); if((A) > (C)) (A) = (C)
#define BOUNDSLIMIT(A, B, C) { if((A) < (B)) (A) = (B); if((A) > (C)) (A) = (C); }
#endif