diff --git a/src/ArduinoLog.cpp b/src/ArduinoLog.cpp new file mode 100644 index 00000000..51336c61 --- /dev/null +++ b/src/ArduinoLog.cpp @@ -0,0 +1,166 @@ +/* + _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ + /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| + / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | + /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| + + Log library for Arduino + version 1.0.3 + https://github.com/thijse/Arduino-Log + +Licensed under the MIT License . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "ArduinoLog.h" + +void Logging::begin(int level, Print * logOutput, bool showLevel) +{ +#ifndef DISABLE_LOGGING + setLevel(level); + setShowLevel(showLevel); + _logOutput = logOutput; +#endif +} + +void Logging::setLevel(int level) +{ +#ifndef DISABLE_LOGGING + _level = constrain(level, LOG_LEVEL_SILENT, LOG_LEVEL_VERBOSE); +#endif +} + +int Logging::getLevel() const +{ +#ifndef DISABLE_LOGGING + return _level; +#else + return 0; +#endif +} + +void Logging::setShowLevel(bool showLevel) +{ +#ifndef DISABLE_LOGGING + _showLevel = showLevel; +#endif +} + +bool Logging::getShowLevel() const +{ +#ifndef DISABLE_LOGGING + return _showLevel; +#else + return false; +#endif +} + +void Logging::setPrefix(printfunction f) +{ +#ifndef DISABLE_LOGGING + _prefix = f; +#endif +} + +void Logging::setSuffix(printfunction f) +{ +#ifndef DISABLE_LOGGING + _suffix = f; +#endif +} + +void Logging::print(const __FlashStringHelper * format, va_list args) +{ +#ifndef DISABLE_LOGGING + PGM_P p = reinterpret_cast(format); + char c = pgm_read_byte(p++); + for(; c != 0; c = pgm_read_byte(p++)) { + if(c == '%') { + c = pgm_read_byte(p++); + printFormat(c, &args); + } else { + _logOutput->print(c); + } + } +#endif +} + +void Logging::print(const char * format, va_list args) +{ +#ifndef DISABLE_LOGGING + for(; *format != 0; ++format) { + if(*format == '%') { + ++format; + printFormat(*format, &args); + } else { + _logOutput->print(*format); + } + } +#endif +} + +void Logging::printFormat(const char format, va_list * args) +{ +#ifndef DISABLE_LOGGING + if(format == '%') { + _logOutput->print(format); + } else if(format == 's') { + register char * s = (char *)va_arg(*args, int); + _logOutput->print(s); + } else if(format == 'S') { + register __FlashStringHelper * s = (__FlashStringHelper *)va_arg(*args, int); + _logOutput->print(s); + } else if(format == 'd' || format == 'i') { + _logOutput->print(va_arg(*args, int), DEC); + } else if(format == 'u') { + _logOutput->print(va_arg(*args, unsigned int), DEC); + } else if(format == 'D' || format == 'F') { + _logOutput->print(va_arg(*args, double)); + } else if(format == 'x') { + _logOutput->print(va_arg(*args, int), HEX); + } else if(format == 'X') { + _logOutput->print("0x"); + _logOutput->print(va_arg(*args, int), HEX); + } else if(format == 'b') { + _logOutput->print(va_arg(*args, int), BIN); + } else if(format == 'B') { + _logOutput->print("0b"); + _logOutput->print(va_arg(*args, int), BIN); + } else if(format == 'l') { + _logOutput->print(va_arg(*args, long), DEC); + } else if(format == 'c') { + _logOutput->print((char)va_arg(*args, int)); + } else if(format == 't') { + if(va_arg(*args, int) == 1) { + _logOutput->print("T"); + } else { + _logOutput->print("F"); + } + } else if(format == 'T') { + if(va_arg(*args, int) == 1) { + _logOutput->print(F("true")); + } else { + _logOutput->print(F("false")); + } + } +#endif +} + +Logging Log = Logging(); diff --git a/src/ArduinoLog.h b/src/ArduinoLog.h new file mode 100644 index 00000000..56082bea --- /dev/null +++ b/src/ArduinoLog.h @@ -0,0 +1,298 @@ +/* + _ ___ ___ _ _ ___ _ _ ___ _ ___ ___ + /_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __| + / _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ | + /_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___| + + Log library for Arduino + version 1.0.3 + https://github.com/thijse/Arduino-Log + +Licensed under the MIT License . + +*/ + +#ifndef LOGGING_H +#define LOGGING_H +#include +#include +#if defined(ARDUINO) && ARDUINO >= 100 +#include "Arduino.h" +#else +#include "WProgram.h" +#endif +typedef void (*printfunction)(int level, Print *); + +//#include +//#include +// ************************************************************************* +// Uncomment line below to fully disable logging, and reduce project size +// ************************************************************************ +//#define DISABLE_LOGGING + +#define LOG_LEVEL_SILENT 0 +#define LOG_LEVEL_FATAL 1 +#define LOG_LEVEL_ERROR 2 +#define LOG_LEVEL_WARNING 3 +#define LOG_LEVEL_NOTICE 4 +#define LOG_LEVEL_TRACE 5 +#define LOG_LEVEL_VERBOSE 6 + +#define CR "\n" +#define LOGGING_VERSION 1_0_3 + +/** + * Logging is a helper class to output informations over + * RS232. If you know log4j or log4net, this logging class + * is more or less similar ;-)
+ * Different loglevels can be used to extend or reduce output + * All methods are able to handle any number of output parameters. + * All methods print out a formated string (like printf).
+ * To reduce output and program size, reduce loglevel. + * + * Output format string can contain below wildcards. Every wildcard + * must be start with percent sign (\%) + * + * ---- Wildcards + * + * %s replace with an string (char*) + * %c replace with an character + * %d replace with an integer value + * %l replace with an long value + * %x replace and convert integer value into hex + * %X like %x but combine with 0x123AB + * %b replace and convert integer value into binary + * %B like %x but combine with 0b10100011 + * %t replace and convert boolean value into "t" or "f" + * %T like %t but convert into "true" or "false" + * + * ---- Loglevels + * + * 0 - LOG_LEVEL_SILENT no output + * 1 - LOG_LEVEL_FATAL fatal errors + * 2 - LOG_LEVEL_ERROR all errors + * 3 - LOG_LEVEL_WARNING errors and warnings + * 4 - LOG_LEVEL_NOTICE errors, warnings and notices + * 5 - LOG_LEVEL_TRACE errors, warnings, notices, traces + * 6 - LOG_LEVEL_VERBOSE all + */ + +class Logging { + public: + /** + * default Constructor + */ + Logging() +#ifndef DISABLE_LOGGING + : _level(LOG_LEVEL_SILENT), _showLevel(true), _logOutput(NULL) +#endif + {} + + /** + * Initializing, must be called as first. Note that if you use + * this variant of Init, you need to initialize the baud rate + * yourself, if printer happens to be a serial port. + * + * \param level - logging levels <= this will be logged. + * \param printer - place that logging output will be sent to. + * \return void + * + */ + void begin(int level, Print * output, bool showLevel = true); + + /** + * Set the log level. + * + * \param level - The new log level. + * \return void + */ + void setLevel(int level); + + /** + * Get the log level. + * + * \return The current log level. + */ + int getLevel() const; + + /** + * Set whether to show the log level. + * + * \param showLevel - true if the log level should be shown for each log + * false otherwise. + * \return void + */ + void setShowLevel(bool showLevel); + + /** + * Get whether the log level is shown during logging + * + * \return true if the log level is be shown for each log + * false otherwise. + */ + bool getShowLevel() const; + + /** + * Sets a function to be called before each log command. + * + * \param f - The function to be called + * \return void + */ + void setPrefix(printfunction f); + + /** + * Sets a function to be called after each log command. + * + * \param f - The function to be called + * \return void + */ + void setSuffix(printfunction f); + + /** + * Output a fatal error message. Output message contains + * F: followed by original message + * Fatal error messages are printed out at + * loglevels >= LOG_LEVEL_FATAL + * + * \param msg format string to output + * \param ... any number of variables + * \return void + */ + template void fatal(T msg, Args... args) + { +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_FATAL, msg, args...); +#endif + } + + /** + * Output an error message. Output message contains + * E: followed by original message + * Error messages are printed out at + * loglevels >= LOG_LEVEL_ERROR + * + * \param msg format string to output + * \param ... any number of variables + * \return void + */ + template void error(T msg, Args... args) + { +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_ERROR, msg, args...); +#endif + } + + /** + * Output a warning message. Output message contains + * W: followed by original message + * Warning messages are printed out at + * loglevels >= LOG_LEVEL_WARNING + * + * \param msg format string to output + * \param ... any number of variables + * \return void + */ + template void warning(T msg, Args... args) + { +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_WARNING, msg, args...); +#endif + } + + /** + * Output a notice message. Output message contains + * N: followed by original message + * Notice messages are printed out at + * loglevels >= LOG_LEVEL_NOTICE + * + * \param msg format string to output + * \param ... any number of variables + * \return void + */ + template void notice(T msg, Args... args) + { +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_NOTICE, msg, args...); +#endif + } + + /** + * Output a trace message. Output message contains + * N: followed by original message + * Trace messages are printed out at + * loglevels >= LOG_LEVEL_TRACE + * + * \param msg format string to output + * \param ... any number of variables + * \return void + */ + template void trace(T msg, Args... args) + { +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_TRACE, msg, args...); +#endif + } + + /** + * Output a verbose message. Output message contains + * V: followed by original message + * Debug messages are printed out at + * loglevels >= LOG_LEVEL_VERBOSE + * + * \param msg format string to output + * \param ... any number of variables + * \return void + */ + template void verbose(T msg, Args... args) + { +#ifndef DISABLE_LOGGING + printLevel(LOG_LEVEL_VERBOSE, msg, args...); +#endif + } + + private: + void print(const char * format, va_list args); + + void print(const __FlashStringHelper * format, va_list args); + + void printFormat(const char format, va_list * args); + + template void printLevel(int level, T msg, ...) + { +#ifndef DISABLE_LOGGING + if(level > _level) { + return; + } + + if(_prefix != NULL) { + _prefix(level, _logOutput); + } + + if(_showLevel) { + static const char levels[] = "FEWNTV"; + _logOutput->print(levels[level - 1]); + _logOutput->print(": "); + } + + va_list args; + va_start(args, msg); + print(msg, args); + + if(_suffix != NULL) { + _suffix(level, _logOutput); + } +#endif + } + +#ifndef DISABLE_LOGGING + int _level; + bool _showLevel; + Print * _logOutput; + + printfunction _prefix = NULL; + printfunction _suffix = NULL; +#endif +}; + +extern Logging Log; +#endif \ No newline at end of file diff --git a/src/hasp_config.cpp b/src/hasp_config.cpp index 7d283ce8..5828fb97 100644 --- a/src/hasp_config.cpp +++ b/src/hasp_config.cpp @@ -1,5 +1,6 @@ #include "Arduino.h" #include "ArduinoJson.h" +#include "ArduinoLog.h" #include // Include the SPIFFS library #if defined(ARDUINO_ARCH_ESP32) @@ -7,24 +8,28 @@ #endif #include "hasp_config.h" -#include "hasp_log.h" +//#include "hasp_log.h" #include "hasp_debug.h" #include "hasp_http.h" -#include "hasp_mqtt.h" #include "hasp_wifi.h" #include "hasp_mdns.h" #include "hasp_gui.h" -// #include "hasp_tft.h" #include "hasp_ota.h" #include "hasp_spiffs.h" #include "hasp_telnet.h" #include "hasp.h" +#include "hasp_conf.h" +#if HASP_USE_MQTT +#include "hasp_mqtt.h" +#endif + void confDebugSet(const char * name) { - char buffer[128]; + /*char buffer[128]; snprintf(buffer, sizeof(buffer), PSTR("CONF: * %s set"), name); - debugPrintln(buffer); + debugPrintln(buffer);*/ + Log.trace(F("CONF: * %s set"), name); } bool configSet(int8_t & value, const JsonVariant & setting, const char * name) @@ -64,26 +69,14 @@ bool configSet(uint16_t & value, const JsonVariant & setting, const char * name) return false; } -bool configChanged() -{ - return false; -} - -void configLoop() -{ - if(configChanged()) { - // configSetConfig(); - } -} - void configStartDebug(bool setupdebug, String & configFile) { if(setupdebug) { debugStart(); // Debug started, now we can use it; HASP header sent - debugPrintln(F("FILE: [SUCCESS] SPI flash FS mounted")); + Log.notice(F("FILE: [SUCCESS] SPI flash FS mounted")); spiffsList(); } - debugPrintln(String(F("CONF: Loading ")) + configFile); + Log.notice(F("CONF: Loading %s"), configFile.c_str()); } void configGetConfig(JsonDocument & settings, bool setupdebug = false) @@ -96,7 +89,7 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) if(file) { size_t size = file.size(); if(size > 1024) { - errorPrintln(F("CONF: %sConfig file size is too large")); + Log.error(F("CONF: Config file size is too large")); return; } @@ -105,7 +98,9 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) file.close(); /* Load Debug params */ - debugPreSetup(settings[F("debug")]); + if(setupdebug) { + debugPreSetup(settings[F("debug")]); + } configStartDebug(setupdebug, configFile); // show settings in log @@ -115,16 +110,16 @@ void configGetConfig(JsonDocument & settings, bool setupdebug = false) output.replace(settings[F("http")][F("pass")].as(), passmask); output.replace(settings[F("mqtt")][F("pass")].as(), passmask); output.replace(settings[F("wifi")][F("pass")].as(), passmask); - debugPrintln(String(F("CONF: ")) + output); + Log.verbose(F("CONF: %s"), output.c_str()); + Log.notice(F("CONF: [SUCCESS] Loaded %s"), configFile.c_str()); - debugPrintln(String(F("CONF: [SUCCESS] Loaded ")) + configFile); - debugSetup(settings[F("debug")]); + if(setupdebug) debugSetup(settings[F("debug")]); return; } } configStartDebug(setupdebug, configFile); - errorPrintln(String(F("CONF: %sFailed to load ")) + configFile); + Log.error(F("CONF: Failed to load %s"), configFile.c_str()); } void configWriteConfig() @@ -134,62 +129,56 @@ void configWriteConfig() configFile = String(FPSTR(HASP_CONFIG_FILE)); /* Read Config File */ - DynamicJsonDocument settings(2 * 1024); - debugPrintln(String(F("CONF: Config LOADING first ")) + configFile); + DynamicJsonDocument settings(1024 * 2); + Log.notice(F("CONF: Config LOADING first %s"), configFile.c_str()); configGetConfig(settings, false); - debugPrintln(String(F("CONF: Config LOADED first ")) + configFile); + Log.trace(F("CONF: Config LOADED first %s"), configFile.c_str()); bool changed = true; #if HASP_USE_WIFI changed |= wifiGetConfig(settings[F("wifi")].to()); - #if HASP_USE_MQTT changed |= mqttGetConfig(settings[F("mqtt")].to()); #endif - #if HASP_USE_TELNET changed |= telnetGetConfig(settings[F("telnet")].to()); #endif - #if HASP_USE_MDNS changed |= mdnsGetConfig(settings[F("mdns")].to()); #endif - #if HASP_USE_HTTP changed |= httpGetConfig(settings[F("http")].to()); #endif - #endif changed |= debugGetConfig(settings[F("debug")].to()); changed |= guiGetConfig(settings[F("gui")].to()); changed |= haspGetConfig(settings[F("hasp")].to()); // changed |= otaGetConfig(settings[F("ota")].to()); - // changed |= tftGetConfig(settings[F("tft")].to()); if(changed) { File file = SPIFFS.open(configFile, "w"); if(file) { - debugPrintln(String(F("CONF: Writing ")) + configFile); + Log.notice(F("CONF: Writing %s"), configFile.c_str()); size_t size = serializeJson(settings, file); file.close(); if(size > 0) { - debugPrintln(String(F("CONF: [SUCCESS] Saved ")) + configFile); + Log.verbose(F("CONF: [SUCCESS] Saved %s"), configFile.c_str()); return; } } - errorPrintln(String(F("CONF: %sFailed to write ")) + configFile); + Log.error(F("CONF: Failed to write %s"), configFile.c_str()); } else { - debugPrintln(F("CONF: Configuration was not changed")); + Log.verbose(F("CONF: Configuration was not changed")); } } void configSetup(JsonDocument & settings) { if(!SPIFFS.begin()) { - errorPrintln(F("FILE: %sSPI flash init failed. Unable to mount FS.")); + Log.error(F("FILE: SPI flash init failed. Unable to mount FS.")); } else { configGetConfig(settings, true); } @@ -212,5 +201,5 @@ void configOutput(const JsonObject & settings) password += F("\""); if(password.length() > 2) output.replace(password, passmask); - debugPrintln(String(F("CONF: ")) + output); + Log.trace(F("CONF: %s"), output.c_str()); } \ No newline at end of file diff --git a/src/hasp_debug.cpp b/src/hasp_debug.cpp index 6a2537b2..2350bbc2 100644 --- a/src/hasp_debug.cpp +++ b/src/hasp_debug.cpp @@ -3,6 +3,8 @@ #include "ArduinoJson.h" #include "lvgl.h" +#include "ArduinoLog.h" + #if defined(ARDUINO_ARCH_ESP8266) #include #else @@ -12,20 +14,22 @@ #include "hasp_log.h" #include "hasp_hal.h" +#include "hasp_mqtt.h" #include "hasp_debug.h" #include "hasp_config.h" #include "hasp_dispatch.h" -#if HASP_USE_TELNET != 0 -#include "hasp_telnet.h" -#endif - #ifdef USE_CONFIG_OVERRIDE #include "user_config_override.h" #endif #if HASP_USE_SYSLOG != 0 -#include +#include "Syslog.h" + +#if HASP_USE_TELNET != 0 +#include "hasp_telnet.h" +//#include "hasp_telnet.cpp" +#endif #ifndef SYSLOG_SERVER #define SYSLOG_SERVER "" @@ -37,9 +41,29 @@ #define APP_NAME "HASP" #endif -std::string debugAppName = APP_NAME; -std::string debugSyslogHost = SYSLOG_SERVER; +//#define TERM_COLOR_Black "\u001b[30m" +#define TERM_COLOR_GRAY "\e[37m" +#define TERM_COLOR_RED "\e[91m" +#define TERM_COLOR_GREEN "\e[92m" +#define TERM_COLOR_YELLOW "\e[93m" +#define TERM_COLOR_BLUE "\e[94m" +#define TERM_COLOR_MAGENTA "\e[35m" +#define TERM_COLOR_CYAN "\e[96m" +#define TERM_COLOR_WHITE "\e[97m" +#define TERM_COLOR_RESET "\e[0m" + +// unsigned char TERM_COLOR_CYAN[] = {27, '[', '3', '6', 'm'}; +// unsigned char TERM_COLOR_RESET[] = {27, '[', '0', 'm'}; + +const char * syslogAppName = APP_NAME; +char debugSyslogHost[32] = SYSLOG_SERVER; uint16_t debugSyslogPort = SYSLOG_PORT; +uint8_t debugSyslogFacility = 0; +uint8_t debugSyslogProtocol = 0; +uint16_t debugSerialBaud = 11520; // Multiplied by 10 +bool debugSerialStarted = false; + +extern char mqttNodeName[16]; // A UDP instance to let us send and receive packets over UDP WiFiUDP syslogClient; @@ -47,8 +71,7 @@ WiFiUDP syslogClient; // Create a new syslog instance with LOG_KERN facility // Syslog syslog(syslogClient, SYSLOG_SERVER, SYSLOG_PORT, MQTT_CLIENT, APP_NAME, LOG_KERN); // Create a new empty syslog instance -Syslog syslog(syslogClient, debugSyslogHost.c_str(), debugSyslogPort, debugAppName.c_str(), debugAppName.c_str(), - LOG_LOCAL0); +Syslog * syslog; #endif unsigned long debugLastMillis = 0; @@ -72,133 +95,226 @@ String debugHaspHeader() void debugStart() { -#if defined(ARDUINO_ARCH_ESP32) - Serial.begin(115200); /* prepare for possible serial debug */ -#else - Serial.begin(74880); /* prepare for possible serial debug */ -#endif - - Serial.flush(); - Serial.println(); - Serial.println(debugHaspHeader()); - Serial.flush(); + if(debugSerialStarted) { + Serial.flush(); + Serial.println(); + Serial.println(debugHaspHeader()); + Serial.flush(); + } // prepare syslog configuration here (can be anywhere before first call of // log/logf method) - -#if HASP_USE_SYSLOG != 0 - syslog.server(debugSyslogHost.c_str(), debugSyslogPort); - syslog.deviceHostname(debugAppName.c_str()); - syslog.appName(debugAppName.c_str()); - syslog.defaultPriority(LOG_LOCAL0); -#endif } -void serialPrintln(const char * debugText) +void serialPrintln(const char * debugText, uint8_t level) { + /* String debugTimeText((char *)0); debugTimeText.reserve(128); - debugTimeText = F("["); + uint8_t heapfrag = halGetHeapFragmentation(); + debugTimeText = F("["); debugTimeText += String(float(millis()) / 1000, 3); debugTimeText += F("s] "); debugTimeText += halGetMaxFreeBlock(); debugTimeText += F("/"); debugTimeText += ESP.getFreeHeap(); debugTimeText += F(" "); - debugTimeText += halGetHeapFragmentation(); + if(heapfrag < 10) debugTimeText += F(" "); + debugTimeText += heapfrag; debugTimeText += F(" "); #if LV_MEM_CUSTOM == 0 - /*lv_mem_monitor_t mem_mon; + lv_mem_monitor_t mem_mon; lv_mem_monitor(&mem_mon); + debugTimeText += F("| "); debugTimeText += mem_mon.used_pct; debugTimeText += F("% "); debugTimeText += mem_mon.free_biggest_size; debugTimeText += F("b/"); debugTimeText += mem_mon.free_size; - debugTimeText += F("b ");*/ + debugTimeText += F("b "); + debugTimeText += (mem_mon.total_size - mem_mon.free_size); + debugTimeText += F("b | "); #endif - Serial.print(debugTimeText); - Serial.println(debugText); + if(debugSerialStarted) { + // Serial.print(debugTimeText); + // Serial.println(debugText); + }*/ + + switch(level) { + case LOG_LEVEL_FATAL: + Log.fatal(debugText); + break; + case LOG_LEVEL_ERROR: + Log.error(debugText); + break; + case LOG_LEVEL_WARNING: + Log.warning(debugText); + break; + case LOG_LEVEL_VERBOSE: + Log.verbose(debugText); + break; + case LOG_LEVEL_TRACE: + Log.trace(debugText); + break; + default: + Log.notice(debugText); + } #if HASP_USE_TELNET != 0 - telnetPrint(debugTimeText.c_str()); + // telnetPrint(debugTimeText.c_str()); telnetPrintln(debugText); #endif } -void serialPrintln(String & debugText) +void serialPrintln(String & debugText, uint8_t level) { - serialPrintln(debugText.c_str()); + serialPrintln(debugText.c_str(), level); } #if HASP_USE_SYSLOG != 0 -void syslogSend(uint8_t log, const char * debugText) +void syslogSend(uint8_t priority, const char * debugText) { - if(WiFi.isConnected() && debugSyslogHost != "") { - switch(log) { - case 1: - syslog.log(LOG_WARNING, debugText); - break; - case 2: - syslog.log(LOG_ERR, debugText); - break; - default: - syslog.log(LOG_INFO, debugText); - } + if(strlen(debugSyslogHost) != 0 && WiFi.isConnected()) { + syslog->log(priority, debugText); } } #endif +void debugSetup(JsonObject settings) +{ + debugSetConfig(settings); + +#if HASP_USE_SYSLOG != 0 + syslog = new Syslog(syslogClient, debugSyslogProtocol == 0 ? SYSLOG_PROTO_IETF : SYSLOG_PROTO_BSD); + syslog->server(debugSyslogHost, debugSyslogPort); + syslog->deviceHostname(mqttNodeName); + syslog->appName(syslogAppName); + uint16_t priority = (uint16_t)(debugSyslogFacility + 16) << 3; // localx facility, x = 0-7 + syslog->defaultPriority(priority); +#endif +} + void debugStop() { - Serial.flush(); + if(debugSerialStarted) Serial.flush(); } bool debugGetConfig(const JsonObject & settings) { + settings[FPSTR(F_CONFIG_BAUD)] = debugSerialBaud; settings[FPSTR(F_DEBUG_TELEPERIOD)] = debugTelePeriod; +#if HASP_USE_SYSLOG != 0 + settings[FPSTR(F_CONFIG_HOST)] = debugSyslogHost; + settings[FPSTR(F_CONFIG_PORT)] = debugSyslogPort; + settings[FPSTR(F_CONFIG_PROTOCOL)] = debugSyslogProtocol; + settings[FPSTR(F_CONFIG_LOG)] = debugSyslogFacility; +#endif + configOutput(settings); return true; } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -bool debugSetConfigLog(const JsonObject & settings, bool silent) +bool debugSetConfig(const JsonObject & settings) { - if(!silent) configOutput(settings); + configOutput(settings); bool changed = false; - if(!settings[FPSTR(F_DEBUG_TELEPERIOD)].isNull()) { - uint16_t period = settings[FPSTR(F_DEBUG_TELEPERIOD)].as(); - if(debugTelePeriod != period) { - if(!silent) debugPrintln(F("debugTelePeriod set")); - debugTelePeriod = period; - changed = true; - } + /* Serial Settings*/ + changed |= configSet(debugSerialBaud, settings[FPSTR(F_CONFIG_BAUD)], PSTR("debugSerialBaud")); + + /* Teleperiod Settings*/ + changed |= configSet(debugTelePeriod, settings[FPSTR(F_DEBUG_TELEPERIOD)], PSTR("debugTelePeriod")); + + /* Syslog Settings*/ +#if HASP_USE_SYSLOG != 0 + if(!settings[FPSTR(F_CONFIG_HOST)].isNull()) { + changed |= strcmp(debugSyslogHost, settings[FPSTR(F_CONFIG_HOST)]) != 0; + strncpy(debugSyslogHost, settings[FPSTR(F_CONFIG_HOST)], sizeof(debugSyslogHost)); } + changed |= configSet(debugSyslogPort, settings[FPSTR(F_CONFIG_PORT)], PSTR("debugSyslogPort")); + changed |= configSet(debugSyslogProtocol, settings[FPSTR(F_CONFIG_PROTOCOL)], PSTR("debugSyslogProtocol")); + changed |= configSet(debugSyslogFacility, settings[FPSTR(F_CONFIG_LOG)], PSTR("debugSyslogFacility")); +#endif return changed; } -bool debugSetConfig(const JsonObject & settings) +void printTimestamp(int level, Print * _logOutput) { - return debugSetConfigLog(settings, false); + char c[128]; + int m = snprintf(c, sizeof(c), PSTR("[%10.3fs] %5u/%5u %2u | "), float(millis()) / 1000, halGetMaxFreeBlock(), + ESP.getFreeHeap(), halGetHeapFragmentation()); + +#if LV_MEM_CUSTOM == 0 + /* lv_mem_monitor_t mem_mon; + lv_mem_monitor(&mem_mon); + debugTimeText += F("| "); + debugTimeText += mem_mon.used_pct; + debugTimeText += F("% "); + debugTimeText += mem_mon.free_biggest_size; + debugTimeText += F("b/"); + debugTimeText += mem_mon.free_size; + debugTimeText += F("b "); + debugTimeText += (mem_mon.total_size - mem_mon.free_size); + debugTimeText += F("b | ");*/ +#endif + + _logOutput->print(TERM_COLOR_CYAN); + _logOutput->print(c); + switch(level) { + case LOG_LEVEL_FATAL: + case LOG_LEVEL_ERROR: + _logOutput->print(TERM_COLOR_RED); + break; + case LOG_LEVEL_WARNING: + _logOutput->print(TERM_COLOR_YELLOW); + break; + case LOG_LEVEL_NOTICE: + _logOutput->print(TERM_COLOR_WHITE); + break; + case LOG_LEVEL_VERBOSE: + _logOutput->print(TERM_COLOR_CYAN); + break; + case LOG_LEVEL_TRACE: + _logOutput->print(TERM_COLOR_GRAY); + break; + default: + _logOutput->print(TERM_COLOR_RESET); + } +} + +void printNewline(int level, Print * _logOutput) +{ + _logOutput->print(TERM_COLOR_MAGENTA); + _logOutput->print("\r\n"); } void debugPreSetup(JsonObject settings) { - debugSetConfigLog(settings, true); -} -void debugSetup(JsonObject settings) -{ - debugSetConfigLog(settings, false); + Log.begin(LOG_LEVEL_VERBOSE, &Serial, true); + Log.setPrefix(printTimestamp); // Uncomment to get timestamps as prefix + Log.setSuffix(printNewline); // Uncomment to get newline as suffix + + uint16_t baudrate = settings[FPSTR(F_CONFIG_BAUD)].as(); + if(baudrate > 0) { + Serial.begin(baudrate * 10); /* prepare for possible serial debug */ + debugSerialStarted = true; + } + + // Serial.begin(74880); /* prepare for possible serial debug */ + // Serial.begin(115200); } void debugLoop() +{} + +void debugEverySecond() { if(debugTelePeriod > 0 && (millis() - debugLastMillis) >= debugTelePeriod * 1000) { dispatchStatusUpdate(); diff --git a/src/hasp_debug.h b/src/hasp_debug.h index 5bc288db..262c0666 100644 --- a/src/hasp_debug.h +++ b/src/hasp_debug.h @@ -8,11 +8,12 @@ String debugHaspHeader(void); void debugPreSetup(JsonObject settings); void debugSetup(JsonObject settings); void debugLoop(void); +void debugEverySecond(void); void debugStart(void); void debugStop(void); -void serialPrintln(String & debugText); -void serialPrintln(const char * debugText); +void serialPrintln(String & debugText, uint8_t level); +void serialPrintln(const char * debugText, uint8_t level); void syslogSend(uint8_t log, const char * debugText); diff --git a/src/hasp_dispatch.cpp b/src/hasp_dispatch.cpp index 5060c0d0..57793a12 100644 --- a/src/hasp_dispatch.cpp +++ b/src/hasp_dispatch.cpp @@ -1,10 +1,10 @@ #include "StringStream.h" #include "ArduinoJson.h" +#include "ArduinoLog.h" #include "hasp_dispatch.h" #include "hasp_config.h" #include "hasp_debug.h" -#include "hasp_mqtt.h" #include "hasp_http.h" #include "hasp_mdns.h" #include "hasp_wifi.h" @@ -12,6 +12,22 @@ #include "hasp_gui.h" #include "hasp.h" +#include "hasp_conf.h" +#if HASP_USE_MQTT +#include "hasp_mqtt.h" +#endif + +void dispatchPrintln(String header, String & data) +{ + /* String message((char *)0); + message.reserve(128); + message = header; + message += F(": "); + message += data; + debugPrintln(message); */ + Log.notice(F("%s: %s"), header.c_str(), data.c_str()); +} + bool isON(const char * payload) { return strcmp_P(payload, PSTR("ON")) == 0; @@ -33,7 +49,9 @@ void dispatchLoop() void dispatchStatusUpdate() { +#if HASP_USE_MQTT mqttStatusUpdate(); +#endif } void dispatchOutput(int output, bool state) @@ -50,31 +68,44 @@ void dispatchOutput(int output, bool state) } } +void dispatchOutput(String strTopic, const char * payload) +{ + String strTemp((char *)0); + strTemp.reserve(128); + strTemp = strTopic.substring(7, strTopic.length()); + dispatchOutput(strTemp.toInt(), isON(payload)); +} + +void dispatchButtonAttribute(String & strTopic, const char * payload) +{ + String strPageId((char *)0); + String strTemp((char *)0); + + strPageId = strTopic.substring(2, strTopic.indexOf("]")); + strTemp = strTopic.substring(strTopic.indexOf("]") + 1, strTopic.length()); + + if(strTemp.startsWith(".b[")) { + String strObjId((char *)0); + String strAttr((char *)0); + + strObjId = strTemp.substring(3, strTemp.indexOf("]")); + strAttr = strTemp.substring(strTemp.indexOf("]") + 1, strTemp.length()); + // debugPrintln(strPageId + " && " + strObjId + " && " + strAttr); + + int pageid = strPageId.toInt(); + int objid = strObjId.toInt(); + + if(pageid >= 0 && pageid <= 255 && objid >= 0 && objid <= 255) { + haspProcessAttribute((uint8_t)pageid, (uint8_t)objid, strAttr, payload); + } // valid page + } +} + // objectattribute=value void dispatchAttribute(String & strTopic, const char * payload) { if(strTopic.startsWith("p[")) { - String strPageId((char *)0); - String strTemp((char *)0); - - strPageId = strTopic.substring(2, strTopic.indexOf("]")); - strTemp = strTopic.substring(strTopic.indexOf("]") + 1, strTopic.length()); - - if(strTemp.startsWith(".b[")) { - String strObjId((char *)0); - String strAttr((char *)0); - - strObjId = strTemp.substring(3, strTemp.indexOf("]")); - strAttr = strTemp.substring(strTemp.indexOf("]") + 1, strTemp.length()); - // debugPrintln(strPageId + " && " + strObjId + " && " + strAttr); - - int pageid = strPageId.toInt(); - int objid = strObjId.toInt(); - - if(pageid >= 0 && pageid <= 255 && objid > 0 && objid <= 255) { - haspProcessAttribute((uint8_t)pageid, (uint8_t)objid, strAttr, payload); - } // valid page - } + dispatchButtonAttribute(strTopic, payload); } else if(strTopic.startsWith(F("output"))) { #if defined(ARDUINO_ARCH_ESP8266) uint8_t state = isON(payload) ? HIGH : LOW; @@ -97,27 +128,29 @@ void dispatchAttribute(String & strTopic, const char * payload) haspDisplayAP(String(F("HASP-ABC123")).c_str(), String(F("haspadmin")).c_str()); } else if(strTopic.length() == 7 && strTopic.startsWith(F("output"))) { - String strTemp((char *)0); - strTemp = strTopic.substring(7, strTopic.length()); - dispatchOutput(strTemp.toInt(), true); + dispatchOutput(strTopic, payload); } } void dispatchPage(String strPageid) { - debugPrintln("PAGE: " + strPageid); + dispatchPrintln(F("PAGE"), strPageid); if(strPageid.length() == 0) { } else { if(strPageid.toInt() <= 250) haspSetPage(strPageid.toInt()); } - String strPayload = String(haspGetPage()); - mqttSendState("page", strPayload.c_str()); + String strPage((char *)0); + strPage.reserve(128); + strPage = haspGetPage(); +#if HASP_USE_MQTT + mqttSendState("page", strPage.c_str()); +#endif } void dispatchClearPage(String strPageid) { - debugPrintln("Clear Page: " + strPageid); + dispatchPrintln(F("CLEAR"), strPageid); if(strPageid.length() == 0) { haspClearPage(haspGetPage()); @@ -130,30 +163,33 @@ void dispatchDim(String strDimLevel) { // Set the current state if(strDimLevel.length() != 0) guiSetDim(strDimLevel.toInt()); - debugPrintln("DIM: " + strDimLevel); + dispatchPrintln(F("DIM"), strDimLevel); // Return the current state String strPayload = String(guiGetDim()); +#if HASP_USE_MQTT mqttSendState("dim", strPayload.c_str()); +#endif } void dispatchBacklight(String strPayload) { strPayload.toUpperCase(); - debugPrintln("LIGHT: " + strPayload); + dispatchPrintln(F("LIGHT"), strPayload); // Set the current state if(strPayload.length() != 0) guiSetBacklight(isON(strPayload.c_str())); // Return the current state strPayload = getOnOff(guiGetBacklight()); +#if HASP_USE_MQTT mqttSendState("light", strPayload.c_str()); +#endif } void dispatchCommand(String cmnd) { - // cmnd.toLowerCase(); - debugPrintln("CMND: " + cmnd); + dispatchPrintln(F("CMND"), cmnd); if(cmnd.startsWith(F("page "))) { cmnd = cmnd.substring(5, cmnd.length()); @@ -236,18 +272,24 @@ void dispatchJsonl(char * strPayload) void dispatchIdle(const __FlashStringHelper * state) { +#if HASP_USE_MQTT mqttSendState(String(F("idle")).c_str(), String(state).c_str()); +#endif } void dispatchReboot(bool saveConfig) { if(saveConfig) configWriteConfig(); +#if HASP_USE_MQTT mqttStop(); // Stop the MQTT Client first +#endif debugStop(); delay(250); wifiStop(); - debugPrintln(F("STOP: Properly Rebooting the MCU now!")); - debugPrintln(F("-------------------------------------")); + // debugPrintln(F("STOP: Properly Rebooting the MCU now!")); + // debugPrintln(F("-------------------------------------")); + Log.notice(F("STOP: Properly Rebooting the MCU now!")); + Log.verbose(F("-------------------------------------")); ESP.restart(); delay(5000); } @@ -256,5 +298,7 @@ void dispatchButton(uint8_t id, char * event) { char buffer[128]; snprintf_P(buffer, sizeof(buffer), PSTR("INPUT%d"), id); +#if HASP_USE_MQTT mqttSendState(buffer, event); +#endif } \ No newline at end of file diff --git a/src/hasp_gui.h b/src/hasp_gui.h index d40bc61a..c0289f3f 100644 --- a/src/hasp_gui.h +++ b/src/hasp_gui.h @@ -16,7 +16,7 @@ void guiTakeScreenshot(ESP8266WebServer & client); void guiTakeScreenshot(WebServer & client); #endif // ESP32 -void guiSetup(TFT_eSPI & screen, JsonObject settings); +void guiSetup(JsonObject settings); void guiLoop(void); void guiStop(void); diff --git a/src/hasp_http.cpp b/src/hasp_http.cpp index 73618c78..62d9aaf9 100644 --- a/src/hasp_http.cpp +++ b/src/hasp_http.cpp @@ -1,4 +1,5 @@ -//#include "webServer.h" +#if 0 + #include "Arduino.h" #include "ArduinoJson.h" //#include "Update.h" @@ -18,12 +19,449 @@ #include "hasp_dispatch.h" #include "hasp.h" +#ifdef ESP32 +#include +#include +#elif defined(ESP8266) +#include +#include +#endif +#include + +AsyncWebServer webServer(80); + #if defined(ARDUINO_ARCH_ESP32) #include "SPIFFS.h" #endif #include #include +bool httpEnable = true; +bool webServerStarted = false; +uint16_t httpPort = 80; +FS * filesystem = &SPIFFS; +File fsUploadFile; +char httpUser[32] = ""; +char httpPassword[32] = ""; +// HTTPUpload * upload; +#define HTTP_PAGE_SIZE (6 * 256) + +const char MAIN_MENU_BUTTON[] PROGMEM = + "

"; +const char MIT_LICENSE[] PROGMEM = "
MIT License

"; + +const char HTTP_DOCTYPE[] PROGMEM = + ""; +const char HTTP_META_GO_BACK[] PROGMEM = ""; +const char HTTP_HEADER[] PROGMEM = "%s"; +const char HTTP_STYLE[] PROGMEM = + ""; +const char HTTP_SCRIPT[] PROGMEM = ""; +const char HTTP_HEADER_END[] PROGMEM = + "
"; + +// Additional CSS style to match Hass theme +const char HASP_STYLE[] PROGMEM = + ""; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// URL for auto-update "version.json" +const char UPDATE_URL[] PROGMEM = "http://haswitchplate.com/update/version.json"; +// Default link to compiled Arduino firmware image +String espFirmwareUrl = "http://haswitchplate.com/update/HASwitchPlate.ino.d1_mini.bin"; +// Default link to compiled Nextion firmware images +String lcdFirmwareUrl = "http://haswitchplate.com/update/HASwitchPlate.tft"; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +String getOption(int value, String label, bool selected) +{ + char buffer[128]; + snprintf_P(buffer, sizeof(buffer), PSTR(""), value, + (selected ? PSTR(" selected") : ""), label.c_str()); + return buffer; +} +String getOption(String value, String label, bool selected) +{ + char buffer[128]; + snprintf_P(buffer, sizeof(buffer), PSTR(""), value.c_str(), + (selected ? PSTR(" selected") : ""), label.c_str()); + return buffer; +} + +bool httpIsAuthenticated(AsyncWebServerRequest * request, const String & page) +{ + if(httpPassword[0] != '\0') { // Request HTTP auth if httpPassword is set + if(!request->authenticate(httpUser, httpPassword)) { + request->requestAuthentication(); + return false; + } + } + + char buffer[128]; + snprintf(buffer, sizeof(buffer), PSTR("HTTP: Sending %s page to client connected from: %s"), page.c_str(), + request->client()->remoteIP().toString().c_str()); + debugPrintln(buffer); + return true; +} + +void webSendFooter(AsyncResponseStream * response) +{ + response->print(F("")); +} + +void webHandleRoot(AsyncWebServerRequest * request) +{ + if(!httpIsAuthenticated(request, F("root"))) return; + AsyncResponseStream * response = request->beginResponseStream("text/html"); + + String nodename((char *)0); + nodename.reserve(128); + nodename = httpGetNodename(); + + response->print(F("

")); + response->print(nodename); + response->print(F("


")); + + response->print(F("

")); + response->print( + F("

")); + response->print(F("

")); + + response->print( + F("

")); + + if(SPIFFS.exists(F("/edit.htm.gz"))) { + response->print(F("

")); + } + + response->print( + F("

")); + + webSendFooter(response); + request->send(response); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void webHandleHaspConfig(AsyncWebServerRequest * request) +{ // http://plate01/config/http + if(!httpIsAuthenticated(request, F("config/hasp"))) return; + AsyncResponseStream * response = request->beginResponseStream("text/html"); + + DynamicJsonDocument settings(256); + haspGetConfig(settings.to()); + + String nodename((char *)0); + nodename.reserve(128); + nodename = httpGetNodename(); + + response->print(F("

")); + response->print(nodename); + response->print(F("


")); + + response->print(F("

")); + response->print(F("


")); + + response->print(F("
")); + response->print(F("

UI Theme (required)
")); + response->print( + F("Hue

")); + response->print(F("

Default Font

")); + + response->print(F("

Startup Layout (optional)
Startup Page (required)

Startup Brightness (required)

")); + + response->print(F("

")); + + response->print( + F("

")); + + webSendFooter(response); + request->send(response); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void webHandleScreenshot(AsyncWebServerRequest * request) +{ // http://plate01/screenshot + if(!httpIsAuthenticated(request, F("screenshot"))) return; + + if(request->hasArg(F("q"))) { + guiTakeScreenshot(request); + } else { + AsyncResponseStream * response = request->beginResponseStream("text/html"); + + String nodename((char *)0); + nodename.reserve(128); + nodename = httpGetNodename(); + + response->print(F("

")); + response->print(nodename); + response->print(F("


")); + + response->print(F("

")); + response->print(F("

print(F("el=document.getElementById('bmp');el.src='?q='+timestamp;return false;\">")); + response->print(F("

")); + // response->print( FPSTR(MAIN_MENU_BUTTON); + + webSendFooter(response); + request->send(response); + } +} +//////////////////////////////////////////////////////////////////////////////////////////////////// +void httpHandleNotFound(AsyncWebServerRequest * request) +{ // webServer 404 + // if(handleFileRead(webServer.uri())) return; + + debugPrintln(String(F("HTTP: Sending 404 to client connected from: ")) + request->client()->remoteIP().toString()); + + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + + httpMessage += F("File Not Found\n\nURI: "); + httpMessage += request->url(); + httpMessage += F("\nMethod: "); + httpMessage += (request->method() == HTTP_GET) ? F("GET") : F("POST"); + httpMessage += F("\nArguments: "); + httpMessage += request->args(); + httpMessage += "\n"; + for(uint8_t i = 0; i < request->args(); i++) { + httpMessage += " " + request->argName(i) + ": " + request->arg(i) + "\n"; + } + request->send(404, F("text/plain"), httpMessage); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void webHandleSaveConfig() +{ + // if(!httpIsAuthenticated(F("saveConfig"))) return; + + configWriteConfig(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void webHandleFirmware() +{ + // if(!httpIsAuthenticated(F("firmware"))) return; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void httpSetup(const JsonObject & settings) +{ + if(WiFi.getMode() == WIFI_AP) { + debugPrintln(F("HTTP: Wifi access point")); + // webServer.on(F("/"), webHandleWifiConfig); + } else { + + webServer.on(String(F("/")).c_str(), HTTP_GET, webHandleRoot); + webServer.on(String(F("/config/hasp")).c_str(), webHandleHaspConfig); + webServer.on(String(F("/screenshot")).c_str(), webHandleScreenshot); + + webServer.onNotFound(httpHandleNotFound); + + webServer.begin(); + + httpReconnect(); + debugPrintln(F("HTTP: Setup Complete")); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void httpReconnect() +{ + if(!httpEnable) return; + + if(webServerStarted) { + webServer.end(); + webServerStarted = false; + debugPrintln(F("HTTP: Server stoped")); + } else if(WiFi.status() == WL_CONNECTED || WiFi.getMode() == WIFI_AP) { + + /* + if(WiFi.getMode() == WIFI_AP) { + webServer.on(F("/"), webHandleWifiConfig); + webServer.on(F("/config"), webHandleConfig); + webServer.onNotFound(httpHandleNotFound); + } else { + } + */ + webServer.begin(); + webServerStarted = true; + + debugPrintln(String(F("HTTP: Server started @ http://")) + + (WiFi.getMode() == WIFI_AP ? WiFi.softAPIP().toString() : WiFi.localIP().toString())); + } +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void httpLoop() +{ + // if(httpEnable) webServer.handleClient(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +void httpEverySecond() +{ + if(httpEnable && !webServerStarted) httpReconnect(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// +bool httpGetConfig(const JsonObject & settings) +{ + settings[FPSTR(F_CONFIG_ENABLE)] = httpEnable; + settings[FPSTR(F_CONFIG_PORT)] = httpPort; + settings[FPSTR(F_CONFIG_USER)] = httpUser; + settings[FPSTR(F_CONFIG_PASS)] = httpPassword; + + configOutput(settings); + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +bool httpSetConfig(const JsonObject & settings) +{ + configOutput(settings); + bool changed = false; + + changed |= configSet(httpPort, settings[FPSTR(F_CONFIG_PORT)], PSTR("httpPort")); + + if(!settings[FPSTR(F_CONFIG_USER)].isNull()) { + changed |= strcmp(httpUser, settings[FPSTR(F_CONFIG_USER)]) != 0; + strncpy(httpUser, settings[FPSTR(F_CONFIG_USER)], sizeof(httpUser)); + } + + if(!settings[FPSTR(F_CONFIG_PASS)].isNull()) { + changed |= strcmp(httpPassword, settings[FPSTR(F_CONFIG_PASS)]) != 0; + strncpy(httpPassword, settings[FPSTR(F_CONFIG_PASS)], sizeof(httpPassword)); + } + + return changed; +} + +#else + +//#include "webServer.h" +#include "Arduino.h" +#include "ArduinoJson.h" +#include "ArduinoLog.h" +#include "lvgl.h" +#include "StringStream.h" + +#ifdef ESP32 +#include "Update.h" +#endif + +#include "hasp_conf.h" + +//#include "hasp_log.h" +#include "hasp_gui.h" +#include "hasp_hal.h" +#include "hasp_debug.h" +#include "hasp_http.h" +#include "hasp_wifi.h" +#include "hasp_spiffs.h" +#include "hasp_config.h" +#include "hasp_dispatch.h" +#include "hasp.h" + +#include "hasp_conf.h" +#if HASP_USE_MQTT +#include "hasp_mqtt.h" +#endif + +#if defined(ARDUINO_ARCH_ESP32) +#include "SPIFFS.h" +#include +#endif +#include +#include + bool httpEnable = true; bool webServerStarted = false; uint16_t httpPort = 80; @@ -52,7 +490,7 @@ const char MIT_LICENSE[] PROGMEM = "
MIT License

"; const char HTTP_DOCTYPE[] PROGMEM = ""; -const char HTTP_META_GO_BACK[] PROGMEM = ""; +const char HTTP_META_GO_BACK[] PROGMEM = ""; const char HTTP_HEADER[] PROGMEM = "%s"; const char HTTP_STYLE[] PROGMEM = ""; + "1px solid red;}input[type=checkbox]{width:20px;}input[type=radio]{width:20px;}"; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -94,6 +532,15 @@ String lcdFirmwareUrl = "http://haswitchplate.com/update/HASwitchPlate.tft"; //////////////////////////////////////////////////////////////////////////////////////////////////// void webHandleHaspConfig(); +static inline String httpGetNodename() +{ +#if HASP_USE_MQTT > 0 + return mqttGetNodename(); +#else + return "na"; +#endif +} + //////////////////////////////////////////////////////////////////////////////////////////////////// bool httpIsAuthenticated(const String & page) { @@ -104,10 +551,10 @@ bool httpIsAuthenticated(const String & page) } } - char buffer[128]; - snprintf(buffer, sizeof(buffer), PSTR("HTTP: Sending %s page to client connected from: %s"), page.c_str(), - webServer.client().remoteIP().toString().c_str()); - debugPrintln(buffer); + { + Log.verbose(F("HTTP: Sending %s page to client connected from: %s"), page.c_str(), + webServer.client().remoteIP().toString().c_str()); + } return true; } @@ -152,9 +599,9 @@ void webSendPage(String & nodename, uint32_t httpdatalength, bool gohome = false contentLength += sizeof(HTTP_END) - 1; contentLength += sizeof(HTTP_FOOTER) - 1; - snprintf_P(buffer, sizeof(buffer), PSTR("HTTP: Sending page with %u static and %u dynamic bytes"), contentLength, - httpdatalength); - debugPrintln(buffer); + if(httpdatalength > HTTP_PAGE_SIZE) { + Log.warning(F("HTTP: Sending page with %u static and %u dynamic bytes"), contentLength, httpdatalength); + } webServer.setContentLength(contentLength + httpdatalength); webServer.send_P(200, PSTR("text/html"), HTTP_DOCTYPE); // 122 @@ -171,7 +618,7 @@ void webSendPage(uint32_t httpdatalength, bool gohome = false) { String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); webSendPage(nodename, httpdatalength, gohome); } @@ -181,7 +628,7 @@ void webHandleRoot() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -218,7 +665,7 @@ void httpHandleReboot() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -241,16 +688,22 @@ void webHandleScreenshot() { // http://plate01/screenshot if(!httpIsAuthenticated(F("screenshot"))) return; - if(webServer.hasArg(F("q"))) { - webServer.setContentLength(122 + 320 * 240 * 2); - webServer.send(200, PSTR("image/bmp"), ""); + if(webServer.hasArg(F("a")) && webServer.arg(F("a")) == F("next")) { + uint8_t page = haspGetPage(); + haspSetPage(page + 1); + } + if(webServer.hasArg(F("a")) && webServer.arg(F("a")) == F("prev")) { + uint8_t page = haspGetPage(); + haspSetPage(page - 1); + } + if(webServer.hasArg(F("q"))) { guiTakeScreenshot(webServer); } else { String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -258,10 +711,16 @@ void webHandleScreenshot() httpMessage += nodename; httpMessage += F("
"); + httpMessage += + F(""); httpMessage += F("

"); - httpMessage += F("

"); - httpMessage += F("

"); + httpMessage += + F("

"); + httpMessage += F("

"); + httpMessage += F("

"); httpMessage += FPSTR(MAIN_MENU_BUTTON); webSendPage(nodename, httpMessage.length(), false); @@ -279,7 +738,7 @@ void webHandleAbout() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -295,15 +754,18 @@ void webHandleAbout() httpMessage += FPSTR(MIT_LICENSE); httpMessage += F("

zi Font Engine

Copyright© 2020 Francis Van Roie"); httpMessage += FPSTR(MIT_LICENSE); - httpMessage += F("

TFT_eSPI Library

Copyright© 2017 Bodmer (https://github.com/Bodmer) All " + httpMessage += F("

TFT_eSPI Library

Copyright© 2020 Bodmer (https://github.com/Bodmer) All " "rights reserved.
FreeBSD License

"); httpMessage += F("

includes parts from the Adafruit_GFX library
Copyright© 2012 Adafruit Industries. " "All rights reserved
BSD License

"); - httpMessage += F("

ArduinoJson

Copyright© 2014-2019 Benoit BLANCHON"); + httpMessage += F("

ArduinoJson

Copyright© 2014-2020 Benoit BLANCHON"); httpMessage += FPSTR(MIT_LICENSE); httpMessage += F("

PubSubClient

Copyright© 2008-2015 Nicholas O'Leary"); httpMessage += FPSTR(MIT_LICENSE); + httpMessage += F("

ArduinoLog

Copyright© 2017,2018 Thijs Elenbaas, MrRobot62, rahuldeo2047, NOX73, " + "dhylands, Josha blemasle, mfalkvidd"); + httpMessage += FPSTR(MIT_LICENSE); httpMessage += F("

Syslog

Copyright© 2016 Martin Sloup"); httpMessage += FPSTR(MIT_LICENSE); httpMessage += F("

QR Code generator

Copyright© Project Nayuki"); @@ -326,7 +788,7 @@ void webHandleInfo() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -342,7 +804,31 @@ void webHandleInfo() httpMessage += F(" "); httpMessage += __TIME__; httpMessage += F(" CET
Uptime: "); - httpMessage += String(long(millis() / 1000)); + + unsigned long time = millis() / 1000; + uint16_t day = time / 86400; + time = time % 86400; + uint8_t hour = time / 3600; + time = time % 3600; + uint8_t min = time / 60; + time = time % 60; + uint8_t sec = time; + + if(day > 0) { + httpMessage += String(day); + httpMessage += F("d "); + } + if(day > 0 || hour > 0) { + httpMessage += String(hour); + httpMessage += F("h "); + } + if(day > 0 || hour > 0 || min > 0) { + httpMessage += String(min); + httpMessage += F("m "); + } + httpMessage += String(sec); + httpMessage += F("s"); + httpMessage += F("
Free Memory: "); httpMessage += spiffsFormatBytes(ESP.getFreeHeap()); httpMessage += F("
Memory Fragmentation: "); @@ -359,7 +845,8 @@ void webHandleInfo() httpMessage += mem_mon.frag_pct; // httpMessage += F("
LCD Model: ")) + String(LV_HASP_HOR_RES_MAX) + " x " + - // String(LV_HASP_VER_RES_MAX); httpMessage += F("
LCD Version: ")) + String(lcdVersion); + // String(LV_HASP_VER_RES_MAX); httpMessage += F("
LCD Version: ")) + + // String(lcdVersion); httpMessage += F("

LCD Active Page: "); httpMessage += String(haspGetPage()); @@ -367,7 +854,23 @@ void webHandleInfo() httpMessage += F("

SSID: "); httpMessage += String(WiFi.SSID()); httpMessage += F("
Signal Strength: "); - httpMessage += String(WiFi.RSSI()); + + int8_t rssi = WiFi.RSSI(); + httpMessage += String(rssi); + httpMessage += F("dBm ("); + + if(rssi >= -50) { + httpMessage += F("Excellent)"); + } else if(rssi >= -60) { + httpMessage += F("Good)"); + } else if(rssi >= -70) { + httpMessage += F("Fair)"); + } else if(rssi >= -80) { + httpMessage += F("Weak)"); + } else { + httpMessage += F("Very Bad)"); + } + httpMessage += F("
IP Address: "); httpMessage += String(WiFi.localIP().toString()); httpMessage += F("
Gateway: "); @@ -377,7 +880,8 @@ void webHandleInfo() httpMessage += F("
MAC Address: "); httpMessage += String(WiFi.macAddress()); - /* Mqtt Stats */ +/* Mqtt Stats */ +#if HASP_USE_MQTT > 0 httpMessage += F("

