Added core frost functionality

This commit is contained in:
Ray Jones 2019-11-01 09:24:58 +11:00
parent f2af9c3fda
commit 7081391f63
16 changed files with 152 additions and 9 deletions

View File

@ -124,8 +124,8 @@
#define RX_DATA_TIMOUT 50
const int FirmwareRevision = 31;
const int FirmwareSubRevision = 6;
const char* FirmwareDate = "27 Oct 2019";
const int FirmwareSubRevision = 7;
const char* FirmwareDate = "30 Oct 2019";
#ifdef ESP32
@ -149,6 +149,7 @@ bool validateFrame(const CProtocol& frame, const char* name);
void checkDisplayUpdate();
void checkDebugCommands();
void manageCyclicMode();
void manageFrostMode();
bool preemptCyclicMode();
void doStreaming();
void heaterOn();
@ -851,6 +852,7 @@ void loop()
FilteredSamples.AmbientTemp.update(fTemperature);
manageCyclicMode();
manageFrostMode();
}
}
else {
@ -941,6 +943,31 @@ void manageCyclicMode()
}
}
void manageFrostMode()
{
uint8_t engage = NVstore.getUserSettings().FrostOn;
if(engage) {
float deltaT = getTemperatureSensor() - engage;
int heaterState = getHeaterInfo().getRunState();
if(deltaT < 0) {
if(heaterState == 0) {
RTC_Store.setFrostOn(true);
DebugPort.printf("FROST MODE: Starting heater, < %d`C\r\n", engage);
heaterOn();
}
}
uint8_t rise = NVstore.getUserSettings().FrostRise;
if(deltaT > rise) {
if(RTC_Store.getFrostOn()) {
DebugPort.printf("FROST MODE: Stopping heater, > %d`C\r\n", engage+rise);
heaterOff();
RTC_Store.setFrostOn(false); // cancel active frost mode
}
}
}
}
bool preemptCyclicMode()
{
const sCyclicThermostat& cyclic = NVstore.getUserSettings().cyclic;
@ -993,6 +1020,7 @@ void requestOn()
{
if(bHasHtrData && (0 == SmartError.checkVolts(FilteredSamples.FastipVolts.getValue(), FilteredSamples.FastGlowAmps.getValue()))) {
RTC_Store.setCyclicEngaged(true); // for cyclic mode
RTC_Store.setFrostOn(false); // cancel frost mode
if(!preemptCyclicMode()) { // only start if below cyclic threshold when enabled
heaterOn();
}
@ -1003,6 +1031,7 @@ void requestOff()
{
heaterOff();
RTC_Store.setCyclicEngaged(false); // for cyclic mode
RTC_Store.setFrostOn(false); // cancel active frost mode
}
void heaterOn()

View File

@ -29,6 +29,7 @@
#include "../Utility/NVStorage.h"
#include "../Protocol/Protocol.h"
#include "../Utility/TempSense.h"
#include "../RTC/RTCStore.h"
#define MAXIFONT tahoma_24ptFontInfo
@ -270,7 +271,7 @@ CBasicScreen::keyHandler(uint8_t event)
if(event & key_Centre) {
if(NVstore.getUserSettings().menuMode < 2) {
int runstate = getHeaterInfo().getRunStateEx();
if(runstate) { // running, including cyclic mode idle
if(runstate && !RTC_Store.getFrostOn()) { // running, including cyclic mode idle
if(repeatCount > 5) {
repeatCount = -1;
requestOff();

View File

@ -28,6 +28,7 @@
#include "../RTC/Clock.h"
#include "../Protocol/Protocol.h"
#include "../Utility/NVStorage.h"
#include "../RTC/RTCStore.h"
///////////////////////////////////////////////////////////////////////////
//
@ -135,7 +136,7 @@ CClockScreen::keyHandler(uint8_t event)
if(event & key_Centre) {
if(NVstore.getUserSettings().menuMode < 2) {
int runstate = getHeaterInfo().getRunStateEx();
if(runstate) { // running, including cyclic mode idle
if(runstate && !RTC_Store.getFrostOn()) { // running, including cyclic mode idle
if(_keyRepeatCount > 5) {
_keyRepeatCount = -1;
requestOff();

View File

@ -28,6 +28,7 @@
#include "../Protocol/Protocol.h"
#include "../Utility/NVStorage.h"
#include "../Utility/FuelGauge.h"
#include "../RTC/RTCStore.h"
#define MINIFONT miniFontInfo
@ -217,7 +218,7 @@ CDetailedScreen::keyHandler(uint8_t event)
if(event & key_Centre) {
int runstate = getHeaterInfo().getRunStateEx();
if(runstate) { // running, including cyclic mode idle
if(runstate && !RTC_Store.getFrostOn()) { // running, including cyclic mode idle
if(_keyRepeatCount > 5) {
_keyRepeatCount = -1; // prevent double handling
requestOff();

View File

@ -33,6 +33,7 @@
#include "../RTC/TimerManager.h"
#include "../Protocol/SmartError.h"
#include "../Utility/DataFilter.h"
#include "../RTC/RTCStore.h"
#define MINIFONT miniFontInfo
@ -329,6 +330,11 @@ CScreenHeader::showBatteryIcon(float voltage)
int
CScreenHeader::showTimers()
{
if(RTC_Store.getFrostOn()) {
int xPos = X_TIMER_ICON;
_drawBitmap(xPos, Y_TIMER_ICON, frostIconInfo);
return 0;
}
int nextTimer = CTimerManager::getNextTimer(); // timer ID and repeat flag info of next scheduled timer
if(nextTimer) {
int xPos = X_TIMER_ICON;
@ -358,12 +364,21 @@ CScreenHeader::showTimers()
}
return 1;
}
_display.fillRect(X_TIMER_ICON-3, Y_TIMER_ICON, TimerIconInfo.width+3, TimerIconInfo.height, BLACK); // erase icon
_display.fillRect(X_TIMER_ICON-3, Y_TIMER_ICON, TimerIconInfo.width+3, 13, BLACK); // erase icon
_display.fillRect(X_TIMER_ICON-5, Y_TIMER_ICON+12, 21, 5, BLACK); // erase annotation
return 0;
}
bool
CScreenHeader::showFrost()
{
if(RTC_Store.getFrostOn()) {
int xPos = X_TIMER_ICON;
_drawBitmap(xPos, Y_TIMER_ICON, frostIconInfo);
return true;
}
return false;
}
void
CScreenHeader::showTime()

View File

@ -54,6 +54,7 @@ protected:
void showBatteryIcon(float voltage);
int showTimers();
virtual void showTime(); // x location depends upon how many timers are active
bool showFrost();
void showHeaderDetail(bool state) { _hdrDetail = state; };
public:
CScreenHeader(C128x64_OLED& disp, CScreenManager& mgr);

View File

@ -1392,3 +1392,26 @@ const uint8_t PROGMEM threshIcon[] =
const BITMAP_INFO threshIconInfo(9, 9, threshIcon);
//
// Image data for frost
//
const uint8_t PROGMEM frostIcon[] =
{
0x15, 0x00, // # # #
0x0A, 0x00, // # #
0xA4, 0xA0, // # # # # #
0x44, 0x40, // # # #
0xA4, 0xA0, // # # # # #
0x15, 0x00, // # # #
0x0E, 0x00, // ###
0x15, 0x00, // # # #
0xA4, 0xA0, // # # # # #
0x44, 0x40, // # # #
0xA4, 0xA0, // # # # # #
0x0A, 0x00, // # #
0x15, 0x00, // # # #
};
const BITMAP_INFO frostIconInfo(11, 13, frostIcon);

View File

@ -159,3 +159,5 @@ extern const BITMAP_INFO algIconInfo;
extern const BITMAP_INFO passwordIconInfo;
extern const BITMAP_INFO threshIconInfo;
extern const BITMAP_INFO frostIconInfo;

View File

@ -154,6 +154,20 @@ CRTC_Store::getDesiredPump()
return _demandPump;
}
void
CRTC_Store::setFrostOn(bool state)
{
_frostOn = state;
_PackAndSaveByte5();
}
bool
CRTC_Store::getFrostOn()
{
_ReadAndUnpackByte5();
return _frostOn;
}
void
CRTC_Store::resetRunTime()
{
@ -230,6 +244,7 @@ CRTC_Store::_ReadAndUnpackByte5()
uint8_t NVval = 0;
Clock.readData((uint8_t*)&NVval, 1, 5);
_demandPump = NVval & 0x3f;
_frostOn = (NVval & 0x40) != 0;
_accessed[2] = true;
DebugPort.printf("RTC_Store - read byte5: pump=%d\r\n", _demandPump);
}
@ -239,6 +254,8 @@ void
CRTC_Store::_PackAndSaveByte5()
{
uint8_t NVval = (_demandPump & 0x3f);
NVval |= _frostOn ? 0x40 : 0;
Clock.saveData((uint8_t*)&NVval, 1, 5);
}

View File

@ -32,6 +32,7 @@ class CRTC_Store {
bool _BootInit; // Byte4[6]
bool _CyclicEngaged; // Byte4[7]
uint8_t _demandPump; // Byte5[0..5]
bool _frostOn; // Byte5[6]
uint8_t _RunTime; // Byte6[0..4]
uint8_t _GlowTime; // Byte6[5..7]
void _ReadAndUnpackByte4();
@ -61,6 +62,8 @@ public:
int getGlowTime();
int getMaxGlowTime() const { return 8; };
int getMaxRunTime() const { return 32; };
void setFrostOn(bool state);
bool getFrostOn();
};
extern CRTC_Store RTC_Store;

View File

@ -33,6 +33,7 @@
#include "Clock.h"
#include "../Utility/NVStorage.h"
#include "../Utility/helpers.h"
#include "../RTC/RTCStore.h"
// main array to hold information of which timer is active at any particular minute of the week
// LSBs are used for the timerID + 1
@ -271,7 +272,9 @@ CTimerManager::manageTime(int _hour, int _minute, int _dow)
}
else {
DebugPort.println("End of timer interval, stopping heater");
requestOff();
// if(!RTC_Store.getFrostOn() && !RTC_Store.getCyclicEngaged())
if(!RTC_Store.getFrostOn())
requestOff();
retval = 2;
}
_activeTimer = newID;

View File

@ -25,6 +25,7 @@
#include "DebugPort.h"
#include "../Protocol/Protocol.h"
#include "../Utility/NVStorage.h"
#include "../RTC/RTCStore.h"
const int BREATHINTERVAL = 45;
const int FADEAMOUNT = 3;
@ -122,7 +123,7 @@ void
CGPIOin1::_doStartStop(bool active)
{
if(active) {
if(getHeaterInfo().getRunStateEx())
if(getHeaterInfo().getRunStateEx() && !RTC_Store.getFrostOn())
requestOff();
else
requestOn();

View File

@ -216,6 +216,8 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
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("FrostOn", NVstore.getUserSettings().FrostOn, root); // temp drops below this, auto start - 0 = disable
bSend |= moderator.addJson("FrostRise", NVstore.getUserSettings().FrostRise, root); // temp rise in frost mode till auto off
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("LowVoltCutout", NVstore.getHeaterTuning().getLVC(), root); // low voltage cutout
@ -283,6 +285,8 @@ bool makeJSONStringGPIO(CModerator& moderator, char* opStr, int len)
bSend |= moderator.addJson("GPmodeIn2", GPIOin2Names[info.in2Mode], root);
bSend |= moderator.addJson("GPmodeOut1", GPIOout1Names[info.out1Mode], root);
bSend |= moderator.addJson("GPmodeOut2", GPIOout2Names[info.out2Mode], root);
bSend |= moderator.addJson("GPOutThr1", NVstore.getUserSettings().GPIO.thresh[0], root);
bSend |= moderator.addJson("GPOutThr2", NVstore.getUserSettings().GPIO.thresh[1], root);
bSend |= moderator.addJson("GPmodeAnlg", GPIOalgNames[info.algMode], root);
bSend |= moderator.addJson("ExtThermoTmout", (uint32_t)NVstore.getUserSettings().ExtThermoTimeout, root);
const char* stop = getExternalThermostatHoldTime();

View File

@ -379,6 +379,8 @@ sUserSettings::load()
}
validatedLoad("thermoWindow", ThermostatWindow, 1.0f, 0.2f, 10.f);
DebugPort.printf("2) Window = %f\r\n", ThermostatWindow);
validatedLoad("frostOn", FrostOn, 0, u8inBounds, 0, 10);
validatedLoad("frostRise", FrostRise, 5, u8inBounds, 0, 20);
validatedLoad("enableWifi", enableWifi, 1, u8inBounds, 0, 1);
validatedLoad("enableOTA", enableOTA, 0, u8inBounds, 0, 1);
validatedLoad("cyclicStop", cyclic.Stop, 0, s8inBounds, 0, 10);
@ -444,6 +446,8 @@ sUserSettings::save()
preferences.putUChar("degF", degF);
preferences.putUChar("thermoMethod", ThermostatMethod);
preferences.putFloat("thermoWindow", ThermostatWindow);
preferences.putUChar("frostOn", FrostOn);
preferences.putUChar("frostRise", FrostRise);
preferences.putUChar("enableWifi", enableWifi);
preferences.putUChar("enableOTA", enableOTA);
preferences.putChar("cyclicStop", cyclic.Stop);

View File

@ -284,6 +284,8 @@ struct sUserSettings : public CESP32_NVStorage {
uint8_t degF;
uint8_t ThermostatMethod; // 0: standard heater, 1: Narrow Hysterisis, 2:Managed Hz mode
float ThermostatWindow;
uint8_t FrostOn;
uint8_t FrostRise;
uint8_t useThermostat;
uint8_t enableWifi;
uint8_t enableOTA;
@ -324,6 +326,8 @@ struct sUserSettings : public CESP32_NVStorage {
degF = 0;
ThermostatMethod = 0;
ThermostatWindow = 1.0;
FrostOn = 0;
FrostRise = 5;
useThermostat = 1;
enableWifi = 1;
enableOTA = 0;
@ -351,6 +355,8 @@ struct sUserSettings : public CESP32_NVStorage {
degF = rhs.degF;
ThermostatMethod = rhs.ThermostatMethod;
ThermostatWindow = rhs.ThermostatWindow;
FrostOn = rhs.FrostOn;
FrostRise = rhs.FrostRise;
useThermostat = rhs.useThermostat;
enableWifi = rhs.enableWifi;
enableOTA = rhs.enableOTA;

View File

@ -309,6 +309,22 @@ void DecodeCmd(const char* cmd, String& payload)
else if(strcmp("GPin2", cmd) == 0) {
simulateGPIOin(payload.toInt() ? 0x02 : 0x00); // simulate key 2 press
}
else if(strcmp("GPOutThr1", cmd) == 0) {
sUserSettings us = NVstore.getUserSettings();
us.GPIO.thresh[0] = payload.toInt(); // 0 = disable; < 0, active if less than abs(val); > 0, active if over val
if(INBOUNDS(us.GPIO.thresh[0], -50, 50)) {
NVstore.setUserSettings(us);
NVstore.save();
}
}
else if(strcmp("GPOutThr2", cmd) == 0) {
sUserSettings us = NVstore.getUserSettings();
us.GPIO.thresh[1] = payload.toInt(); // 0 = disable; < 0, active if less than abs(val); > 0, active if over val
if(INBOUNDS(us.GPIO.thresh[1], -50, 50)) {
NVstore.setUserSettings(us);
NVstore.save();
}
}
else if(strcmp("JSONpack", cmd) == 0) {
sUserSettings us = NVstore.getUserSettings();
uint8_t packed = payload.toInt() ? 0x00 : 0x01;
@ -395,5 +411,21 @@ void DecodeCmd(const char* cmd, String& payload)
else if(strcmp("SysHourMeters", cmd) == 0) {
pHourMeter->resetHard();
}
else if(strcmp("FrostOn", cmd) == 0) {
sUserSettings us = NVstore.getUserSettings();
us.FrostOn = payload.toInt();
if(INBOUNDS(us.FrostOn, 0, 30)) {
NVstore.setUserSettings(us);
NVstore.save();
}
}
else if(strcmp("FrostRise", cmd) == 0) {
sUserSettings us = NVstore.getUserSettings();
us.FrostRise = payload.toInt();
if(INBOUNDS(us.FrostRise, 1, 30)) {
NVstore.setUserSettings(us);
NVstore.save();
}
}
}