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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Modifications performed:
|
||||
Pullup on Debug Rx line
|
||||
Swapped GPIO In#1 with Analogue input
|
||||
5V via blocking diode to GPIO port
|
||||
|
||||
OLED intact
|
||||
Latest firmware uploaded
|
||||
SPIFFS uploaded
|
||||
Check temperature sensor
|
||||
Keypad functions OK
|
||||
Indicator LEDs function
|
||||
Web server functions and serves heater control page
|
||||
Bluetooth pairs and streams SPP data
|
||||
Set time
|
||||
Install battery
|
||||
|
||||
GPIO units only
|
||||
~~~~~~~~~~~~~~~
|
||||
Check pressure sensor
|
||||
GPIO functions:
|
||||
Input x2
|
||||
Output x2
|
||||
|
|
|
@ -97,7 +97,7 @@
|
|||
#include "Protocol/Protocol.h"
|
||||
#include "Protocol/TxManage.h"
|
||||
#include "Protocol/SmartError.h"
|
||||
#include "Utility/helpers.h"
|
||||
#include "Utility/helpers.h"
|
||||
#include "Utility/NVStorage.h"
|
||||
#include "Utility/DebugPort.h"
|
||||
#include "Utility/macros.h"
|
||||
|
@ -124,10 +124,10 @@
|
|||
|
||||
#define RX_DATA_TIMOUT 50
|
||||
|
||||
const int FirmwareRevision = 31;
|
||||
const int FirmwareSubRevision = 9;
|
||||
const int FirmwareMinorRevision = 1;
|
||||
const char* FirmwareDate = "15 Jan 2020";
|
||||
const int FirmwareRevision = 32;
|
||||
const int FirmwareSubRevision = 0;
|
||||
const int FirmwareMinorRevision = 0;
|
||||
const char* FirmwareDate = "21 Mar 2020";
|
||||
|
||||
|
||||
#ifdef ESP32
|
||||
|
@ -367,9 +367,6 @@ void setup() {
|
|||
digitalWrite(GPIOout2_pin, LOW);
|
||||
#endif
|
||||
|
||||
nvs_stats_t nvs_stats;
|
||||
nvs_get_stats(NULL, &nvs_stats);
|
||||
|
||||
// initialise TelnetSpy (port 23) as well as Serial to 115200
|
||||
// Serial is the usual USB connection to a PC
|
||||
// DO THIS BEFORE WE TRY AND SEND DEBUG INFO!
|
||||
|
@ -383,6 +380,11 @@ void setup() {
|
|||
DebugPort.begin(115200);
|
||||
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("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();
|
||||
|
||||
// pinMode(0, OUTPUT);
|
||||
// digitalWrite(0, LOW);
|
||||
|
||||
#if USE_SW_WATCHDOG == 1 && USE_JTAG == 0
|
||||
// create a high priority FreeRTOS task as a watchdog monitor
|
||||
TaskHandle_t wdTask;
|
||||
|
@ -984,15 +989,18 @@ void manageFrostMode()
|
|||
if(heaterState == 0) {
|
||||
RTC_Store.setFrostOn(true);
|
||||
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();
|
||||
}
|
||||
}
|
||||
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()) {
|
||||
DebugPort.printf("FROST MODE: Stopping heater, > %d`C\r\n", engage+rise);
|
||||
heaterOff();
|
||||
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)
|
||||
{
|
||||
static long lasttime = millis();
|
||||
static float tempsave = 0;
|
||||
long tDelta;
|
||||
// NVstore always holds primary sensor as index 0
|
||||
float retval;
|
||||
TempSensor.getTemperature(source, 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)
|
||||
|
@ -2031,4 +2020,7 @@ CTempSense& getTempSensor()
|
|||
return TempSensor;
|
||||
}
|
||||
|
||||
|
||||
void reqHeaterCalUpdate()
|
||||
{
|
||||
TxManage.queueSysUpdate();
|
||||
}
|
||||
|
|
|
@ -135,6 +135,10 @@ CGPIOInfoScreen::animate()
|
|||
_drawBitmap(99, 15, threshIconInfo);
|
||||
_drawBitmap(110, 13, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
||||
break;
|
||||
case CGPIOout1::HtrActive:
|
||||
_drawBitmap(99, 15, onOffIconInfo);
|
||||
_drawBitmap(110, 13, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
#if USE_JTAG == 0
|
||||
|
@ -151,6 +155,9 @@ CGPIOInfoScreen::animate()
|
|||
_drawBitmap(99, 27, threshIconInfo);
|
||||
_drawBitmap(110, 26, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
||||
break;
|
||||
case CGPIOout2::HtrActive:
|
||||
_drawBitmap(99, 27, onOffIconInfo);
|
||||
_drawBitmap(110, 26, bulbmode ? BulbOnIconInfo : BulbOffIconInfo);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ CGPIOSetupScreen::show()
|
|||
const char* msgText = NULL;
|
||||
switch(_GPIOparams.out1Mode) {
|
||||
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::Thresh:
|
||||
if(_rowSel == 6) {
|
||||
|
@ -151,6 +151,7 @@ CGPIOSetupScreen::show()
|
|||
_printMenuText(Column2, Line3, msg, _rowSel == 8);
|
||||
}
|
||||
break;
|
||||
case CGPIOout1::HtrActive: msgText ="OnSts"; break;
|
||||
}
|
||||
if(msgText)
|
||||
_printMenuText(Column2, Line3, msgText, _rowSel == 6);
|
||||
|
@ -173,6 +174,7 @@ CGPIOSetupScreen::show()
|
|||
_printMenuText(Column2, Line2, msg, _rowSel == 7);
|
||||
}
|
||||
break;
|
||||
case CGPIOout2::HtrActive: msgText ="OnSts"; break;
|
||||
}
|
||||
if(msgText)
|
||||
_printMenuText(Column2, Line2, msgText, _rowSel == 5);
|
||||
|
@ -256,6 +258,7 @@ CGPIOSetupScreen::animate()
|
|||
else
|
||||
pMsg = " Output 2: Active if under temperature. Hold LEFT to set under. Hold RIGHT to set over. ";
|
||||
break;
|
||||
case CGPIOout2::HtrActive: pMsg = " Output 2: Active if heater is running. "; break;
|
||||
}
|
||||
if(pMsg)
|
||||
_scrollMessage(56, pMsg, _scrollChar);
|
||||
|
@ -272,6 +275,7 @@ CGPIOSetupScreen::animate()
|
|||
else
|
||||
pMsg = " Output 1: Active if under temperature. Hold LEFT to set under. Hold RIGHT to set over. ";
|
||||
break;
|
||||
case CGPIOout1::HtrActive: pMsg = " Output 1: Active if heater is running. "; break;
|
||||
}
|
||||
if(pMsg)
|
||||
_scrollMessage(56, pMsg, _scrollChar);
|
||||
|
@ -483,13 +487,13 @@ CGPIOSetupScreen::_adjust(int dir)
|
|||
case 5: // outputs mode
|
||||
tVal = _GPIOparams.out2Mode;
|
||||
tVal += dir;
|
||||
WRAPLIMITS(tVal, 0, 2);
|
||||
WRAPLIMITS(tVal, 0, 3);
|
||||
_GPIOparams.out2Mode = (CGPIOout2::Modes)tVal;
|
||||
break;
|
||||
case 6: // outputs mode
|
||||
tVal = _GPIOparams.out1Mode;
|
||||
tVal += dir;
|
||||
WRAPLIMITS(tVal, 0, 3);
|
||||
WRAPLIMITS(tVal, 0, 4);
|
||||
_GPIOparams.out1Mode = (CGPIOout1::Modes)tVal;
|
||||
break;
|
||||
case 7:
|
||||
|
|
|
@ -229,6 +229,15 @@ CScreenHeader::showWifiIcon()
|
|||
{
|
||||
if(isWifiConnected() || isWifiAP()) { // STA or AP mode active
|
||||
_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
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "BasicScreen.h"
|
||||
#include "PrimingScreen.h"
|
||||
#include "WiFiScreen.h"
|
||||
#include "WiFiSTAScreen.h"
|
||||
#include "FuelMixtureScreen.h"
|
||||
#include "SetClockScreen.h"
|
||||
#include "SetTimerScreen.h"
|
||||
|
@ -492,6 +493,7 @@ CScreenManager::_loadScreens()
|
|||
menuloop.push_back(new CHourMeterScreen(*_pDisplay, *this)); // Hour Meter screen
|
||||
}
|
||||
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 CBTScreen(*_pDisplay, *this));
|
||||
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);
|
||||
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
|
|
@ -159,5 +159,6 @@ extern const BITMAP_INFO algIconInfo;
|
|||
|
||||
extern const BITMAP_INFO passwordIconInfo;
|
||||
extern const BITMAP_INFO threshIconInfo;
|
||||
extern const BITMAP_INFO onOffIconInfo;
|
||||
extern const BITMAP_INFO frostIconInfo;
|
||||
extern const BITMAP_INFO humidityIconInfo;
|
||||
|
|
|
@ -238,6 +238,13 @@ CProtocol::setAltitude(float altitude)
|
|||
Controller.Altitude_LSB = (alt >> 0) & 0xff;
|
||||
}
|
||||
|
||||
int
|
||||
CProtocol::getAltitude() const
|
||||
{
|
||||
int alt = (Controller.Altitude_MSB << 8) | Controller.Altitude_LSB;
|
||||
return alt;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
CProtocol::Init(int FrameMode)
|
||||
|
|
|
@ -163,6 +163,7 @@ public:
|
|||
void setTemperature_HeatExchg(uint16_t degC); // temperature of heat exchanger
|
||||
// altitude
|
||||
void setAltitude(float altitude);
|
||||
int getAltitude() const;
|
||||
|
||||
void DebugReport(const char* hdr, const char* ftr);
|
||||
|
||||
|
@ -210,6 +211,7 @@ public:
|
|||
float getGlow_Current() const { return Heater.getGlowPlug_Current(); };
|
||||
float getSystemVoltage() const { return Controller.getSystemVoltage(); };
|
||||
int getGlow_Drive() const { return Controller.getGlowDrive(); };
|
||||
int getAltitude() const { return Controller.getAltitude(); };
|
||||
|
||||
// void setRefTime();
|
||||
void reportFrames(bool isOEM);
|
||||
|
|
|
@ -126,6 +126,8 @@ CSmartError::monitor(uint8_t newRunState)
|
|||
int
|
||||
CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
|
||||
{
|
||||
const unsigned long LVCholdoffTime = 10000;
|
||||
static unsigned long LVCShutdownHoldoff = 0;
|
||||
// check for low voltage
|
||||
// Native NV values here are x10 integers
|
||||
|
||||
|
@ -139,27 +141,32 @@ CSmartError::checkVolts(float ipVolts, float glowI, bool throwfault)
|
|||
|
||||
// test low voltage cutout
|
||||
if(ipVolts < threshLVC) {
|
||||
if(throwfault) { // only throw faults if directed to do so
|
||||
_Error = 2; // internals error codes are +1 over displayed error code
|
||||
requestOff(); // shut heater down
|
||||
if(LVCShutdownHoldoff == 0) {
|
||||
// initial detection of LVC - introduce a hold off period
|
||||
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
|
||||
}
|
||||
else {
|
||||
if(LVCShutdownHoldoff)
|
||||
DebugPort.println("LVC holdoff cancelled");
|
||||
LVCShutdownHoldoff = 0; // disable holdoff, voltage now OK
|
||||
}
|
||||
|
||||
// warning threshold
|
||||
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) {
|
||||
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_TxFrame(CProtocol::CtrlMode)
|
||||
{
|
||||
m_sysUpdate = 0;
|
||||
m_bOnReq = false;
|
||||
m_bOffReq = false;
|
||||
m_bTxPending = false;
|
||||
|
@ -107,6 +108,12 @@ CTxManage::queueRawCommand(uint8_t val)
|
|||
_rawCommand = val;
|
||||
}
|
||||
|
||||
void
|
||||
CTxManage::queueSysUpdate()
|
||||
{
|
||||
m_sysUpdate = 10;
|
||||
}
|
||||
|
||||
void
|
||||
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
|
||||
// heater is happy either way, the OEM controller has set the max/min stuff already
|
||||
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_Max(NVstore.getHeaterTuning().Fmax);
|
||||
m_TxFrame.setPump_Min(NVstore.getHeaterTuning().getPmin());
|
||||
|
|
|
@ -26,6 +26,7 @@ class CTxManage
|
|||
const int m_nStartDelay = 20;
|
||||
const int m_nFrameTime = 14;
|
||||
const int m_nFrontPorch = 0;
|
||||
int m_sysUpdate;
|
||||
|
||||
public:
|
||||
CTxManage(int TxGatePin, HardwareSerial& serial);
|
||||
|
@ -38,6 +39,7 @@ public:
|
|||
void begin();
|
||||
const CProtocol& getFrame() const { return m_TxFrame; };
|
||||
static void GateTerminate();
|
||||
void queueSysUpdate(); // use to implant NV settings into heater
|
||||
|
||||
private:
|
||||
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",
|
||||
"Status",
|
||||
"User",
|
||||
"Thresh"
|
||||
"Thresh",
|
||||
"HeaterOn"
|
||||
};
|
||||
const char* GPIOout2Names[] = {
|
||||
"Disabled",
|
||||
"User",
|
||||
"Thresh"
|
||||
"Thresh",
|
||||
"HeaterOn"
|
||||
};
|
||||
|
||||
const char* GPIOalgNames[] = {
|
||||
|
@ -216,7 +218,7 @@ CGPIOin2::_doThermostat(bool active)
|
|||
}
|
||||
|
||||
const char*
|
||||
CGPIOin2::getExtThermTime()
|
||||
CGPIOin2:: getExtThermTime()
|
||||
{
|
||||
if((_OffHoldoff == 0) || (NVstore.getUserSettings().ThermostatMethod != 3) || (NVstore.getUserSettings().ExtThermoTimeout == 0))
|
||||
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
|
||||
|
@ -503,7 +511,7 @@ CGPIOout1::begin(int pin, CGPIOout1::Modes mode)
|
|||
void
|
||||
CGPIOout1::setMode(CGPIOout1::Modes mode)
|
||||
{
|
||||
if(mode >= Disabled && mode <= Thresh)
|
||||
if(mode >= Disabled && mode <= HtrActive)
|
||||
_Mode = mode;
|
||||
_prevState = -1;
|
||||
if(_getPin())
|
||||
|
@ -523,6 +531,7 @@ CGPIOout1::manage()
|
|||
case CGPIOout1::Status: _doStatus(); break;
|
||||
case CGPIOout1::User: _doUser(); 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
|
||||
ledcWrite(0, _statusState);
|
||||
_breatheDelay = millis() + BREATHINTERVAL;
|
||||
_ledState = 2;
|
||||
break;
|
||||
case 2:
|
||||
ledcDetachPin(pin); // detach PWM from IO line
|
||||
|
@ -590,11 +600,13 @@ CGPIOout1::_doStatus()
|
|||
_statusState = 255;
|
||||
ledcWrite(0, _statusState);
|
||||
_breatheDelay = millis() + BREATHINTERVAL;
|
||||
_ledState = 3;
|
||||
break;
|
||||
case 4:
|
||||
ledcDetachPin(pin); // detach PWM from IO line
|
||||
_breatheDelay += (FLASHPERIOD - ONFLASHINTERVAL); // extended off
|
||||
_setPinState(LOW);
|
||||
_ledState = 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -631,7 +643,7 @@ CGPIOout1::_doStopMode() // breath down PWM
|
|||
_statusState &= 0xff;
|
||||
ledcWrite(0, _statusState);
|
||||
}
|
||||
_ledState = 2;
|
||||
_ledState = 3;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -657,7 +669,7 @@ CGPIOout1::_doSuspendMode() // brief flash
|
|||
if(tDelta >= 0)
|
||||
stretch = 0;
|
||||
}
|
||||
_ledState = stretch ? 1 : 0;
|
||||
_ledState = 4;
|
||||
}
|
||||
|
||||
uint8_t
|
||||
|
@ -666,6 +678,7 @@ CGPIOout1::getState()
|
|||
switch(_Mode) {
|
||||
case User:
|
||||
case Thresh:
|
||||
case HtrActive:
|
||||
return _getPinState();
|
||||
case Status:
|
||||
return _ledState; // special pulse extender for suspend mode
|
||||
|
@ -695,7 +708,7 @@ CGPIOout2::begin(int pin, Modes mode)
|
|||
void
|
||||
CGPIOout2::setMode(CGPIOout2::Modes mode)
|
||||
{
|
||||
if(mode >= Disabled && mode <= Thresh)
|
||||
if(mode >= Disabled && mode <= HtrActive)
|
||||
_Mode = mode;
|
||||
int pin = _getPin();
|
||||
if(pin)
|
||||
|
@ -714,6 +727,7 @@ CGPIOout2::manage()
|
|||
case CGPIOout2::Disabled: break;
|
||||
case CGPIOout2::User: _doUser(); break;
|
||||
case CGPIOout2::Thresh: _doThresh(); break;
|
||||
case CGPIOout2::HtrActive: _doActive(); break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -724,6 +738,7 @@ CGPIOout2::getState()
|
|||
switch (_Mode) {
|
||||
case CGPIOout2::User:
|
||||
case CGPIOout2::Thresh:
|
||||
case CGPIOout2::HtrActive:
|
||||
return _getPinState();
|
||||
default:
|
||||
return 0;
|
||||
|
|
|
@ -107,6 +107,7 @@ class CGPIOoutBase {
|
|||
bool _userState;
|
||||
int _pin;
|
||||
protected:
|
||||
void _doActive();
|
||||
void _doThresh();
|
||||
void _doUser();
|
||||
bool _getUserState();
|
||||
|
@ -126,7 +127,8 @@ public:
|
|||
Disabled,
|
||||
Status,
|
||||
User,
|
||||
Thresh
|
||||
Thresh,
|
||||
HtrActive
|
||||
};
|
||||
CGPIOout1();
|
||||
void begin(int pin, Modes mode);
|
||||
|
@ -152,7 +154,8 @@ public:
|
|||
enum Modes {
|
||||
Disabled,
|
||||
User,
|
||||
Thresh
|
||||
Thresh,
|
||||
HtrActive,
|
||||
};
|
||||
CGPIOout2();
|
||||
void begin(int pin, Modes mode);
|
||||
|
@ -207,8 +210,8 @@ struct sGPIOparams {
|
|||
};
|
||||
|
||||
struct sGPIO {
|
||||
bool outState[2];
|
||||
bool inState[2];
|
||||
uint8_t outState[2];
|
||||
uint8_t inState[2];
|
||||
int algVal;
|
||||
sGPIO() {
|
||||
outState[0] = outState[1] = false;
|
||||
|
|
|
@ -142,26 +142,26 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len)
|
|||
float tidyTemp = getTemperatureSensor();
|
||||
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||
if(tidyTemp > -80) {
|
||||
bSend |= moderator.addJson("TempCurrent", tidyTemp, root);
|
||||
bSend |= moderator.addJson("TempCurrent", tidyTemp, root, 5000);
|
||||
}
|
||||
if(getTempSensor().getNumSensors() > 1) {
|
||||
getTempSensor().getTemperature(1, tidyTemp);
|
||||
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||
if(tidyTemp > -80) {
|
||||
bSend |= moderator.addJson("Temp2Current", tidyTemp, root);
|
||||
bSend |= moderator.addJson("Temp2Current", tidyTemp, root, 5000);
|
||||
}
|
||||
if(getTempSensor().getNumSensors() > 2) {
|
||||
getTempSensor().getTemperature(2, tidyTemp);
|
||||
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||
if(tidyTemp > -80) {
|
||||
bSend |= moderator.addJson("Temp3Current", tidyTemp, root);
|
||||
bSend |= moderator.addJson("Temp3Current", tidyTemp, root, 5000);
|
||||
}
|
||||
}
|
||||
if(getTempSensor().getNumSensors() > 3) {
|
||||
getTempSensor().getTemperature(3, tidyTemp);
|
||||
tidyTemp = int(tidyTemp * 10 + 0.5) * 0.1f; // round to 0.1 resolution
|
||||
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) {
|
||||
bSend |= moderator.addJson("TempMin", getHeaterInfo().getTemperature_Min(), 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("RunString", getHeaterInfo().getRunStateStr(), root); // verbose it up!
|
||||
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("FanMin", getHeaterInfo().getFan_Min(), root );
|
||||
bSend |= moderator.addJson("FanMax", getHeaterInfo().getFan_Max(), root );
|
||||
bSend |= moderator.addJson("FanRPM", getFanSpeed(), root );
|
||||
bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root );
|
||||
bSend |= moderator.addJson("FanRPM", getFanSpeed(), root, 2000 );
|
||||
bSend |= moderator.addJson("FanVoltage", getHeaterInfo().getFan_Voltage(), root, 2500 );
|
||||
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("GlowVoltage", getGlowVolts(), root );
|
||||
bSend |= moderator.addJson("GlowCurrent", getGlowCurrent(), root );
|
||||
bSend |= moderator.addJson("GlowVoltage", getGlowVolts(), root, 5000 );
|
||||
bSend |= moderator.addJson("GlowCurrent", getGlowCurrent(), root, 5000 );
|
||||
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("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("PumpCount", RTC_Store.getFuelGauge(), root, 10000); // 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
|
||||
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("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("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) {
|
||||
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("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("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();
|
||||
|
@ -311,7 +323,8 @@ bool makeJSONStringMQTT(CModerator& moderator, char* opStr, int len)
|
|||
sMQTTparams info = NVstore.getMQTTinfo();
|
||||
|
||||
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("MPort", info.port, 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_STAMAC", getWifiSTAMACStr(), 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("BT_MAC", getBluetoothClient().getMAC(), root);
|
||||
|
||||
|
@ -518,10 +533,12 @@ void resetAllJSONmoderators()
|
|||
#else
|
||||
initJSONTimermoderator();
|
||||
#endif
|
||||
initJSONMQTTmoderator();
|
||||
initJSONIPmoderator();
|
||||
initJSONSysModerator();
|
||||
resetJSONMQTTmoderator(); // initJSONMQTTmoderator();
|
||||
resetJSONIPmoderator(); // initJSONIPmoderator();
|
||||
resetJSONSysModerator(); // initJSONSysModerator();
|
||||
GPIOmoderator.reset();
|
||||
// create and send a validation code (then client knows AB is capable of reboot over JSON)
|
||||
doJSONreboot(0);
|
||||
}
|
||||
|
||||
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 resetJSONMQTTmoderator();
|
||||
void validateTimer(int ID);
|
||||
void doJSONreboot(uint16_t code);
|
||||
|
||||
template<class T>
|
||||
const char* createJSON(const char* name, T value)
|
||||
|
|
|
@ -51,13 +51,42 @@ public:
|
|||
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>
|
||||
class TModerator {
|
||||
std::map<const char*, T> Memory;
|
||||
std::map<const char*, sModeratorHoldoff> _holdoff;
|
||||
public:
|
||||
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(const char* name);
|
||||
};
|
||||
|
@ -69,7 +98,21 @@ bool TModerator<T>::shouldSend(const char* name, T value)
|
|||
auto it = Memory.find(name);
|
||||
if(it != Memory.end()) {
|
||||
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 {
|
||||
Memory[name] = value;
|
||||
|
@ -78,11 +121,26 @@ bool TModerator<T>::shouldSend(const char* name, T value)
|
|||
}
|
||||
|
||||
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);
|
||||
if(retval)
|
||||
if(retval) {
|
||||
root.set(name, value);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
@ -93,15 +151,26 @@ void TModerator<T>::reset()
|
|||
for(auto it = Memory.begin(); it != Memory.end(); ++it) {
|
||||
it->second = it->second+100;
|
||||
}
|
||||
for(auto it = _holdoff.begin(); it != _holdoff.end(); ++it) {
|
||||
it->second.expire();
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void TModerator<T>::reset(const char* name)
|
||||
{
|
||||
auto it = Memory.find(name);
|
||||
if(it != Memory.end()) {
|
||||
DebugPort.printf("Resetting moderator: \"%s\"", name);
|
||||
it->second = it->second+100;
|
||||
{
|
||||
auto it = Memory.find(name);
|
||||
if(it != Memory.end()) {
|
||||
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);
|
||||
};
|
||||
// float values
|
||||
bool addJson(const char* name, float value, JsonObject& root) {
|
||||
return fModerator.addJson(name, value, root);
|
||||
bool addJson(const char* name, float value, JsonObject& root, unsigned long holdoff=0) {
|
||||
return fModerator.addJson(name, value, root, holdoff);
|
||||
};
|
||||
// uint8_t values
|
||||
bool addJson(const char* name, uint8_t value, JsonObject& root) {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "DebugPort.h"
|
||||
#include <functional>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
#define INBOUNDS(TST, MIN, MAX) (((TST) >= (MIN)) && ((TST) <= (MAX)))
|
||||
|
||||
|
@ -31,20 +32,31 @@
|
|||
bool
|
||||
CESP32_NVStorage::validatedLoad(const char* key, char* val, int maxlen, const char* defVal)
|
||||
{
|
||||
char probe[128];
|
||||
bool retval = true;
|
||||
strcpy(probe, "TestPresence");
|
||||
int len = preferences.getString(key, probe, 127);
|
||||
if(len == 0 || strcmp(probe, "TestPresence") == 0) {
|
||||
if(!preferences.hasString(key)) {
|
||||
preferences.putString(key, defVal);
|
||||
DebugPort.printf("CESP32HeaterStorage::validatedLoad<char*> default installed %s=%s", key, defVal);
|
||||
retval = false;
|
||||
DebugPort.printf("CESP32HeaterStorage::validatedLoad<char*> default installed %s=%s\r\n", key, defVal);
|
||||
}
|
||||
preferences.getString(key, val, maxlen);
|
||||
val[maxlen] = 0; // ensure null terminated
|
||||
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
|
||||
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
|
||||
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)) {
|
||||
|
||||
DebugPort.printf("CESP32HeaterStorage::validatedLoad<float> invalid read %s=%f", key, val);
|
||||
DebugPort.printf(" validator(%f,%f) reset to %f\r\n", min, max, 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 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)
|
||||
{
|
||||
return INBOUNDS(test, minLim, maxLim);
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#ifndef __BTC_NV_CORE_H__
|
||||
#define __BTC_NV_CORE_H__
|
||||
|
||||
#include <Preferences.h>
|
||||
#include "ABpreferences.h"
|
||||
#include <functional>
|
||||
|
||||
|
||||
|
@ -46,15 +46,17 @@ class CNVStorage {
|
|||
|
||||
class CESP32_NVStorage {
|
||||
protected:
|
||||
Preferences preferences;
|
||||
ABpreferences preferences;
|
||||
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, 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, 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, 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 "DebugPort.h"
|
||||
#include <driver/adc.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
bool
|
||||
sNVStore::valid()
|
||||
|
@ -131,6 +131,10 @@ CHeaterStorage::getMQTTinfo() const
|
|||
void
|
||||
CHeaterStorage::setMQTTinfo(const sMQTTparams& info)
|
||||
{
|
||||
if(_calValues.MQTT != info) {
|
||||
requestMQTTrestart();
|
||||
}
|
||||
|
||||
_calValues.MQTT = info;
|
||||
}
|
||||
|
||||
|
@ -268,13 +272,18 @@ sHeaterTuning::load()
|
|||
validatedLoad("tempOffset0", DS18B20probe[0].offset, 0.0, -10.0, +10.0);
|
||||
validatedLoad("tempOffset1", DS18B20probe[1].offset, 0.0, -10.0, +10.0);
|
||||
validatedLoad("tempOffset2", DS18B20probe[2].offset, 0.0, -10.0, +10.0);
|
||||
preferences.getBytes("probeSerial0", DS18B20probe[0].romCode.bytes, 8);
|
||||
preferences.getBytes("probeSerial1", DS18B20probe[1].romCode.bytes, 8);
|
||||
preferences.getBytes("probeSerial2", DS18B20probe[2].romCode.bytes, 8);
|
||||
memset(DS18B20probe[0].romCode.bytes, 0, 8);
|
||||
memset(DS18B20probe[1].romCode.bytes, 0, 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("probeBMEPrmy", BME280probe.bPrimary, 0, u8inBounds, 0, 1);
|
||||
preferences.end();
|
||||
|
||||
// save();
|
||||
|
||||
// for(int i=0; i<3; i++) {
|
||||
// DebugPort.printf("Rd Probe[%d] %02X:%02X:%02X:%02X:%02X:%02X\r\n",
|
||||
// i,
|
||||
|
@ -291,6 +300,20 @@ sHeaterTuning::load()
|
|||
void
|
||||
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
|
||||
// **** MAX LENGTH is 15 for names ****
|
||||
preferences.begin("Calibration", false);
|
||||
|
@ -302,15 +325,55 @@ sHeaterTuning::save()
|
|||
preferences.putUChar("fanSensor", fanSensor);
|
||||
preferences.putUChar("glowDrive", glowDrive);
|
||||
preferences.putUChar("lowVolts", lowVolts);
|
||||
preferences.putFloat("pumpCal", pumpCal);
|
||||
preferences.putFloat("tempOffset0", DS18B20probe[0].offset);
|
||||
preferences.putFloat("tempOffset1", DS18B20probe[1].offset);
|
||||
preferences.putFloat("tempOffset2", DS18B20probe[2].offset);
|
||||
saveFloat("pumpCal", pumpCal);
|
||||
saveFloat("tempOffset0", DS18B20probe[0].offset);
|
||||
saveFloat("tempOffset1", DS18B20probe[1].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("probeSerial1", DS18B20probe[1].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);
|
||||
|
||||
|
||||
/*// 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();
|
||||
|
||||
// for(int i=0; i<3; i++) {
|
||||
|
@ -417,8 +480,8 @@ sUserSettings::load()
|
|||
preferences.putUChar("GPIOout1Mode", GPIO.out1Mode); // set new
|
||||
preferences.putUChar("GPIOout2Mode", GPIO.out2Mode); // set new
|
||||
}
|
||||
validatedLoad("GPIOout1Mode", tVal, 0, u8inBounds, 0, 3); GPIO.out1Mode = (CGPIOout1::Modes)tVal;
|
||||
validatedLoad("GPIOout2Mode", tVal, 0, u8inBounds, 0, 2); GPIO.out2Mode = (CGPIOout2::Modes)tVal;
|
||||
validatedLoad("GPIOout1Mode", tVal, 0, u8inBounds, 0, 4); GPIO.out1Mode = (CGPIOout1::Modes)tVal;
|
||||
validatedLoad("GPIOout2Mode", tVal, 0, u8inBounds, 0, 3); GPIO.out2Mode = (CGPIOout2::Modes)tVal;
|
||||
validatedLoad("GPIOout1Thresh", GPIO.thresh[0], 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;
|
||||
|
@ -447,7 +510,8 @@ sUserSettings::save()
|
|||
preferences.putUChar("thermostat", useThermostat);
|
||||
preferences.putUChar("degF", degF);
|
||||
preferences.putUChar("thermoMethod", ThermostatMethod);
|
||||
preferences.putFloat("thermoWindow", ThermostatWindow);
|
||||
// preferences.putFloat("thermoWindow", ThermostatWindow);
|
||||
saveFloat("thermoWindow", ThermostatWindow);
|
||||
preferences.putUChar("frostOn", FrostOn);
|
||||
preferences.putUChar("frostRise", FrostRise);
|
||||
// preferences.putUChar("enableWifi", enableWifi);
|
||||
|
@ -484,9 +548,9 @@ sMQTTparams::load()
|
|||
validatedLoad("enabled", enabled, 0, u8inBounds, 0, 1);
|
||||
validatedLoad("port", port, 1883, u16inBounds, 0, 0xffff);
|
||||
validatedLoad("qos", qos, 0, u8inBounds, 0, 2);
|
||||
validatedLoad("host", host, 127, "");
|
||||
validatedLoad("username", username, 31, "");
|
||||
validatedLoad("password", password, 31, "");
|
||||
validatedLoad("host", host, 127, "broker");
|
||||
validatedLoad("username", username, 31, "username");
|
||||
validatedLoad("password", password, 31, "password");
|
||||
validatedLoad("topic", topicPrefix, 31, "Afterburner");
|
||||
preferences.end();
|
||||
}
|
||||
|
@ -572,4 +636,4 @@ sHourMeter::load()
|
|||
validatedLoad("GlowTime", GlowTime, 0, 0, 0xffffffffL);
|
||||
preferences.end();
|
||||
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;
|
||||
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 save();
|
||||
bool valid();
|
||||
|
|
|
@ -432,7 +432,7 @@ CBME280Sensor::getTemperature(float& tempReading, bool filtered)
|
|||
}
|
||||
|
||||
CSensor::getTemperature(tempReading, filtered);
|
||||
tempReading += NVstore.getHeaterTuning().BME280probe.offset;;
|
||||
// tempReading += NVstore.getHeaterTuning().BME280probe.offset;;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -559,16 +559,26 @@ CTempSense::setOffset(int usrIdx, float offset)
|
|||
bool
|
||||
CTempSense::getTemperature(int usrIdx, float& temperature, bool filtered)
|
||||
{
|
||||
bool bRetVal = false;
|
||||
float offset = 0;
|
||||
switch(getSensorType(usrIdx)) {
|
||||
case 0:
|
||||
return BME280.getTemperature(temperature, filtered);
|
||||
bRetVal = BME280.getTemperature(temperature, filtered);
|
||||
offset = getOffset(usrIdx);
|
||||
break;
|
||||
case 1:
|
||||
return DS18B20.getTemperature(usrIdx, temperature, filtered);
|
||||
bRetVal = DS18B20.getTemperature(usrIdx, temperature, filtered);
|
||||
offset = getOffset(usrIdx);
|
||||
break;
|
||||
case 2:
|
||||
return DS18B20.getTemperature(usrIdx-1, temperature, filtered);
|
||||
default:
|
||||
return false;
|
||||
bRetVal = DS18B20.getTemperature(usrIdx-1, temperature, filtered);
|
||||
offset = getOffset(usrIdx-1);
|
||||
break;
|
||||
}
|
||||
if(bRetVal) {
|
||||
temperature += offset;
|
||||
}
|
||||
return bRetVal;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -422,10 +422,22 @@ void DecodeCmd(const char* cmd, String& payload)
|
|||
else if(strcmp("FrostRise", cmd) == 0) {
|
||||
sUserSettings us = NVstore.getUserSettings();
|
||||
us.FrostRise = payload.toInt();
|
||||
if(INBOUNDS(us.FrostRise, 1, 30)) {
|
||||
if(INBOUNDS(us.FrostRise, 0, 30)) {
|
||||
NVstore.setUserSettings(us);
|
||||
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 reloadScreens();
|
||||
extern CTempSense& getTempSensor() ;
|
||||
extern void reqHeaterCalUpdate();
|
||||
|
||||
|
||||
void setSSID(const char* name);
|
||||
|
@ -99,5 +100,6 @@ extern void ShowOTAScreen(int percent=0, eOTAmodes updateType=eOTAnormal);
|
|||
|
||||
extern void updateMQTT();
|
||||
extern void refreshMQTT();
|
||||
extern void requestMQTTrestart();
|
||||
|
||||
#endif
|
|
@ -51,7 +51,8 @@ extern void DecodeCmd(const char* cmd, String& payload);
|
|||
AsyncMqttClient MQTTclient;
|
||||
char topicnameJSONin[128];
|
||||
char topicnameCmd[128];
|
||||
CModerator MQTTmoderator;
|
||||
CModerator MQTTmoderator; // for basic MQTT interface
|
||||
unsigned long MQTTrestart = 0;
|
||||
|
||||
void subscribe(const char* topic);
|
||||
|
||||
|
@ -100,14 +101,10 @@ void onMqttConnect(bool sessionPresent)
|
|||
sprintf(statusTopic, "%s/status", NVstore.getMQTTinfo().topicPrefix);
|
||||
sprintf(topicnameJSONin, "%s/JSONin", NVstore.getMQTTinfo().topicPrefix);
|
||||
sprintf(topicnameCmd, "%s/cmd/#", NVstore.getMQTTinfo().topicPrefix);
|
||||
// subscribe to that topic
|
||||
// DebugPort.printf("MQTT: Subscribing to \"%s\"\r\n", topicnameJSONin);
|
||||
// MQTTclient.subscribe(topicnameJSONin, NVstore.getMQTTinfo().qos);
|
||||
// MQTTclient.subscribe(topicnameCmd, NVstore.getMQTTinfo().qos);
|
||||
// MQTTclient.subscribe(statusTopic, NVstore.getMQTTinfo().qos);
|
||||
subscribe(topicnameJSONin);
|
||||
subscribe(topicnameCmd);
|
||||
subscribe(statusTopic);
|
||||
|
||||
subscribe(topicnameJSONin); // subscribe to the JSONin topic
|
||||
subscribe(topicnameCmd); // subscribe to the basic command topic
|
||||
subscribe(statusTopic); // subscribe to the status topic
|
||||
|
||||
// spit out an "I'm here" message
|
||||
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
|
||||
if(strcmp(szPayload, "1") == 0) {
|
||||
MQTTmoderator.reset();
|
||||
// MQTTmoderator.reset();
|
||||
MQTTclient.publish(statusTopic, NVstore.getMQTTinfo().qos, true, "online");
|
||||
}
|
||||
}
|
||||
|
@ -199,9 +196,11 @@ bool mqttInit()
|
|||
#else
|
||||
mqttReconnect = 0;
|
||||
#endif
|
||||
MQTTrestart = 0;
|
||||
|
||||
memset(topicnameJSONin, 0, sizeof(topicnameJSONin));
|
||||
|
||||
DebugPort.println("MQTT: Initialising...");
|
||||
MQTTclient.disconnect(true);
|
||||
long escape = millis() + 10000;
|
||||
while(MQTTclient.connected()) {
|
||||
|
@ -274,6 +273,16 @@ void kickMQTT() {
|
|||
|
||||
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!!!
|
||||
if(NVstore.getMQTTinfo().enabled) {
|
||||
#ifndef USE_RTOS_MQTTTIMER
|
||||
|
@ -411,4 +420,9 @@ void subscribe(const char* topic)
|
|||
MQTTclient.subscribe(topic, NVstore.getMQTTinfo().qos);
|
||||
}
|
||||
|
||||
void requestMQTTrestart()
|
||||
{
|
||||
MQTTrestart = (millis() + 1000) | 1;
|
||||
}
|
||||
|
||||
#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)
|
||||
DebugPort.println("handleFileRead: " + path);
|
||||
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 pathWithGz = path + ".gz";
|
||||
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 rename;
|
||||
if(withHTMLanchors == 2) {
|
||||
rename = "<button class='rename' onClick=onRename('" + fn + "')>Rename</button>";
|
||||
ers = "<input class='del' type='button' value='X' onClick=onErase('" + fn + "')>";
|
||||
String htmlNm = 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) {
|
||||
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"
|
||||
}
|
||||
if(fn2.length() != 0) {
|
||||
fn2.replace(" ", "%20");
|
||||
// create hyperlink if web page file
|
||||
fn = "<a href=\"" + fn2 + "\">" + file.name() + "</a>";
|
||||
}
|
||||
|
@ -678,6 +682,7 @@ void addTableData(String& HTML, String dta)
|
|||
void onErase()
|
||||
{
|
||||
String filename = server.arg("filename"); // get request argument value by name
|
||||
filename.replace("%20", " "); // convert HTML spaces to real spaces
|
||||
|
||||
if(filename.length() != 0) {
|
||||
DebugPort.printf("onErase: %s ", filename.c_str());
|
||||
|
@ -986,6 +991,8 @@ void onRename()
|
|||
DebugPort.println("WEB: POST /reboot");
|
||||
String oldname = server.arg("oldname"); // 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 != "") {
|
||||
DebugPort.printf("Renaming %s to %s\r\n", oldname.c_str(), newname.c_str());
|
||||
SPIFFS.rename(oldname.c_str(), newname.c_str());
|
||||
|
|
|
@ -279,6 +279,38 @@ const char* getWifiSTAAddrStr()
|
|||
else
|
||||
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()
|
||||
{
|
||||
|
|
|
@ -28,8 +28,10 @@ void doWiFiManager();
|
|||
bool initWifi(const char *failedssid, const char *failedpassword);
|
||||
const char* getWifiAPAddrStr();
|
||||
const char* getWifiSTAAddrStr();
|
||||
const char* getWifiGatewayAddrStr();
|
||||
const char* getWifiAPMACStr();
|
||||
const char* getWifiSTAMACStr();
|
||||
int8_t getWifiRSSI();
|
||||
String getSSID();
|
||||
|
||||
bool isWifiConnected();
|
||||
|
|
|
@ -63,6 +63,8 @@ sBrowserUpload::begin(String& filename, int filesize)
|
|||
}
|
||||
}
|
||||
else {
|
||||
SrcFile.name.replace("%20", " "); // convert HTML spaces to real spaces
|
||||
|
||||
// SPIFFS UPLOAD START
|
||||
DebugPort.printf("Starting SPIFFS upload: %s\r\n", SrcFile.name.c_str());
|
||||
|
||||
|
|
Loading…
Reference in New Issue