MQTT Status: "); if(mqttIsConnected()) { // Check MQTT connection httpMessage += F("Connected"); @@ -387,14 +891,11 @@ void webHandleInfo() } httpMessage += F("
MQTT ClientID: "); httpMessage += nodename; +#endif /* ESP Stats */ - httpMessage += F("

ESP Chip Id: "); -#if defined(ARDUINO_ARCH_ESP32) - httpMessage += String(ESP.getChipRevision()); -#else - httpMessage += String(ESP.getChipId()); -#endif + httpMessage += F("

MCU Model: "); + httpMessage += halGetChipModel(); httpMessage += F("
CPU Frequency: "); httpMessage += String(ESP.getCpuFreqMHz()); httpMessage += F("MHz
Flash Chip Size: "); @@ -505,32 +1006,76 @@ bool handleFileRead(String path) return false; } -/* -void handleFirmwareUpdate() +static unsigned long htppLastLoopTime = 0; +void webUploadProgress() +{ + if(millis() - htppLastLoopTime >= 1250) { + Log.verbose(F(" * Uploaded %u bytes"), upload->totalSize + upload->currentSize); + htppLastLoopTime = millis(); + } +} + +void webUpdatePrintError() +{ + String output((char *)0); + output.reserve(128); + StringStream stream((String &)output); + Update.printError(stream); + Log.error(F("HTTP: %s"), output.c_str()); +} + +void webUpdateReboot() +{ + Log.notice(F("Update Success: %u bytes received. Rebooting..."), upload->totalSize); + + String nodename((char *)0); + nodename.reserve(128); + nodename = httpGetNodename(); + + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += nodename; + httpMessage += F("


