Added Low Volt Cutout, Temperature probe offset

Tarted up fuel mixture adjust screen
This commit is contained in:
Ray Jones 2019-07-21 21:17:54 +10:00
parent dd5e62c8cb
commit 06e69acc77
42 changed files with 466 additions and 143 deletions

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,7 +447,11 @@ 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());
// demandDegC = RTC_Store.getDesiredTemp(); // demandDegC = RTC_Store.getDesiredTemp();
@ -796,6 +801,9 @@ void loop()
updateFilteredData(); updateFilteredData();
FuelGauge.Integrate(HeaterFrame2.getPump_Actual()); FuelGauge.Integrate(HeaterFrame2.getPump_Actual());
} }
if(INBOUNDS(HeaterFrame2.getRunState(), 1, 5)) { // check for Low Voltage Cutout
SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue());
}
updateJSONclients(bReportJSONData); updateJSONclients(bReportJSONData);
CommState.set(CommStates::Idle); CommState.set(CommStates::Idle);
NVstore.doSave(); // now is a good time to store to the NV storage, well away from any blue wire activity NVstore.doSave(); // now is a good time to store to the NV storage, well away from any blue wire activity
@ -822,7 +830,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,8 +891,10 @@ bool validateFrame(const CProtocol& frame, const char* name)
void requestOn() void requestOn()
{ {
heaterOn(); if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) {
RTC_Store.setCyclicEngaged(true); // for cyclic mode heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode
}
} }
void requestOff() void requestOff()
@ -1041,7 +1051,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,12 +1459,15 @@ 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
return FilteredSamples.ipVolts.getValue(); if(fast)
return FilteredSamples.FastipVolts.getValue();
else
return FilteredSamples.ipVolts.getValue();
#endif #endif
} }
@ -1491,6 +1504,8 @@ void updateFilteredData()
FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage()); FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage());
FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current()); FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current());
FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual()); FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual());
FilteredSamples.FastipVolts.update(HeaterFrame2.getVoltage_Supply());
FilteredSamples.FastGlowAmps.update(HeaterFrame2.getGlowPlug_Current());
} }
int sysUptime() int sysUptime()

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

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/MiniThermo.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

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,7 +447,11 @@ 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());
// demandDegC = RTC_Store.getDesiredTemp(); // demandDegC = RTC_Store.getDesiredTemp();
@ -796,6 +801,9 @@ void loop()
updateFilteredData(); updateFilteredData();
FuelGauge.Integrate(HeaterFrame2.getPump_Actual()); FuelGauge.Integrate(HeaterFrame2.getPump_Actual());
} }
if(INBOUNDS(HeaterFrame2.getRunState(), 1, 5)) { // check for Low Voltage Cutout
SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue());
}
updateJSONclients(bReportJSONData); updateJSONclients(bReportJSONData);
CommState.set(CommStates::Idle); CommState.set(CommStates::Idle);
NVstore.doSave(); // now is a good time to store to the NV storage, well away from any blue wire activity NVstore.doSave(); // now is a good time to store to the NV storage, well away from any blue wire activity
@ -822,7 +830,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,8 +891,10 @@ bool validateFrame(const CProtocol& frame, const char* name)
void requestOn() void requestOn()
{ {
heaterOn(); if(SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue())) {
RTC_Store.setCyclicEngaged(true); // for cyclic mode heaterOn();
RTC_Store.setCyclicEngaged(true); // for cyclic mode
}
} }
void requestOff() void requestOff()
@ -1041,7 +1051,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,12 +1459,15 @@ 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
return FilteredSamples.ipVolts.getValue(); if(fast)
return FilteredSamples.FastipVolts.getValue();
else
return FilteredSamples.ipVolts.getValue();
#endif #endif
} }
@ -1491,6 +1504,8 @@ void updateFilteredData()
FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage()); FilteredSamples.GlowVolts.update(HeaterFrame2.getGlowPlug_Voltage());
FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current()); FilteredSamples.GlowAmps.update(HeaterFrame2.getGlowPlug_Current());
FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual()); FilteredSamples.Fan.update(HeaterFrame2.getFan_Actual());
FilteredSamples.FastipVolts.update(HeaterFrame2.getVoltage_Supply());
FilteredSamples.FastGlowAmps.update(HeaterFrame2.getGlowPlug_Current());
} }
int sysUptime() int sysUptime()

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

