version 1.3.0

This commit is contained in:
proddy
2019-01-09 23:41:41 +01:00
parent 2d2ee1927d
commit 22823545da
28 changed files with 1730 additions and 758 deletions

View File

@@ -3,31 +3,32 @@
*
* Paul Derbyshire - December 2018
*
* Some ideas from https://github.com/JoaoLopesF/ESP8266-RemoteDebug-Telnet
* Ideas from Espurna https://github.com/xoseperez/espurna
* Ideas borrowed from Espurna https://github.com/xoseperez/espurna
*/
#include "MyESP.h"
// constructor
MyESP::MyESP() {
_app_hostname = strdup("MyESP");
_app_name = strdup("MyESP");
_app_version = strdup("1.0.0");
_boottime = strdup("unknown");
_extern_WIFICallback = NULL;
_extern_WIFICallbackSet = false;
_consoleCallbackProjectCmds = NULL;
_helpProjectCmds = NULL;
_helpProjectCmds_count = 0;
_mqtt_host = NULL;
_mqtt_password = NULL;
_mqtt_username = NULL;
_wifi_password = NULL;
_wifi_ssid = NULL;
_mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN;
_suspendMessages = true;
_command = (char *)malloc(TELNET_MAX_COMMAND_LENGTH); // reserve buffer for Serial/Telnet commands
_app_hostname = strdup("MyESP");
_app_name = strdup("MyESP");
_app_version = strdup("1.0.0");
_boottime = strdup("unknown");
_extern_WIFICallback = NULL;
_extern_WIFICallbackSet = false;
_telnetcommand_callback = NULL;
_telnet_callback = NULL;
_helpProjectCmds = NULL;
_helpProjectCmds_count = 0;
_mqtt_host = NULL;
_mqtt_password = NULL;
_mqtt_username = NULL;
_wifi_password = NULL;
_wifi_ssid = NULL;
_mqttbase = NULL;
_suspendOutput = false;
_mqtt_reconnect_delay = MQTT_RECONNECT_DELAY_MIN;
_command = (char *)malloc(TELNET_MAX_COMMAND_LENGTH); // reserve buffer for Serial/Telnet commands
}
MyESP::~MyESP() {
@@ -41,10 +42,9 @@ void MyESP::end() {
jw.disconnect();
}
// general debug to the telnet or serial channels
void MyESP::myDebug(const char * format, ...) {
if (!_suspendMessages)
if (_suspendOutput)
return;
va_list args;
@@ -62,6 +62,9 @@ void MyESP::myDebug(const char * format, ...) {
// for flashmemory. Must use PSTR()
void MyESP::myDebug_P(PGM_P format_P, ...) {
if (_suspendOutput)
return;
char format[strlen_P(format_P) + 1];
memcpy_P(format, format_P, sizeof(format));
@@ -85,7 +88,7 @@ void MyESP::myDebug_P(PGM_P format_P, ...) {
// called when WiFi is connected, and used to start MDNS
void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) {
if ((code == MESSAGE_CONNECTED) || (code == MESSAGE_ACCESSPOINT_CREATED)) {
if ((code == MESSAGE_CONNECTED)) {
#if defined(ARDUINO_ARCH_ESP32)
String hostname = String(WiFi.getHostname());
#else
@@ -102,13 +105,6 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) {
myDebug_P(PSTR("[WIFI] DNS %s"), WiFi.dnsIP().toString().c_str());
myDebug_P(PSTR("[WIFI] HOST %s"), hostname.c_str());
if (WiFi.getMode() & WIFI_AP) {
myDebug_P(PSTR("[WIFI] MODE AP --------------------------------------"));
myDebug_P(PSTR("[WIFI] SSID %s"), jw.getAPSSID().c_str());
myDebug_P(PSTR("[WIFI] IP %s"), WiFi.softAPIP().toString().c_str());
myDebug_P(PSTR("[WIFI] MAC %s"), WiFi.softAPmacAddress().c_str());
}
// start MDNS
if (MDNS.begin((char *)hostname.c_str())) {
myDebug_P(PSTR("[MDNS] OK"));
@@ -118,7 +114,18 @@ void MyESP::_wifiCallback(justwifi_messages_t code, char * parameter) {
// call any final custom settings
if (_extern_WIFICallbackSet) {
// myDebug_P(PSTR("[WIFI] calling custom wifi settings function"));
_extern_WIFICallback(); // call callback to set any custom things
}
}
if (code == MESSAGE_ACCESSPOINT_CREATED) {
myDebug_P(PSTR("[WIFI] MODE AP --------------------------------------"));
myDebug_P(PSTR("[WIFI] SSID %s"), jw.getAPSSID().c_str());
myDebug_P(PSTR("[WIFI] IP %s"), WiFi.softAPIP().toString().c_str());
myDebug_P(PSTR("[WIFI] MAC %s"), WiFi.softAPmacAddress().c_str());
// call any final custom settings
if (_extern_WIFICallbackSet) {
_extern_WIFICallback(); // call callback to set any custom things
}
}
@@ -160,9 +167,9 @@ void MyESP::_mqttOnMessage(char * topic, char * payload, size_t len) {
topic = topic_magnitude + 1;
}
// check for bootime, something specific I fetch as an acknolwegdemtn from Home Assistant
// check for bootime, something specific I fetch as an acknowledgement from Home Assistant
if (strcmp(topic, MQTT_TOPIC_START) == 0) {
myDebug_P(PSTR("[MQTT] boottime: %s"), message);
myDebug_P(PSTR("[MQTT] received boottime: %s"), message);
setBoottime(message);
return;
}
@@ -172,20 +179,22 @@ void MyESP::_mqttOnMessage(char * topic, char * payload, size_t len) {
}
// MQTT subscribe
// to MQTT_BASE/app_hostname/topic
void MyESP::mqttSubscribe(const char * topic) {
if (mqttClient.connected() && (strlen(topic) > 0)) {
char s[100];
snprintf(s, sizeof(s), "%s%s/%s", MQTT_BASE, _app_hostname, topic);
snprintf(s, sizeof(s), "%s/%s/%s", _mqttbase, _app_hostname, topic);
unsigned int packetId = mqttClient.subscribe(s, MQTT_QOS);
myDebug_P(PSTR("[MQTT] Subscribing to %s (PID %d)"), s, packetId);
}
}
// MQTT unsubscribe
// to MQTT_BASE/app_hostname/topic
void MyESP::mqttUnsubscribe(const char * topic) {
if (mqttClient.connected() && (strlen(topic) > 0)) {
char s[100];
snprintf(s, sizeof(s), "%s%s/%s", MQTT_BASE, _app_hostname, topic);
snprintf(s, sizeof(s), "%s/%s/%s", _mqttbase, _app_hostname, topic);
unsigned int packetId = mqttClient.unsubscribe(s);
myDebug_P(PSTR("[MQTT] Unsubscribing to %s (PID %d)"), s, packetId);
}
@@ -194,7 +203,7 @@ void MyESP::mqttUnsubscribe(const char * topic) {
// MQTT Publish
void MyESP::mqttPublish(const char * topic, const char * payload) {
char s[MQTT_MAX_SIZE];
snprintf(s, sizeof(s), "%s%s/%s", MQTT_BASE, _app_hostname, topic);
snprintf(s, sizeof(s), "%s/%s/%s", _mqttbase, _app_hostname, topic);
// myDebug_P(PSTR("[MQTT] Sending pubish to %s with payload %s"), s, payload);
mqttClient.publish(s, MQTT_QOS, false, payload);
}
@@ -211,11 +220,11 @@ void MyESP::_mqttOnConnect() {
// send specific start command to HA via MQTT, which returns the boottime
char s[48];
snprintf(s, sizeof(s), "%s%s/%s", MQTT_BASE, _app_hostname, MQTT_TOPIC_START);
snprintf(s, sizeof(s), "%s/%s/%s", _mqttbase, _app_hostname, MQTT_TOPIC_START);
mqttClient.publish(s, MQTT_QOS, false, MQTT_TOPIC_START_PAYLOAD);
#endif
// call custom
// call custom function to handle mqtt receives
(_mqtt_callback)(MQTT_CONNECT_EVENT, NULL, NULL);
}
@@ -265,7 +274,7 @@ void MyESP::_wifi_setup() {
jw.enableAP(false);
jw.setConnectTimeout(WIFI_CONNECT_TIMEOUT);
jw.setReconnectTimeout(WIFI_RECONNECT_INTERVAL);
jw.enableAPFallback(true); // AP mode only as fallback, but disabled
jw.enableAPFallback(true); // AP mode only as fallback
jw.enableSTA(true); // Enable STA mode (connecting to a router)
jw.enableScan(false); // Configure it to scan available networks and connect in order of dBm
jw.cleanNetworks(); // Clean existing network configuration
@@ -299,6 +308,10 @@ void MyESP::_mdns_setup() {
// OTA Setup
void MyESP::_ota_setup() {
if (!_wifi_ssid) {
return;
}
ArduinoOTA.setPort(OTA_PORT);
ArduinoOTA.setHostname(_app_hostname);
ArduinoOTA.onStart([this]() { myDebug_P(PSTR("[OTA] Start")); });
@@ -336,25 +349,38 @@ void MyESP::setBoottime(char * boottime) {
_boottime = strdup(boottime);
}
// returns boottime
char * MyESP::getBoottime() {
return _boottime;
// sets boottime
void MyESP::setMQTTbase(char * mqttbase) {
if (_mqttbase) {
free(_mqttbase);
}
_mqttbase = strdup(mqttbase);
}
// Set callback of sketch function to process project messages
void MyESP::consoleSetCallBackProjectCmds(command_t * cmds, uint8_t count, void (*callback)()) {
_helpProjectCmds = cmds; // command list
_helpProjectCmds_count = count; // number of commands
_consoleCallbackProjectCmds = callback; // external function to handle commands
void MyESP::setTelnetCommands(command_t * cmds, uint8_t count, telnetcommand_callback_f callback) {
_helpProjectCmds = cmds; // command list
_helpProjectCmds_count = count; // number of commands
_telnetcommand_callback = callback; // external function to handle commands
}
void MyESP::setTelnetCallback(telnet_callback_f callback) {
_telnet_callback = callback;
}
void MyESP::_telnetConnected() {
myDebug_P(PSTR("[TELNET] Telnet connection established"));
_consoleShowHelp(); // Show the initial message
if (_telnet_callback) {
(_telnet_callback)(TELNET_EVENT_CONNECT); // call callback
}
}
void MyESP::_telnetDisconnected() {
myDebug_P(PSTR("[TELNET] Telnet connection closed"));
if (_telnet_callback) {
(_telnet_callback)(TELNET_EVENT_DISCONNECT); // call callback
}
}
// Initialize the telnet server
@@ -375,37 +401,48 @@ void MyESP::_telnet_setup() {
// Show help of commands
void MyESP::_consoleShowHelp() {
SerialAndTelnet.printf("\n\r* Connected to: %s version %s\n\r", _app_name, _app_version);
if (WiFi.getMode() & WIFI_AP) {
SerialAndTelnet.printf("* ESP8266 is in AP mode with SSID %s\n\r", jw.getAPSSID().c_str());
} else {
#if defined(ARDUINO_ARCH_ESP32)
String hostname = String(WiFi.getHostname());
String hostname = String(WiFi.getHostname());
#else
String hostname = WiFi.hostname();
String hostname = WiFi.hostname();
#endif
SerialAndTelnet.printf("* Hostname: %s IP: %s MAC: %s\n\r",
hostname.c_str(),
WiFi.localIP().toString().c_str(),
WiFi.macAddress().c_str());
SerialAndTelnet.printf("* Connected to WiFi SSID: %s\n\r", WiFi.SSID().c_str());
SerialAndTelnet.printf("* Boot time: %s\n\r", _boottime);
}
SerialAndTelnet.println("*********************************");
SerialAndTelnet.println("* Console and Log Monitoring *");
SerialAndTelnet.println("*********************************");
SerialAndTelnet.printf("* %s version %s\n\r", _app_name, _app_version);
SerialAndTelnet.printf("* Hostname: %s IP: %s MAC: %s\n\r",
hostname.c_str(),
WiFi.localIP().toString().c_str(),
WiFi.macAddress().c_str());
SerialAndTelnet.printf("* Connected to WiFi AP: %s\n\r", WiFi.SSID().c_str());
SerialAndTelnet.printf("* Boot time: %s\n\r", _boottime);
SerialAndTelnet.printf("* Free RAM: %d bytes\n\r", ESP.getFreeHeap());
#ifdef DEBUG_SUPPORT
SerialAndTelnet.println("* !! in DEBUG_SUPPORT mode !!\n\r");
SerialAndTelnet.println("* Warning: in DEBUG_SUPPORT mode!");
#endif
SerialAndTelnet.println("*\n\r* Commands:\n\r* ?=this help, CTRL-D=quit, $=show free memory, !=reboot ESP, &=suspend all messages");
SerialAndTelnet.println("*\n\r* Commands:\n\r* ?=help, CTRL-D=quit, !=reboot");
SerialAndTelnet.println(FPSTR("* set <wifi_ssid | wifi_password | mqtt_host | mqtt_username | mqtt_password> [value]"));
SerialAndTelnet.println(FPSTR("* set erase"));
SerialAndTelnet.println(FPSTR("*"));
// print custom commands if available. Take from progmem
if (_consoleCallbackProjectCmds) {
if (_telnetcommand_callback) {
// find the longest key length so we can right align it
uint8_t max_len = 0;
for (uint8_t i = 0; i < _helpProjectCmds_count; i++) {
if (strlen(_helpProjectCmds[i].key) > max_len)
max_len = strlen(_helpProjectCmds[i].key);
}
for (uint8_t i = 0; i < _helpProjectCmds_count; i++) {
SerialAndTelnet.print(FPSTR("* "));
SerialAndTelnet.print(FPSTR(_helpProjectCmds[i].key));
for (uint8_t j = 0; j < (8 - strlen(_helpProjectCmds[i].key)); j++) {
SerialAndTelnet.print(FPSTR(" ")); // padding
for (uint8_t j = 0; j < ((max_len + 5) - strlen(_helpProjectCmds[i].key)); j++) { // account for longest string length
SerialAndTelnet.print(FPSTR(" ")); // padding
}
SerialAndTelnet.println(FPSTR(_helpProjectCmds[i].description));
}
@@ -424,90 +461,207 @@ void MyESP::resetESP() {
#endif
}
// Get last command received
char * MyESP::consoleGetLastCommand() {
return _command;
}
// Process user command over telnet
void MyESP::consoleProcessCommand() {
uint8_t cmd = _command[0];
// Process the command
if (cmd == '?') {
_consoleShowHelp(); // Show help
} else if (cmd == '$') {
myDebug("* Free RAM (bytes): %d", ESP.getFreeHeap());
} else if (cmd == '!') {
resetESP();
} else if (cmd == '&') {
myDebug("Suspend all messages is %s", !_suspendMessages ? "disabled" : "enabled");
_suspendMessages = !_suspendMessages; // toggle
} else {
// custom Project commands
if (_consoleCallbackProjectCmds) {
_consoleCallbackProjectCmds();
}
}
if (!_suspendMessages) {
myDebug("Warning, all log messages have been supsended. Use & to re-enable.");
}
}
// sends a MQTT notification message to Home Assistant
// sends a MQTT notification message to Home Assistant (HA)
void MyESP::sendHANotification(const char * message) {
char payload[48];
snprintf(payload, sizeof(payload), "%s : %s", _app_hostname, message);
myDebug_P(PSTR("[MQTT] Sending HA notification %s"), payload);
mqttClient.publish(MQTT_NOTIFICATION, MQTT_QOS, false, payload);
mqttClient.publish(MQTT_HA_NOTIFICATION, MQTT_QOS, false, payload);
}
// send specific command to HA via MQTT
// send specific command to Home Assistant (HA) via MQTT
// format is: home/<hostname>/command with payload <cmd>
void MyESP::sendHACommand(const char * cmd) {
myDebug_P(PSTR("[MQTT] Sending HA command %s"), cmd);
char topic[48];
snprintf(topic, sizeof(topic), "%s%s/%s", MQTT_BASE, _app_hostname, MQTT_TOPIC_COMMAND);
snprintf(topic, sizeof(topic), "%s/%s/%s", _mqttbase, _app_hostname, MQTT_TOPIC_COMMAND);
mqttClient.publish(topic, MQTT_QOS, false, cmd);
}
char * MyESP::_telnet_readWord() {
char * word = strtok(NULL, ", \n");
return word;
}
// change settings - always as strings
// messy code but effective since we don't have too many settings
void MyESP::_changeSetting(const char * setting, const char * value) {
bool ok = false;
// validate 2nd argument
if (strcmp(setting, "erase") == 0) {
_fs_eraseConfig();
return;
}
if (strcmp(setting, "wifi_ssid") == 0) {
if (_wifi_ssid)
free(_wifi_ssid);
_wifi_ssid = NULL; // just to be sure
if (value) {
_wifi_ssid = strdup(value);
}
ok = true;
}
if (strcmp(setting, "wifi_password") == 0) {
if (_wifi_password)
free(_wifi_password);
_wifi_password = NULL; // just to be sure
if (value) {
_wifi_password = strdup(value);
}
ok = true;
}
if (strcmp(setting, "mqtt_host") == 0) {
if (_mqtt_host)
free(_mqtt_host);
_mqtt_host = NULL; // just to be sure
if (value) {
_mqtt_host = strdup(value);
}
ok = true;
}
if (strcmp(setting, "mqtt_username") == 0) {
if (_mqtt_username)
free(_mqtt_username);
_mqtt_username = NULL; // just to be sure
if (value) {
_mqtt_username = strdup(value);
}
ok = true;
}
if (strcmp(setting, "mqtt_password") == 0) {
if (_mqtt_password)
free(_mqtt_password);
_mqtt_password = NULL; // just to be sure
if (value) {
_mqtt_password = strdup(value);
}
ok = true;
}
if (!ok) {
SerialAndTelnet.println("\nInvalid parameter for set command.");
return;
}
// check for 2 params
if (value == nullptr) {
SerialAndTelnet.printf("%s setting deleted\n\r", setting);
} else {
// 3 params
SerialAndTelnet.printf("%s changed to %s\n\r", setting, value);
}
if (_fs_saveConfig()) {
SerialAndTelnet.println("Changes will have effect after the next restart. Please reboot using ! command");
}
}
void MyESP::_telnetCommand(char * commandLine) {
// count the number of arguments
char * str = commandLine;
bool state = false;
unsigned wc = 0;
while (*str) {
if (*str == ' ' || *str == '\n' || *str == '\t') {
state = false;
} else if (state == false) {
state = true;
++wc;
}
++str;
}
// check first for reserved commands
char * temp = strdup(commandLine); // because strotok kills original string buffer
char * ptrToCommandName = strtok((char *)temp, ", \n");
if (strcmp(ptrToCommandName, "set") == 0) {
if (wc == 1) {
SerialAndTelnet.println("\n\Stored settings:");
SerialAndTelnet.printf(" wifi_ssid=%s\n\r", (!_wifi_ssid) ? "<not set>" : _wifi_ssid);
SerialAndTelnet.printf(" wifi_password=");
if (!_wifi_password) {
SerialAndTelnet.print("<not set>");
} else {
for (uint8_t i = 0; i < strlen(_wifi_password); i++)
SerialAndTelnet.print("*");
}
SerialAndTelnet.printf("\n\r mqtt_host=%s\n\r", (!_mqtt_host) ? "<not set>" : _mqtt_host);
SerialAndTelnet.printf(" mqtt_username=%s\n\r", (!_mqtt_username) ? "<not set>" : _mqtt_username);
SerialAndTelnet.printf(" mqtt_password=");
if (!_mqtt_password) {
SerialAndTelnet.print("<not set>");
} else {
for (uint8_t i = 0; i < strlen(_mqtt_password); i++)
SerialAndTelnet.print("*");
}
SerialAndTelnet.println("\n\r\n\rUsage: set <setting> <value>");
} else if (wc == 2) {
char * setting = _telnet_readWord();
_changeSetting(setting, NULL);
} else if (wc == 3) {
char * setting = _telnet_readWord();
char * value = _telnet_readWord();
_changeSetting(setting, value);
}
return;
}
// call callback function
(_telnetcommand_callback)(wc, commandLine);
}
// handler for Telnet
void MyESP::_telnetHandle() {
SerialAndTelnet.handle();
char last = ' '; // To avoid processing double "\r\n"
static uint8_t charsRead = 0;
// read asynchronously until full command input
while (SerialAndTelnet.available()) {
char character = SerialAndTelnet.read(); // Get character
// check for ctrl-D (EOF) or EOT
if ((character == 0xEC) || (character == 0x04)) {
SerialAndTelnet.disconnectClient();
}
// if we reached our buffer limit, send what we have
if (strlen(_command) >= TELNET_MAX_COMMAND_LENGTH) {
consoleProcessCommand(); // Process the command
memset(_command, 0, TELNET_MAX_COMMAND_LENGTH); // reset for next command
}
// Check for newline (CR or LF)
if (_isCRLF(character) == true) {
if (_isCRLF(last) == false) {
if (strlen(_command) > 0) {
consoleProcessCommand(); // Process the command
}
char c = SerialAndTelnet.read();
#ifdef DEBUG_SUPPORT
Serial.print(c);
#endif
switch (c) {
case '\r': // likely have full command in buffer now, commands are terminated by CR and/or LF
case '\n':
_command[charsRead] = '\0'; // null terminate our command char array
if (charsRead > 0) {
charsRead = 0; // is static, so have to reset
_suspendOutput = false;
_telnetCommand(_command);
}
memset(_command, 0, TELNET_MAX_COMMAND_LENGTH); // reset for next command
} else if (isPrintable(character)) {
// Concat char to end of buffer
uint16_t len = strlen(_command);
_command[len] = character;
_command[len + 1] = '\0';
break;
case '\b': // handle backspace in input: put a space in last char
if (charsRead > 0) { // and adjust commandLine and charsRead
_command[--charsRead] = '\0';
SerialAndTelnet << byte('\b') << byte(' ') << byte('\b'); //no idea how this works, found it on the Internet
}
break;
case '?':
_consoleShowHelp();
break;
case '!':
resetESP();
break;
case 0x04: // EOT
myDebug_P(PSTR("* exiting telnet session"));
SerialAndTelnet.disconnectClient();
break;
default:
_suspendOutput = true;
c = tolower(c);
if (charsRead < TELNET_MAX_COMMAND_LENGTH) {
_command[charsRead++] = c;
}
_command[charsRead] = '\0'; // just in case
break;
}
last = character; // remember last char
}
}
@@ -522,11 +676,6 @@ void MyESP::setMQTTCallback(mqtt_callback_f callback) {
_mqtt_callback = callback;
}
// Is CR or LF ?
bool MyESP::_isCRLF(char character) {
return (character == '\r' || character == '\n');
}
// ensure we have a connection to MQTT broker
void MyESP::_mqttConnect() {
if (!_mqtt_host || mqttClient.connected() || (WiFi.status() != WL_CONNECTED)) {
@@ -560,19 +709,7 @@ void MyESP::_mqttConnect() {
}
// Setup everything we need
void MyESP::setup(char * app_hostname,
char * app_name,
char * app_version,
char * wifi_ssid,
char * wifi_password,
char * mqtt_host,
char * mqtt_username,
char * mqtt_password) {
// get general params first
_app_hostname = strdup(app_hostname);
_app_name = strdup(app_name);
_app_version = strdup(app_version);
void MyESP::setConnection(char * wifi_ssid, char * wifi_password, char * mqtt_host, char * mqtt_username, char * mqtt_password) {
// Check SSID too long or missing
if (!wifi_ssid || *wifi_ssid == 0x00 || strlen(wifi_ssid) > 31) {
_wifi_ssid = NULL;
@@ -581,7 +718,7 @@ void MyESP::setup(char * app_hostname,
}
// Check PASS too long
if (wifi_password && strlen(wifi_password) > 63) {
if (!wifi_password || *wifi_ssid == 0x00 || strlen(wifi_password) > 31) {
_wifi_password = NULL;
} else {
_wifi_password = strdup(wifi_password);
@@ -607,9 +744,120 @@ void MyESP::setup(char * app_hostname,
} else {
_mqtt_password = strdup(mqtt_password);
}
}
// print contents of file
void MyESP::_fs_printConfig() {
File configFile = SPIFFS.open("/config.json", "r");
myDebug_P(PSTR("[FS] Contents...."));
while (configFile.available()) {
SerialAndTelnet.print((char)configFile.read());
}
SerialAndTelnet.println();
configFile.close();
}
// format File System
void MyESP::_fs_eraseConfig() {
myDebug_P(PSTR("[FS] Erasing settings. Please wait. ESP will automatically restart when finished."));
if (SPIFFS.format()) {
resetESP();
}
}
// load from spiffs
bool MyESP::_fs_loadConfig() {
File configFile = SPIFFS.open("/config.json", "r");
if (!configFile) {
myDebug_P(PSTR("[FS] Failed to open config file"));
return false;
}
size_t size = configFile.size();
if (size > 1024) {
myDebug_P(PSTR("[FS] Config file size is too large"));
return false;
}
// assign buffer
std::unique_ptr<char[]> buf(new char[size]);
// use configFile.readString
configFile.readBytes(buf.get(), size);
StaticJsonBuffer<300> jsonBuffer; // https://arduinojson.org/v5/assistant/
JsonObject & json = jsonBuffer.parseObject(buf.get());
const char * value;
value = json["wifi_ssid"];
_wifi_ssid = (value) ? strdup(value) : NULL;
value = json["wifi_password"];
_wifi_password = (value) ? strdup(value) : NULL;
value = json["mqtt_host"];
_mqtt_host = (value) ? strdup(value) : NULL;
value = json["mqtt_username"];
_mqtt_username = (value) ? strdup(value) : NULL;
value = json["mqtt_password"];
_mqtt_password = (value) ? strdup(value) : NULL;
configFile.close();
return true;
}
// save settings to spiffs
bool MyESP::_fs_saveConfig() {
StaticJsonBuffer<200> jsonBuffer;
JsonObject & json = jsonBuffer.createObject();
json["wifi_ssid"] = _wifi_ssid;
json["wifi_password"] = _wifi_password;
json["mqtt_host"] = _mqtt_host;
json["mqtt_username"] = _mqtt_username;
json["mqtt_password"] = _mqtt_password;
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
myDebug_P(PSTR("[FS] Failed to open config file for writing"));
return false;
}
json.printTo(configFile);
return true;
}
// init the SPIFF file system and load the config
// if it doesn't exist try and create it
void MyESP::_fs_setup() {
if (!SPIFFS.begin()) {
myDebug_P(PSTR("[FS] Failed to mount the file system"));
return;
}
// load the config file. if it doesn't exist create it with anything that was specified
if (!_fs_loadConfig()) {
_fs_saveConfig();
}
}
// register new instance
void MyESP::begin(char * app_hostname, char * app_name, char * app_version) {
_app_hostname = strdup(app_hostname);
_app_name = strdup(app_name);
_app_version = strdup(app_version);
// call setup of the services...
_telnet_setup(); // Telnet setup
_fs_setup(); // SPIFFS setup
_wifi_setup(); // WIFI setup
_mqtt_setup(); // MQTT Setup
_mdns_setup(); // MDNS setup
@@ -620,8 +868,13 @@ void MyESP::setup(char * app_hostname,
* Loop. This is called as often as possible and it handles wifi, telnet, mqtt etc
*/
void MyESP::loop() {
jw.loop(); // WiFi
_telnetHandle(); // Telnet/Debugger
jw.loop(); // WiFi
_telnetHandle(); // Telnet/Debugger
if (WiFi.getMode() & WIFI_AP) {
return;
}
ArduinoOTA.handle(); // OTA
_mqttConnect(); // MQTT