"); + httpMessage += F("Upload complete. Rebooting device, please wait..."); + + webSendPage(nodename, httpMessage.length(), true); + webServer.sendContent(httpMessage); + httpMessage.clear(); + webSendFooter(); + + delay(250); + dispatchReboot(true); // Save the current config + delay(5000); +} + +void webHandleFirmwareUpdate() { upload = &webServer.upload(); if(upload->status == UPLOAD_FILE_START) { - if(!httpIsAuthenticated(F("firmwareupdate"))) return false; - Serial.printf("Update: %s\n", upload->filename.c_str()); - if(!Update.begin(UPDATE_SIZE_UNKNOWN)) { // start with max available size - Update.printError(Serial); + if(!httpIsAuthenticated(F("update"))) return; + Log.notice(F("Update: %s"), upload->filename.c_str()); + // WiFiUDP::stopAll(); + uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; + // if(!Update.begin(UPDATE_SIZE_UNKNOWN)) { // start with max available size + if(!Update.begin(maxSketchSpace)) { // start with max available size + webUpdatePrintError(); } } else if(upload->status == UPLOAD_FILE_WRITE) { - // flashing firmware to / -if(Update.write(upload->buf, upload->currentSize) != upload->currentSize) { - Update.printError(Serial); -} -} -else if(upload->status == UPLOAD_FILE_END) -{ - if(Update.end(true)) { // true to set the size to the current progress - Serial.printf("Update Success: %u\nRebooting...\n", upload->totalSize); - } else { - Update.printError(Serial); + // flashing firmware to ESP + if(Update.write(upload->buf, upload->currentSize) != upload->currentSize) { + webUpdatePrintError(); + } else { + webUploadProgress(); + } + } else if(upload->status == UPLOAD_FILE_END) { + if(Update.end(true)) { // true to set the size to the current progress + webUpdateReboot(); + } else { + webUpdatePrintError(); + } } } -} -*/ void handleFileUpload() { @@ -549,25 +1094,22 @@ void handleFileUpload() } if(filename.length() < 32) { fsUploadFile = filesystem->open(filename, "w"); - filename = String(F("handleFileUpload Name: ")) + filename; - debugPrintln(filename); + Log.notice(F("handleFileUpload Name: %s"), filename.c_str()); } else { - filename = String(F("%sFilename is too long: ")) + filename; - errorPrintln(filename); + Log.error(F("Filename %s is too long"), filename.c_str()); } } else if(upload->status == UPLOAD_FILE_WRITE) { // DBG_OUTPUT_PORT.print("handleFileUpload Data: "); debugPrintln(upload.currentSize); if(fsUploadFile) { - fsUploadFile.write(upload->buf, upload->currentSize); - char buffer[128]; - sprintf_P(buffer, PSTR(" * Uploaded %u bytes"), upload->totalSize + upload->currentSize); - debugPrintln(buffer); + if(fsUploadFile.write(upload->buf, upload->currentSize) != upload->currentSize) { + Log.error(F("HTTP: Failed to write received data to file")); + } else { + webUploadProgress(); // Moved to httpEverySecond Loop + } } } else if(upload->status == UPLOAD_FILE_END) { if(fsUploadFile) { - char buffer[128]; - sprintf_P(buffer, PSTR("Uploaded %s (%u bytes)"), fsUploadFile.name(), upload->totalSize); - debugPrintln(buffer); + Log.verbose(F("Uploaded %s (%u bytes)"), fsUploadFile.name(), upload->totalSize); fsUploadFile.close(); } @@ -589,7 +1131,7 @@ void handleFileDelete() return webServer.send_P(500, mimetype, PSTR("BAD ARGS")); } String path = webServer.arg(0); - debugPrintln(String(F("handleFileDelete: ")) + path); + Log.verbose(F("handleFileDelete: %s"), path.c_str()); if(path == "/") { return webServer.send_P(500, mimetype, PSTR("BAD PATH")); } @@ -609,7 +1151,7 @@ void handleFileCreate() return webServer.send(500, PSTR("text/plain"), PSTR("BAD ARGS")); } String path = webServer.arg(0); - debugPrintln(String(F("handleFileCreate: ")) + path); + Log.verbose(F("handleFileCreate: %s"), path.c_str()); if(path == "/") { return webServer.send(500, PSTR("text/plain"), PSTR("BAD PATH")); } @@ -636,7 +1178,7 @@ void handleFileList() } String path = webServer.arg(F("dir")); - debugPrintln(String(F("handleFileList: ")) + path); + Log.verbose(F("handleFileList: %s"), path.c_str()); path.clear(); #if defined(ARDUINO_ARCH_ESP32) @@ -703,8 +1245,10 @@ void webHandleConfig() if(save == String(PSTR("hasp"))) { haspSetConfig(settings.as()); +#if HASP_USE_MQTT > 0 } else if(save == String(PSTR("mqtt"))) { mqttSetConfig(settings.as()); +#endif } else if(save == String(PSTR("gui"))) { guiSetConfig(settings.as()); @@ -730,7 +1274,7 @@ void webHandleConfig() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -778,7 +1322,7 @@ void webHandleMqttConfig() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); DynamicJsonDocument settings(256); mqttGetConfig(settings.to()); @@ -832,7 +1376,7 @@ void webHandleGuiConfig() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -907,7 +1451,7 @@ void webHandleWifiConfig() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -949,7 +1493,7 @@ void webHandleHttpConfig() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -988,7 +1532,7 @@ void webHandleDebugConfig() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -997,11 +1541,41 @@ void webHandleDebugConfig() httpMessage += F("
"); httpMessage += F("
"); - httpMessage += F("

