Assortment of tweaks and fixes
New Features: GPIO "Run" status output (not standby) RSSI of STA connection STA gatewayIP Only run as "active" controller when changes to fuel mixture etc for a short while. Timed moderation added for frequently changing JSON vars Altitude & Humidity via JSON JSON reboot (mainly for MQTT clients) Bug Fixes: Cyclic not enabled when frost start LVC holdoff added for "starting car" situation Better handling of string and float NV Storage defaults FrostRise limits 1-30 now 0-30 Handle spaces in SPIFFS file uploads
This commit is contained in:
parent
3ca3e633ae
commit
4986a4d741
|
@ -1,18 +1,20 @@
|
||||||
Afterburner operation checklist
|
Afterburner operation checklist
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
Modifications performed:
|
|
||||||
Pullup on Debug Rx line
|
|
||||||
Swapped GPIO In#1 with Analogue input
|
|
||||||
5V via blocking diode to GPIO port
|
|
||||||
|
|
||||||
OLED intact
|
OLED intact
|
||||||
Latest firmware uploaded
|
Latest firmware uploaded
|
||||||
SPIFFS uploaded
|
SPIFFS uploaded
|
||||||
|
Check temperature sensor
|
||||||
Keypad functions OK
|
Keypad functions OK
|
||||||
Indicator LEDs function
|
Indicator LEDs function
|
||||||
Web server functions and serves heater control page
|
Web server functions and serves heater control page
|
||||||
Bluetooth pairs and streams SPP data
|
Bluetooth pairs and streams SPP data
|
||||||
|
Set time
|
||||||
|
Install battery
|
||||||
|
|
||||||
|
GPIO units only
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
Check pressure sensor
|
||||||
GPIO functions:
|
GPIO functions:
|
||||||
Input x2
|
Input x2
|
||||||
Output x2
|
Output x2
|
||||||
|
|
|
@ -97,7 +97,7 @@
|
||||||
#include "Protocol/Protocol.h"
|
#include "Protocol/Protocol.h"
|
||||||
#include "Protocol/TxManage.h"
|
#include "Protocol/TxManage.h"
|
||||||
#include "Protocol/SmartError.h"
|
#include "Protocol/SmartError.h"
|
||||||
#include "Utility/helpers.h"
|
#include "Utility/helpers.h"
|
||||||
#include "Utility/NVStorage.h"
|
#include "Utility/NVStorage.h"
|
||||||
#include "Utility/DebugPort.h"
|
#include "Utility/DebugPort.h"
|
||||||
#include "Utility/macros.h"
|
#include "Utility/macros.h"
|
||||||
|
@ -124,10 +124,10 @@
|
||||||
|
|
||||||
#define RX_DATA_TIMOUT 50
|
#define RX_DATA_TIMOUT 50
|
||||||
|
|
||||||
const int FirmwareRevision = 31;
|
const int FirmwareRevision = 32;
|
||||||
const int FirmwareSubRevision = 9;
|
const int FirmwareSubRevision = 0;
|
||||||
const int FirmwareMinorRevision = 1;
|
const int FirmwareMinorRevision = 0;
|
||||||
const char* FirmwareDate = "15 Jan 2020";
|
const char* FirmwareDate = "21 Mar 2020";
|
||||||
|
|
||||||
|
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
|
@ -367,9 +367,6 @@ void setup() {
|
||||||
digitalWrite(GPIOout2_pin, LOW);
|
digitalWrite(GPIOout2_pin, LOW);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nvs_stats_t nvs_stats;
|
|
||||||
nvs_get_stats(NULL, &nvs_stats);
|
|
||||||
|
|
||||||
// initialise TelnetSpy (port 23) as well as Serial to 115200
|
// initialise TelnetSpy (port 23) as well as Serial to 115200
|
||||||
// Serial is the usual USB connection to a PC
|
// Serial is the usual USB connection to a PC
|
||||||
// DO THIS BEFORE WE TRY AND SEND DEBUG INFO!
|
// DO THIS BEFORE WE TRY AND SEND DEBUG INFO!
|
||||||
|
@ -383,6 +380,11 @@ void setup() {
|
||||||
DebugPort.begin(115200);
|
DebugPort.begin(115200);
|
||||||
DebugPort.println("_______________________________________________________________");
|
DebugPort.println("_______________________________________________________________");
|
||||||
|
|
||||||
|
DebugPort.printf("Getting NVS stats\r\n");
|
||||||
|
|
||||||
|
nvs_stats_t nvs_stats;
|
||||||
|
while( nvs_get_stats(NULL, &nvs_stats) == ESP_ERR_NVS_NOT_INITIALIZED);
|
||||||
|
|
||||||
DebugPort.printf("Reset reason: core0:%d, core1:%d\r\n", rtc_get_reset_reason(0), rtc_get_reset_reason(0));
|
DebugPort.printf("Reset reason: core0:%d, core1:%d\r\n", rtc_get_reset_reason(0), rtc_get_reset_reason(0));
|
||||||
// DebugPort.printf("Previous user ON = %d\r\n", bUserON); // state flag required for cyclic mode to persist properly after a WD reboot :-)
|
// DebugPort.printf("Previous user ON = %d\r\n", bUserON); // state flag required for cyclic mode to persist properly after a WD reboot :-)
|
||||||
|
|
||||||
|
@ -482,6 +484,9 @@ void setup() {
|
||||||
|
|
||||||
setupGPIO();
|
setupGPIO();
|
||||||
|
|
||||||
|
// pinMode(0, OUTPUT);
|
||||||
|
// digitalWrite(0, LOW);
|
||||||
|
|
||||||
#if USE_SW_WATCHDOG == 1 && USE_JTAG == 0
|
#if USE_SW_WATCHDOG == 1 && USE_JTAG == 0
|
||||||
// create a high priority FreeRTOS task as a watchdog monitor
|
// create a high priority FreeRTOS task as a watchdog monitor
|
||||||
TaskHandle_t wdTask;
|
TaskHandle_t wdTask;
|
||||||
|
@ -984,15 +989,18 @@ void manageFrostMode()
|
||||||
if(heaterState == 0) {
|
if(heaterState == 0) {
|
||||||
RTC_Store.setFrostOn(true);
|
RTC_Store.setFrostOn(true);
|
||||||
DebugPort.printf("FROST MODE: Starting heater, < %d`C\r\n", engage);
|
DebugPort.printf("FROST MODE: Starting heater, < %d`C\r\n", engage);
|
||||||
|
if(NVstore.getUserSettings().FrostRise == 0)
|
||||||
|
RTC_Store.setCyclicEngaged(true); // enable cyclic mode if user stop
|
||||||
heaterOn();
|
heaterOn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t rise = NVstore.getUserSettings().FrostRise;
|
uint8_t rise = NVstore.getUserSettings().FrostRise;
|
||||||
if(rise && (deltaT > rise)) { // if rsie is set to 0, user must shut off heater
|
if(rise && (deltaT > rise)) { // if rise is set to 0, user must shut off heater
|
||||||
if(RTC_Store.getFrostOn()) {
|
if(RTC_Store.getFrostOn()) {
|
||||||
DebugPort.printf("FROST MODE: Stopping heater, > %d`C\r\n", engage+rise);
|
DebugPort.printf("FROST MODE: Stopping heater, > %d`C\r\n", engage+rise);
|
||||||
heaterOff();
|
heaterOff();
|
||||||
RTC_Store.setFrostOn(false); // cancel active frost mode
|
RTC_Store.setFrostOn(false); // cancel active frost mode
|
||||||
|
RTC_Store.setCyclicEngaged(false); // for cyclic mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1271,29 +1279,10 @@ float getTemperatureDesired()
|
||||||
|
|
||||||
float getTemperatureSensor(int source)
|
float getTemperatureSensor(int source)
|
||||||
{
|
{
|
||||||
static long lasttime = millis();
|
|
||||||
static float tempsave = 0;
|
|
||||||
long tDelta;
|
|
||||||
// NVstore always holds primary sensor as index 0
|
|
||||||
float retval;
|
float retval;
|
||||||
TempSensor.getTemperature(source, retval);
|
TempSensor.getTemperature(source, retval);
|
||||||
return retval;
|
return retval;
|
||||||
|
|
||||||
// switch (source) {
|
|
||||||
// case 0:
|
|
||||||
// return FilteredSamples.AmbientTemp.getValue() + NVstore.getHeaterTuning().DS18B20probe[0].offset;
|
|
||||||
// case 1:
|
|
||||||
// BMESensor.getTemperature(tempsave);
|
|
||||||
// /* tDelta = millis() - lasttime;
|
|
||||||
// if(tDelta >= 0) {
|
|
||||||
// bme.takeForcedMeasurement();
|
|
||||||
// tempsave = bme.readTemperature();
|
|
||||||
// lasttime = millis() + 10000;
|
|
||||||
// }*/
|
|
||||||
// return tempsave;
|
|
||||||
// default:
|
|
||||||
// return -100;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setPumpMin(float val)
|
void setPumpMin(float val)
|
||||||
|
@ -2031,4 +2020,7 @@ CTempSense& getTempSensor()
|
||||||
return TempSensor;
|
return TempSensor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void reqHeaterCalUpdate()
|
||||||
|
{
|
||||||
|
TxManage.queueSysUpdate();
|
||||||
|
}
|
||||||
|
|
|
@ -135,6 +135,10 @@ CGPIOInfoScreen::animate()
|
||||||
_drawBitmap(99, 15, threshIconInfo);
|
_drawBitmap(99, 15, threshIconInfo);
|
||||||
_drawBitmap(110, 13, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
_drawBitmap(110, 13, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
||||||
break;
|
break;
|
||||||
|
case CGPIOout1::HtrActive:
|
||||||
|
_drawBitmap(99, 15, onOffIconInfo);
|
||||||
|
_drawBitmap(110, 13, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_JTAG == 0
|
#if USE_JTAG == 0
|
||||||
|
@ -151,6 +155,9 @@ CGPIOInfoScreen::animate()
|
||||||
_drawBitmap(99, 27, threshIconInfo);
|
_drawBitmap(99, 27, threshIconInfo);
|
||||||
_drawBitmap(110, 26, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
_drawBitmap(110, 26, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
||||||
break;
|
break;
|
||||||
|
case CGPIOout2::HtrActive:
|
||||||
|
_drawBitmap(99, 27, onOffIconInfo);
|
||||||
|
_drawBitmap(110, 26, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -138,7 +138,7 @@ CGPIOSetupScreen::show()
|
||||||
const char* msgText = NULL;
|
const char* msgText = NULL;
|
||||||
switch(_GPIOparams.out1Mode) {
|
switch(_GPIOparams.out1Mode) {
|
||||||
case CGPIOout1::Disabled: msgText = "---"; break;
|
case CGPIOout1::Disabled: msgText = "---"; break;
|
||||||
case CGPIOout1::Status: msgText = "Status"; break;
|
case CGPIOout1::Status: msgText = "stsLED"; break;
|
||||||
case CGPIOout1::User: msgText = "User"; break;
|
case CGPIOout1::User: msgText = "User"; break;
|
||||||
case CGPIOout1::Thresh:
|
case CGPIOout1::Thresh:
|
||||||
if(_rowSel == 6) {
|
if(_rowSel == 6) {
|
||||||
|
@ -151,6 +151,7 @@ CGPIOSetupScreen::show()
|
||||||
_printMenuText(Column2, Line3, msg, _rowSel == 8);
|
_printMenuText(Column2, Line3, msg, _rowSel == 8);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CGPIOout1::HtrActive: msgText ="OnSts"; break;
|
||||||
}
|
}
|
||||||
if(msgText)
|
if(msgText)
|
||||||
_printMenuText(Column2, Line3, msgText, _rowSel == 6);
|
_printMenuText(Column2, Line3, msgText, _rowSel == 6);
|
||||||
|
@ -173,6 +174,7 @@ CGPIOSetupScreen::show()
|
||||||
_printMenuText(Column2, Line2, msg, _rowSel == 7);
|
_printMenuText(Column2, Line2, msg, _rowSel == 7);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CGPIOout2::HtrActive: msgText ="OnSts"; break;
|
||||||
}
|
}
|
||||||
if(msgText)
|
if(msgText)
|
||||||
_printMenuText(Column2, Line2, msgText, _rowSel == 5);
|
_printMenuText(Column2, Line2, msgText, _rowSel == 5);
|
||||||
|
@ -256,6 +258,7 @@ CGPIOSetupScreen::animate()
|
||||||
else
|
else
|
||||||
pMsg = " Output 2: Active if under temperature. Hold LEFT to set under. Hold RIGHT to set over. ";
|
pMsg = " Output 2: Active if under temperature. Hold LEFT to set under. Hold RIGHT to set over. ";
|
||||||
break;
|
break;
|
||||||
|
case CGPIOout2::HtrActive: pMsg = " Output 2: Active if heater is running. "; break;
|
||||||
}
|
}
|
||||||
if(pMsg)
|
if(pMsg)
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
_scrollMessage(56, pMsg, _scrollChar);
|
||||||
|
@ -272,6 +275,7 @@ CGPIOSetupScreen::animate()
|
||||||
else
|
else
|
||||||
pMsg = " Output 1: Active if under temperature. Hold LEFT to set under. Hold RIGHT to set over. ";
|
pMsg = " Output 1: Active if under temperature. Hold LEFT to set under. Hold RIGHT to set over. ";
|
||||||
break;
|
break;
|
||||||
|
case CGPIOout1::HtrActive: pMsg = " Output 1: Active if heater is running. "; break;
|
||||||
}
|
}
|
||||||
if(pMsg)
|
if(pMsg)
|
||||||
_scrollMessage(56, pMsg, _scrollChar);
|
_scrollMessage(56, pMsg, _scrollChar);
|
||||||
|
@ -483,13 +487,13 @@ CGPIOSetupScreen::_adjust(int dir)
|
||||||
case 5: // outputs mode
|
case 5: // outputs mode
|
||||||
tVal = _GPIOparams.out2Mode;
|
tVal = _GPIOparams.out2Mode;
|
||||||
tVal += dir;
|
tVal += dir;
|
||||||
WRAPLIMITS(tVal, 0, 2);
|
WRAPLIMITS(tVal, 0, 3);
|
||||||
_GPIOparams.out2Mode = (CGPIOout2::Modes)tVal;
|
_GPIOparams.out2Mode = (CGPIOout2::Modes)tVal;
|
||||||
break;
|
break;
|
||||||
case 6: // outputs mode
|
case 6: // outputs mode
|
||||||
tVal = _GPIOparams.out1Mode;
|
tVal = _GPIOparams.out1Mode;
|
||||||
tVal += dir;
|
tVal += dir;
|
||||||
WRAPLIMITS(tVal, 0, 3);
|
WRAPLIMITS(tVal, 0, 4);
|
||||||
_GPIOparams.out1Mode = (CGPIOout1::Modes)tVal;
|
_GPIOparams.out1Mode = (CGPIOout1::Modes)tVal;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
|
|
|
@ -229,6 +229,15 @@ CScreenHeader::showWifiIcon()
|
||||||
{
|
{
|
||||||
if(isWifiConnected() || isWifiAP()) { // STA or AP mode active
|
if(isWifiConnected() || isWifiAP()) { // STA or AP mode active
|
||||||
_drawBitmap(X_WIFI_ICON, Y_WIFI_ICON, WifiWideIconInfo, WHITE, BLACK); // wide icon erases annotations!
|
_drawBitmap(X_WIFI_ICON, Y_WIFI_ICON, WifiWideIconInfo, WHITE, BLACK); // wide icon erases annotations!
|
||||||
|
int8_t RSSI = getWifiRSSI();
|
||||||
|
if(RSSI < -70) {
|
||||||
|
_display.fillRect(X_WIFI_ICON, Y_WIFI_ICON, WifiWideIconInfo.width, 6, BLACK);
|
||||||
|
}
|
||||||
|
else if(RSSI < -55) {
|
||||||
|
_display.fillRect(X_WIFI_ICON, Y_WIFI_ICON, WifiWideIconInfo.width, 3, BLACK);
|
||||||
|
_display.fillRect(X_WIFI_ICON, Y_WIFI_ICON, 1, 4, BLACK);
|
||||||
|
_display.fillRect(X_WIFI_ICON+WifiIconInfo.width-1, Y_WIFI_ICON, 1, 4, BLACK);
|
||||||
|
}
|
||||||
|
|
||||||
int xPos = X_WIFI_ICON + WifiIconInfo.width + 1; // x loaction of upload/download arrows
|
int xPos = X_WIFI_ICON + WifiIconInfo.width + 1; // x loaction of upload/download arrows
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "BasicScreen.h"
|
#include "BasicScreen.h"
|
||||||
#include "PrimingScreen.h"
|
#include "PrimingScreen.h"
|
||||||
#include "WiFiScreen.h"
|
#include "WiFiScreen.h"
|
||||||
|
#include "WiFiSTAScreen.h"
|
||||||
#include "FuelMixtureScreen.h"
|
#include "FuelMixtureScreen.h"
|
||||||
#include "SetClockScreen.h"
|
#include "SetClockScreen.h"
|
||||||
#include "SetTimerScreen.h"
|
#include "SetTimerScreen.h"
|
||||||
|
@ -492,6 +493,7 @@ CScreenManager::_loadScreens()
|
||||||
menuloop.push_back(new CHourMeterScreen(*_pDisplay, *this)); // Hour Meter screen
|
menuloop.push_back(new CHourMeterScreen(*_pDisplay, *this)); // Hour Meter screen
|
||||||
}
|
}
|
||||||
menuloop.push_back(new CWiFiScreen(*_pDisplay, *this));
|
menuloop.push_back(new CWiFiScreen(*_pDisplay, *this));
|
||||||
|
menuloop.push_back(new CWiFiSTAScreen(*_pDisplay, *this));
|
||||||
menuloop.push_back(new CMQTTScreen(*_pDisplay, *this));
|
menuloop.push_back(new CMQTTScreen(*_pDisplay, *this));
|
||||||
menuloop.push_back(new CBTScreen(*_pDisplay, *this));
|
menuloop.push_back(new CBTScreen(*_pDisplay, *this));
|
||||||
if(getTempSensor().getBME280().getCount()) {
|
if(getTempSensor().getBME280().getCount()) {
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the "bluetoothheater" distribution
|
||||||
|
* (https://gitlab.com/mrjones.id.au/bluetoothheater)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Ray Jones <ray@mrjones.id.au>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "WiFiSTAScreen.h"
|
||||||
|
#include "KeyPad.h"
|
||||||
|
#include "../Utility/helpers.h"
|
||||||
|
#include "../Utility/NVStorage.h"
|
||||||
|
#include "../WiFi/BTCWifi.h"
|
||||||
|
#include "fonts/Arial.h"
|
||||||
|
#include "fonts/Icons.h"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// CWiFiSTAScreen
|
||||||
|
//
|
||||||
|
// This screen presents information about the STA connection
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
CWiFiSTAScreen::CWiFiSTAScreen(C128x64_OLED& display, CScreenManager& mgr) : CScreen(display, mgr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
CWiFiSTAScreen::show()
|
||||||
|
{
|
||||||
|
CScreen::show();
|
||||||
|
|
||||||
|
_display.clearDisplay();
|
||||||
|
_showTitle("WiFi STA status");
|
||||||
|
|
||||||
|
int yPos = 15;
|
||||||
|
|
||||||
|
if(NVstore.getUserSettings().wifiMode == 0 || !isWifiSTA()) {
|
||||||
|
if(NVstore.getUserSettings().wifiMode == 0)
|
||||||
|
_printMenuText(border, yPos, "DISABLED");
|
||||||
|
else
|
||||||
|
_printMenuText(border, yPos, "NOT CONNECTED");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_printMenuText(0, yPos, "ADDR:");
|
||||||
|
_printMenuText(31, yPos, getWifiSTAAddrStr());
|
||||||
|
|
||||||
|
yPos += _display.textHeight() + 3;
|
||||||
|
_printMenuText(0, yPos, " GW:");
|
||||||
|
_printMenuText(31, yPos, getWifiGatewayAddrStr());
|
||||||
|
|
||||||
|
// yPos += _display.textHeight() + 2;
|
||||||
|
// _printMenuText(0, yPos, " MAC:");
|
||||||
|
// _printMenuText(31, yPos, getWifiSTAMACStr());
|
||||||
|
|
||||||
|
yPos += _display.textHeight() + 3;
|
||||||
|
_printMenuText(0, yPos, "RSSI:");
|
||||||
|
int8_t RSSI = getWifiRSSI();
|
||||||
|
char RSSIstr[16];
|
||||||
|
sprintf(RSSIstr, "%ddBm", RSSI);
|
||||||
|
_printMenuText(31, yPos, RSSIstr);
|
||||||
|
|
||||||
|
int xPos = 90;
|
||||||
|
_drawBitmap(xPos, yPos, WifiIconInfo, WHITE, BLACK); // wide icon erases annotations!
|
||||||
|
if(RSSI < -70) {
|
||||||
|
_display.fillRect(xPos, yPos, WifiIconInfo.width, 6, BLACK);
|
||||||
|
}
|
||||||
|
else if(RSSI < -55) {
|
||||||
|
_display.fillRect(xPos, yPos, WifiWideIconInfo.width, 3, BLACK);
|
||||||
|
_display.fillRect(xPos, yPos, 1, 4, BLACK);
|
||||||
|
_display.fillRect(xPos+WifiIconInfo.width-1, yPos, 1, 4, BLACK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_printMenuText(_display.xCentre(), 53, "\021 \020", true, eCentreJustify);
|
||||||
|
_printMenuText(_display.xCentre(), 53, "Exit", false, eCentreJustify);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
CWiFiSTAScreen::keyHandler(uint8_t event)
|
||||||
|
{
|
||||||
|
if(event & keyPressed) {
|
||||||
|
// press LEFT
|
||||||
|
if(event & key_Left) {
|
||||||
|
_ScreenManager.prevMenu();
|
||||||
|
}
|
||||||
|
// press RIGHT
|
||||||
|
if(event & key_Right) {
|
||||||
|
_ScreenManager.nextMenu();
|
||||||
|
}
|
||||||
|
// press UP
|
||||||
|
if(event & key_Up) {
|
||||||
|
}
|
||||||
|
// press DOWN
|
||||||
|
if(event & key_Down) {
|
||||||
|
}
|
||||||
|
if(event & key_Centre) {
|
||||||
|
_ScreenManager.selectMenu(CScreenManager::RootMenuLoop); // force return to main menu
|
||||||
|
}
|
||||||
|
_ScreenManager.reqUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* 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 __WIFISTASCREEN_H__
|
||||||
|
#define __WIFISTASCREEN_H__
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "Screen.h"
|
||||||
|
|
||||||
|
class C128x64_OLED;
|
||||||
|
class CScreenManager;
|
||||||
|
|
||||||
|
class CWiFiSTAScreen : public CScreen {
|
||||||
|
public:
|
||||||
|
CWiFiSTAScreen(C128x64_OLED& display, CScreenManager& mgr);
|
||||||
|
bool show();
|
||||||
|
bool keyHandler(uint8_t event);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -1301,6 +1301,22 @@ const uint8_t PROGMEM threshIcon[] =
|
||||||
|
|
||||||
const BITMAP_INFO threshIconInfo(9, 9, threshIcon);
|
const BITMAP_INFO threshIconInfo(9, 9, threshIcon);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Image data for onOff
|
||||||
|
//
|
||||||
|
|
||||||
|
const uint8_t PROGMEM onOffIcon[] =
|
||||||
|
{
|
||||||
|
0x10, // #
|
||||||
|
0x54, // # # #
|
||||||
|
0x92, // # # #
|
||||||
|
0x92, // # # #
|
||||||
|
0x82, // # #
|
||||||
|
0x44, // # #
|
||||||
|
0x38, // ###
|
||||||
|
};
|
||||||
|
|
||||||
|
const BITMAP_INFO onOffIconInfo(7, 7, onOffIcon);
|
||||||
//
|
//
|
||||||
// Image data for frost
|
// Image data for frost
|
||||||
//
|
//
|
||||||
|
|
|
@ -159,5 +159,6 @@ extern const BITMAP_INFO algIconInfo;
|
||||||
|
|
||||||
extern const BITMAP_INFO passwordIconInfo;
|
extern const BITMAP_INFO passwordIconInfo;
|
||||||
extern const BITMAP_INFO threshIconInfo;
|
extern const BITMAP_INFO threshIconInfo;
|
||||||
|
extern const BITMAP_INFO onOffIconInfo;
|
||||||
extern const BITMAP_INFO frostIconInfo;
|
extern const BITMAP_INFO frostIconInfo;
|
||||||
extern const BITMAP_INFO humidityIconInfo;
|
extern const BITMAP_INFO humidityIconInfo;
|
||||||
|
|
|
@ -238,6 +238,13 @@ CProtocol::setAltitude(float altitude)
|
||||||
Controller.Altitude_LSB = (alt >> 0) & 0xff;
|
Controller.Altitude_LSB = (alt >> 0) & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CProtocol::getAltitude() const
|
||||||
|
{
|
||||||
|
int alt = (Controller.Altitude_MSB << 8) | Controller.Altitude_LSB;
|
||||||
|
return alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
CProtocol::Init(int FrameMode)
|
CProtocol::Init(int FrameMode)
|
||||||
|
|
|
@ -163,6 +163,7 @@ public:
|
||||||
void setTemperature_HeatExchg(uint16_t degC); // temperature of heat exchanger
|
void setTemperature_HeatExchg(uint16_t degC); // temperature of heat exchanger
|
||||||
// altitude
|
// altitude
|
||||||
void setAltitude(float altitude);
|
void setAltitude(float altitude);
|
||||||
|
int getAltitude() const;
|
||||||
|
|
||||||
void DebugReport(const char* hdr, const char* ftr);
|
void DebugReport(const char* hdr, const char* ftr);
|
||||||
|
|
||||||
|
@ -210,6 +211,7 @@ public:
|
||||||
float getGlow_Current() const { return Heater.getGlowPlug_Current(); };
|
float getGlow_Current() const { return Heater.getGlowPlug_Current(); };
|
||||||
float getSystemVoltage() const { return Controller.getSystemVoltage(); };
|
float getSystemVoltage() const { return Controller.getSystemVoltage(); };
|
||||||
int getGlow_Drive() const { return Controller.getGlowDrive(); };
|
int getGlow_Drive() const { return Controller.getGlowDrive(); };
|
||||||
|
int getAltitude() const { return Controller.getAltitude(); };
|
||||||
|
|
||||||
// void setRefTime();
|
// void setRefTime();
|
||||||
void reportFrames(bool isOEM);
|
void reportFrames(bool isOEM);
|
||||||
|
|
|
@ -126,6 +126,8 @@ CSmartError::monitor(uint8_t newRunState)
|
||||||
int
|
int
|
||||||
CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
|
CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
|
||||||
{
|
{
|
||||||
|
const unsigned long LVCholdoffTime = 10000;
|
||||||
|
static unsigned long LVCShutdownHoldoff = 0;
|
||||||
// check for low voltage
|
// check for low voltage
|
||||||
// Native NV values here are x10 integers
|
// Native NV values here are x10 integers
|
||||||
|
|
||||||
|
@ -139,27 +141,32 @@ CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
|
||||||
|
|
||||||
// test low voltage cutout
|
// test low voltage cutout
|
||||||
if(ipVolts < threshLVC) {
|
if(ipVolts < threshLVC) {
|
||||||
if(throwfault) { // only throw faults if directed to do so
|
if(LVCShutdownHoldoff == 0) {
|
||||||
_Error = 2; // internals error codes are +1 over displayed error code
|
// initial detection of LVC - introduce a hold off period
|
||||||
requestOff(); // shut heater down
|
DebugPort.println("LVC holdoff enagaged");
|
||||||
|
LVCShutdownHoldoff = (millis() + LVCholdoffTime) | 1; // ensure non zero!
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
long tDelta = millis() - LVCShutdownHoldoff;
|
||||||
|
if(tDelta > 0) {
|
||||||
|
LVCShutdownHoldoff = 0;
|
||||||
|
if(throwfault) { // only throw faults if directed to do so
|
||||||
|
DebugPort.println("LVC shutting heater down");
|
||||||
|
_Error = 2; // internals error codes are +1 over displayed error code
|
||||||
|
requestOff(); // shut heater down
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 2; // Low voltage return value = 2
|
return 2; // Low voltage return value = 2
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if(LVCShutdownHoldoff)
|
||||||
|
DebugPort.println("LVC holdoff cancelled");
|
||||||
|
LVCShutdownHoldoff = 0; // disable holdoff, voltage now OK
|
||||||
|
}
|
||||||
|
|
||||||
// warning threshold
|
// warning threshold
|
||||||
float threshWarn = threshLVC + 0.5; // nominally create a warning threshold, 0.5V over LVC threhsold
|
float threshWarn = threshLVC + 0.5; // nominally create a warning threshold, 0.5V over LVC threhsold
|
||||||
/*
|
|
||||||
float alertlimit; // but always introduce it if below system voltage
|
|
||||||
if(NVstore.getHeaterTuning().sysVoltage == 120) {
|
|
||||||
alertlimit = 12.0 - cableComp;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
alertlimit = 24.0 - cableComp;
|
|
||||||
}
|
|
||||||
if(threshWarn < alertlimit) {
|
|
||||||
threshWarn = alertlimit;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if(ipVolts < threshWarn) {
|
if(ipVolts < threshWarn) {
|
||||||
return 1; // LVC OK, but below warning threshold, return code = 1
|
return 1; // LVC OK, but below warning threshold, return code = 1
|
||||||
|
|
|
@ -55,6 +55,7 @@ CTxManage::CTxManage(int TxGatePin, HardwareSerial& serial) :
|
||||||
m_BlueWireSerial(serial),
|
m_BlueWireSerial(serial),
|
||||||
m_TxFrame(CProtocol::CtrlMode)
|
m_TxFrame(CProtocol::CtrlMode)
|
||||||
{
|
{
|
||||||
|
m_sysUpdate = 0;
|
||||||
m_bOnReq = false;
|
m_bOnReq = false;
|
||||||
m_bOffReq = false;
|
m_bOffReq = false;
|
||||||
m_bTxPending = false;
|
m_bTxPending = false;
|
||||||
|
@ -107,6 +108,12 @@ CTxManage::queueRawCommand(uint8_t val)
|
||||||
_rawCommand = val;
|
_rawCommand = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CTxManage::queueSysUpdate()
|
||||||
|
{
|
||||||
|
m_sysUpdate = 10;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
|
CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
|
||||||
{
|
{
|
||||||
|
@ -139,7 +146,13 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
|
||||||
// 0x78 prevents the controller showing bum information when we parrot the OEM controller
|
// 0x78 prevents the controller showing bum information when we parrot the OEM controller
|
||||||
// heater is happy either way, the OEM controller has set the max/min stuff already
|
// heater is happy either way, the OEM controller has set the max/min stuff already
|
||||||
if(isBTCmaster) {
|
if(isBTCmaster) {
|
||||||
m_TxFrame.setActiveMode(); // this allows heater to save the tuning params to EEPROM
|
if(m_sysUpdate) {
|
||||||
|
m_sysUpdate--;
|
||||||
|
m_TxFrame.setActiveMode(); // this allows heater to save the tuning params to EEPROM
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_TxFrame.setPassiveMode(); // this prevents the tuning parameters being saved by heater
|
||||||
|
}
|
||||||
m_TxFrame.setFan_Min(NVstore.getHeaterTuning().Fmin);
|
m_TxFrame.setFan_Min(NVstore.getHeaterTuning().Fmin);
|
||||||
m_TxFrame.setFan_Max(NVstore.getHeaterTuning().Fmax);
|
m_TxFrame.setFan_Max(NVstore.getHeaterTuning().Fmax);
|
||||||
m_TxFrame.setPump_Min(NVstore.getHeaterTuning().getPmin());
|
m_TxFrame.setPump_Min(NVstore.getHeaterTuning().getPmin());
|
||||||
|
|
|
@ -26,6 +26,7 @@ class CTxManage
|
||||||
const int m_nStartDelay = 20;
|
const int m_nStartDelay = 20;
|
||||||
const int m_nFrameTime = 14;
|
const int m_nFrameTime = 14;
|
||||||
const int m_nFrontPorch = 0;
|
const int m_nFrontPorch = 0;
|
||||||
|
int m_sysUpdate;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CTxManage(int TxGatePin, HardwareSerial& serial);
|
CTxManage(int TxGatePin, HardwareSerial& serial);
|
||||||
|
@ -38,6 +39,7 @@ public:
|
||||||
void begin();
|
void begin();
|
||||||
const CProtocol& getFrame() const { return m_TxFrame; };
|
const CProtocol& getFrame() const { return m_TxFrame; };
|
||||||
static void GateTerminate();
|
static void GateTerminate();
|
||||||
|
void queueSysUpdate(); // use to implant NV settings into heater
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HardwareSerial& m_BlueWireSerial;
|
HardwareSerial& m_BlueWireSerial;
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include "ABpreferences.h"
|
||||||
|
|
||||||
|
#include "nvs.h"
|
||||||
|
|
||||||
|
const char * nvs_errors2[] = { "OTHER", "NOT_INITIALIZED", "NOT_FOUND", "TYPE_MISMATCH", "READ_ONLY", "NOT_ENOUGH_SPACE", "INVALID_NAME", "INVALID_HANDLE", "REMOVE_FAILED", "KEY_TOO_LONG", "PAGE_FULL", "INVALID_STATE", "INVALID_LENGHT"};
|
||||||
|
#define nvs_error(e) (((e)>ESP_ERR_NVS_BASE)?nvs_errors2[(e)&~(ESP_ERR_NVS_BASE)]:nvs_errors2[0])
|
||||||
|
|
||||||
|
bool
|
||||||
|
ABpreferences::hasBytes(const char *key)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
if(!_started || !key){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
esp_err_t err = nvs_get_blob(_handle, key, NULL, &len);
|
||||||
|
if(err == ESP_ERR_NVS_NOT_FOUND) { // NOT FOUND - expected!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(err) { // remaining errors - print it
|
||||||
|
log_e("nvs_get_blob len fail: %s %s", key, nvs_error(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return len != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ABpreferences::hasString(const char *key)
|
||||||
|
{
|
||||||
|
size_t len = 0;
|
||||||
|
if(!_started || !key){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
esp_err_t err = nvs_get_str(_handle, key, NULL, &len);
|
||||||
|
if(err == ESP_ERR_NVS_NOT_FOUND) { // NOT FOUND - expected!
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(err) { // remaining errors - print it
|
||||||
|
log_e("nvs_get_str len fail: %s %s", key, nvs_error(err));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return len != 0;
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
|
||||||
|
#include <Preferences.h>
|
||||||
|
|
||||||
|
class ABpreferences : public Preferences {
|
||||||
|
public:
|
||||||
|
bool hasBytes(const char* key);
|
||||||
|
bool hasString(const char* key);
|
||||||
|
};
|
|
@ -50,12 +50,14 @@ const char* GPIOout1Names[] = {
|
||||||
"Disabled",
|
"Disabled",
|
||||||
"Status",
|
"Status",
|
||||||
"User",
|
"User",
|
||||||
"Thresh"
|
"Thresh",
|
||||||
|
"HeaterOn"
|
||||||
};
|
};
|
||||||
const char* GPIOout2Names[] = {
|
const char* GPIOout2Names[] = {
|
||||||
"Disabled",
|
"Disabled",
|
||||||
"User",
|
"User",
|
||||||
"Thresh"
|
"Thresh",
|
||||||
|
"HeaterOn"
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* GPIOalgNames[] = {
|
const char* GPIOalgNames[] = {
|
||||||
|
@ -216,7 +218,7 @@ CGPIOin2::_doThermostat(bool active)
|
||||||
}
|
}
|
||||||
|
|
||||||
const char*
|
const char*
|
||||||
CGPIOin2::getExtThermTime()
|
CGPIOin2:: getExtThermTime()
|
||||||
{
|
{
|
||||||
if((_OffHoldoff == 0) || (NVstore.getUserSettings().ThermostatMethod != 3) || (NVstore.getUserSettings().ExtThermoTimeout == 0))
|
if((_OffHoldoff == 0) || (NVstore.getUserSettings().ThermostatMethod != 3) || (NVstore.getUserSettings().ExtThermoTimeout == 0))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -406,6 +408,12 @@ CGPIOoutBase::_doThresh()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CGPIOoutBase::_doActive()
|
||||||
|
{
|
||||||
|
int runstate = getHeaterInfo().getRunState(); // raw state, not suspend mode enhanced
|
||||||
|
digitalWrite(_pin, runstate ? HIGH : LOW); // activates output when heater is not in standby
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************************************************
|
/*********************************************************************************************************
|
||||||
** GPIO out manager
|
** GPIO out manager
|
||||||
|
@ -503,7 +511,7 @@ CGPIOout1::begin(int pin, CGPIOout1::Modes mode)
|
||||||
void
|
void
|
||||||
CGPIOout1::setMode(CGPIOout1::Modes mode)
|
CGPIOout1::setMode(CGPIOout1::Modes mode)
|
||||||
{
|
{
|
||||||
if(mode >= Disabled && mode <= Thresh)
|
if(mode >= Disabled && mode <= HtrActive)
|
||||||
_Mode = mode;
|
_Mode = mode;
|
||||||
_prevState = -1;
|
_prevState = -1;
|
||||||
if(_getPin())
|
if(_getPin())
|
||||||
|
@ -523,6 +531,7 @@ CGPIOout1::manage()
|
||||||
case CGPIOout1::Status: _doStatus(); break;
|
case CGPIOout1::Status: _doStatus(); break;
|
||||||
case CGPIOout1::User: _doUser(); break;
|
case CGPIOout1::User: _doUser(); break;
|
||||||
case CGPIOout1::Thresh: _doThresh(); break;
|
case CGPIOout1::Thresh: _doThresh(); break;
|
||||||
|
case CGPIOout1::HtrActive: _doActive(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,6 +588,7 @@ CGPIOout1::_doStatus()
|
||||||
ledcAttachPin(pin, 0); // attach PWM to GPIO line
|
ledcAttachPin(pin, 0); // attach PWM to GPIO line
|
||||||
ledcWrite(0, _statusState);
|
ledcWrite(0, _statusState);
|
||||||
_breatheDelay = millis() + BREATHINTERVAL;
|
_breatheDelay = millis() + BREATHINTERVAL;
|
||||||
|
_ledState = 2;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
ledcDetachPin(pin); // detach PWM from IO line
|
ledcDetachPin(pin); // detach PWM from IO line
|
||||||
|
@ -590,11 +600,13 @@ CGPIOout1::_doStatus()
|
||||||
_statusState = 255;
|
_statusState = 255;
|
||||||
ledcWrite(0, _statusState);
|
ledcWrite(0, _statusState);
|
||||||
_breatheDelay = millis() + BREATHINTERVAL;
|
_breatheDelay = millis() + BREATHINTERVAL;
|
||||||
|
_ledState = 3;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
ledcDetachPin(pin); // detach PWM from IO line
|
ledcDetachPin(pin); // detach PWM from IO line
|
||||||
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
|
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
|
||||||
_setPinState(LOW);
|
_setPinState(LOW);
|
||||||
|
_ledState = 4;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -631,7 +643,7 @@ CGPIOout1::_doStopMode() // breath down PWM
|
||||||
_statusState &= 0xff;
|
_statusState &= 0xff;
|
||||||
ledcWrite(0, _statusState);
|
ledcWrite(0, _statusState);
|
||||||
}
|
}
|
||||||
_ledState = 2;
|
_ledState = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -657,7 +669,7 @@ CGPIOout1::_doSuspendMode() // brief flash
|
||||||
if(tDelta >= 0)
|
if(tDelta >= 0)
|
||||||
stretch = 0;
|
stretch = 0;
|
||||||
}
|
}
|
||||||
_ledState = stretch ? 1 : 0;
|
_ledState = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t
|
uint8_t
|
||||||
|
@ -666,6 +678,7 @@ CGPIOout1::getState()
|
||||||
switch(_Mode) {
|
switch(_Mode) {
|
||||||
case User:
|
case User:
|
||||||
case Thresh:
|
case Thresh:
|
||||||
|
case HtrActive:
|
||||||
return _getPinState();
|
return _getPinState();
|
||||||
case Status:
|
case Status:
|
||||||
return _ledState; // special pulse extender for suspend mode
|
return _ledState; // special pulse extender for suspend mode
|
||||||
|
@ -695,7 +708,7 @@ CGPIOout2::begin(int pin, Modes mode)
|
||||||
void
|
void
|
||||||
CGPIOout2::setMode(CGPIOout2::Modes mode)
|
CGPIOout2::setMode(CGPIOout2::Modes mode)
|
||||||
{
|
{
|
||||||
if(mode >= Disabled && mode <= Thresh)
|
if(mode >= Disabled && mode <= HtrActive)
|
||||||
_Mode = mode;
|
_Mode = mode;
|
||||||
int pin = _getPin();
|
int pin = _getPin();
|
||||||
if(pin)
|
if(pin)
|
||||||
|
@ -714,6 +727,7 @@ CGPIOout2::manage()
|
||||||
case CGPIOout2::Disabled: break;
|
case CGPIOout2::Disabled: break;
|
||||||
case CGPIOout2::User: _doUser(); break;
|
case CGPIOout2::User: _doUser(); break;
|
||||||
case CGPIOout2::Thresh: _doThresh(); break;
|
case CGPIOout2::Thresh: _doThresh(); break;
|
||||||
|
case CGPIOout2::HtrActive: _doActive(); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -724,6 +738,7 @@ CGPIOout2::getState()
|
||||||
switch (_Mode) {
|
switch (_Mode) {
|
||||||
case CGPIOout2::User:
|
case CGPIOout2::User:
|
||||||
case CGPIOout2::Thresh:
|
case CGPIOout2::Thresh:
|
||||||
|
case CGPIOout2::HtrActive:
|
||||||
return _getPinState();
|
return _getPinState();
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -107,6 +107,7 @@ class CGPIOoutBase {
|
||||||
bool _userState;
|
bool _userState;
|
||||||
int _pin;
|
int _pin;
|
||||||
protected:
|
protected:
|
||||||
|
void _doActive();
|
||||||
void _doThresh();
|
void _doThresh();
|
||||||
void _doUser();
|
void _doUser();
|
||||||
bool _getUserState();
|
bool _getUserState();
|
||||||
|
@ -126,7 +127,8 @@ public:
|
||||||
Disabled,
|
Disabled,
|
||||||
Status,
|
Status,
|
||||||
User,
|
User,
|
||||||
Thresh
|
Thresh,
|
||||||
|
HtrActive
|
||||||
};
|
};
|
||||||
CGPIOout1();
|
CGPIOout1();
|
||||||
void begin(int pin, Modes mode);
|
void begin(int pin, Modes mode);
|
||||||
|
@ -152,7 +154,8 @@ public:
|
||||||
enum Modes {
|
enum Modes {
|
||||||
Disabled,
|
Disabled,
|
||||||
User,
|
User,
|
||||||
Thresh
|
Thresh,
|
||||||
|
HtrActive,
|
||||||
};
|
};
|
||||||
CGPIOout2();
|
CGPIOout2();
|
||||||
void begin(int pin, Modes mode);
|
void begin(int pin, Modes mode);
|
||||||
|
@ -207,8 +210,8 @@ struct sGPIOparams {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sGPIO {
|
struct sGPIO {
|
||||||
bool outState[2];
|
uint8_t outState[2];
|
||||||
bool inState[2];
|
uint8_t inState[2];
|
||||||
int algVal;
|
int algVal;
|
||||||
sGPIO() {
|
sGPIO() {
|
||||||
outState[0] = outState[1] = false;
|
outState[0] = outState[1] = false;
|
||||||
|
|
|
@ -142,26 +142,26 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len)
|
||||||
float tidyTemp = getTemperatureSensor();
|
float tidyTemp = getTemperatureSensor();
|
||||||
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||||
if(tidyTemp > -80) {
|
if(tidyTemp > -80) {
|
||||||
bSend |= moderator.addJson("TempCurrent", tidyTemp, root);
|
bSend |= moderator.addJson("TempCurrent", tidyTemp, root, 5000);
|
||||||
}
|
}
|
||||||
if(getTempSensor().getNumSensors() > 1) {
|
if(getTempSensor().getNumSensors() > 1) {
|
||||||
getTempSensor().getTemperature(1, tidyTemp);
|
getTempSensor().getTemperature(1, tidyTemp);
|
||||||
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||||
if(tidyTemp > -80) {
|
if(tidyTemp > -80) {
|
||||||
bSend |= moderator.addJson("Temp2Current", tidyTemp, root);
|
bSend |= moderator.addJson("Temp2Current", tidyTemp, root, 5000);
|
||||||
}
|
}
|
||||||
if(getTempSensor().getNumSensors() > 2) {
|
if(getTempSensor().getNumSensors() > 2) {
|
||||||
getTempSensor().getTemperature(2, tidyTemp);
|
getTempSensor().getTemperature(2, tidyTemp);
|
||||||
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||||
if(tidyTemp > -80) {
|
if(tidyTemp > -80) {
|
||||||
bSend |= moderator.addJson("Temp3Current", tidyTemp, root);
|
bSend |= moderator.addJson("Temp3Current", tidyTemp, root, 5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(getTempSensor().getNumSensors() > 3) {
|
if(getTempSensor().getNumSensors() > 3) {
|
||||||
getTempSensor().getTemperature(3, tidyTemp);
|
getTempSensor().getTemperature(3, tidyTemp);
|
||||||
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||||
if(tidyTemp > -80) {
|
if(tidyTemp > -80) {
|
||||||
bSend |= moderator.addJson("Temp4Current", tidyTemp, root);
|
bSend |= moderator.addJson("Temp4Current", tidyTemp, root, 5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,7 +170,7 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len)
|
||||||
if(NVstore.getUserSettings().menuMode < 2) {
|
if(NVstore.getUserSettings().menuMode < 2) {
|
||||||
bSend |= moderator.addJson("TempMin", getHeaterInfo().getTemperature_Min(), root);
|
bSend |= moderator.addJson("TempMin", getHeaterInfo().getTemperature_Min(), root);
|
||||||
bSend |= moderator.addJson("TempMax", getHeaterInfo().getTemperature_Max(), root);
|
bSend |= moderator.addJson("TempMax", getHeaterInfo().getTemperature_Max(), root);
|
||||||
bSend |= moderator.addJson("TempBody", getHeaterInfo().getTemperature_HeatExchg(), root);
|
bSend |= moderator.addJson("TempBody", getHeaterInfo().getTemperature_HeatExchg(), root, 5000);
|
||||||
bSend |= moderator.addJson("RunState", getHeaterInfo().getRunStateEx(), root);
|
bSend |= moderator.addJson("RunState", getHeaterInfo().getRunStateEx(), root);
|
||||||
bSend |= moderator.addJson("RunString", getHeaterInfo().getRunStateStr(), root); // verbose it up!
|
bSend |= moderator.addJson("RunString", getHeaterInfo().getRunStateStr(), root); // verbose it up!
|
||||||
bSend |= moderator.addJson("ErrorState", getHeaterInfo().getErrState(), root );
|
bSend |= moderator.addJson("ErrorState", getHeaterInfo().getErrState(), root );
|
||||||
|
@ -182,13 +182,13 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len)
|
||||||
bSend |= moderator.addJson("PumpActual", getHeaterInfo().getPump_Actual(), root );
|
bSend |= moderator.addJson("PumpActual", getHeaterInfo().getPump_Actual(), root );
|
||||||
bSend |= moderator.addJson("FanMin", getHeaterInfo().getFan_Min(), root );
|
bSend |= moderator.addJson("FanMin", getHeaterInfo().getFan_Min(), root );
|
||||||
bSend |= moderator.addJson("FanMax", getHeaterInfo().getFan_Max(), root );
|
bSend |= moderator.addJson("FanMax", getHeaterInfo().getFan_Max(), root );
|
||||||
bSend |= moderator.addJson("FanRPM", getFanSpeed(), root );
|
bSend |= moderator.addJson("FanRPM", getFanSpeed(), root, 2000 );
|
||||||
bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root );
|
bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root, 2500 );
|
||||||
bSend |= moderator.addJson("FanSensor", getHeaterInfo().getFan_Sensor(), root );
|
bSend |= moderator.addJson("FanSensor", getHeaterInfo().getFan_Sensor(), root );
|
||||||
bSend |= moderator.addJson("InputVoltage", getBatteryVoltage(false), root );
|
bSend |= moderator.addJson("InputVoltage", getBatteryVoltage(false), root, 10000 );
|
||||||
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, 5000 );
|
||||||
bSend |= moderator.addJson("GlowCurrent", getGlowCurrent(), root );
|
bSend |= moderator.addJson("GlowCurrent", getGlowCurrent(), root, 5000 );
|
||||||
bSend |= moderator.addJson("BluewireStat", getBlueWireStatStr(), root );
|
bSend |= moderator.addJson("BluewireStat", getBlueWireStatStr(), root );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,9 +218,12 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
|
||||||
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("FrostOn", NVstore.getUserSettings().FrostOn, root); // temp drops below this, auto start - 0 = disable
|
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("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("PumpCount", RTC_Store.getFuelGauge(), root, 10000); // 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("LowVoltCutout", NVstore.getHeaterTuning().getLVC(), root); // low voltage cutout
|
bSend |= moderator.addJson("LowVoltCutout", NVstore.getHeaterTuning().getLVC(), root); // low voltage cutout
|
||||||
|
if(getTempSensor().getBME280().getCount()) {
|
||||||
|
bSend |= moderator.addJson("HumidStart", NVstore.getUserSettings().humidityStart, root); // BME280 ONLY
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bSend |= moderator.addJson("TempOffset", getTempSensor().getOffset(0), root); // degC offset
|
bSend |= moderator.addJson("TempOffset", getTempSensor().getOffset(0), root); // degC offset
|
||||||
bSend |= moderator.addJson("TempType", getTempSensor().getID(0), root); // BME280 vs DS18B20
|
bSend |= moderator.addJson("TempType", getTempSensor().getID(0), root); // BME280 vs DS18B20
|
||||||
|
@ -236,6 +239,15 @@ bool makeJSONStringEx(CModerator& moderator, char* opStr, int len)
|
||||||
bSend |= moderator.addJson("Temp4Offset", getTempSensor().getOffset(3), root); // degC offset
|
bSend |= moderator.addJson("Temp4Offset", getTempSensor().getOffset(3), root); // degC offset
|
||||||
bSend |= moderator.addJson("Temp4Type", getTempSensor().getID(3), root); // BME280 vs DS18B20
|
bSend |= moderator.addJson("Temp4Type", getTempSensor().getID(3), root); // BME280 vs DS18B20
|
||||||
}
|
}
|
||||||
|
if(getTempSensor().getBME280().getCount()) {
|
||||||
|
|
||||||
|
bSend |= moderator.addJson("Altitude", getHeaterInfo().getAltitude(), root, 60000); // BME280 ONLY
|
||||||
|
float humidity;
|
||||||
|
getTempSensor().getHumidity(humidity);
|
||||||
|
humidity = int(humidity * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||||
|
bSend |= moderator.addJson("Humidity", humidity, root, 30000); // BME280 ONLY
|
||||||
|
}
|
||||||
|
|
||||||
if(bSend) {
|
if(bSend) {
|
||||||
root.printTo(opStr, len);
|
root.printTo(opStr, len);
|
||||||
}
|
}
|
||||||
|
@ -285,8 +297,8 @@ bool makeJSONStringGPIO(CModerator& moderator, char* opStr, int len)
|
||||||
bSend |= moderator.addJson("GPmodeIn2", GPIOin2Names[info.in2Mode], root);
|
bSend |= moderator.addJson("GPmodeIn2", GPIOin2Names[info.in2Mode], root);
|
||||||
bSend |= moderator.addJson("GPmodeOut1", GPIOout1Names[info.out1Mode], root);
|
bSend |= moderator.addJson("GPmodeOut1", GPIOout1Names[info.out1Mode], root);
|
||||||
bSend |= moderator.addJson("GPmodeOut2", GPIOout2Names[info.out2Mode], root);
|
bSend |= moderator.addJson("GPmodeOut2", GPIOout2Names[info.out2Mode], root);
|
||||||
bSend |= moderator.addJson("GPOutThr1", NVstore.getUserSettings().GPIO.thresh[0], root);
|
bSend |= moderator.addJson("GPoutThr1", NVstore.getUserSettings().GPIO.thresh[0], root);
|
||||||
bSend |= moderator.addJson("GPOutThr2", NVstore.getUserSettings().GPIO.thresh[1], root);
|
bSend |= moderator.addJson("GPoutThr2", NVstore.getUserSettings().GPIO.thresh[1], root);
|
||||||
bSend |= moderator.addJson("GPmodeAnlg", GPIOalgNames[info.algMode], root);
|
bSend |= moderator.addJson("GPmodeAnlg", GPIOalgNames[info.algMode], root);
|
||||||
bSend |= moderator.addJson("ExtThermoTmout", (uint32_t)NVstore.getUserSettings().ExtThermoTimeout, root);
|
bSend |= moderator.addJson("ExtThermoTmout", (uint32_t)NVstore.getUserSettings().ExtThermoTimeout, root);
|
||||||
const char* stop = getExternalThermostatHoldTime();
|
const char* stop = getExternalThermostatHoldTime();
|
||||||
|
@ -311,7 +323,8 @@ bool makeJSONStringMQTT(CModerator& moderator, char* opStr, int len)
|
||||||
sMQTTparams info = NVstore.getMQTTinfo();
|
sMQTTparams info = NVstore.getMQTTinfo();
|
||||||
|
|
||||||
bSend |= moderator.addJson("MEn", info.enabled, root);
|
bSend |= moderator.addJson("MEn", info.enabled, root);
|
||||||
bSend |= moderator.addJson("MOnline", isMQTTconnected(), root);
|
uint8_t online = isMQTTconnected() ? 1 : 0;
|
||||||
|
bSend |= moderator.addJson("MOnline", online, root);
|
||||||
bSend |= moderator.addJson("MHost", info.host, root);
|
bSend |= moderator.addJson("MHost", info.host, root);
|
||||||
bSend |= moderator.addJson("MPort", info.port, root);
|
bSend |= moderator.addJson("MPort", info.port, root);
|
||||||
bSend |= moderator.addJson("MUser", info.username, root);
|
bSend |= moderator.addJson("MUser", info.username, root);
|
||||||
|
@ -375,6 +388,8 @@ bool makeJSONStringIP(CModerator& moderator, char* opStr, int len)
|
||||||
bSend |= moderator.addJson("IP_STA", getWifiSTAAddrStr(), root);
|
bSend |= moderator.addJson("IP_STA", getWifiSTAAddrStr(), root);
|
||||||
bSend |= moderator.addJson("IP_STAMAC", getWifiSTAMACStr(), root);
|
bSend |= moderator.addJson("IP_STAMAC", getWifiSTAMACStr(), root);
|
||||||
bSend |= moderator.addJson("IP_STASSID", getSSID().c_str(), root);
|
bSend |= moderator.addJson("IP_STASSID", getSSID().c_str(), root);
|
||||||
|
bSend |= moderator.addJson("IP_STAGATEWAY", getWifiGatewayAddrStr(), root);
|
||||||
|
bSend |= moderator.addJson("IP_STARSSI", getWifiRSSI(), root, 10000);
|
||||||
bSend |= moderator.addJson("IP_OTA", NVstore.getUserSettings().enableOTA, root);
|
bSend |= moderator.addJson("IP_OTA", NVstore.getUserSettings().enableOTA, root);
|
||||||
bSend |= moderator.addJson("BT_MAC", getBluetoothClient().getMAC(), root);
|
bSend |= moderator.addJson("BT_MAC", getBluetoothClient().getMAC(), root);
|
||||||
|
|
||||||
|
@ -518,10 +533,12 @@ void resetAllJSONmoderators()
|
||||||
#else
|
#else
|
||||||
initJSONTimermoderator();
|
initJSONTimermoderator();
|
||||||
#endif
|
#endif
|
||||||
initJSONMQTTmoderator();
|
resetJSONMQTTmoderator(); // initJSONMQTTmoderator();
|
||||||
initJSONIPmoderator();
|
resetJSONIPmoderator(); // initJSONIPmoderator();
|
||||||
initJSONSysModerator();
|
resetJSONSysModerator(); // initJSONSysModerator();
|
||||||
GPIOmoderator.reset();
|
GPIOmoderator.reset();
|
||||||
|
// create and send a validation code (then client knows AB is capable of reboot over JSON)
|
||||||
|
doJSONreboot(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void initJSONMQTTmoderator()
|
void initJSONMQTTmoderator()
|
||||||
|
@ -575,3 +592,30 @@ void Expand(std::string& str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sendJSONtext(const char* jsonStr)
|
||||||
|
{
|
||||||
|
sendWebSocketString( jsonStr );
|
||||||
|
mqttPublishJSON(jsonStr);
|
||||||
|
getBluetoothClient().send( jsonStr );
|
||||||
|
}
|
||||||
|
|
||||||
|
void doJSONreboot(uint16_t PIN)
|
||||||
|
{
|
||||||
|
char jsonStr[20];
|
||||||
|
static uint16_t validate = 0;
|
||||||
|
if(PIN == 0) {
|
||||||
|
validate = random(1, 10000);
|
||||||
|
|
||||||
|
char jsonStr[20];
|
||||||
|
sprintf(jsonStr, "{\"Reboot\":%04d}", validate);
|
||||||
|
|
||||||
|
sendJSONtext( jsonStr );
|
||||||
|
}
|
||||||
|
else if(PIN == validate) {
|
||||||
|
strcpy(jsonStr, "{\"Reboot\":-1}");
|
||||||
|
sendJSONtext( jsonStr );
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
ESP.restart(); // reboot
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ void resetJSONIPmoderator();
|
||||||
void resetJSONSysModerator();
|
void resetJSONSysModerator();
|
||||||
void resetJSONMQTTmoderator();
|
void resetJSONMQTTmoderator();
|
||||||
void validateTimer(int ID);
|
void validateTimer(int ID);
|
||||||
|
void doJSONreboot(uint16_t code);
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
const char* createJSON(const char* name, T value)
|
const char* createJSON(const char* name, T value)
|
||||||
|
|
|
@ -51,13 +51,42 @@ public:
|
||||||
void reset(const char* name);
|
void reset(const char* name);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class sModeratorHoldoff {
|
||||||
|
unsigned long period;
|
||||||
|
unsigned long tripTime;
|
||||||
|
public:
|
||||||
|
sModeratorHoldoff() {
|
||||||
|
period = 0;
|
||||||
|
tripTime = 0;
|
||||||
|
}
|
||||||
|
sModeratorHoldoff(const sModeratorHoldoff& rhs) {
|
||||||
|
period = rhs.period;
|
||||||
|
tripTime = rhs.tripTime;
|
||||||
|
}
|
||||||
|
void set(unsigned long per) {
|
||||||
|
period = per;
|
||||||
|
reArm();
|
||||||
|
}
|
||||||
|
void reArm() {
|
||||||
|
tripTime = (millis() + period) | 1;
|
||||||
|
}
|
||||||
|
bool expired() {
|
||||||
|
long tDelta = millis() - tripTime;
|
||||||
|
return tDelta >= 0;
|
||||||
|
}
|
||||||
|
void expire() {
|
||||||
|
tripTime = millis();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class TModerator {
|
class TModerator {
|
||||||
std::map<const char*, T> Memory;
|
std::map<const char*, T> Memory;
|
||||||
|
std::map<const char*, sModeratorHoldoff> _holdoff;
|
||||||
public:
|
public:
|
||||||
bool shouldSend(const char* name, T value);
|
bool shouldSend(const char* name, T value);
|
||||||
bool addJson(const char* name, T value, JsonObject& root);
|
void setHoldoff(const char* name, unsigned long period);
|
||||||
|
bool addJson(const char* name, T value, JsonObject& root, unsigned long holdoff=0);
|
||||||
void reset();
|
void reset();
|
||||||
void reset(const char* name);
|
void reset(const char* name);
|
||||||
};
|
};
|
||||||
|
@ -69,7 +98,21 @@ bool TModerator<T>::shouldSend(const char* name, T value)
|
||||||
auto it = Memory.find(name);
|
auto it = Memory.find(name);
|
||||||
if(it != Memory.end()) {
|
if(it != Memory.end()) {
|
||||||
retval = it->second != value;
|
retval = it->second != value;
|
||||||
it->second = value;
|
if(retval) {
|
||||||
|
// check if a minimum refresh interval has been defined
|
||||||
|
auto holdoff = _holdoff.find(name);
|
||||||
|
if(holdoff != _holdoff.end()) {
|
||||||
|
if(holdoff->second.expired()) {
|
||||||
|
holdoff->second.reArm();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
retval = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(retval) {
|
||||||
|
it->second = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Memory[name] = value;
|
Memory[name] = value;
|
||||||
|
@ -78,11 +121,26 @@ bool TModerator<T>::shouldSend(const char* name, T value)
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
bool TModerator<T>::addJson(const char* name, T value, JsonObject& root)
|
void TModerator<T>::setHoldoff(const char* name, unsigned long period)
|
||||||
{
|
{
|
||||||
|
if(period) {
|
||||||
|
auto it = _holdoff.find(name);
|
||||||
|
if(it == _holdoff.end()) {
|
||||||
|
sModeratorHoldoff holdoff;
|
||||||
|
holdoff.set(period);
|
||||||
|
_holdoff[name] = holdoff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
bool TModerator<T>::addJson(const char* name, T value, JsonObject& root, unsigned long holdoff)
|
||||||
|
{
|
||||||
|
setHoldoff(name, holdoff);
|
||||||
bool retval = shouldSend(name, value);
|
bool retval = shouldSend(name, value);
|
||||||
if(retval)
|
if(retval) {
|
||||||
root.set(name, value);
|
root.set(name, value);
|
||||||
|
}
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,15 +151,26 @@ void TModerator<T>::reset()
|
||||||
for(auto it = Memory.begin(); it != Memory.end(); ++it) {
|
for(auto it = Memory.begin(); it != Memory.end(); ++it) {
|
||||||
it->second = it->second+100;
|
it->second = it->second+100;
|
||||||
}
|
}
|
||||||
|
for(auto it = _holdoff.begin(); it != _holdoff.end(); ++it) {
|
||||||
|
it->second.expire();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
void TModerator<T>::reset(const char* name)
|
void TModerator<T>::reset(const char* name)
|
||||||
{
|
{
|
||||||
auto it = Memory.find(name);
|
{
|
||||||
if(it != Memory.end()) {
|
auto it = Memory.find(name);
|
||||||
DebugPort.printf("Resetting moderator: \"%s\"", name);
|
if(it != Memory.end()) {
|
||||||
it->second = it->second+100;
|
DebugPort.printf("Resetting moderator: \"%s\"", name);
|
||||||
|
it->second = it->second+100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
auto it = _holdoff.find(name);
|
||||||
|
if(it != _holdoff.end()) {
|
||||||
|
it->second.expire();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,8 +192,8 @@ public:
|
||||||
return u32Moderator.addJson(name, value, root);
|
return u32Moderator.addJson(name, value, root);
|
||||||
};
|
};
|
||||||
// float values
|
// float values
|
||||||
bool addJson(const char* name, float value, JsonObject& root) {
|
bool addJson(const char* name, float value, JsonObject& root, unsigned long holdoff=0) {
|
||||||
return fModerator.addJson(name, value, root);
|
return fModerator.addJson(name, value, root, holdoff);
|
||||||
};
|
};
|
||||||
// uint8_t values
|
// uint8_t values
|
||||||
bool addJson(const char* name, uint8_t value, JsonObject& root) {
|
bool addJson(const char* name, uint8_t value, JsonObject& root) {
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "DebugPort.h"
|
#include "DebugPort.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#define INBOUNDS(TST, MIN, MAX) (((TST) >= (MIN)) && ((TST) <= (MAX)))
|
#define INBOUNDS(TST, MIN, MAX) (((TST) >= (MIN)) && ((TST) <= (MAX)))
|
||||||
|
|
||||||
|
@ -31,20 +32,31 @@
|
||||||
bool
|
bool
|
||||||
CESP32_NVStorage::validatedLoad(const char* key, char* val, int maxlen, const char* defVal)
|
CESP32_NVStorage::validatedLoad(const char* key, char* val, int maxlen, const char* defVal)
|
||||||
{
|
{
|
||||||
char probe[128];
|
|
||||||
bool retval = true;
|
bool retval = true;
|
||||||
strcpy(probe, "TestPresence");
|
if(!preferences.hasString(key)) {
|
||||||
int len = preferences.getString(key, probe, 127);
|
|
||||||
if(len == 0 || strcmp(probe, "TestPresence") == 0) {
|
|
||||||
preferences.putString(key, defVal);
|
preferences.putString(key, defVal);
|
||||||
DebugPort.printf("CESP32HeaterStorage::validatedLoad<char*> default installed %s=%s", key, defVal);
|
DebugPort.printf("CESP32HeaterStorage::validatedLoad<char*> default installed %s=%s\r\n", key, defVal);
|
||||||
retval = false;
|
|
||||||
}
|
}
|
||||||
preferences.getString(key, val, maxlen);
|
preferences.getString(key, val, maxlen);
|
||||||
val[maxlen] = 0; // ensure null terminated
|
val[maxlen] = 0; // ensure null terminated
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CESP32_NVStorage::validatedLoad(const char* key, uint8_t* val, int len)
|
||||||
|
{
|
||||||
|
bool retval = true;
|
||||||
|
if(!preferences.hasBytes(key)) {
|
||||||
|
DebugPort.printf("CESP32HeaterStorage::validatedLoad<uint8_t*> default installed for %s\r\n", key);
|
||||||
|
preferences.putBytes(key, val, len);
|
||||||
|
}
|
||||||
|
len = preferences.getBytes(key, val, len);
|
||||||
|
if(len == 0) {
|
||||||
|
retval = false;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CESP32_NVStorage::validatedLoad(const char* key, uint8_t& val, uint8_t defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, uint8_t min, uint8_t max, uint8_t mask)
|
CESP32_NVStorage::validatedLoad(const char* key, uint8_t& val, uint8_t defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, uint8_t min, uint8_t max, uint8_t mask)
|
||||||
{
|
{
|
||||||
|
@ -129,19 +141,42 @@ CESP32_NVStorage::validatedLoad(const char* key, uint32_t& val, uint32_t defVal,
|
||||||
bool
|
bool
|
||||||
CESP32_NVStorage::validatedLoad(const char* key, float& val, float defVal, float min, float max)
|
CESP32_NVStorage::validatedLoad(const char* key, float& val, float defVal, float min, float max)
|
||||||
{
|
{
|
||||||
val = preferences.getFloat(key, defVal);
|
// preferences.getFloat() does not do a default value for use
|
||||||
|
// use some skull duggery via unsigned long to get one installed
|
||||||
|
unsigned long* pUL = (unsigned long*)&defVal; // point to bytes of float default value as a long
|
||||||
|
unsigned long ULVal = *pUL; // copy as an unsigned long
|
||||||
|
|
||||||
|
unsigned long tmpVal = preferences.getULong(key, ULVal);
|
||||||
|
|
||||||
|
// pUL = (unsigned long*)&val; // point to val we exchange, as an usigned long
|
||||||
|
float* ptmpVal = (float*)&tmpVal; // create a pointer to flaot, that was our UL returned value
|
||||||
|
float* pVal = &val; // point to our FP exchange value
|
||||||
|
*pVal = *ptmpVal; // copy as a float
|
||||||
|
|
||||||
|
// val = preferences.getFloat(key, defVal);
|
||||||
if(!INBOUNDS(val, min, max)) {
|
if(!INBOUNDS(val, min, max)) {
|
||||||
|
|
||||||
DebugPort.printf("CESP32HeaterStorage::validatedLoad<float> invalid read %s=%f", key, val);
|
DebugPort.printf("CESP32HeaterStorage::validatedLoad<float> invalid read %s=%f", key, val);
|
||||||
DebugPort.printf(" validator(%f,%f) reset to %f\r\n", min, max, defVal);
|
DebugPort.printf(" validator(%f,%f) reset to %f\r\n", min, max, defVal);
|
||||||
|
|
||||||
val = defVal;
|
val = defVal;
|
||||||
preferences.putFloat(key, val);
|
// preferences.putFloat(key, val);
|
||||||
|
pUL = (unsigned long*)&val; // point to bytes of float default value as a long
|
||||||
|
ULVal = *pUL; // copy as an unsigned long
|
||||||
|
preferences.putULong(key, ULVal);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
CESP32_NVStorage::saveFloat(const char* key, float val)
|
||||||
|
{
|
||||||
|
unsigned long* pUL = (unsigned long*)&val; // point to bytes of float default value as a long
|
||||||
|
unsigned long ULVal = *pUL; // copy as an unsigned long
|
||||||
|
return preferences.putULong(key, ULVal);
|
||||||
|
}
|
||||||
|
|
||||||
bool finBounds(float test, float minLim, float maxLim)
|
bool finBounds(float test, float minLim, float maxLim)
|
||||||
{
|
{
|
||||||
return INBOUNDS(test, minLim, maxLim);
|
return INBOUNDS(test, minLim, maxLim);
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#ifndef __BTC_NV_CORE_H__
|
#ifndef __BTC_NV_CORE_H__
|
||||||
#define __BTC_NV_CORE_H__
|
#define __BTC_NV_CORE_H__
|
||||||
|
|
||||||
#include <Preferences.h>
|
#include "ABpreferences.h"
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,15 +46,17 @@ class CNVStorage {
|
||||||
|
|
||||||
class CESP32_NVStorage {
|
class CESP32_NVStorage {
|
||||||
protected:
|
protected:
|
||||||
Preferences preferences;
|
ABpreferences preferences;
|
||||||
protected:
|
protected:
|
||||||
bool validatedLoad(const char* key, int8_t& val, int8_t defVal, std::function<bool(int8_t, int8_t, int8_t)> validator, int8_t min, int8_t max);
|
bool validatedLoad(const char* key, int8_t& val, int8_t defVal, std::function<bool(int8_t, int8_t, int8_t)> validator, int8_t min, int8_t max);
|
||||||
bool validatedLoad(const char* key, uint8_t& val, uint8_t defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, uint8_t min, uint8_t max, uint8_t mask=0xff);
|
bool validatedLoad(const char* key, uint8_t& val, uint8_t defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, uint8_t min, uint8_t max, uint8_t mask=0xff);
|
||||||
bool validatedLoad(const char* key, uint16_t& val, uint16_t defVal, std::function<bool(uint16_t, uint16_t, uint16_t)> validator, uint16_t min, uint16_t max);
|
bool validatedLoad(const char* key, uint16_t& val, uint16_t defVal, std::function<bool(uint16_t, uint16_t, uint16_t)> validator, uint16_t min, uint16_t max);
|
||||||
bool validatedLoad(const char* key, long& val, long defVal, long min, long max);
|
bool validatedLoad(const char* key, long& val, long defVal, long min, long max);
|
||||||
bool validatedLoad(const char* key, char* val, int maxlen, const char* defVal);
|
bool validatedLoad(const char* key, char* val, int maxlen, const char* defVal); // string
|
||||||
|
bool validatedLoad(const char* key, uint8_t* val, int len); // bytes
|
||||||
bool validatedLoad(const char* key, float& val, float defVal, float min, float max);
|
bool validatedLoad(const char* key, float& val, float defVal, float min, float max);
|
||||||
bool validatedLoad(const char* key, uint32_t& val, uint32_t defVal, uint32_t min, uint32_t max);
|
bool validatedLoad(const char* key, uint32_t& val, uint32_t defVal, uint32_t min, uint32_t max);
|
||||||
|
size_t saveFloat(const char* key, float val);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include "NVStorage.h"
|
#include "NVStorage.h"
|
||||||
#include "DebugPort.h"
|
#include "DebugPort.h"
|
||||||
#include <driver/adc.h>
|
#include <driver/adc.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sNVStore::valid()
|
sNVStore::valid()
|
||||||
|
@ -131,6 +131,10 @@ CHeaterStorage::getMQTTinfo() const
|
||||||
void
|
void
|
||||||
CHeaterStorage::setMQTTinfo(const sMQTTparams& info)
|
CHeaterStorage::setMQTTinfo(const sMQTTparams& info)
|
||||||
{
|
{
|
||||||
|
if(_calValues.MQTT != info) {
|
||||||
|
requestMQTTrestart();
|
||||||
|
}
|
||||||
|
|
||||||
_calValues.MQTT = info;
|
_calValues.MQTT = info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -268,13 +272,18 @@ sHeaterTuning::load()
|
||||||
validatedLoad("tempOffset0", DS18B20probe[0].offset, 0.0, -10.0, +10.0);
|
validatedLoad("tempOffset0", DS18B20probe[0].offset, 0.0, -10.0, +10.0);
|
||||||
validatedLoad("tempOffset1", DS18B20probe[1].offset, 0.0, -10.0, +10.0);
|
validatedLoad("tempOffset1", DS18B20probe[1].offset, 0.0, -10.0, +10.0);
|
||||||
validatedLoad("tempOffset2", DS18B20probe[2].offset, 0.0, -10.0, +10.0);
|
validatedLoad("tempOffset2", DS18B20probe[2].offset, 0.0, -10.0, +10.0);
|
||||||
preferences.getBytes("probeSerial0", DS18B20probe[0].romCode.bytes, 8);
|
memset(DS18B20probe[0].romCode.bytes, 0, 8);
|
||||||
preferences.getBytes("probeSerial1", DS18B20probe[1].romCode.bytes, 8);
|
memset(DS18B20probe[1].romCode.bytes, 0, 8);
|
||||||
preferences.getBytes("probeSerial2", DS18B20probe[2].romCode.bytes, 8);
|
memset(DS18B20probe[2].romCode.bytes, 0, 8);
|
||||||
|
validatedLoad("probeSerial0", DS18B20probe[0].romCode.bytes, 8);
|
||||||
|
validatedLoad("probeSerial1", DS18B20probe[1].romCode.bytes, 8);
|
||||||
|
validatedLoad("probeSerial2", DS18B20probe[2].romCode.bytes, 8);
|
||||||
validatedLoad("tempOffsetBME", BME280probe.offset, 0.0, -10.0, +10.0);
|
validatedLoad("tempOffsetBME", BME280probe.offset, 0.0, -10.0, +10.0);
|
||||||
validatedLoad("probeBMEPrmy", BME280probe.bPrimary, 0, u8inBounds, 0, 1);
|
validatedLoad("probeBMEPrmy", BME280probe.bPrimary, 0, u8inBounds, 0, 1);
|
||||||
preferences.end();
|
preferences.end();
|
||||||
|
|
||||||
|
// save();
|
||||||
|
|
||||||
// for(int i=0; i<3; i++) {
|
// for(int i=0; i<3; i++) {
|
||||||
// DebugPort.printf("Rd Probe[%d] %02X:%02X:%02X:%02X:%02X:%02X\r\n",
|
// DebugPort.printf("Rd Probe[%d] %02X:%02X:%02X:%02X:%02X:%02X\r\n",
|
||||||
// i,
|
// i,
|
||||||
|
@ -291,6 +300,20 @@ sHeaterTuning::load()
|
||||||
void
|
void
|
||||||
sHeaterTuning::save()
|
sHeaterTuning::save()
|
||||||
{
|
{
|
||||||
|
sHeaterTuning currentSettings;
|
||||||
|
currentSettings.load();
|
||||||
|
|
||||||
|
bool requestHeaterUpdate = false;
|
||||||
|
requestHeaterUpdate |= currentSettings.sysVoltage != this->sysVoltage;
|
||||||
|
requestHeaterUpdate |= currentSettings.fanSensor != this->fanSensor;
|
||||||
|
requestHeaterUpdate |= currentSettings.glowDrive != this->glowDrive;
|
||||||
|
requestHeaterUpdate |= currentSettings.Pmin != this->Pmin;
|
||||||
|
requestHeaterUpdate |= currentSettings.Pmax != this->Pmax;
|
||||||
|
requestHeaterUpdate |= currentSettings.Fmin != this->Fmin;
|
||||||
|
requestHeaterUpdate |= currentSettings.Fmax != this->Fmax;
|
||||||
|
if(requestHeaterUpdate) {
|
||||||
|
reqHeaterCalUpdate();
|
||||||
|
}
|
||||||
// section for heater calibration params
|
// section for heater calibration params
|
||||||
// **** MAX LENGTH is 15 for names ****
|
// **** MAX LENGTH is 15 for names ****
|
||||||
preferences.begin("Calibration", false);
|
preferences.begin("Calibration", false);
|
||||||
|
@ -302,15 +325,55 @@ sHeaterTuning::save()
|
||||||
preferences.putUChar("fanSensor", fanSensor);
|
preferences.putUChar("fanSensor", fanSensor);
|
||||||
preferences.putUChar("glowDrive", glowDrive);
|
preferences.putUChar("glowDrive", glowDrive);
|
||||||
preferences.putUChar("lowVolts", lowVolts);
|
preferences.putUChar("lowVolts", lowVolts);
|
||||||
preferences.putFloat("pumpCal", pumpCal);
|
saveFloat("pumpCal", pumpCal);
|
||||||
preferences.putFloat("tempOffset0", DS18B20probe[0].offset);
|
saveFloat("tempOffset0", DS18B20probe[0].offset);
|
||||||
preferences.putFloat("tempOffset1", DS18B20probe[1].offset);
|
saveFloat("tempOffset1", DS18B20probe[1].offset);
|
||||||
preferences.putFloat("tempOffset2", DS18B20probe[2].offset);
|
saveFloat("tempOffset2", DS18B20probe[2].offset);
|
||||||
|
// preferences.putFloat("pumpCal", pumpCal);
|
||||||
|
// preferences.putFloat("tempOffset0", DS18B20probe[0].offset);
|
||||||
|
// preferences.putFloat("tempOffset1", DS18B20probe[1].offset);
|
||||||
|
// preferences.putFloat("tempOffset2", DS18B20probe[2].offset);
|
||||||
|
|
||||||
|
/*// START TESTO
|
||||||
|
for(int i=0; i<8; i++)
|
||||||
|
DS18B20probe[0].romCode.bytes[i] = i;
|
||||||
|
// END TESTO*/
|
||||||
|
|
||||||
preferences.putBytes("probeSerial0", DS18B20probe[0].romCode.bytes, 8);
|
preferences.putBytes("probeSerial0", DS18B20probe[0].romCode.bytes, 8);
|
||||||
preferences.putBytes("probeSerial1", DS18B20probe[1].romCode.bytes, 8);
|
preferences.putBytes("probeSerial1", DS18B20probe[1].romCode.bytes, 8);
|
||||||
preferences.putBytes("probeSerial2", DS18B20probe[2].romCode.bytes, 8);
|
preferences.putBytes("probeSerial2", DS18B20probe[2].romCode.bytes, 8);
|
||||||
preferences.putFloat("tempOffsetBME", BME280probe.offset);
|
// preferences.putFloat("tempOffsetBME", BME280probe.offset);
|
||||||
|
saveFloat("tempOffsetBME", BME280probe.offset);
|
||||||
preferences.putUChar("probeBMEPrmy", BME280probe.bPrimary);
|
preferences.putUChar("probeBMEPrmy", BME280probe.bPrimary);
|
||||||
|
|
||||||
|
|
||||||
|
/*// START TESTO
|
||||||
|
preferences.getBytes("probeSerial0", DS18B20probe[0].romCode.bytes, 8);
|
||||||
|
DebugPort.printf("getBytes %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
DS18B20probe[0].romCode.bytes[0],
|
||||||
|
DS18B20probe[0].romCode.bytes[1],
|
||||||
|
DS18B20probe[0].romCode.bytes[2],
|
||||||
|
DS18B20probe[0].romCode.bytes[3],
|
||||||
|
DS18B20probe[0].romCode.bytes[4],
|
||||||
|
DS18B20probe[0].romCode.bytes[5],
|
||||||
|
DS18B20probe[0].romCode.bytes[6],
|
||||||
|
DS18B20probe[0].romCode.bytes[7]
|
||||||
|
);
|
||||||
|
|
||||||
|
uint64_t tVal = preferences.getULong64("probeSerial0", 0xffffffffffffffff);
|
||||||
|
unsigned char* pTst = (unsigned char*)&tVal;
|
||||||
|
DebugPort.printf("getULong %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X",
|
||||||
|
pTst[0],
|
||||||
|
pTst[1],
|
||||||
|
pTst[2],
|
||||||
|
pTst[3],
|
||||||
|
pTst[4],
|
||||||
|
pTst[5],
|
||||||
|
pTst[6],
|
||||||
|
pTst[7]
|
||||||
|
);
|
||||||
|
// END TESTO*/
|
||||||
|
|
||||||
preferences.end();
|
preferences.end();
|
||||||
|
|
||||||
// for(int i=0; i<3; i++) {
|
// for(int i=0; i<3; i++) {
|
||||||
|
@ -417,8 +480,8 @@ sUserSettings::load()
|
||||||
preferences.putUChar("GPIOout1Mode", GPIO.out1Mode); // set new
|
preferences.putUChar("GPIOout1Mode", GPIO.out1Mode); // set new
|
||||||
preferences.putUChar("GPIOout2Mode", GPIO.out2Mode); // set new
|
preferences.putUChar("GPIOout2Mode", GPIO.out2Mode); // set new
|
||||||
}
|
}
|
||||||
validatedLoad("GPIOout1Mode", tVal, 0, u8inBounds, 0, 3); GPIO.out1Mode = (CGPIOout1::Modes)tVal;
|
validatedLoad("GPIOout1Mode", tVal, 0, u8inBounds, 0, 4); GPIO.out1Mode = (CGPIOout1::Modes)tVal;
|
||||||
validatedLoad("GPIOout2Mode", tVal, 0, u8inBounds, 0, 2); GPIO.out2Mode = (CGPIOout2::Modes)tVal;
|
validatedLoad("GPIOout2Mode", tVal, 0, u8inBounds, 0, 3); GPIO.out2Mode = (CGPIOout2::Modes)tVal;
|
||||||
validatedLoad("GPIOout1Thresh", GPIO.thresh[0], 0, s8inBounds, -50, 50);
|
validatedLoad("GPIOout1Thresh", GPIO.thresh[0], 0, s8inBounds, -50, 50);
|
||||||
validatedLoad("GPIOout2Thresh", GPIO.thresh[1], 0, s8inBounds, -50, 50);
|
validatedLoad("GPIOout2Thresh", GPIO.thresh[1], 0, s8inBounds, -50, 50);
|
||||||
validatedLoad("GPIOalgMode", tVal, 0, u8inBounds, 0, 2); GPIO.algMode = (CGPIOalg::Modes)tVal;
|
validatedLoad("GPIOalgMode", tVal, 0, u8inBounds, 0, 2); GPIO.algMode = (CGPIOalg::Modes)tVal;
|
||||||
|
@ -447,7 +510,8 @@ sUserSettings::save()
|
||||||
preferences.putUChar("thermostat", useThermostat);
|
preferences.putUChar("thermostat", useThermostat);
|
||||||
preferences.putUChar("degF", degF);
|
preferences.putUChar("degF", degF);
|
||||||
preferences.putUChar("thermoMethod", ThermostatMethod);
|
preferences.putUChar("thermoMethod", ThermostatMethod);
|
||||||
preferences.putFloat("thermoWindow", ThermostatWindow);
|
// preferences.putFloat("thermoWindow", ThermostatWindow);
|
||||||
|
saveFloat("thermoWindow", ThermostatWindow);
|
||||||
preferences.putUChar("frostOn", FrostOn);
|
preferences.putUChar("frostOn", FrostOn);
|
||||||
preferences.putUChar("frostRise", FrostRise);
|
preferences.putUChar("frostRise", FrostRise);
|
||||||
// preferences.putUChar("enableWifi", enableWifi);
|
// preferences.putUChar("enableWifi", enableWifi);
|
||||||
|
@ -484,9 +548,9 @@ sMQTTparams::load()
|
||||||
validatedLoad("enabled", enabled, 0, u8inBounds, 0, 1);
|
validatedLoad("enabled", enabled, 0, u8inBounds, 0, 1);
|
||||||
validatedLoad("port", port, 1883, u16inBounds, 0, 0xffff);
|
validatedLoad("port", port, 1883, u16inBounds, 0, 0xffff);
|
||||||
validatedLoad("qos", qos, 0, u8inBounds, 0, 2);
|
validatedLoad("qos", qos, 0, u8inBounds, 0, 2);
|
||||||
validatedLoad("host", host, 127, "");
|
validatedLoad("host", host, 127, "broker");
|
||||||
validatedLoad("username", username, 31, "");
|
validatedLoad("username", username, 31, "username");
|
||||||
validatedLoad("password", password, 31, "");
|
validatedLoad("password", password, 31, "password");
|
||||||
validatedLoad("topic", topicPrefix, 31, "Afterburner");
|
validatedLoad("topic", topicPrefix, 31, "Afterburner");
|
||||||
preferences.end();
|
preferences.end();
|
||||||
}
|
}
|
||||||
|
@ -572,4 +636,4 @@ sHourMeter::load()
|
||||||
validatedLoad("GlowTime", GlowTime, 0, 0, 0xffffffffL);
|
validatedLoad("GlowTime", GlowTime, 0, 0, 0xffffffffL);
|
||||||
preferences.end();
|
preferences.end();
|
||||||
DebugPort.printf("Hourmeter NV read: Run=%d, Glow=%d\r\n", RunTime, GlowTime);
|
DebugPort.printf("Hourmeter NV read: Run=%d, Glow=%d\r\n", RunTime, GlowTime);
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,6 +272,16 @@ struct sMQTTparams : public CESP32_NVStorage {
|
||||||
topicPrefix[31] = 0;
|
topicPrefix[31] = 0;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
bool operator!=(const sMQTTparams& rhs) {
|
||||||
|
bool retval = false;
|
||||||
|
retval |= enabled != rhs.enabled;
|
||||||
|
retval |= port != rhs.port;
|
||||||
|
retval |= qos != rhs.qos;
|
||||||
|
retval |= strcmp(host, rhs.host) != 0;
|
||||||
|
retval |= strcmp(password, rhs.password) != 0;
|
||||||
|
retval |= strcmp(topicPrefix, rhs.topicPrefix) != 0;
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
void load();
|
void load();
|
||||||
void save();
|
void save();
|
||||||
bool valid();
|
bool valid();
|
||||||
|
|
|
@ -432,7 +432,7 @@ CBME280Sensor::getTemperature(float& tempReading, bool filtered)
|
||||||
}
|
}
|
||||||
|
|
||||||
CSensor::getTemperature(tempReading, filtered);
|
CSensor::getTemperature(tempReading, filtered);
|
||||||
tempReading += NVstore.getHeaterTuning().BME280probe.offset;;
|
// tempReading += NVstore.getHeaterTuning().BME280probe.offset;;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -559,16 +559,26 @@ CTempSense::setOffset(int usrIdx, float offset)
|
||||||
bool
|
bool
|
||||||
CTempSense::getTemperature(int usrIdx, float& temperature, bool filtered)
|
CTempSense::getTemperature(int usrIdx, float& temperature, bool filtered)
|
||||||
{
|
{
|
||||||
|
bool bRetVal = false;
|
||||||
|
float offset = 0;
|
||||||
switch(getSensorType(usrIdx)) {
|
switch(getSensorType(usrIdx)) {
|
||||||
case 0:
|
case 0:
|
||||||
return BME280.getTemperature(temperature, filtered);
|
bRetVal = BME280.getTemperature(temperature, filtered);
|
||||||
|
offset = getOffset(usrIdx);
|
||||||
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
return DS18B20.getTemperature(usrIdx, temperature, filtered);
|
bRetVal = DS18B20.getTemperature(usrIdx, temperature, filtered);
|
||||||
|
offset = getOffset(usrIdx);
|
||||||
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
return DS18B20.getTemperature(usrIdx-1, temperature, filtered);
|
bRetVal = DS18B20.getTemperature(usrIdx-1, temperature, filtered);
|
||||||
default:
|
offset = getOffset(usrIdx-1);
|
||||||
return false;
|
break;
|
||||||
}
|
}
|
||||||
|
if(bRetVal) {
|
||||||
|
temperature += offset;
|
||||||
|
}
|
||||||
|
return bRetVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -422,10 +422,22 @@ void DecodeCmd(const char* cmd, String& payload)
|
||||||
else if(strcmp("FrostRise", cmd) == 0) {
|
else if(strcmp("FrostRise", cmd) == 0) {
|
||||||
sUserSettings us = NVstore.getUserSettings();
|
sUserSettings us = NVstore.getUserSettings();
|
||||||
us.FrostRise = payload.toInt();
|
us.FrostRise = payload.toInt();
|
||||||
if(INBOUNDS(us.FrostRise, 1, 30)) {
|
if(INBOUNDS(us.FrostRise, 0, 30)) {
|
||||||
NVstore.setUserSettings(us);
|
NVstore.setUserSettings(us);
|
||||||
NVstore.save();
|
NVstore.save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(strcmp("HumidStart", cmd) == 0) {
|
||||||
|
sUserSettings us = NVstore.getUserSettings();
|
||||||
|
us.humidityStart = payload.toInt();
|
||||||
|
if((us.humidityStart == 0) || INBOUNDS(us.humidityStart, 50, 100)) {
|
||||||
|
NVstore.setUserSettings(us);
|
||||||
|
NVstore.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(strcmp("Reboot", cmd) == 0) {
|
||||||
|
int16_t code = payload.toInt();
|
||||||
|
doJSONreboot(code);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,7 @@ extern int sysUptime();
|
||||||
extern void doJSONwatchdog(int topup);
|
extern void doJSONwatchdog(int topup);
|
||||||
extern void reloadScreens();
|
extern void reloadScreens();
|
||||||
extern CTempSense& getTempSensor() ;
|
extern CTempSense& getTempSensor() ;
|
||||||
|
extern void reqHeaterCalUpdate();
|
||||||
|
|
||||||
|
|
||||||
void setSSID(const char* name);
|
void setSSID(const char* name);
|
||||||
|
@ -99,5 +100,6 @@ extern void ShowOTAScreen(int percent=0, eOTAmodes updateType=eOTAnormal);
|
||||||
|
|
||||||
extern void updateMQTT();
|
extern void updateMQTT();
|
||||||
extern void refreshMQTT();
|
extern void refreshMQTT();
|
||||||
|
extern void requestMQTTrestart();
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -51,7 +51,8 @@ extern void DecodeCmd(const char* cmd, String& payload);
|
||||||
AsyncMqttClient MQTTclient;
|
AsyncMqttClient MQTTclient;
|
||||||
char topicnameJSONin[128];
|
char topicnameJSONin[128];
|
||||||
char topicnameCmd[128];
|
char topicnameCmd[128];
|
||||||
CModerator MQTTmoderator;
|
CModerator MQTTmoderator; // for basic MQTT interface
|
||||||
|
unsigned long MQTTrestart = 0;
|
||||||
|
|
||||||
void subscribe(const char* topic);
|
void subscribe(const char* topic);
|
||||||
|
|
||||||
|
@ -100,14 +101,10 @@ void onMqttConnect(bool sessionPresent)
|
||||||
sprintf(statusTopic, "%s/status", NVstore.getMQTTinfo().topicPrefix);
|
sprintf(statusTopic, "%s/status", NVstore.getMQTTinfo().topicPrefix);
|
||||||
sprintf(topicnameJSONin, "%s/JSONin", NVstore.getMQTTinfo().topicPrefix);
|
sprintf(topicnameJSONin, "%s/JSONin", NVstore.getMQTTinfo().topicPrefix);
|
||||||
sprintf(topicnameCmd, "%s/cmd/#", NVstore.getMQTTinfo().topicPrefix);
|
sprintf(topicnameCmd, "%s/cmd/#", NVstore.getMQTTinfo().topicPrefix);
|
||||||
// subscribe to that topic
|
|
||||||
// DebugPort.printf("MQTT: Subscribing to \"%s\"\r\n", topicnameJSONin);
|
subscribe(topicnameJSONin); // subscribe to the JSONin topic
|
||||||
// MQTTclient.subscribe(topicnameJSONin, NVstore.getMQTTinfo().qos);
|
subscribe(topicnameCmd); // subscribe to the basic command topic
|
||||||
// MQTTclient.subscribe(topicnameCmd, NVstore.getMQTTinfo().qos);
|
subscribe(statusTopic); // subscribe to the status topic
|
||||||
// MQTTclient.subscribe(statusTopic, NVstore.getMQTTinfo().qos);
|
|
||||||
subscribe(topicnameJSONin);
|
|
||||||
subscribe(topicnameCmd);
|
|
||||||
subscribe(statusTopic);
|
|
||||||
|
|
||||||
// spit out an "I'm here" message
|
// spit out an "I'm here" message
|
||||||
MQTTclient.publish(statusTopic, NVstore.getMQTTinfo().qos, true, "online");
|
MQTTclient.publish(statusTopic, NVstore.getMQTTinfo().qos, true, "online");
|
||||||
|
@ -152,7 +149,7 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
|
||||||
}
|
}
|
||||||
else if(strcmp(topic, statusTopic) == 0) { // check if incoming topic is our general status
|
else if(strcmp(topic, statusTopic) == 0) { // check if incoming topic is our general status
|
||||||
if(strcmp(szPayload, "1") == 0) {
|
if(strcmp(szPayload, "1") == 0) {
|
||||||
MQTTmoderator.reset();
|
// MQTTmoderator.reset();
|
||||||
MQTTclient.publish(statusTopic, NVstore.getMQTTinfo().qos, true, "online");
|
MQTTclient.publish(statusTopic, NVstore.getMQTTinfo().qos, true, "online");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -199,9 +196,11 @@ bool mqttInit()
|
||||||
#else
|
#else
|
||||||
mqttReconnect = 0;
|
mqttReconnect = 0;
|
||||||
#endif
|
#endif
|
||||||
|
MQTTrestart = 0;
|
||||||
|
|
||||||
memset(topicnameJSONin, 0, sizeof(topicnameJSONin));
|
memset(topicnameJSONin, 0, sizeof(topicnameJSONin));
|
||||||
|
|
||||||
|
DebugPort.println("MQTT: Initialising...");
|
||||||
MQTTclient.disconnect(true);
|
MQTTclient.disconnect(true);
|
||||||
long escape = millis() + 10000;
|
long escape = millis() + 10000;
|
||||||
while(MQTTclient.connected()) {
|
while(MQTTclient.connected()) {
|
||||||
|
@ -274,6 +273,16 @@ void kickMQTT() {
|
||||||
|
|
||||||
void doMQTT()
|
void doMQTT()
|
||||||
{
|
{
|
||||||
|
// manage restart of MQTT
|
||||||
|
if(MQTTrestart) {
|
||||||
|
long tDelta = millis() - MQTTrestart;
|
||||||
|
if(tDelta > 0) {
|
||||||
|
MQTTrestart = 0;
|
||||||
|
mqttInit();
|
||||||
|
// connectToMqtt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// most MQTT is managed via callbacks!!!
|
// most MQTT is managed via callbacks!!!
|
||||||
if(NVstore.getMQTTinfo().enabled) {
|
if(NVstore.getMQTTinfo().enabled) {
|
||||||
#ifndef USE_RTOS_MQTTTIMER
|
#ifndef USE_RTOS_MQTTTIMER
|
||||||
|
@ -411,4 +420,9 @@ void subscribe(const char* topic)
|
||||||
MQTTclient.subscribe(topic, NVstore.getMQTTinfo().qos);
|
MQTTclient.subscribe(topic, NVstore.getMQTTinfo().qos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void requestMQTTrestart()
|
||||||
|
{
|
||||||
|
MQTTrestart = (millis() + 1000) | 1;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -162,6 +162,7 @@ String getContentType(String filename) { // convert the file extension to the MI
|
||||||
bool handleFileRead(String path) { // send the right file to the client (if it exists)
|
bool handleFileRead(String path) { // send the right file to the client (if it exists)
|
||||||
DebugPort.println("handleFileRead: " + path);
|
DebugPort.println("handleFileRead: " + path);
|
||||||
if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file
|
if (path.endsWith("/")) path += "index.html"; // If a folder is requested, send the index file
|
||||||
|
path.replace("%20", " "); // convert HTML spaces to normal spaces
|
||||||
String contentType = getContentType(path); // Get the MIME type
|
String contentType = getContentType(path); // Get the MIME type
|
||||||
String pathWithGz = path + ".gz";
|
String pathWithGz = path + ".gz";
|
||||||
if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { // If the file exists as a compressed archive, or normal
|
if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)) { // If the file exists as a compressed archive, or normal
|
||||||
|
@ -622,8 +623,10 @@ void listSPIFFS(const char * dirname, uint8_t levels, String& HTMLreport, int wi
|
||||||
String ers;
|
String ers;
|
||||||
String rename;
|
String rename;
|
||||||
if(withHTMLanchors == 2) {
|
if(withHTMLanchors == 2) {
|
||||||
rename = "<button class='rename' onClick=onRename('" + fn + "')>Rename</button>";
|
String htmlNm = fn;
|
||||||
ers = "<input class='del' type='button' value='X' onClick=onErase('" + fn + "')>";
|
htmlNm.replace(" ", "%20");
|
||||||
|
rename = "<button class='rename' onClick=onRename('" + htmlNm + "')>Rename</button>";
|
||||||
|
ers = "<input class='del' type='button' value='X' onClick=onErase('" + htmlNm + "')>";
|
||||||
}
|
}
|
||||||
if(withHTMLanchors) {
|
if(withHTMLanchors) {
|
||||||
String fn2;
|
String fn2;
|
||||||
|
@ -638,6 +641,7 @@ void listSPIFFS(const char * dirname, uint8_t levels, String& HTMLreport, int wi
|
||||||
fn2.remove(fn2.length()-3, 3); // strip trailing ".gz"
|
fn2.remove(fn2.length()-3, 3); // strip trailing ".gz"
|
||||||
}
|
}
|
||||||
if(fn2.length() != 0) {
|
if(fn2.length() != 0) {
|
||||||
|
fn2.replace(" ", "%20");
|
||||||
// create hyperlink if web page file
|
// create hyperlink if web page file
|
||||||
fn = "<a href=\"" + fn2 + "\">" + file.name() + "</a>";
|
fn = "<a href=\"" + fn2 + "\">" + file.name() + "</a>";
|
||||||
}
|
}
|
||||||
|
@ -678,6 +682,7 @@ void addTableData(String& HTML, String dta)
|
||||||
void onErase()
|
void onErase()
|
||||||
{
|
{
|
||||||
String filename = server.arg("filename"); // get request argument value by name
|
String filename = server.arg("filename"); // get request argument value by name
|
||||||
|
filename.replace("%20", " "); // convert HTML spaces to real spaces
|
||||||
|
|
||||||
if(filename.length() != 0) {
|
if(filename.length() != 0) {
|
||||||
DebugPort.printf("onErase: %s ", filename.c_str());
|
DebugPort.printf("onErase: %s ", filename.c_str());
|
||||||
|
@ -986,6 +991,8 @@ void onRename()
|
||||||
DebugPort.println("WEB: POST /reboot");
|
DebugPort.println("WEB: POST /reboot");
|
||||||
String oldname = server.arg("oldname"); // get request argument value by name
|
String oldname = server.arg("oldname"); // get request argument value by name
|
||||||
String newname = server.arg("newname"); // get request argument value by name
|
String newname = server.arg("newname"); // get request argument value by name
|
||||||
|
newname.replace("%20", " "); // convert html spaces to real spaces
|
||||||
|
oldname.replace("%20", " ");
|
||||||
if(oldname != "" && newname != "") {
|
if(oldname != "" && newname != "") {
|
||||||
DebugPort.printf("Renaming %s to %s\r\n", oldname.c_str(), newname.c_str());
|
DebugPort.printf("Renaming %s to %s\r\n", oldname.c_str(), newname.c_str());
|
||||||
SPIFFS.rename(oldname.c_str(), newname.c_str());
|
SPIFFS.rename(oldname.c_str(), newname.c_str());
|
||||||
|
|
|
@ -279,6 +279,38 @@ const char* getWifiSTAAddrStr()
|
||||||
else
|
else
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char* getWifiGatewayAddrStr()
|
||||||
|
{
|
||||||
|
if(NVstore.getUserSettings().wifiMode) {
|
||||||
|
IPAddress IPaddr = WiFi.gatewayIP(); // use stepping stone - function returns an automatic stack var - LAME!
|
||||||
|
static char GWIPaddr[16];
|
||||||
|
sprintf(GWIPaddr, "%d.%d.%d.%d", IPaddr[0], IPaddr[1], IPaddr[2], IPaddr[3]);
|
||||||
|
return GWIPaddr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t getWifiRSSI()
|
||||||
|
{
|
||||||
|
if(NVstore.getUserSettings().wifiMode) {
|
||||||
|
static unsigned long updateRSSI = millis() + 2500;
|
||||||
|
static int8_t RSSI = 0;
|
||||||
|
long tDelta = millis() - updateRSSI;
|
||||||
|
if(tDelta > 0) {
|
||||||
|
updateRSSI = millis() + 2500;
|
||||||
|
RSSI = WiFi.RSSI();
|
||||||
|
}
|
||||||
|
return RSSI;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char* getWifiAPMACStr()
|
const char* getWifiAPMACStr()
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,8 +28,10 @@ void doWiFiManager();
|
||||||
bool initWifi(const char *failedssid, const char *failedpassword);
|
bool initWifi(const char *failedssid, const char *failedpassword);
|
||||||
const char* getWifiAPAddrStr();
|
const char* getWifiAPAddrStr();
|
||||||
const char* getWifiSTAAddrStr();
|
const char* getWifiSTAAddrStr();
|
||||||
|
const char* getWifiGatewayAddrStr();
|
||||||
const char* getWifiAPMACStr();
|
const char* getWifiAPMACStr();
|
||||||
const char* getWifiSTAMACStr();
|
const char* getWifiSTAMACStr();
|
||||||
|
int8_t getWifiRSSI();
|
||||||
String getSSID();
|
String getSSID();
|
||||||
|
|
||||||
bool isWifiConnected();
|
bool isWifiConnected();
|
||||||
|
|
|
@ -63,6 +63,8 @@ sBrowserUpload::begin(String& filename, int filesize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
SrcFile.name.replace("%20", " "); // convert HTML spaces to real spaces
|
||||||
|
|
||||||
// SPIFFS UPLOAD START
|
// SPIFFS UPLOAD START
|
||||||
DebugPort.printf("Starting SPIFFS upload: %s\r\n", SrcFile.name.c_str());
|
DebugPort.printf("Starting SPIFFS upload: %s\r\n", SrcFile.name.c_str());
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue