Refactored string in JSON moderator - const char* are BAD AND EVIL in a std::map

MQTT parameter exchange via JSON and NV storage
This commit is contained in:
Ray Jones 2019-05-12 20:15:18 +10:00
parent 38711533cd
commit 04fab40742
20 changed files with 322 additions and 138 deletions

View file

@ -115,9 +115,9 @@
#define RX_DATA_TIMOUT 50
const int FirmwareRevision = 22;
const int FirmwareSubRevision = 3;
const char* FirmwareDate = "11 May 2019";
const int FirmwareRevision = 23;
const int FirmwareSubRevision = 0;
const char* FirmwareDate = "12 May 2019";
#ifdef ESP32
@ -267,7 +267,7 @@ const char* print18B20Address(DeviceAddress deviceAddress)
#if USE_SPIFFS == 1
void listDir(fs::FS &fs, const char * dirname, uint8_t levels)
{
DebugPort.print("Listing directory: "); DebugPort.println(dirname);
DebugPort.printf("Listing directory: %s\r\n", dirname);
File root = fs.open(dirname);
if (!root) {
@ -282,16 +282,12 @@ void listDir(fs::FS &fs, const char * dirname, uint8_t levels)
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
DebugPort.print(" DIR : ");
DebugPort.println(file.name());
DebugPort.printf(" DIR : %s\r\n", file.name());
if (levels) {
listDir(fs, file.name(), levels - 1);
}
} else {
DebugPort.print(" FILE: ");
DebugPort.print(file.name());
DebugPort.print(" SIZE: ");
DebugPort.println(file.size());
DebugPort.printf(" FILE: %s SIZE: %ld\r\n", file.name(), file.size());
}
file = root.openNextFile();
}
@ -314,11 +310,10 @@ void setup() {
DebugPort.println("_______________________________________________________________");
DebugPort.println("DS18B20 status dump");
sprintf(msg, " Temperature for device#1 (idx 0) is: %.1f", TempSensor.getTempCByIndex(0));
DebugPort.println(msg);
DebugPort.printf(" Temperature for device#1 (idx 0) is: %.1f\r\n", TempSensor.getTempCByIndex(0));
BoardRevision = BoardDetect();
DebugPort.print("Board revision: V"); DebugPort.println(float(BoardRevision) * 0.1, 1);
DebugPort.printf("Board revision: V%.1f\r\n", float(BoardRevision) * 0.1);
#if USE_SPIFFS == 1
// Initialize SPIFFS
@ -338,12 +333,10 @@ void setup() {
// Grab a count of devices on the wire
int numberOfDevices = TempSensor.getDeviceCount();
sprintf(msg, " Found %d devices", numberOfDevices);
DebugPort.println(msg);
DebugPort.printf(" Found %d devices\r\n", numberOfDevices);
// report parasite power requirements
sprintf(msg, " Parasite power is: %s", TempSensor.isParasitePowerMode() ? "ON" : "OFF");
DebugPort.println(msg);
DebugPort.printf(" Parasite power is: %s\r\n", TempSensor.isParasitePowerMode() ? "ON" : "OFF");
// Loop through each device, print out address
for(int i=0;i<numberOfDevices; i++)
@ -351,14 +344,11 @@ void setup() {
// Search the wire for address
DeviceAddress tempDeviceAddress;
if(TempSensor.getAddress(tempDeviceAddress, i)) {
sprintf(msg, " Found DS18B20 device#%d with address: %s", i+1, print18B20Address(tempDeviceAddress));
DebugPort.println(msg);
DebugPort.printf(" Found DS18B20 device#%d with address: %s\r\n", i+1, print18B20Address(tempDeviceAddress));
sprintf(msg, " Resolution: %d bits", TempSensor.getResolution(tempDeviceAddress));
DebugPort.println(msg);
DebugPort.printf(" Resolution: %d bits\r\n", TempSensor.getResolution(tempDeviceAddress));
} else {
sprintf(msg, " Found ghost @ device#%d, but could not detect address. Check power and cabling", i+1);
DebugPort.println(msg);
DebugPort.printf(" Found ghost @ device#%d, but could not detect address. Check power and cabling\r\n", i+1);
}
}
memset(tempSensorAddress, 0, 8);
@ -373,6 +363,7 @@ void setup() {
NVstore.init();
NVstore.load();
initMQTTJSONmoderator(); // prevent JSON for MQTT unless requested
KeyPad.begin(keyLeft_pin, keyRight_pin, keyCentre_pin, keyUp_pin, keyDown_pin);
KeyPad.setCallback(parentKeyHandler);
@ -516,8 +507,7 @@ void loop()
if(RxTimeElapsed >= moderator) {
moderator += 10;
if(bReportRecyleEvents) {
DebugPort.print(RxTimeElapsed);
DebugPort.print("ms - ");
DebugPort.printf("%ldms - ", RxTimeElapsed);
}
if(CommState.is(CommStates::OEMCtrlRx)) {
bHasOEMController = false;
@ -579,9 +569,7 @@ void loop()
if(BlueWireData.available() && (RxTimeElapsed > RX_DATA_TIMOUT+10)) {
if(bReportOEMresync) {
DebugPort.print("Re-sync'd with OEM Controller. ");
DebugPort.print(RxTimeElapsed);
DebugPort.println("ms Idle time.");
DebugPort.printf("Re-sync'd with OEM Controller. %ldms Idle time.\r\n", RxTimeElapsed);
}
bHasHtrData = false;
@ -785,7 +773,7 @@ void loop()
if(tDelta > TEMPERATURE_INTERVAL) { // maintain a minimum holdoff period
lastTemperatureTime += TEMPERATURE_INTERVAL; // reset time to observe temeprature
fTemperature = TempSensor.getTempC(tempSensorAddress); // read sensor
// DebugPort.print("DS18B20 = "); DebugPort.println(fTemperature);
// DebugPort.printf("DS18B20 = %f\r\n", fTemperature);
// initialise filtered temperature upon very first pass
if(fTemperature > -80) { // avoid disconnected sensor readings being integrated
if(DS18B20holdoff)
@ -834,8 +822,7 @@ void manageCyclicMode()
if(cyclic.Stop && bUserON) { // cyclic mode enabled, and user has started heater
int stopDeltaT = cyclic.Stop + 1; // bump up by 1 degree - no point invoking at 1 deg over!
float deltaT = fFilteredTemperature - getSetTemp();
// DebugPort.print("Cyclic = "); DebugPort.print(cyclic); DebugPort.print(" bUserON = "); DebugPort.print(bUserON);
// DebugPort.print(" deltaT = "); DebugPort.println(deltaT);
// DebugPort.printf("Cyclic=%d bUserOn=%d deltaT=%d\r\n", cyclic, bUserON, deltaT);
// ensure we cancel user ON mode if heater throws an error
int errState = getHeaterInfo().getErrState();
@ -848,7 +835,7 @@ void manageCyclicMode()
// check if over temp, turn off heater
if(deltaT > stopDeltaT) {
if(heaterState > 0 && heaterState <= 5) {
DebugPort.print("CYCLIC MODE: Stopping heater, deltaT > +"); DebugPort.println(stopDeltaT);
DebugPort.printf("CYCLIC MODE: Stopping heater, deltaT > +%d\r\n", stopDeltaT);
heaterOff(); // over temp - request heater stop
}
}
@ -856,7 +843,7 @@ void manageCyclicMode()
if(deltaT < cyclic.Start) {
// typ. 1 degree below set point - restart heater
if(heaterState == 0) {
DebugPort.print("CYCLIC MODE: Restarting heater, deltaT <"); DebugPort.println(cyclic.Start);
DebugPort.printf("CYCLIC MODE: Restarting heater, deltaT <%d\r\n", cyclic.Start);
heaterOn();
}
}
@ -883,9 +870,7 @@ bool validateFrame(const CProtocol& frame, const char* name)
{
if(!frame.verifyCRC()) {
// Bad CRC - restart blue wire Serial port
DebugPort.print("\007Bad CRC detected for ");
DebugPort.print(name);
DebugPort.println(" frame - restarting blue wire's serial port");
DebugPort.printf("\007Bad CRC detected for %s frame - restarting blue wire's serial port\r\n", name);
DebugReportFrame("BAD CRC:", frame, "\r\n");
initBlueWireSerial();
CommState.set(CommStates::TemperatureRead);
@ -1101,11 +1086,11 @@ void checkDebugCommands()
DebugPort.print("\014");
DebugPort.println("MENU options");
DebugPort.println("");
DebugPort.print(" <B> - toggle raw blue wire data reporting, currently "); DebugPort.println(bReportBlueWireData ? "ON" : "OFF");
DebugPort.print(" <J> - toggle output JSON reporting, currently "); DebugPort.println(bReportJSONData ? "ON" : "OFF");
DebugPort.print(" <W> - toggle reporting of blue wire timeout/recycling event, currently "); DebugPort.println(bReportRecyleEvents ? "ON" : "OFF");
DebugPort.print(" <O> - toggle reporting of OEM resync event, currently "); DebugPort.println(bReportOEMresync ? "ON" : "OFF");
DebugPort.print(" <S> - toggle reporting of state machine transits "); DebugPort.println(bReportOEMresync ? "ON" : "OFF");
DebugPort.printf(" <B> - toggle raw blue wire data reporting, currently %s\r\n", bReportBlueWireData ? "ON" : "OFF");
DebugPort.printf(" <J> - toggle output JSON reporting, currently %s\r\n", bReportJSONData ? "ON" : "OFF");
DebugPort.printf(" <W> - toggle reporting of blue wire timeout/recycling event, currently %s\r\n", bReportRecyleEvents ? "ON" : "OFF");
DebugPort.printf(" <O> - toggle reporting of OEM resync event, currently %s\r\n", bReportOEMresync ? "ON" : "OFF");
DebugPort.printf(" <S> - toggle reporting of state machine transits %s\r\n", CommState.isReporting() ? "ON" : "OFF");
DebugPort.println(" <+> - request heater turns ON");
DebugPort.println(" <-> - request heater turns OFF");
DebugPort.println(" <R> - restart the ESP");
@ -1154,19 +1139,19 @@ void checkDebugCommands()
#endif
else if(rxVal == 'b') {
bReportBlueWireData = !bReportBlueWireData;
DebugPort.print("Toggled raw blue wire data reporting "); DebugPort.println(bReportBlueWireData ? "ON" : "OFF");
DebugPort.printf("Toggled raw blue wire data reporting %s\r\n", bReportBlueWireData ? "ON" : "OFF");
}
else if(rxVal == 'j') {
bReportJSONData = !bReportJSONData;
DebugPort.print("Toggled JSON data reporting "); DebugPort.println(bReportJSONData ? "ON" : "OFF");
DebugPort.printf("Toggled JSON data reporting %s\r\n", bReportJSONData ? "ON" : "OFF");
}
else if(rxVal == 'w') {
bReportRecyleEvents = !bReportRecyleEvents;
DebugPort.print("Toggled blue wire recycling event reporting "); DebugPort.println(bReportRecyleEvents ? "ON" : "OFF");
DebugPort.printf("Toggled blue wire recycling event reporting %s\r\n", bReportRecyleEvents ? "ON" : "OFF");
}
else if(rxVal == 'o') {
bReportOEMresync = !bReportOEMresync;
DebugPort.print("Toggled OEM resync event reporting "); DebugPort.println(bReportOEMresync ? "ON" : "OFF");
DebugPort.printf("Toggled OEM resync event reporting %s\r\n", bReportOEMresync ? "ON" : "OFF");
}
else if(rxVal == 's') {
CommState.toggleReporting();
@ -1197,7 +1182,7 @@ void checkDebugCommands()
DefaultBTCParams.Controller.Unknown2_LSB = (val >> 0) & 0xff; // always 0xac 16bit: "3500" ?? Ignition fan max RPM????
break;
case 4:
DebugPort.print("Forced controller command = "); DebugPort.println(val&0xff);
DebugPort.printf("Forced controller command = %d\r\n", val&0xff);
DefaultBTCParams.Controller.Command = val & 0xff;
break;
}
@ -1224,7 +1209,7 @@ int getBlueWireStat()
const char* getBlueWireStatStr()
{
const char* BlueWireStates[] = { "BTC,Htr", "BTC", "OEM,Htr", "OEM" };
static const char* BlueWireStates[] = { "BTC,Htr", "BTC", "OEM,Htr", "OEM" };
return BlueWireStates[getBlueWireStat()];
}
@ -1293,14 +1278,14 @@ void setupGPIO()
void setGPIO(int channel, bool state)
{
DebugPort.print("setGPIO: Output #"); DebugPort.print(channel+1); DebugPort.print(" = "); DebugPort.println(state);
DebugPort.printf("setGPIO: Output #%d = %d\r\n", channel+1, state);
GPIOout.setState(channel, state);
}
bool getGPIO(int channel)
{
bool retval = GPIOout.getState(channel);
DebugPort.print("getGPIO: Output #"); DebugPort.print(channel+1); DebugPort.print(" = "); DebugPort.println(retval);
DebugPort.printf("getGPIO: Output #%d = %d\r\n", channel+1, retval);
return retval;
}

View file

@ -63,9 +63,7 @@ CBluetoothHC05::begin()
int BTidx = 0;
int maxTries = sizeof(BTRates)/sizeof(int);
for(BTidx = 0; BTidx < maxTries; BTidx++) {
DebugPort.print(" @ ");
DebugPort.print(BTRates[BTidx]);
DebugPort.print(" baud... ");
DebugPort.printf(" @ %d baud... ", BTRates[BTidx]);
openSerial(BTRates[BTidx]); // open serial port at a std. baud rate
delay(10);
flush();

View file

@ -298,7 +298,7 @@ CScreenManager::checkUpdate()
}
else {
_rootMenu = _subMenu = 1;
DebugPort.print("Screen Manager: Menu timeout, falling back to Basic control screen");
DebugPort.println("Screen Manager: Menu timeout, falling back to Basic control screen");
}
}
_enterScreen();

View file

@ -76,10 +76,7 @@ CProtocol::verifyCRC(bool bSilent) const
unsigned short FrameCRC = getCRC();
bool bOK = (FrameCRC == CRC);
if(!bOK && !bSilent) {
DebugPort.print("verifyCRC FAILED: calc:");
DebugPort.print(CRC, HEX);
DebugPort.print(" data:");
DebugPort.println(FrameCRC, HEX);
DebugPort.printf("verifyCRC FAILED: calc: %04X data: %04X\r\n", CRC, FrameCRC);
}
return bOK; // does it match the stored values?
}

View file

@ -137,7 +137,7 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
float tDelta = tCurrent - tDesired;
float fTemp;
#ifdef DEBUG_THERMOSTAT
DebugPort.print("Window = "); DebugPort.print(Window); DebugPort.print(" tCurrent = "); DebugPort.print(tCurrent); DebugPort.print(" tDesired = "); DebugPort.print(tDesired); DebugPort.print(" tDelta = "); DebugPort.println(tDelta);
DebugPort.printf("Window=%.1f tCurrent=%.1f tDesired=%.1f tDelta=%.1f\r\n", Window, tCurrent, tDesired, tDelta);
#endif
Window /= 2;
switch(ThermoMode) {
@ -148,7 +148,7 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
u8Temp = (uint8_t)(tActual + 0.5);
m_TxFrame.setTemperature_Actual(u8Temp);
#ifdef DEBUG_THERMOSTAT
DebugPort.print("Conventional thermostat mode: tActual = "); DebugPort.println(u8Temp);
DebugPort.printf("Conventional thermostat mode: tActual = %d\r\n", u8Temp);
#endif
break;
@ -165,7 +165,7 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
}
m_TxFrame.setTemperature_Actual(u8Temp);
#ifdef DEBUG_THERMOSTAT
DebugPort.print("Heater controlled windowed thermostat mode: tActual = "); DebugPort.println(u8Temp);
DebugPort.printf("Heater controlled windowed thermostat mode: tActual=%d\r\n", u8Temp);
#endif
break;
@ -175,7 +175,7 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
// so create a desired "temp" according the the current hystersis
tDelta /= Window; // convert tDelta to fraction of window (CAUTION - may be > +-1 !)
#ifdef DEBUG_THERMOSTAT
DebugPort.print("Linear window thermostat mode: Fraction = "); DebugPort.print(tDelta);
DebugPort.printf("Linear window thermostat mode: Fraction=%f", tDelta);
#endif
fTemp = (m_TxFrame.getTemperature_Max() + m_TxFrame.getTemperature_Min()) * 0.5; // midpoint - tDelta = 0 hinges here
tDelta *= (m_TxFrame.getTemperature_Max() - fTemp); // linear offset from setpoint
@ -189,7 +189,7 @@ CTxManage::PrepareFrame(const CProtocol& basisFrame, bool isBTCmaster)
m_TxFrame.setThermostatModeProtocol(0); // direct heater to use Hz Mode
m_TxFrame.setTemperature_Actual(0); // must force actual to 0 for Hz mode
#ifdef DEBUG_THERMOSTAT
DebugPort.print(" tDesired (pseudo Hz demand) = "); DebugPort.println(u8Temp);
DebugPort.printf(" tDesired (pseudo Hz demand) = %d\r\n", u8Temp);
#endif
break;
}

View file

@ -109,7 +109,7 @@ CClock::set(const DateTime& newTimeDate)
void setDateTime(const char* newTime)
{
DebugPort.print("setting time to: "); DebugPort.println(newTime);
DebugPort.printf("setting time to: %s\r\n", newTime);
int month,day,year,hour,minute,second;
if(6 == sscanf(newTime, "%d/%d/%d %d:%d:%d", &day, &month, &year, &hour, &minute, &second)) {
DateTime newDateTime(year, month, day, hour, minute, second);
@ -119,7 +119,7 @@ void setDateTime(const char* newTime)
void setDate(const char* newDate)
{
DebugPort.print("setting date to: "); DebugPort.println(newDate);
DebugPort.printf("setting date to: %s\r\n", newDate);
int month,day,year;
if(3 == sscanf(newDate, "%d/%d/%d", &day, &month, &year)) {
DateTime currentDateTime = Clock.get();
@ -130,7 +130,7 @@ void setDate(const char* newDate)
void setTime(const char* newTime)
{
DebugPort.print("setting time to: "); DebugPort.println(newTime);
DebugPort.printf("setting time to: %s\r\n", newTime);
int hour,minute,second;
if(3 == sscanf(newTime, "%d:%d:%d", &hour, &minute, &second)) {
DateTime currentDateTime = Clock.get();

View file

@ -222,11 +222,9 @@ CTimerManager::manageTime(int _hour, int _minute, int _dow)
int newID = weekTimerIDs[dow][dayMinute];
if(activeTimer != newID) {
DebugPort.print("Timer ID change detected ");
DebugPort.print(activeTimer & 0x0f);
DebugPort.printf("Timer ID change detected: %d", activeTimer & 0x0f);
if(activeTimer & 0x80) DebugPort.print("(repeating)");
DebugPort.print(" -> ");
DebugPort.print(newID & 0x0f);
DebugPort.printf(" -> %d", newID & 0x0f);
if(newID & 0x80) DebugPort.print("(repeating)");
DebugPort.println("");
@ -239,7 +237,7 @@ CTimerManager::manageTime(int _hour, int _minute, int _dow)
}
else { // non repeating timer
// delete one shot timer - note that this may require ticking off each day as they appear
DebugPort.print("Expired timer does not repeat - Cancelling"); DebugPort.println(activeTimer);
DebugPort.printf("Expired timer does not repeat - Cancelling %d\r\n", activeTimer);
int ID = activeTimer & 0x0f;
if(ID) {
ID--;
@ -251,7 +249,7 @@ CTimerManager::manageTime(int _hour, int _minute, int _dow)
timer.enabled = 0; // ouright cancel anyday timer
}
else {
DebugPort.print("Cancelling specific day idx"); DebugPort.println(activeDow);
DebugPort.printf("Cancelling specific day idx %d\r\n", activeDow);
timer.enabled &= ~(0x01 << activeDow); // cancel specific day that started the timer
}
NVstore.setTimerInfo(ID, timer);

View file

@ -35,6 +35,7 @@ char defaultJSONstr[64];
CModerator JSONmoderator;
CTimerModerator TimerModerator;
int timerConflict = 0;
CModerator MQTTmoderator;
void validateTimer(int ID);
@ -43,12 +44,7 @@ void interpretJsonCommand(char* pLine)
if(strlen(pLine) == 0)
return;
DebugPort.print("JSON parse... "); DebugPort.print(pLine);
/* for(int i=0; i<strlen(pLine); i++) {
char msg[8];
sprintf(msg, "%02X ", pLine[i]);
DebugPort.print(msg);
}*/
DebugPort.printf("JSON parse %s...", pLine);
StaticJsonBuffer<512> jsonBuffer; // create a JSON buffer on the heap
JsonObject& obj = jsonBuffer.parseObject(pLine);
@ -157,6 +153,38 @@ void interpretJsonCommand(char* pLine)
else if(strcmp("FanSensor", it->key) == 0) {
setFanSensor(it->value.as<unsigned char>());
}
// MQTT parameters
else if(strcmp("MQuery", it->key) == 0) {
MQTTmoderator.reset(); // force MQTT params to be sent
}
else if(strcmp("MEn", it->key) == 0) {
sMQTTparams info = NVstore.getMQTTinfo();
info.enabled = it->value.as<unsigned char>();
NVstore.setMQTTinfo(info);
}
else if(strcmp("MPort", it->key) == 0) {
sMQTTparams info = NVstore.getMQTTinfo();
info.port = it->value.as<unsigned short>();
NVstore.setMQTTinfo(info);
}
else if(strcmp("MHost", it->key) == 0) {
sMQTTparams info = NVstore.getMQTTinfo();
strncpy(info.host, it->value.as<const char*>(), 127);
info.host[127] = 0;
NVstore.setMQTTinfo(info);
}
else if(strcmp("MUser", it->key) == 0) {
sMQTTparams info = NVstore.getMQTTinfo();
strncpy(info.username, it->value.as<const char*>(), 31);
info.username[31] = 0;
NVstore.setMQTTinfo(info);
}
else if(strcmp("MPasswd", it->key) == 0) {
sMQTTparams info = NVstore.getMQTTinfo();
strncpy(info.password, it->value.as<const char*>(), 31);
info.password[31] = 0;
NVstore.setMQTTinfo(info);
}
}
}
@ -259,6 +287,27 @@ bool makeJSONTimerString(int channel, char* opStr, int len)
}
bool makeJSONStringMQTT(CModerator& moderator, char* opStr, int len)
{
StaticJsonBuffer<800> jsonBuffer; // create a JSON buffer on the stack
JsonObject& root = jsonBuffer.createObject(); // create object to add JSON commands to
bool bSend = false; // reset should send flag
const sMQTTparams& info = NVstore.getMQTTinfo();
bSend |= moderator.addJson("MEn", info.enabled, root);
bSend |= moderator.addJson("MPort", info.port, root);
bSend |= moderator.addJson("MHost", info.host, root);
bSend |= moderator.addJson("MUser", info.username, root);
bSend |= moderator.addJson("MPasswd", info.password, root);
if(bSend) {
root.printTo(opStr, len);
}
return bSend;
}
void updateJSONclients(bool report)
{
@ -267,7 +316,7 @@ void updateJSONclients(bool report)
{
if(makeJSONString(JSONmoderator, jsonStr, sizeof(jsonStr))) {
if (report) {
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
DebugPort.printf("JSON send: %s\r\n", jsonStr);
}
sendWebServerString( jsonStr );
getBluetoothClient().send( jsonStr );
@ -277,7 +326,7 @@ void updateJSONclients(bool report)
{
if(makeJSONStringEx(JSONmoderator, jsonStr, sizeof(jsonStr))) {
if (report) {
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
DebugPort.printf("JSON send: %s\r\n", jsonStr);
}
sendWebServerString( jsonStr );
getBluetoothClient().send( jsonStr );
@ -291,7 +340,7 @@ void updateJSONclients(bool report)
if(makeJSONTimerString(tmr, jsonStr, sizeof(jsonStr))) {
unsigned long tJSON = millis() - tStart;
if (report) {
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
DebugPort.printf("JSON send: %s\r\n", jsonStr);
}
tStart = millis();
sendWebServerString( jsonStr );
@ -300,7 +349,7 @@ void updateJSONclients(bool report)
getBluetoothClient().send( jsonStr );
unsigned long tBT = millis() - tStart;
bNewTimerInfo = true;
DebugPort.print("JSON times : "); DebugPort.print(tJSON); DebugPort.print(",");DebugPort.print(tBT); DebugPort.print(",");DebugPort.println(tWF);
DebugPort.printf("JSON times : %ld,%ld,%ld\r\n", tJSON, tBT, tWF);
}
}
// request timer refesh upon clients
@ -315,10 +364,21 @@ void updateJSONclients(bool report)
root.set("TimerRefresh", 1);
root.printTo(jsonStr, 800);
DebugPort.print("JSON send: "); DebugPort.println(jsonStr);
DebugPort.printf("JSON send: %s\r\n", jsonStr);
sendWebServerString( jsonStr );
getBluetoothClient().send( jsonStr );
}
// report MQTT params
{
if(makeJSONStringMQTT(MQTTmoderator, jsonStr, sizeof(jsonStr))) {
if (report) {
DebugPort.printf("JSON send: %s\r\n", jsonStr);
}
sendWebServerString( jsonStr );
getBluetoothClient().send( jsonStr );
}
}
}
@ -328,5 +388,10 @@ void resetJSONmoderator()
TimerModerator.reset();
}
void initMQTTJSONmoderator()
{
char jsonStr[800];
makeJSONStringMQTT(MQTTmoderator, jsonStr, sizeof(jsonStr));
}

View file

@ -31,6 +31,8 @@ bool makeJSONString(CModerator& moderator, char* opStr, int len);
bool makeJSONStringEx(CModerator& moderator, char* opStr, int len);
bool makeJSONTimerString(int channel, char* opStr, int len);
void updateJSONclients(bool report);
bool makeJSONStringMQTT(CModerator& moderator, char* opStr, int len);
void initMQTTJSONmoderator();
template<class T>
const char* createJSON(const char* name, T value)

View file

@ -81,7 +81,7 @@ int BoardDetect()
uint8_t revision = 0;
uint8_t val = preferences.getUChar("Board Revision", revision);
if(val != 0) {
DebugPort.print("Board detect: Using saved revision V"); DebugPort.println(float(val) * 0.1f, 1);
DebugPort.printf("Board detect: Using saved revision V%.1f\r\n", float(val) * 0.1f);
return val;
}
@ -117,6 +117,6 @@ int BoardDetect()
preferences.putUChar("Board Revision", revision);
}
DebugPort.print("Board detect: Result = V"); DebugPort.println(float(revision)*0.1f, 1);
DebugPort.printf("Board detect: Result = V%.1f\r\n", float(revision)*0.1f);
return revision;
}

View file

@ -98,3 +98,45 @@ CTimerModerator::reset(int timer)
}
}
bool
CStringModerator::shouldSend(const char* name, const char* value)
{
bool retval = true;
std::string sValue = value;
auto it = Memory.find(name);
if(it != Memory.end()) {
retval = it->second != sValue;
it->second = sValue;
}
else {
Memory[name] = sValue;
}
return retval;
}
bool
CStringModerator::addJson(const char* name, const char* value, JsonObject& root)
{
bool retval;
if( retval = shouldSend(name, value) ) {
root.set(name, value);
}
return retval;
}
void
CStringModerator::reset()
{
for(auto it = Memory.begin(); it != Memory.end(); ++it) {
Memory.erase(it);
}
}
void
CStringModerator::reset(const char* name)
{
auto it = Memory.find(name);
if(it != Memory.end()) {
Memory.erase(it);
}
}

View file

@ -39,6 +39,15 @@ public:
void reset(int channel);
};
class CStringModerator {
std::map<const char*, std::string> Memory;
public:
bool shouldSend(const char* name, const char* value);
bool addJson(const char* name, const char* value, JsonObject& root);
void reset();
void reset(const char* name);
};
template <class T>
class TModerator {
@ -79,12 +88,7 @@ template<class T>
void TModerator<T>::reset()
{
for(auto it = Memory.begin(); it != Memory.end(); ++it) {
if(std::is_pointer<T>::value) {
it->second = NULL;
}
else {
it->second = it->second+100;
}
it->second = it->second+100;
}
}
@ -93,13 +97,8 @@ void TModerator<T>::reset(const char* name)
{
auto it = Memory.find(name);
if(it != Memory.end()) {
DebugPort.print("Resetting moderator: \""); DebugPort.print(name); DebugPort.println("\"");
if(std::is_pointer<T>::value) {
it->second = NULL;
}
else {
it->second = it->second+100;
}
DebugPort.printf("Resetting moderator: \"%s\"", name);
it->second = it->second+100;
}
}
@ -107,7 +106,7 @@ class CModerator {
TModerator<int> iModerator;
TModerator<float> fModerator;
TModerator<unsigned char> ucModerator;
TModerator<const char*> szModerator;
CStringModerator szModerator;
public:
// integer values
bool shouldSend(const char* name, int value) {

View file

@ -375,6 +375,20 @@ CHeaterStorage::setHomeMenu(sHomeMenuActions val)
_calValues.Options.HomeMenu = val;
}
// MQTT parameter read/save
const sMQTTparams&
CHeaterStorage::getMQTTinfo() const
{
return _calValues.MQTT;
}
void
CHeaterStorage::setMQTTinfo(const sMQTTparams& info)
{
_calValues.MQTT = info;
}
///////////////////////////////////////////////////////////////////////////////////////
// ESP32
//
@ -402,6 +416,7 @@ CESP32HeaterStorage::load()
loadTimer(i);
}
loadUI();
loadMQTT();
}
void
@ -413,6 +428,7 @@ CESP32HeaterStorage::save()
saveTimer(i);
}
saveUI();
saveMQTT();
}
// **** MAX LENGTH is 15 for name and values ****
@ -533,16 +549,38 @@ CESP32HeaterStorage::saveUI()
preferences.end();
}
void
CESP32HeaterStorage::loadMQTT()
{
preferences.begin("mqtt", false);
validatedLoad("enabled", _calValues.MQTT.enabled, 0, u8inBounds, 0, 1);
validatedLoad("port", _calValues.MQTT.port, 0, u16inBounds, 0, 0xffff);
preferences.getString("host", _calValues.MQTT.host, 127);
preferences.getString("username", _calValues.MQTT.username, 31);
preferences.getString("password", _calValues.MQTT.password, 31);
preferences.end();
}
void
CESP32HeaterStorage::saveMQTT()
{
preferences.begin("mqtt", false);
preferences.putUChar("enabled", _calValues.MQTT.enabled);
preferences.putUShort("port", _calValues.MQTT.port);
preferences.putString("host", _calValues.MQTT.host);
preferences.putString("username", _calValues.MQTT.username);
preferences.putString("password", _calValues.MQTT.password);
preferences.end();
}
bool
CESP32HeaterStorage::validatedLoad(const char* key, uint8_t& val, int defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, int min, int max, uint8_t mask)
{
val = preferences.getUChar(key, defVal);
if(!validator(val & mask, min, max)) {
DebugPort.print("CESP32HeaterStorage::validatedLoad<uint8_t> invalid read ");
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
DebugPort.print(" validator("); DebugPort.print(min); DebugPort.print(","); DebugPort.print(max); DebugPort.print(") reset to ");
DebugPort.println(defVal);
DebugPort.printf("CESP32HeaterStorage::validatedLoad<uint8_t> invalid read %s=%d", key, val);
DebugPort.printf(" validator(%d,%d) reset to %d\r\n", min, max, defVal);
val = defVal;
preferences.putUChar(key, val);
@ -557,10 +595,8 @@ CESP32HeaterStorage::validatedLoad(const char* key, int8_t& val, int defVal, std
val = preferences.getChar(key, defVal);
if(!validator(val, min, max)) {
DebugPort.print("CESP32HeaterStorage::validatedLoad<uint8_t> invalid read ");
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
DebugPort.print(" validator("); DebugPort.print(min); DebugPort.print(","); DebugPort.print(max); DebugPort.print(") reset to ");
DebugPort.println(defVal);
DebugPort.printf("CESP32HeaterStorage::validatedLoad<int8_t> invalid read %s=%d", key, val);
DebugPort.printf(" validator(%d,%d) reset to %d\r\n", min, max, defVal);
val = defVal;
preferences.putChar(key, val);
@ -575,10 +611,8 @@ CESP32HeaterStorage::validatedLoad(const char* key, uint16_t& val, int defVal, s
val = preferences.getUShort(key, defVal);
if(!validator(val, min, max)) {
DebugPort.print("CESP32HeaterStorage::validatedLoad<uint16_t> invalid read ");
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
DebugPort.print(" validator("); DebugPort.print(min); DebugPort.print(","); DebugPort.print(max); DebugPort.print(") reset to ");
DebugPort.println(defVal);
DebugPort.printf("CESP32HeaterStorage::validatedLoad<uint16_t> invalid read %s=%d", key, val);
DebugPort.printf(" validator(%d,%d) reset to %d\r\n", min, max, defVal);
val = defVal;
preferences.putUShort(key, val);
@ -593,10 +627,8 @@ CESP32HeaterStorage::validatedLoad(const char* key, long& val, long defVal, std:
val = preferences.getLong(key, defVal);
if(!validator(val, min, max)) {
DebugPort.print("CESP32HeaterStorage::validatedLoad<long> invalid read ");
DebugPort.print(key); DebugPort.print("="); DebugPort.print(val);
DebugPort.print(" validator("); DebugPort.print(min); DebugPort.print(","); DebugPort.print(max); DebugPort.print(") reset to ");
DebugPort.println(defVal);
DebugPort.printf("CESP32HeaterStorage::validatedLoad<long> invalid read %s=%ld", key, val);
DebugPort.printf(" validator(%ld,%ld) reset to %ld\r\n", min, max, defVal);
val = defVal;
preferences.putLong(key, val);

View file

@ -103,6 +103,31 @@ struct sCyclicThermostat {
}
};
struct sMQTTparams {
uint8_t enabled;
uint16_t port;
char host[128];
char username[32];
char password[32];
void init() {
enabled = false;
port = 1234;
memset(host, 0, 128);
memset(username, 0, 32);
memset(password, 0, 32);
}
sMQTTparams& operator=(const sMQTTparams& rhs) {
enabled = rhs.enabled;
port = rhs.port;
memcpy(host, rhs.host, 128);
memcpy(username, rhs.username, 32);
memcpy(password, rhs.password, 32);
host[127] = 0;
username[31] = 0;
password[31] = 0;
}
};
struct sBTCoptions {
long dimTime;
long menuTimeout;
@ -154,6 +179,7 @@ struct sNVStore {
sHeater Heater;
sBTCoptions Options;
sTimer timer[14];
sMQTTparams MQTT;
bool valid();
void init();
};
@ -200,6 +226,7 @@ public:
unsigned char getWifiEnabled();
unsigned char getOTAEnabled();
const sCyclicThermostat& getCyclicMode() const;
const sMQTTparams& getMQTTinfo() const;
GPIOinModes getGPIOinMode();
GPIOoutModes getGPIOoutMode();
GPIOalgModes getGPIOalgMode();
@ -231,11 +258,12 @@ public:
void getTimerInfo(int idx, sTimer& timerInfo);
void setTimerInfo(int idx, const sTimer& timerInfo);
void setMQTTinfo(const sMQTTparams& info);
};
#ifdef ESP32
//#ifdef ESP32
#include <Preferences.h>
#include <functional>
@ -254,13 +282,15 @@ public:
void saveTimer(int idx);
void loadUI();
void saveUI();
void loadMQTT();
void saveMQTT();
bool validatedLoad(const char* key, int8_t& val, int defVal, std::function<bool(int8_t, int8_t, int8_t)> validator, int min, int max);
bool validatedLoad(const char* key, uint8_t& val, int defVal, std::function<bool(uint8_t, uint8_t, uint8_t)> validator, int min, int max, uint8_t mask=0xff);
bool validatedLoad(const char* key, uint16_t& val, int defVal, std::function<bool(uint16_t, uint16_t, uint16_t)> validator, int min, int max);
bool validatedLoad(const char* key, long& val, long defVal, std::function<bool(long, long, long)> validator, long min, long max);
};
#endif
//#endif
extern CHeaterStorage& NVstore;

View file

@ -38,7 +38,7 @@ CommStates::set(eCS eState)
"BTC_Tx", "HeaterRx2", "HeaterValidate2", "HeaterReport2", "TemperatureRead"
};
if(_State == Idle) DebugPort.println(""); // clear screen
DebugPort.print("State:");DebugPort.println(stateNames[_State]);
DebugPort.printf("State: %s\r\n", stateNames[_State]);
}
}

View file

@ -62,7 +62,7 @@ public:
void setDelay(int ms);
bool delayExpired();
bool toggleReporting() { _report = !_report; };
bool isReporting() {return _report != 0;};
};
@ -124,22 +124,18 @@ public:
refTime = millis();
};
void report(bool isDelta) {
char msg[32];
if(isDelta) {
long delta = millis() - prevTime;
sprintf(msg, "%+8ldms ", delta);
DebugPort.printf("%+8ldms ", delta);
}
else {
prevTime = millis();
sprintf(msg, "%8dms ", prevTime - refTime);
DebugPort.printf("%8ldms ", prevTime - refTime);
}
DebugPort.print(msg);
};
void report() {
char msg[32];
prevTime = millis();
sprintf(msg, "%8dms ", prevTime - refTime);
DebugPort.print(msg);
DebugPort.printf("%8dlms ", prevTime - refTime);
};
};

View file

@ -90,7 +90,6 @@ void handleBTCRoot() {
}
#endif
void handleWMConfig() {
server.send(200, "text/plain", "Start Config Portal - Retaining credential");
DebugPort.println("Starting web portal for wifi config");
@ -138,6 +137,8 @@ void handleBTCNotFound() {
digitalWrite(led, 0);
}
const char* serverIndex = "<form method='POST' action='/updatenow' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
void initWebServer(void) {
@ -150,6 +151,44 @@ void initWebServer(void) {
server.on("/wmconfig", handleWMConfig);
server.on("/resetwifi", handleReset);
server.on("/formatspiffs", handleFormat);
// magical code shaemlessly lifted from Arduino WebUpdate example, slightly modified in paths
// this allows pushing new firmware to the ESP via OTA from a WEB BROWSER!
//
// Initial launch page
server.on("/update", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
// actual guts that manages the new firmware upload
server.on("/updatenow", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
DebugPort.setDebugOutput(true);
DebugPort.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin()) { //start with max available size
Update.printError(DebugPort);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(DebugPort);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
DebugPort.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(DebugPort);
}
DebugPort.setDebugOutput(false);
} else {
DebugPort.printf("Update Failed Unexpectedly (likely broken connection): status=%d\n", upload.status);
}
});
#if USE_SPIFFS == 1
// NOTE: this serves the default home page, and favicon.ico
server.onNotFound([]()
@ -199,7 +238,7 @@ bool sendWebServerString(const char* Str)
bTxWebData = true; // OLED tx data animation flag
webSocket.broadcastTXT(Str);
unsigned long tWeb = millis() - tStart;
// DebugPort.print("Websend times : "); DebugPort.print(tCon); DebugPort.print(","); DebugPort.println(tWeb);
// DebugPort.printf("Websend times : %ld,%ld\r\n", tCon, tWeb);
return true;
}
return false;

View file

@ -35,6 +35,7 @@
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
#include <WebSocketsServer.h>

View file

@ -59,10 +59,10 @@ bool initWifi(int initpin,const char *failedssid, const char *failedpassword)
uint8_t MAC[6];
esp_read_mac(MAC, ESP_MAC_WIFI_STA);
sprintf(MACstr[0], "%02X:%02X:%02X:%02X:%02X:%02X", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
DebugPort.print(" STA MAC address: "); DebugPort.println(MACstr[0]);
DebugPort.printf(" STA MAC address: %s\r\n", MACstr[0]);
esp_read_mac(MAC, ESP_MAC_WIFI_SOFTAP);
sprintf(MACstr[1], "%02X:%02X:%02X:%02X:%02X:%02X", MAC[0], MAC[1], MAC[2], MAC[3], MAC[4], MAC[5]);
DebugPort.print(" AP MAC address: "); DebugPort.println(MACstr[1]);
DebugPort.printf(" AP MAC address: %s\r\n", MACstr[1]);
char APname[32];
sprintf(APname, "%s", failedssid);
@ -99,7 +99,7 @@ bool initWifi(int initpin,const char *failedssid, const char *failedpassword)
// bool res = wm.autoConnect(failedssid, failedpassword); // auto generated AP name from chipid
bool res = wm.autoConnect(APname, failedpassword); // auto generated AP name from chipid
DebugPort.print("WifiMode after autoConnect = "); DebugPort.println(WiFi.getMode());
DebugPort.printf("WifiMode after autoConnect = "); DebugPort.println(WiFi.getMode());
int chnl = 1;
bool retval = false;
@ -113,10 +113,10 @@ bool initWifi(int initpin,const char *failedssid, const char *failedpassword)
// if you get here you have connected to the WiFi
isSTA = true;
DebugPort.println("WiFiManager connected in STA mode OK");
DebugPort.print(" STA IP address: "); DebugPort.println(WiFi.localIP());
DebugPort.printf(" STA IP address: %s\r\n", WiFi.localIP());
// must use same radio channel as STA to go to STA+AP, otherwise we drop the STA!
chnl = WiFi.channel();
DebugPort.print("Now promoting to STA+AP mode");
DebugPort.println("Now promoting to STA+AP mode...");
retval = true;
}
#ifdef USE_AP
@ -127,9 +127,9 @@ bool initWifi(int initpin,const char *failedssid, const char *failedpassword)
// WiFi.softAP(failedssid, failedpassword, chnl);
WiFi.softAP(APname, failedpassword, chnl);
WiFi.enableAP(true);
DebugPort.print(" AP SSID: "); DebugPort.println(WiFi.softAPgetHostname());
DebugPort.print(" AP IP address: "); DebugPort.println(WiFi.softAPIP());
DebugPort.print("WifiMode after initWifi = "); DebugPort.println(WiFi.getMode());
DebugPort.printf(" AP SSID: %s\r\n", WiFi.softAPgetHostname());
DebugPort.printf(" AP IP address: %s\r\n", WiFi.softAPIP());
DebugPort.printf("WifiMode after initWifi = %d\r\n", WiFi.getMode());
#endif
// even though we may have started in STA mode - start the config portal if demanded via the NV flag
@ -177,7 +177,7 @@ void doWiFiManager()
if(pinDown) {
pinDown = false;
tDelta = millis() - pinTime;
DebugPort.print("Wifi config button tDelta = "); DebugPort.println(tDelta);
DebugPort.printf("Wifi config button tDelta = %ld\r\n", tDelta);
// > 5 second press?
if(tDelta > 5000) {
wifiEnterConfigPortal(true, true); // very long press - clear credentials, reboot into portal
@ -311,7 +311,7 @@ void prepBootIntoConfigPortal(bool state)
NV.begin("user");
NV.putBool("bootPortal", state);
NV.end();
DebugPort.print("Setting boot config portal if WiFiManager fails = "); DebugPort.println(state);
DebugPort.printf("Setting boot config portal if WiFiManager fails = %d\r\n", state);
}
// test the NV flag whether the config portal should run after reboot
@ -321,7 +321,7 @@ bool shouldBootIntoConfigPortal()
NV.begin("user");
bool retval = NV.getBool("bootPortal", false);
NV.end();
DebugPort.print("Boot config portal if WiFiManager fails = "); DebugPort.println(retval);
DebugPort.printf("Boot config portal if WiFiManager fails = %d\r\n", retval);
return retval;
}

Binary file not shown.