@ -82,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();
@ -133,7 +133,7 @@ CDetailedScreen::show()
} }
if(!bGlowActive) { if(!bGlowActive) {
showBowser(FuelGauge.Used_ml()); showBowser(FuelGauge.Used_mL());
} }
showRunState(runstate, errstate); showRunState(runstate, errstate);
return true; return true;

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,7 +274,10 @@ 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) {
case 1: case 1:

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,11 +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 "../Utility/NVStorage.h"
#include "../Protocol/Protocol.h" #include "../Protocol/Protocol.h"
#include "fonts/Icons.h"
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
// //
@ -264,6 +266,8 @@ CFuelCalScreen::CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr) : CPa
{ {
_initUI(); _initUI();
_mlPerStroke = 0.02; _mlPerStroke = 0.02;
_LVC = 115;
_tOfs = 0;
} }
void void
@ -272,6 +276,8 @@ CFuelCalScreen::onSelect()
CPasswordScreen::onSelect(); CPasswordScreen::onSelect();
_initUI(); _initUI();
_mlPerStroke = NVstore.getHeaterTuning().pumpCal; _mlPerStroke = NVstore.getHeaterTuning().pumpCal;
_LVC = NVstore.getHeaterTuning().lowVolts;
_tOfs = NVstore.getHeaterTuning().tempOfs;
} }
void void
@ -285,7 +291,10 @@ bool
CFuelCalScreen::show() CFuelCalScreen::show()
{ {
char msg[20]; char msg[20];
_display.clearDisplay(); 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(!CPasswordScreen::show()) { // for showing "saving settings"
@ -295,13 +304,31 @@ CFuelCalScreen::show()
_printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify); _printMenuText(_display.xCentre(), 43, "confirm save", false, eCentreJustify);
} }
else { else {
int col = 80; if(_animateCount < 0) {
_printInverted(_display.xCentre(), 0, " Fuel Calibration ", true, eCentreJustify); _display.clearDisplay();
_printMenuText(col, Line1, "ml / stroke:", false, eRightJustify); _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); sprintf(msg, "%.03f", _mlPerStroke);
_printMenuText(col+1, Line1, msg, _rowSel == 1); _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 // navigation line
int yPos = 53; yPos = 53;
int xPos = _display.xCentre(); int xPos = _display.xCentre();
switch(_rowSel) { switch(_rowSel) {
@ -324,43 +351,44 @@ CFuelCalScreen::show()
bool bool
CFuelCalScreen::animate() CFuelCalScreen::animate()
{ {
/* char msg[16]; 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;
}
if(isPasswordBusy() || (_rowSel == 4)) { // Password screen activity
_printMenuText(Column, Line2, " ");
_printMenuText(Column, Line1, " ");
if(_rowSel == 4)
_printMenuText(_display.xCentre(), 43, "Confirm save", false, eCentreJustify);
}
else {
_animateCount++; _animateCount++;
WRAPUPPERLIMIT(_animateCount, 9, 0); WRAPUPPERLIMIT(_animateCount, 9, 0);
}
if(_rowSel == 1) {
_display.drawRect(Column-border, Line1-border, 34, 8+2*border, BLACK);
_display.drawRoundRect(Column-border, Line1-border, 34, 8+2*border, radius, WHITE);
}
else {
_printMenuText(Column, Line1, " ");
}
if(_animateCount < 4)
sprintf(msg, "PF-%d ", _glowDrive);
else
sprintf(msg, "(%dW)", plugPowers[_glowDrive-1]);
_printMenuText(Column, Line1, msg);
int xPos = Column;
_printMenuText(xPos, Line2, " ", _rowSel == 2); // erase, but create selection loop
if(_animateCount < 4) {
sprintf(msg, "SN-%d", _fanSensor);
_printMenuText(Column, Line2, msg);
}
else {
sprintf(msg, "(\365%d)", _fanSensor); // \365 is division character
_printMenuText(xPos, Line2, msg);
}
}*/
return true; return true;
} }
@ -370,6 +398,15 @@ CFuelCalScreen::keyHandler(uint8_t event)
{ {
sHeaterTuning tuning; sHeaterTuning tuning;
if(event & keyRepeat) {
if(event & key_Left) {
_adjust(-1);
}
if(event & key_Right) {
_adjust(+1);
}
}
if(event & keyPressed) { if(event & keyPressed) {
// press LEFT to select previous screen // press LEFT to select previous screen
if(event & key_Left) { if(event & key_Left) {
@ -418,9 +455,13 @@ CFuelCalScreen::keyHandler(uint8_t event)
UPPERLIMIT(_rowSel, 3); UPPERLIMIT(_rowSel, 3);
break; break;
case 4: // confirmed save case 4: // confirmed save
_display.clearDisplay();
_animateCount = -1;
_showStoringMessage(); _showStoringMessage();
tuning = NVstore.getHeaterTuning(); tuning = NVstore.getHeaterTuning();
tuning.pumpCal = _mlPerStroke; tuning.pumpCal = _mlPerStroke;
tuning.lowVolts = _LVC;
tuning.tempOfs = _tOfs;
NVstore.setHeaterTuning(tuning); NVstore.setHeaterTuning(tuning);
saveNV(); saveNV();
_rowSel = 0; _rowSel = 0;
@ -436,6 +477,8 @@ CFuelCalScreen::keyHandler(uint8_t event)
case 1: case 1:
case 2: case 2:
case 3: case 3:
_animateCount = -1;
_display.clearDisplay();
_rowSel = 4; _rowSel = 4;
break; break;
} }
@ -452,10 +495,34 @@ CFuelCalScreen::_adjust(int dir)
switch(_rowSel) { switch(_rowSel) {
case 1: case 1:
_mlPerStroke += dir * 0.001; _mlPerStroke += dir * 0.001;
BOUNDSLIMIT(_mlPerStroke, 0.001, 1);
break; break;
case 2: 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; break;
case 3: case 3:
_tOfs += dir * 0.1;
BOUNDSLIMIT(_tOfs, -10, 10);
break; break;
} }
} }

View File

@ -45,19 +45,4 @@ public:
void onSelect(); void onSelect();
}; };
class CFuelCalScreen : public CPasswordScreen
{
int _rowSel;
void _adjust(int dir);
float _mlPerStroke;
int _animateCount;
void _initUI();
public:
CFuelCalScreen(C128x64_OLED& display, CScreenManager& mgr);
bool show();
bool animate();
bool keyHandler(uint8_t event);
void onSelect();
};
#endif #endif

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

@ -46,6 +46,7 @@ CPrimingScreen::CPrimingScreen(C128x64_OLED& display, CScreenManager& mgr) : CSc
void void
CPrimingScreen::onSelect() CPrimingScreen::onSelect()
{ {
CScreenHeader::onSelect();
_stopPump(); _stopPump();
_initUI(); _initUI();
} }
@ -69,7 +70,7 @@ CPrimingScreen::_initUI()
bool bool
CPrimingScreen::show() CPrimingScreen::show()
{ {
CScreenHeader::show(); CScreenHeader::show(false);
CRect extents; CRect extents;
@ -200,7 +201,7 @@ CPrimingScreen::show()
} }
else { else {
char msg[16]; char msg[16];
sprintf(msg, "%.02fL", FuelGauge.Used_ml() * 0.001); sprintf(msg, "%.02fL", FuelGauge.Used_mL() * 0.001);
_printMenuText(loc.xPos+1, midline+3, msg); _printMenuText(loc.xPos+1, midline+3, msg);
} }

View File

@ -63,6 +63,7 @@ CScreen::show()
void void
CScreen::onSelect() CScreen::onSelect()
{ {
_display.clearDisplay();
} }
void void

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"

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,7 +66,7 @@ CSettingsScreen::show()
{ {
char str[16]; char str[16];
CScreenHeader::show(); CScreenHeader::show(false);
_display.writeFillRect(0, 16, 84, 12, WHITE); _display.writeFillRect(0, 16, 84, 12, WHITE);
_printInverted(3, 18, "Heater Tuning", true); _printInverted(3, 18, "Heater Tuning", true);

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, // #####
@ -1083,3 +1102,25 @@ const uint8_t PROGMEM resetIcon[] =
}; };
const BITMAP_INFO resetIconInfo(17, 10, resetIcon); 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,7 +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; extern const BITMAP_INFO CrossIconInfo
;
// Bitmap for open // Bitmap for open
extern const BITMAP_INFO OpenIconInfo; extern const BITMAP_INFO OpenIconInfo;
@ -137,3 +138,4 @@ extern const BITMAP_INFO ThermostatDegCIconInfo;
extern const BITMAP_INFO ThermostatDegFIconInfo; extern const BITMAP_INFO ThermostatDegFIconInfo;
extern const BITMAP_INFO ThermostatHzIconInfo; extern const BITMAP_INFO ThermostatHzIconInfo;
extern const BITMAP_INFO resetIconInfo; 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
} }
} }
} }
@ -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 // return our smart error, if it exists, as the registered code

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

@ -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 = fCal;
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 );
@ -354,9 +376,11 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
bSend |= moderator.addJson("ThermostatUndertemp", NVstore.getUserSettings().cyclic.Start, root); bSend |= moderator.addJson("ThermostatUndertemp", NVstore.getUserSettings().cyclic.Start, root);
bSend |= moderator.addJson("CyclicTemp", getDemandDegC(), root); // actual pivot point for cyclic mode 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("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().lowVolts, 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

@ -71,7 +71,7 @@ CFuelGauge::Integrate(float Hz)
} }
float float
CFuelGauge::Used_ml() CFuelGauge::Used_mL()
{ {
return _pumpStrokes * _pumpCal; // strokes * millilitre / stroke return _pumpStrokes * _pumpCal; // strokes * millilitre / stroke
} }

View File

@ -34,7 +34,7 @@ public:
void init(float fuelUsed = 0); void init(float fuelUsed = 0);
void reset(); void reset();
void Integrate(float Hz); void Integrate(float Hz);
float Used_ml(); float Used_mL();
float Used_strokes(); float Used_strokes();
}; };

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 {

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