Switch to ArduinoLog library

This commit is contained in:
fvanroie 2020-03-25 13:43:25 +01:00
parent 8a04961d0e
commit 3a965b18e5
12 changed files with 1660 additions and 423 deletions

166
src/ArduinoLog.cpp Normal file
View File

@ -0,0 +1,166 @@
/*
_ ___ ___ _ _ ___ _ _ ___ _ ___ ___
/_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __|
/ _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ |
/_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___|
Log library for Arduino
version 1.0.3
https://github.com/thijse/Arduino-Log
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
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<PGM_P>(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();

298
src/ArduinoLog.h Normal file
View File

@ -0,0 +1,298 @@
/*
_ ___ ___ _ _ ___ _ _ ___ _ ___ ___
/_\ | _ \ \| | | |_ _| \| |/ _ \| | / _ \ / __|
/ _ \| / |) | |_| || || .` | (_) | |_| (_) | (_ |
/_/ \_\_|_\___/ \___/|___|_|\_|\___/|____\___/ \___|
Log library for Arduino
version 1.0.3
https://github.com/thijse/Arduino-Log
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
*/
#ifndef LOGGING_H
#define LOGGING_H
#include <inttypes.h>
#include <stdarg.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
typedef void (*printfunction)(int level, Print *);
//#include <stdint.h>
//#include <stddef.h>
// *************************************************************************
// 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 ;-) <br>
* 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).<br>
* 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 <class T, typename... Args> 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 <class T, typename... Args> 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 <class T, typename... Args> 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 <class T, typename... Args> 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 <class T, typename... Args> 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 <class T, typename... Args> 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 <class T> 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

View File

@ -1,5 +1,6 @@
#include "Arduino.h"
#include "ArduinoJson.h"
#include "ArduinoLog.h"
#include <FS.h> // 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<String>(), passmask);
output.replace(settings[F("mqtt")][F("pass")].as<String>(), passmask);
output.replace(settings[F("wifi")][F("pass")].as<String>(), 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<JsonObject>());
#if HASP_USE_MQTT
changed |= mqttGetConfig(settings[F("mqtt")].to<JsonObject>());
#endif
#if HASP_USE_TELNET
changed |= telnetGetConfig(settings[F("telnet")].to<JsonObject>());
#endif
#if HASP_USE_MDNS
changed |= mdnsGetConfig(settings[F("mdns")].to<JsonObject>());
#endif
#if HASP_USE_HTTP
changed |= httpGetConfig(settings[F("http")].to<JsonObject>());
#endif
#endif
changed |= debugGetConfig(settings[F("debug")].to<JsonObject>());
changed |= guiGetConfig(settings[F("gui")].to<JsonObject>());
changed |= haspGetConfig(settings[F("hasp")].to<JsonObject>());
// changed |= otaGetConfig(settings[F("ota")].to<JsonObject>());
// changed |= tftGetConfig(settings[F("tft")].to<JsonObject>());
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());
}

View File

@ -3,6 +3,8 @@
#include "ArduinoJson.h"
#include "lvgl.h"
#include "ArduinoLog.h"
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
#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 <Syslog.h>
#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<uint16_t>();
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<uint16_t>();
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();

View File

@ -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);

View File

@ -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
}

View File

@ -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);

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,6 @@
#include "hasp_conf.h"
#include <Arduino.h>
#include "ArduinoLog.h"
#if defined(ARDUINO_ARCH_ESP8266)
#include <ESP8266WiFi.h>
@ -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
}

View File

@ -1,5 +1,13 @@
#include "hasp_conf.h"
#if HASP_USE_MQTT
#include <Arduino.h>
#include "ArduinoJson.h"
#include "ArduinoLog.h"
#include "PubSubClient.h"
#include "hasp_conf.h"
#include "hasp_mqtt.h"
#if defined(ARDUINO_ARCH_ESP32)
#include <Wifi.h>
@ -8,9 +16,8 @@
#include <EEPROM.h>
#include <ESP.h>
#endif
#include <PubSubClient.h>
#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

View File

@ -1,8 +1,9 @@
#include <Arduino.h>
#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
}

View File

@ -1,19 +1,24 @@
#include <Arduino.h>
#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 <Wifi.h>
#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();
}