Telemetry Period "); + httpMessage += getOption(0, F("Disabled"), baudrate == 0); + httpMessage += getOption(960, F("9600"), baudrate == 960); + httpMessage += getOption(1920, F("19200"), baudrate == 1920); + httpMessage += getOption(3840, F("38400"), baudrate == 3840); + httpMessage += getOption(5760, F("57600"), baudrate == 5760); + httpMessage += getOption(7488, F("74880"), baudrate == 7488); + httpMessage += getOption(11520, F("115200"), baudrate == 11520); + httpMessage += F("

Telemetry Period (Seconds, 0=disable) " + "

"); - httpMessage += F("

"); + + httpMessage += F("Syslog Hostame (optional)
Syslog Port (optional) Syslog Facility
Syslog Protocol () == 0) httpMessage += F(" checked"); + httpMessage += F(">IETF (RFC 5424)   () == 1) httpMessage += F(" checked"); + httpMessage += F(">BSD (RFC 3164)"); + + httpMessage += F("

"); httpMessage += PSTR("

"); @@ -1022,7 +1596,7 @@ void webHandleHaspConfig() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -1122,7 +1696,7 @@ void httpHandleNotFound() { // webServer 404 if(handleFileRead(webServer.uri())) return; - debugPrintln(String(F("HTTP: Sending 404 to client connected from: ")) + webServer.client().remoteIP().toString()); + Log.notice(F("HTTP: Sending 404 to client connected from: %s"), webServer.client().remoteIP().toString().c_str()); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -1152,6 +1726,31 @@ void webHandleSaveConfig() void webHandleFirmware() { if(!httpIsAuthenticated(F("firmware"))) return; + + String nodename((char *)0); + nodename.reserve(128); + nodename = httpGetNodename(); + + String httpMessage((char *)0); + httpMessage.reserve(HTTP_PAGE_SIZE); + httpMessage += F("

"); + httpMessage += nodename; + httpMessage += F("


"); + + httpMessage += F("

"); + httpMessage += F("

"); + + httpMessage += F("

"); + httpMessage += F("

"); + + httpMessage += FPSTR(MAIN_MENU_BUTTON); + + webSendPage(nodename, httpMessage.length(), false); + webServer.sendContent(httpMessage); + httpMessage.clear(); + webSendFooter(); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1161,7 +1760,7 @@ void httpHandleEspFirmware() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -1177,7 +1776,7 @@ void httpHandleEspFirmware() httpMessage.clear(); webSendFooter(); - debugPrintln(String(F("HTTP: Attempting ESP firmware update from: ")) + String(webServer.arg("espFirmware"))); + Log.notice(F("HTTP: Attempting ESP firmware update from: %s"), webServer.arg("espFirmware").c_str()); // espStartOta(webServer.arg("espFirmware")); } @@ -1190,7 +1789,7 @@ void httpHandleResetConfig() String nodename((char *)0); nodename.reserve(128); - nodename = mqttGetNodename(); + nodename = httpGetNodename(); String httpMessage((char *)0); httpMessage.reserve(HTTP_PAGE_SIZE); @@ -1234,8 +1833,10 @@ void httpHandleResetConfig() //////////////////////////////////////////////////////////////////////////////////////////////////// void httpSetup(const JsonObject & settings) { + httpSetConfig(settings); + if(WiFi.getMode() == WIFI_AP) { - debugPrintln(F("HTTP: Wifi access point")); + Log.notice(F("HTTP: Wifi access point")); webServer.on(F("/"), webHandleWifiConfig); } else { @@ -1258,7 +1859,8 @@ void httpSetup(const JsonObject & settings) webServer.on(F("/edit"), HTTP_DELETE, handleFileDelete); // first callback is called after the request has ended with all parsed arguments // second callback handles file uploads at that location - webServer.on(F("/edit"), HTTP_POST, []() { webServer.send(200, "text/plain", ""); }, handleFileUpload); + webServer.on( + F("/edit"), HTTP_POST, []() { webServer.send(200, "text/plain", ""); }, handleFileUpload); // get heap status, analog input value and all GPIO statuses in one json call /*webServer.on(F("/all"), HTTP_GET, []() { String json; @@ -1292,6 +1894,8 @@ void httpSetup(const JsonObject & settings) webServer.on(F("/saveConfig"), webHandleSaveConfig); webServer.on(F("/resetConfig"), httpHandleResetConfig); webServer.on(F("/firmware"), webHandleFirmware); + webServer.on( + F("/update"), HTTP_POST, []() { webServer.send(200, "text/plain", ""); }, webHandleFirmwareUpdate); webServer.on(F("/espfirmware"), httpHandleEspFirmware); webServer.on(F("/reboot"), httpHandleReboot); webServer.onNotFound(httpHandleNotFound); @@ -1303,7 +1907,7 @@ void httpSetup(const JsonObject & settings) webServer.onNotFound(httpHandleNotFound); httpReconnect(); - debugPrintln(F("HTTP: Setup Complete")); + Log.verbose(F("HTTP: Setup Complete")); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -1314,22 +1918,13 @@ void httpReconnect() if(webServerStarted) { webServer.stop(); webServerStarted = false; - debugPrintln(F("HTTP: Server stoped")); + Log.warning(F("HTTP: Server stoped")); } else if(WiFi.status() == WL_CONNECTED || WiFi.getMode() == WIFI_AP) { - - /* - if(WiFi.getMode() == WIFI_AP) { - webServer.on(F("/"), webHandleWifiConfig); - webServer.on(F("/config"), webHandleConfig); - webServer.onNotFound(httpHandleNotFound); - } else { - } - */ webServer.begin(); webServerStarted = true; - - debugPrintln(String(F("HTTP: Server started @ http://")) + - (WiFi.getMode() == WIFI_AP ? WiFi.softAPIP().toString() : WiFi.localIP().toString())); + Log.notice( + F("HTTP: Server started @ http://%s"), + (WiFi.getMode() == WIFI_AP ? WiFi.softAPIP().toString().c_str() : WiFi.localIP().toString().c_str())); } } @@ -1340,7 +1935,7 @@ void httpLoop() } //////////////////////////////////////////////////////////////////////////////////////////////////// -void httpEverySecond() +void httpEvery5Seconds() { if(httpEnable && !webServerStarted) httpReconnect(); } @@ -1377,4 +1972,6 @@ bool httpSetConfig(const JsonObject & settings) } return changed; -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/hasp_log.cpp b/src/hasp_log.cpp index 02048709..77108129 100644 --- a/src/hasp_log.cpp +++ b/src/hasp_log.cpp @@ -1,5 +1,6 @@ #include "hasp_conf.h" #include +#include "ArduinoLog.h" #if defined(ARDUINO_ARCH_ESP8266) #include @@ -17,10 +18,10 @@ void debugPrintln(String & debugText) { - serialPrintln(debugText); + serialPrintln(debugText, LOG_LEVEL_NOTICE); #if HASP_USE_SYSLOG != 0 - syslogSend(0, debugText.c_str()); + syslogSend(LOG_INFO, debugText.c_str()); #endif } @@ -34,10 +35,10 @@ void debugPrintln(const __FlashStringHelper * debugText) void debugPrintln(const char * debugText) { - serialPrintln(debugText); + serialPrintln(debugText, LOG_LEVEL_NOTICE); #if HASP_USE_SYSLOG != 0 - syslogSend(0, debugText); + syslogSend(LOG_INFO, debugText); #endif } @@ -45,10 +46,10 @@ void errorPrintln(String debugText) { char buffer[128]; sprintf_P(buffer, debugText.c_str(), PSTR("[ERROR] ")); - serialPrintln(buffer); + serialPrintln(buffer, LOG_LEVEL_ERROR); #if HASP_USE_SYSLOG != 0 - syslogSend(2, buffer); + syslogSend(LOG_ERR, buffer); #endif } @@ -56,9 +57,9 @@ void warningPrintln(String debugText) { char buffer[128]; sprintf_P(buffer, debugText.c_str(), PSTR("[WARNING] ")); - serialPrintln(buffer); + serialPrintln(buffer, LOG_LEVEL_WARNING); #if HASP_USE_SYSLOG != 0 - syslogSend(1, buffer); + syslogSend(LOG_WARNING, buffer); #endif } \ No newline at end of file diff --git a/src/hasp_mqtt.cpp b/src/hasp_mqtt.cpp index fac72f2d..a44868a6 100644 --- a/src/hasp_mqtt.cpp +++ b/src/hasp_mqtt.cpp @@ -1,5 +1,13 @@ +#include "hasp_conf.h" +#if HASP_USE_MQTT + #include #include "ArduinoJson.h" +#include "ArduinoLog.h" +#include "PubSubClient.h" + +#include "hasp_conf.h" +#include "hasp_mqtt.h" #if defined(ARDUINO_ARCH_ESP32) #include @@ -8,9 +16,8 @@ #include #include #endif -#include -#include "hasp_log.h" +//#include "hasp_log.h" #include "hasp_hal.h" #include "hasp_debug.h" #include "hasp_config.h" @@ -32,12 +39,13 @@ String mqttCommandTopic; // MQTT topic for incoming panel commands String mqttGroupCommandTopic; // MQTT topic for incoming group panel commands String mqttStatusTopic; // MQTT topic for publishing device connectivity state String mqttSensorTopic; // MQTT topic for publishing device information in JSON format -*/ + String mqttLightCommandTopic; // MQTT topic for incoming panel backlight on/off commands String mqttLightStateTopic; // MQTT topic for outgoing panel backlight on/off state String mqttLightBrightCommandTopic; // MQTT topic for incoming panel backlight dimmer commands String mqttLightBrightStateTopic; // MQTT topic for outgoing panel backlight dimmer state // String mqttMotionStateTopic; // MQTT topic for outgoing motion sensor state +*/ #ifdef MQTT_NODENAME char mqttNodeName[16] = MQTT_NODENAME; @@ -51,9 +59,11 @@ char mqttGroupName[16] = MQTT_GROUPNAME; char mqttGroupName[16] = ""; #endif -String mqttClientId((char *)0); // Auto-generated MQTT ClientID -String mqttNodeTopic((char *)0); -String mqttGroupTopic((char *)0); +// String mqttClientId((char *)0); // Auto-generated MQTT ClientID +// String mqttNodeTopic((char *)0); +// String mqttGroupTopic((char *)0); +char mqttNodeTopic[24]; +char mqttGroupTopic[24]; bool mqttEnabled; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -99,29 +109,24 @@ void IRAM_ATTR mqttSendState(const char * subtopic, const char * payload) // light = 0/1 // brightness = 100 - // char mqttPayload[128 * 5]; - if(mqttClient.connected()) { - char mqttTopic[128]; - snprintf_P(mqttTopic, sizeof(mqttTopic), PSTR("%sstate/%s"), mqttNodeTopic.c_str(), subtopic); - mqttClient.publish(mqttTopic, payload); + char topic[128]; + snprintf_P(topic, sizeof(topic), PSTR("%sstate/%s"), mqttNodeTopic, subtopic); + mqttClient.publish(topic, payload); + Log.notice(F("MQTT OUT: %s = %s"), topic, payload); - String msg((char *)0); - msg.reserve(512); + // String msg((char *)0); + /* msg.reserve(256 + 128); msg = F("MQTT OUT: "); msg += mqttTopic; msg += " = "; msg += payload; debugPrintln(msg); + msg.clear(); + */ } else { - errorPrintln(F("MQTT: %sNot connected")); + Log.error(F("MQTT: Not connected")); } - - // as json - // snprintf_P(mqttTopic, sizeof(mqttTopic), PSTR("%sstate/json"), mqttNodeTopic.c_str()); - // snprintf_P(mqttPayload, sizeof(mqttPayload), PSTR("{\"%s\":\"%s\"}"), subtopic, payload); - // mqttClient.publish(mqttTopic, mqttPayload); - // debugPrintln(String(F("MQTT OUT: ")) + String(mqttTopic) + " = " + String(mqttPayload)); } void IRAM_ATTR mqttSendNewValue(uint8_t pageid, uint8_t btnid, const char * attribute, String txt) @@ -162,7 +167,7 @@ void mqttStatusUpdate() mqttStatusPayload += "{"; mqttStatusPayload += F("\"status\":\"available\","); - mqttStatusPayload += F("\"espVersion\":\""); + mqttStatusPayload += F("\"version\":\""); mqttStatusPayload += buffer; mqttStatusPayload += F("\","); /* if(updateEspAvailable) { @@ -183,31 +188,24 @@ void mqttStatusUpdate() } else { mqttStatusPayload += F("\"updateLcdAvailable\":false,"); }*/ - mqttStatusPayload += F("\"espUptime\":"); + mqttStatusPayload += F("\"uptime\":"); mqttStatusPayload += String(long(millis() / 1000)); mqttStatusPayload += F(","); - mqttStatusPayload += F("\"signalStrength\":"); + mqttStatusPayload += F("\"rssi\":"); mqttStatusPayload += String(WiFi.RSSI()); mqttStatusPayload += F(","); - mqttStatusPayload += F("\"haspIP\":\""); + mqttStatusPayload += F("\"ip\":\""); mqttStatusPayload += WiFi.localIP().toString(); mqttStatusPayload += F("\","); mqttStatusPayload += F("\"heapFree\":"); mqttStatusPayload += String(ESP.getFreeHeap()); mqttStatusPayload += F(","); - mqttStatusPayload += F("\"heapFragmentation\":"); + mqttStatusPayload += F("\"heapFrag\":"); mqttStatusPayload += String(halGetHeapFragmentation()); mqttStatusPayload += F(","); mqttStatusPayload += F("\"espCore\":\""); mqttStatusPayload += halGetCoreVersion(); mqttStatusPayload += F("\""); - -#if defined(ARDUINO_ARCH_ESP8266) - mqttStatusPayload += F(","); - mqttStatusPayload += F("\"Vcc\":\""); - mqttStatusPayload += (float)ESP.getVcc() / 1000; - mqttStatusPayload += F("\""); -#endif mqttStatusPayload += "}"; // mqttClient.publish(mqttSensorTopic, mqttStatusPayload); @@ -223,11 +221,22 @@ void mqttStatusUpdate() void mqttCallback(char * topic, byte * payload, unsigned int length) { // Handle incoming commands from MQTT payload[length] = '\0'; - String strTopic = topic; - // strTopic: homeassistant/haswitchplate/devicename/command/p[1].b[4].txt - // strPayload: "Lights On" - // subTopic: p[1].b[4].txt + String strTopic((char *)0); + strTopic.reserve(MQTT_MAX_PACKET_SIZE); + + Log.notice(F("MQTT IN: %s = %s"), topic, (char *)payload); + + /* Debug feedback */ + /* strTopic = F("MQTT IN: '"); + strTopic += topic; + strTopic += F("' : '"); + strTopic += (char *)payload; + strTopic += F("'"); + debugPrintln(strTopic); */ + + /* Reset the actual topic */ + strTopic = topic; // Incoming Namespace (replace /device/ with /group/ for group commands) // '[...]/device/command' -m '' = No command requested, respond with mqttStatusUpdate() @@ -244,12 +253,10 @@ void mqttCallback(char * topic, byte * payload, unsigned int length) // '[...]/device/command/p[1].b[4].txt' -m '' = nextionGetAttr("p[1].b[4].txt") // '[...]/device/command/p[1].b[4].txt' -m '"Lights On"' = nextionSetAttr("p[1].b[4].txt", "\"Lights On\"") - debugPrintln(String(F("MQTT IN: '")) + strTopic + "' : '" + (char *)payload + "'"); - if(strTopic.startsWith(mqttNodeTopic)) { - strTopic = strTopic.substring(mqttNodeTopic.length(), strTopic.length()); + strTopic = strTopic.substring(strlen(mqttNodeTopic), strTopic.length()); } else if(strTopic.startsWith(mqttGroupTopic)) { - strTopic = strTopic.substring(mqttGroupTopic.length(), strTopic.length()); + strTopic = strTopic.substring(strlen(mqttGroupTopic), strTopic.length()); } else { return; } @@ -278,77 +285,124 @@ void mqttCallback(char * topic, byte * payload, unsigned int length) return; } + /* String strPayload = (char *)payload; - if(strTopic == mqttLightBrightCommandTopic) { // change the brightness from the light topic - int panelDim = map(strPayload.toInt(), 0, 255, 0, 100); - // nextionSetAttr("dim", String(panelDim)); - // nextionSendCmd("dims=dim"); - // mqttClient.publish(mqttLightBrightStateTopic, strPayload); - } else if(strTopic == mqttLightCommandTopic && - strPayload == F("OFF")) { // set the panel dim OFF from the light topic, saving current dim level first - // nextionSendCmd("dims=dim"); - // nextionSetAttr("dim", "0"); - mqttClient.publish(mqttLightStateTopic.c_str(), PSTR("OFF")); - } else if(strTopic == mqttLightCommandTopic && - strPayload == F("ON")) { // set the panel dim ON from the light topic, restoring saved dim level - // nextionSendCmd("dim=dims"); - mqttClient.publish(mqttLightStateTopic.c_str(), PSTR("ON")); - } + if(strTopic == mqttLightBrightCommandTopic) { // change the brightness from the light topic + int panelDim = map(strPayload.toInt(), 0, 255, 0, 100); + // nextionSetAttr("dim", String(panelDim)); + // nextionSendCmd("dims=dim"); + // mqttClient.publish(mqttLightBrightStateTopic, strPayload); + } else if(strTopic == mqttLightCommandTopic && + strPayload == F("OFF")) { // set the panel dim OFF from the light topic, saving current dim level + first + // nextionSendCmd("dims=dim"); + // nextionSetAttr("dim", "0"); + mqttClient.publish(mqttLightStateTopic.c_str(), PSTR("OFF")); + } else if(strTopic == mqttLightCommandTopic && + strPayload == F("ON")) { // set the panel dim ON from the light topic, restoring saved dim level + // nextionSendCmd("dim=dims"); + mqttClient.publish(mqttLightStateTopic.c_str(), PSTR("ON")); + } + */ - if(strTopic == F("status") && - strPayload == F("OFF")) { // catch a dangling LWT from a previous connection if it appears + // catch a dangling LWT from a previous connection if it appears + if(strTopic == F("status") && strcmp_P((char *)payload, PSTR("OFF")) == 0) { char topicBuffer[128]; - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%sstatus"), mqttNodeTopic.c_str()); + snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%sstatus"), mqttNodeTopic); mqttClient.publish(topicBuffer, "ON", true); - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: binary_sensor state: [%sstatus] : ON"), - mqttNodeTopic.c_str()); - debugPrintln(topicBuffer); + Log.notice(F("MQTT: binary_sensor state: [status] : ON")); + // snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: binary_sensor state: [%sstatus] : ON"), + // mqttNodeTopic); debugPrintln(topicBuffer); return; } } +void mqttSubscribeTo(const char * format, const char * data) +{ + char buffer[128]; + char topic[128]; + snprintf_P(topic, sizeof(topic), format, data); + if(mqttClient.subscribe(topic)) { + Log.verbose(F("MQTT: * Subscribed to %s"), topic); + + // snprintf_P(buffer, sizeof(buffer), PSTR("MQTT: * Subscribed to %s"), topic); + // debugPrintln(buffer); + } else { + Log.error(F("MQTT: Failed to subscribe to %s"), topic); + + // snprintf_P(buffer, sizeof(buffer), PSTR("MQTT: %%sFailed to subscribe to %s"), topic); + // errorPrintln(buffer); + } +} + void mqttReconnect() { static uint8_t mqttReconnectCount = 0; bool mqttFirstConnect = true; - String nodeName((char *)0); - nodeName.reserve(128); - nodeName = haspGetNodename(); - char topicBuffer[128]; + char mqttClientId[128]; + char buffer[128]; - // Generate an MQTT client ID as haspNode + our MAC address - mqttClientId.reserve(128); - mqttClientId = nodeName; - mqttClientId += F("-"); - mqttClientId += wifiGetMacAddress(3, ""); - WiFi.macAddress(); - - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("hasp/%s/"), mqttNodeName); - mqttNodeTopic = topicBuffer; - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("hasp/%s/"), mqttGroupName); - mqttGroupTopic = topicBuffer; - - // haspSetPage(0); - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: Attempting connection to broker %s as clientID %s"), - mqttServer, mqttClientId.c_str()); - debugPrintln(topicBuffer); + snprintf(mqttClientId, sizeof(mqttClientId), PSTR("%s-%s"), mqttNodeName, wifiGetMacAddress(3, "").c_str()); + snprintf_P(mqttNodeTopic, sizeof(mqttNodeTopic), PSTR("hasp/%s/"), mqttNodeName); + snprintf_P(mqttGroupTopic, sizeof(mqttGroupTopic), PSTR("hasp/%s/"), mqttGroupName); // Attempt to connect and set LWT and Clean Session - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%sstatus"), mqttNodeTopic.c_str()); - if(!mqttClient.connect(mqttClientId.c_str(), mqttUser, mqttPassword, topicBuffer, 0, false, "OFF", true)) { + snprintf_P(buffer, sizeof(buffer), PSTR("%sstatus"), mqttNodeTopic); + if(!mqttClient.connect(mqttClientId, mqttUser, mqttPassword, buffer, 0, false, "OFF", true)) { // Retry until we give up and restart after connectTimeout seconds mqttReconnectCount++; + snprintf_P(buffer, sizeof(buffer), PSTR("MQTT: %%s")); + switch(mqttClient.state()) { + case MQTT_CONNECTION_TIMEOUT: + strcat_P(buffer, PSTR("Server didn't respond within the keepalive time")); + break; + case MQTT_CONNECTION_LOST: + strcat_P(buffer, PSTR("Network connection was broken")); + break; + case MQTT_CONNECT_FAILED: + strcat_P(buffer, PSTR("Network connection failed")); + break; + case MQTT_DISCONNECTED: + strcat_P(buffer, PSTR("Client is disconnected cleanly")); + break; + case MQTT_CONNECTED: + strcat_P(buffer, PSTR("(Client is connected")); + break; + case MQTT_CONNECT_BAD_PROTOCOL: + strcat_P(buffer, PSTR("Server doesn't support the requested version of MQTT")); + break; + case MQTT_CONNECT_BAD_CLIENT_ID: + strcat_P(buffer, PSTR("Server rejected the client identifier")); + break; + case MQTT_CONNECT_UNAVAILABLE: + strcat_P(buffer, PSTR("Server was unable to accept the connection")); + break; + case MQTT_CONNECT_BAD_CREDENTIALS: + strcat_P(buffer, PSTR("Username or Password rejected")); + break; + case MQTT_CONNECT_UNAUTHORIZED: + strcat_P(buffer, PSTR("Client was not authorized to connect")); + break; + default: + strcat_P(buffer, PSTR("Unknown failure")); + } + Log.warning(buffer); + // errorPrintln(buffer); - Serial.print(String(F("failed, rc="))); - Serial.print(mqttClient.state()); - // Wait 5 seconds before retrying - // delay(50); + if(mqttReconnectCount > 50) { + Log.error(F("MQTT: %sRetry count exceeded, rebooting...")); + // errorPrintln(F("MQTT: %sRetry count exceeded, rebooting...")); + dispatchReboot(false); + } return; } - debugPrintln(F("MQTT: MQTT Client is Connected")); + Log.notice(F("MQTT: [SUCCESS] Connected to broker %s as clientID %s"), mqttServer, mqttClientId); + /* snprintf_P(buffer, sizeof(buffer), PSTR("MQTT: [SUCCESS] Connected to broker %s as clientID %s"), mqttServer, + mqttClientId); + debugPrintln(buffer); */ haspReconnect(); /* @@ -374,46 +428,24 @@ void mqttReconnect() // Attempt to connect to broker, setting last will and testament // Subscribe to our incoming topics - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%scommand/#"), mqttGroupTopic.c_str()); - if(mqttClient.subscribe(topicBuffer)) { - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: * Subscribed to %scommand/#"), - mqttGroupTopic.c_str()); - debugPrintln(topicBuffer); - } + mqttSubscribeTo(PSTR("%scommand/#"), mqttGroupTopic); + mqttSubscribeTo(PSTR("%scommand/#"), mqttNodeTopic); + mqttSubscribeTo(PSTR("%slight/#"), mqttNodeTopic); + mqttSubscribeTo(PSTR("%sbrightness/#"), mqttNodeTopic); + mqttSubscribeTo(PSTR("%sstatus"), mqttNodeTopic); - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%scommand/#"), mqttNodeTopic.c_str()); - if(mqttClient.subscribe(topicBuffer)) { - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: * Subscribed to %scommand/#"), - mqttNodeTopic.c_str()); - debugPrintln(topicBuffer); - } - - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%slight/#"), mqttNodeTopic.c_str()); - if(mqttClient.subscribe(topicBuffer)) { - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: * Subscribed to %slight/#"), mqttNodeTopic.c_str()); - debugPrintln(topicBuffer); - } - - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%sbrightness/#"), mqttNodeTopic.c_str()); - if(mqttClient.subscribe(topicBuffer)) { - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: * Subscribed to %sbrightness/#"), - mqttNodeTopic.c_str()); - debugPrintln(topicBuffer); - } - - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%sstatus"), mqttNodeTopic.c_str()); - if(mqttClient.subscribe(topicBuffer)) { - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: * Subscribed to %sstatus"), mqttNodeTopic.c_str()); - debugPrintln(topicBuffer); - } // Force any subscribed clients to toggle OFF/ON when we first connect to // make sure we get a full panel refresh at power on. Sending OFF, // "ON" will be sent by the mqttStatusTopic subscription action. - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%sstatus"), mqttNodeTopic.c_str()); - mqttClient.publish(topicBuffer, mqttFirstConnect ? "OFF" : "ON", true); //, 1); - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("MQTT: binary_sensor state: [%sstatus] : %s"), - mqttNodeTopic.c_str(), mqttFirstConnect ? PSTR("OFF") : PSTR("ON")); - debugPrintln(topicBuffer); + snprintf_P(buffer, sizeof(buffer), PSTR("%sstatus"), mqttNodeTopic); + mqttClient.publish(buffer, mqttFirstConnect ? "OFF" : "ON", true); //, 1); + + Log.notice(F("MQTT: binary_sensor state: [%sstatus] : %s"), mqttNodeTopic, + mqttFirstConnect ? PSTR("OFF") : PSTR("ON")); + + /* snprintf_P(buffer, sizeof(buffer), PSTR("MQTT: binary_sensor state: [%sstatus] : %s"), mqttNodeTopic, + mqttFirstConnect ? PSTR("OFF") : PSTR("ON")); + debugPrintln(buffer); */ mqttFirstConnect = false; mqttReconnectCount = 0; @@ -421,10 +453,6 @@ void mqttReconnect() void mqttSetup(const JsonObject & settings) { - mqttClientId.reserve(128); - mqttNodeTopic.reserve(128); - mqttGroupTopic.reserve(128); - mqttSetConfig(settings); mqttEnabled = strcmp(mqttServer, "") != 0 && mqttPort > 0; @@ -433,17 +461,20 @@ void mqttSetup(const JsonObject & settings) mqttClient.setServer(mqttServer, 1883); mqttClient.setCallback(mqttCallback); - debugPrintln(F("MQTT: Setup Complete")); + Log.notice(F("MQTT: Setup Complete")); + // debugPrintln(F("MQTT: Setup Complete")); } -void mqttLoop(bool wifiIsConnected) +void mqttLoop() { if(!mqttEnabled) return; + mqttClient.loop(); +} - if(wifiIsConnected && !mqttClient.connected()) - mqttReconnect(); - else - mqttClient.loop(); +void mqttEvery5Seconds(bool wifiIsConnected) +{ + if(!mqttEnabled) return; + if(wifiIsConnected && !mqttClient.connected()) mqttReconnect(); } String mqttGetNodename() @@ -461,14 +492,15 @@ void mqttStop() if(mqttClient.connected()) { char topicBuffer[128]; - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%sstatus"), mqttNodeTopic.c_str()); + snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%sstatus"), mqttNodeTopic); mqttClient.publish(topicBuffer, "OFF"); - snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%ssensor"), mqttNodeTopic.c_str()); + snprintf_P(topicBuffer, sizeof(topicBuffer), PSTR("%ssensor"), mqttNodeTopic); mqttClient.publish(topicBuffer, "{\"status\": \"unavailable\"}"); mqttClient.disconnect(); - debugPrintln(F("MQTT: Disconnected from broker")); + Log.notice(F("MQTT: Disconnected from broker")); + // debugPrintln(F("MQTT: Disconnected from broker")); } } @@ -528,3 +560,5 @@ bool mqttSetConfig(const JsonObject & settings) return changed; } + +#endif // HASP_USE_MQTT diff --git a/src/hasp_spiffs.cpp b/src/hasp_spiffs.cpp index 5273ebc5..a257e2ab 100644 --- a/src/hasp_spiffs.cpp +++ b/src/hasp_spiffs.cpp @@ -1,8 +1,9 @@ #include #include "ArduinoJson.h" +#include "ArduinoLog.h" #include "hasp_conf.h" -#include "hasp_log.h" +//#include "hasp_log.h" #include "hasp_spiffs.h" #if HASP_USE_SPIFFS @@ -14,24 +15,20 @@ void spiffsList() { - char buffer[128]; - debugPrintln(PSTR("FILE: Listing files on the internal flash:")); + Log.verbose(F("FILE: Listing files on the internal flash:")); #if defined(ARDUINO_ARCH_ESP32) File root = SPIFFS.open("/"); File file = root.openNextFile(); while(file) { - snprintf(buffer, sizeof(buffer), PSTR("FILE: * %s (%u bytes)"), file.name(), (uint32_t)file.size()); - debugPrintln(buffer); + Log.verbose(F("FILE: * %s (%u bytes)"), file.name(), (uint32_t)file.size()); file = root.openNextFile(); } #endif #if defined(ARDUINO_ARCH_ESP8266) Dir dir = SPIFFS.openDir("/"); while(dir.next()) { - snprintf(buffer, sizeof(buffer), PSTR("FILE: * %s (%u bytes)"), dir.fileName().c_str(), - (uint32_t)dir.fileSize()); - debugPrintln(buffer); + Log.notice(F("FILE: * %s (%u bytes)"), dir.fileName().c_str(), (uint32_t)dir.fileSize()); } #endif } @@ -41,17 +38,14 @@ void spiffsSetup() // no SPIFFS settings, as settings depend on SPIFFS #if HASP_USE_SPIFFS - char buffer[128]; #if defined(ARDUINO_ARCH_ESP8266) if(!SPIFFS.begin()) { #else if(!SPIFFS.begin(true)) { #endif - snprintf(buffer, sizeof(buffer), PSTR("FILE: %%sSPI flash init failed. Unable to mount FS.")); - errorPrintln(buffer); + Log.error(F("FILE: SPI flash init failed. Unable to mount FS.")); } else { - snprintf(buffer, sizeof(buffer), PSTR("FILE: SPI Flash FS mounted")); - debugPrintln(buffer); + Log.notice(F("FILE: SPI Flash FS mounted")); } #endif } diff --git a/src/hasp_wifi.cpp b/src/hasp_wifi.cpp index b5d0abe1..cd0a1fbe 100644 --- a/src/hasp_wifi.cpp +++ b/src/hasp_wifi.cpp @@ -1,19 +1,24 @@ #include #include "ArduinoJson.h" +#include "ArduinoLog.h" #include "hasp_conf.h" #include "hasp_wifi.h" -#include "hasp_mqtt.h" #include "hasp_http.h" #include "hasp_mdns.h" -#include "hasp_log.h" +//#include "hasp_log.h" #include "hasp_debug.h" #include "hasp_config.h" #include "hasp_dispatch.h" #include "hasp_gui.h" #include "hasp.h" +#include "hasp_conf.h" +#if HASP_USE_MQTT +#include "hasp_mqtt.h" +#endif + #if defined(ARDUINO_ARCH_ESP32) #include #else @@ -61,16 +66,15 @@ String wifiGetMacAddress(int start, const char * seperator) void wifiConnected(IPAddress ipaddress) { - bool isConnected = WiFi.status() == WL_CONNECTED; char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("WIFI: Received IP address %s"), ipaddress.toString().c_str()); - debugPrintln(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR("WIFI: Connected = %s"), isConnected ? PSTR("yes") : PSTR("no")); - debugPrintln(buffer); + bool isConnected = WiFi.status() == WL_CONNECTED; + + Log.notice(F("WIFI: Received IP address %s"), ipaddress.toString().c_str()); + Log.verbose(F("WIFI: Connected = %s"), isConnected ? PSTR("yes") : PSTR("no")); if(isConnected) { - /* mqttReconnect(); - haspReconnect();*/ + // mqttReconnect(); + // haspReconnect(); httpReconnect(); // mdnsStart(); } @@ -81,19 +85,15 @@ void wifiDisconnected(const char * ssid, uint8_t reason) char buffer[128]; wifiReconnectCounter++; if(wifiReconnectCounter > 45) { - snprintf_P(buffer, sizeof(buffer), PSTR("WIFI: %%s Retries exceed %u: Rebooting..."), wifiReconnectCounter); - errorPrintln(buffer); + Log.error(F("WIFI: Retries exceed %u: Rebooting..."), wifiReconnectCounter); dispatchReboot(false); } - snprintf_P(buffer, sizeof(buffer), PSTR("WIFI: Disconnected from %s (Reason: %d)"), ssid, reason); - debugPrintln(buffer); + Log.warning(F("WIFI: Disconnected from %s (Reason: %d)"), ssid, reason); } void wifiSsidConnected(const char * ssid) { - char buffer[128]; - snprintf_P(buffer, sizeof(buffer), PSTR("WIFI: Connected to SSID %s. Requesting IP..."), ssid); - debugPrintln(buffer); + Log.notice(F("WIFI: Connected to SSID %s. Requesting IP..."), ssid); wifiReconnectCounter = 0; } @@ -156,16 +156,13 @@ void wifiSetup(JsonObject settings) // dnsServer.start(DNS_PORT, "*", apIP); IPAddress IP = WiFi.softAPIP(); - sprintf_P(buffer, PSTR("WIFI: Temporary Access Point %s password: %s"), apSsdid.c_str(), PSTR("haspadmin")); - debugPrintln(buffer); - sprintf_P(buffer, PSTR("WIFI: AP IP address : %s"), IP.toString().c_str()); - debugPrintln(buffer); + Log.warning(F("WIFI: Temporary Access Point %s password: %s"), apSsdid.c_str(), PSTR("haspadmin")); + Log.warning(F("WIFI: AP IP address : %s"), IP.toString().c_str()); // httpReconnect(); } else { WiFi.mode(WIFI_STA); - snprintf_P(buffer, sizeof(buffer), PSTR("WIFI: Connecting to : %s"), wifiSsid); - debugPrintln(buffer); + Log.notice(F("WIFI: Connecting to : %s"), wifiSsid); #if defined(ARDUINO_ARCH_ESP8266) // wifiEventHandler[0] = WiFi.onStationModeConnected(wifiSTAConnected); @@ -219,7 +216,7 @@ bool wifiSetConfig(const JsonObject & settings) void wifiStop() { - debugPrintln(F("WIFI: Stopped")); + Log.warning(F("WIFI: Stopped")); WiFi.mode(WIFI_OFF); WiFi.disconnect(); } \ No newline at end of file