From 81d88e61e6e4ff8202bcda9e2a4cb332bf3bf622 Mon Sep 17 00:00:00 2001 From: Naguissa Date: Tue, 12 Nov 2024 12:44:28 +0100 Subject: [PATCH] v.1.0.0 --- .github/FUNDING.yml | 2 + LICENSE | 166 +++++++ README.md | 320 ++++++++++++++ .../uEspConfigLib_example.ino | 231 ++++++++++ library.properties | 11 + src/uEspConfigLib.cpp | 413 ++++++++++++++++++ src/uEspConfigLib.h | 189 ++++++++ src/uEspConfigLibFSInterface.h | 101 +++++ src/uEspConfigLibFSLittlefs.cpp | 165 +++++++ src/uEspConfigLibFSLittlefs.h | 96 ++++ src/uEspConfigLibFSNone.cpp | 76 ++++ src/uEspConfigLibFSNone.h | 83 ++++ src/uEspConfigLibFSSd.cpp | 158 +++++++ src/uEspConfigLibFSSd.h | 95 ++++ src/uEspConfigLibFSSpiffs.cpp | 164 +++++++ src/uEspConfigLibFSSpiffs.h | 94 ++++ src/~gvfM9dX.tmp | 0 17 files changed, 2364 insertions(+) create mode 100644 .github/FUNDING.yml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 examples/uEspConfigLib_example/uEspConfigLib_example.ino create mode 100644 library.properties create mode 100644 src/uEspConfigLib.cpp create mode 100644 src/uEspConfigLib.h create mode 100644 src/uEspConfigLibFSInterface.h create mode 100644 src/uEspConfigLibFSLittlefs.cpp create mode 100644 src/uEspConfigLibFSLittlefs.h create mode 100644 src/uEspConfigLibFSNone.cpp create mode 100644 src/uEspConfigLibFSNone.h create mode 100644 src/uEspConfigLibFSSd.cpp create mode 100644 src/uEspConfigLibFSSd.h create mode 100644 src/uEspConfigLibFSSpiffs.cpp create mode 100644 src/uEspConfigLibFSSpiffs.h create mode 100644 src/~gvfM9dX.tmp diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..03771c1 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: Naguissa +custom: https://www.paypal.me/foroelectro diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..341c30b --- /dev/null +++ b/LICENSE @@ -0,0 +1,166 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..00b396e --- /dev/null +++ b/README.md @@ -0,0 +1,320 @@ +# The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib + +## What is this repository for? + +This library consist in 2 parts: + + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + + * One interface to manage different configuration storages. + +Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + + +## Usage ## + + +To use it at any point on your sketch, define needed globals: + +``` +uEspConfigLibFSInterface * configFs; +uEspConfigLib * config; +``` + + +Then, at setup(), you need to choose an storage option among this: +``` +configFs = new uEspConfigLibFSNone(); +configFs = new uEspConfigLibFSSpiffs("/config.ini", bool initFS); +configFs = new uEspConfigLibFSLittlefs("/config.ini", bool initFS); +configFs = new uEspConfigLibFSSd("/config.ini", bool initFS, uint8_t CS_pin); +``` + +- If initFS option is true the class will initialize the filesystem as needed, even format it if still not done. +- Use CS_pin on SD card option to define CS pin when you use a non-standard one. + +Still on setup, then you define your config object: + +``` +config = new uEspConfigLib(configFs); +``` + +Finally you need to define your desired configuration options: + +``` +config->addOption("name", "Description", "Default value"); +``` + +A typical example could be: + +``` +config->addOption("wifi_mode", "WiFi mode (C=Client, other=Access Point)", ""); +config->addOption("wifi_ssid", "SSID of your WiFi", "Unconfigured_device"); +config->addOption("wifi_password", "Password of your WiFi", "wifi_password"); +``` + +**Note:** When an option is defined inmediately its value is set to defined default value. + + + +After that, you can start to use and manipulate any defined option. + + + +**Read an option:** + +``` +char * charArrayPointer = config->getPointer("name"); +``` + +Following previous example: + +``` +readResult = config->getPointer("wifi_mode"); +Serial.print("wifi_mode: "); +Serial.println(readResult); +readResult = config->getPointer("wifi_ssid"); +Serial.print("wifi_ssid: "); +Serial.println(readResult); +readResult = config->getPointer("wifi_password"); +Serial.print("wifi_password: "); +Serial.println(readResult); +``` + +**Note:** If option "name" is not defined it will return a NULL pointer. + + + +**Change an option:** + + +You can change any defined option using: + +``` +bool optionFound = config->set("name", "new_value"); +``` + +Following previous example: + +``` +config->set("wifi_mode", "A"); +config->set("wifi_ssid", "uEspConfigLib_EXAMPLE"); +config->set("wifi_password", ""); +``` + + + +This may be useful by itself, and this is why uEspConfigLibFSNone is available, but here's one huge extra: FS classes. + + +**Configuration file:** + +This library uses a plain text file to store configuration options. File structure is: + +``` +# uConfigLib Configuration file +# Visit https://github.com/Naguissa/uEspConfigLib for details +# Syntax: +# variable = value +# (spaces and empty lines doesn't care) +# This file comments: lines starting with #, ; or // + +# variable_name -- variable_description +# Default value: variable_default_value +variable_name = variable_value + +# variable_name -- variable_description +# Default value: variable_default_value +variable_name = variable_value + +# variable_name -- variable_description +# Default value: variable_default_value +variable_name = variable_value +``` + +**Note:** This file can be edited manually if you want, but saving values will recreate and overwrite the file- + + + +**Load configuration from filesystem:** + +``` +bool readResult = config->loadConfigFile(); +``` + +This will open configuration file, parse it and set any of the defined options contained in that file. + + +**Store configuration from filesystem:** + +``` +bool saveResult = config->saveConfigFile(); +``` + + +This will recreate and overwrite configuration file with current values. + + + + + +**Web functionality, the last magic touch:** + +If you are using ESP web server: + +``` +#ifdef ARDUINO_ARCH_ESP32 + WebServer server(80); +#else + ESP8266WebServer server(80); +#endif +``` + + +You can use the configuration-related web functionality: + + +**Generate and serve an HTML page with a configuration form:** + + +``` +void handleGetConfigHtml() { + config->handleConfigRequestHtml(&server, "optional_post_path"); +} + +//[...] + +server.on("/config_path", HTTP_GET, handleGetConfigHtml); +``` + + +This makes uEspConfigLib to serve a configuration form on "/config_path" route when accessed via browser. + +The optional "optional_post_path" indicates the path where the form values will be posted on submit. Default value is "/uConfigLib/saveConfig" + + +**Generate and serve a JSON document with current configuration:** + +``` +void handleGetConfigJson() { + config->handleConfigRequestJson(&server); +} + +//[...] + + +server.on("/config_json_path", HTTP_GET, handleGetConfigJson); +``` + +This makes uEspConfigLib to serve a configuration JSON file with this format: + +``` +{ + "data": [ + { + "name": "variable_name", + "description": "variable_description", + "defaultValue": "variable_default_value", + "value": "variable_current_value" + }, + { + "name": "variable_name", + "description": "variable_description", + "defaultValue": "variable_default_value", + "value": "variable_current_value" + }, + { + "name": "variable_name", + "description": "variable_description", + "defaultValue": "variable_default_value", + "value": "variable_current_value" + } + ] +} +``` + +This is useful if you have a complete webpage, as you can add your look&feel to the configuration system. + + + + +**Process and store configuration:** + +``` +void handleSaveConfig() { + config->handleSaveConfig(&server); +} + +//[...] + +server.on("/save_config_path", HTTP_POST, handleSaveConfig); +``` + +This will process and store any defined value passed as argument. This accepts any number of valid values, from one to all. + +If a configuration option is not defined as argument it will skip it. But if the argument is defined but empty it will store empty string as new value. + + +There's an special argument: if "format" is defined as "json" this call will respond a JSON document: + +``` +{ + "data": { + "result": 1 + } +} +``` + +Otherwise it will respond redirecting using 302 redirect to "/?saved=1" + +This way it can be used both for simple HTML requests and for JSON requests. + + +**Note:** This function also calls saveConfigFile(), so it's not needed to do so manually. + + + + +## How do I get set up? + +You can get it from Arduino libraries directly, searching by uEspConfigLib. + +For manual installation: + + * Get the ZIP from releases link: https://github.com/Naguissa/uEspConfigLib/releases + * Rename to uEspConfigLib.zip + * Install library on Arduino + + +## Documentation + +You can find all documentation in this repository: https://github.com/Naguissa/uEspConfigLib_doc_and_extras + +You can read documentation online here: https://naguissa.github.io/uEspConfigLib_doc_and_extras/ + + + +## Example + +Included on example folder, available on Arduino IDE. The example shows example code in this file but with a fully working sketch and adds extra use cases. + + +## Who do I talk to? + + * [Naguissa](https://github.com/Naguissa) + * https://www.foroelectro.net + + +## Contribute + +Any code contribution, report or comment are always welcome. Don't hesitate to use GitHub for that. + + + * You can sponsor this project using GitHub's Sponsor button: https://github.com/Naguissa/uEspConfigLib + * You can make a donation via PayPal: https://paypal.me/foroelectro + + +Thanks for your support. + + +Contributors hall of fame: https://www.foroelectro.net/hall-of-fame-f32/contributors-contribuyentes-t271.html diff --git a/examples/uEspConfigLib_example/uEspConfigLib_example.ino b/examples/uEspConfigLib_example/uEspConfigLib_example.ino new file mode 100644 index 0000000..6b94a7d --- /dev/null +++ b/examples/uEspConfigLib_example/uEspConfigLib_example.ino @@ -0,0 +1,231 @@ +/** + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - Example sketch + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLib_example.ino + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ + +#include "Arduino.h" + +#include "uEspConfigLib.h" + + + +// Caution: It need to be a global variable or a global pointer. +// if FS is a 'setup' variable it will lead to crashes +uEspConfigLibFSInterface * configFsA; +uEspConfigLibFSInterface * configFsB; +uEspConfigLibFSInterface * configFsC; +uEspConfigLibFSInterface * configFsD; +uEspConfigLib * config; + + +#ifdef ARDUINO_ARCH_ESP32 + WebServer server(80); +#else + ESP8266WebServer server(80); +#endif + + +/// Available functions: +void setupWiFi(); +void setup(); +void loop(); +void handleGetConfigHtml(); +void handleGetConfigJson(); +void handleSaveConfig(); +void handleDefault(); + + + +void setup() { + Serial.begin(115200); + Serial.println(); + Serial.println("init"); + delay(1500); + + Serial.println(" - SETUP -"); + + + configFsA = new uEspConfigLibFSNone("/config.ini", true); + if (configFsA->status() == uEspConfigLibFS_STATUS_FATAL) { + Serial.println(" * Error initializing FS none"); + } + // Cannot use SPIFFS and LittleFS at same time + //configFsB = new uEspConfigLibFSSpiffs("/config.ini", true); + //if (configFsB->status() == uEspConfigLibFS_STATUS_FATAL) { + // Serial.println(" * Error initializing FS SPIFFS"); + //} + configFsC = new uEspConfigLibFSLittlefs("/config.ini", true); + if (configFsC->status() == uEspConfigLibFS_STATUS_FATAL) { + Serial.println(" * Error initializing FS LittleFS"); + } + configFsD = new uEspConfigLibFSSd("/config.ini", true); + if (configFsD->status() == uEspConfigLibFS_STATUS_FATAL) { + Serial.println(" * Error initializing FS SD"); + } + + config = new uEspConfigLib(configFsC); + + char * readResult; + + Serial.println("\n - configure -"); + // 1st step is to define your variables: Name, Description, Default value + config->addOption("wifi_mode", "WiFi mode (C=Client, other=Access Point)", ""); + config->addOption("wifi_ssid", "SSID of your WiFi", "Unconfigured_device"); + config->addOption("wifi_password", "Password of your WiFi", "wifi_password"); + + + Serial.println("\n - default values -"); + + readResult = config->getPointer("wifi_mode"); + Serial.print("wifi_mode: "); + Serial.println(readResult); + readResult = config->getPointer("wifi_ssid"); + Serial.print("wifi_ssid: "); + Serial.println(readResult); + readResult = config->getPointer("wifi_password"); + Serial.print("wifi_password: "); + Serial.println(readResult); + + + config->loadConfigFile(); + Serial.println("\n - loaded values -"); + + readResult = config->getPointer("wifi_mode"); + Serial.print("wifi_mode: "); + Serial.println(readResult); + readResult = config->getPointer("wifi_ssid"); + Serial.print("wifi_ssid: "); + Serial.println(readResult); + readResult = config->getPointer("wifi_password"); + Serial.print("wifi_password: "); + Serial.println(readResult); + + + Serial.println("\n - manually set values (mode and pass) -"); + + config->set("wifi_mode", "A"); + config->set("wifi_ssid", "uEspConfigLib_EXAMPLE"); + config->set("wifi_password", ""); + + readResult = config->getPointer("wifi_mode"); + Serial.print("wifi_mode: "); + Serial.println(readResult); + readResult = config->getPointer("wifi_ssid"); + Serial.print("wifi_ssid: "); + Serial.println(readResult); + readResult = config->getPointer("wifi_password"); + Serial.print("wifi_password: "); + Serial.println(readResult); + + + + Serial.println("\n - start wifi with last parameters-"); + setupWiFi(); + + Serial.println("\n\n - END -"); + Serial.println(); +} + + +void loop() { + yield(); + server.handleClient(); + yield(); // Important!! +} + + + +void setupWiFi() { + char *mode, *ssid, *pass; + + server.stop(); + WiFi.disconnect(); + #ifndef ARDUINO_ARCH_ESP32 + WiFi.setAutoConnect(true); + #endif + WiFi.setAutoReconnect(true); + + mode = config->getPointer("wifi_mode"); + ssid = config->getPointer("wifi_ssid"); + pass = config->getPointer("wifi_password"); + + if (strcmp(mode, "S") == 0) { + WiFi.mode(WIFI_STA); + WiFi.begin(ssid, pass); + // Wait for connection + uint8_t i = 0; + while (WiFi.status() != WL_CONNECTED && i++ < 30) { //wait 30*2 seconds + Serial.print('.'); + delay(2000); + } + if (i == 31) { + Serial.print("Could not connect to "); + Serial.println(ssid); + return; + } + Serial.print("Connected! IP address: "); + Serial.println(WiFi.localIP()); + } else { // Default mode, 'A' (AP) + WiFi.mode(WIFI_AP); + WiFi.softAP(ssid, pass); + Serial.print("SoftAP created! IP address: "); + Serial.println(WiFi.softAPIP()); + } + + server.on("/configHtml", HTTP_GET, handleGetConfigHtml); + server.on("/configJson", HTTP_GET, handleGetConfigJson); + server.on("/uConfigLib/saveConfig", HTTP_POST, handleSaveConfig); + server.onNotFound(handleDefault); + yield(); + server.begin(); + yield(); + Serial.println("HTTP server started"); +} + +void handleGetConfigHtml() { + Serial.println(" -> Requested configHTML"); + yield(); + config->handleConfigRequestHtml(&server); +} +void handleGetConfigJson() { + Serial.println(" -> Requested configJSON"); + yield(); + config->handleConfigRequestJson(&server); +} +void handleSaveConfig() { + Serial.println(" -> Requested saveConfig"); + yield(); + config->handleSaveConfig(&server); +} +void handleDefault() { + Serial.println(" -> Requested default"); + server.setContentLength(CONTENT_LENGTH_UNKNOWN); + yield(); + server.send(200, "text/html", ""); + yield(); + server.sendContent("IoT device config - uConfigLib

Example. Available items:

"); + yield(); + + server.sendContent("

HTML config page

"); + yield(); + server.sendContent("

JSON config info

"); + yield(); + server.sendContent(""); +} + + diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..40021d2 --- /dev/null +++ b/library.properties @@ -0,0 +1,11 @@ +name=uEspConfigLib +version=1.0.0 +author=Naguissa +maintainer=Naguissa +sentence=The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib +paragraph=Supports ESP32 and ESP8266 microcontrollers. Manages configurations, web requests and storage persistence. +category=Data Processing +url=https://github.com/Naguissa/uEspConfigLib +architectures=esp32,esp8266 +includes=uEspConfigLib.h + diff --git a/src/uEspConfigLib.cpp b/src/uEspConfigLib.cpp new file mode 100644 index 0000000..7834d3d --- /dev/null +++ b/src/uEspConfigLib.cpp @@ -0,0 +1,413 @@ +/** + * \class uEspConfigLib + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLib.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#include +#include "uEspConfigLib.h" +#include "uEspConfigLibFSInterface.h" +#ifdef ARDUINO_ARCH_ESP32 + #include "WebServer.h" +#else + #include "ESP8266WebServer.h" +#endif + + +/** + * \brief Constructor + * + * @param fs Selected uEspConfigLibFSInterface to be used + */ +uEspConfigLib::uEspConfigLib(uEspConfigLibFSInterface * fs) { + _fs = fs; + list = 0; +} + +void uEspConfigLib::_copyName(uEspConfigLibList * slot, const char * value) { + uEspConfigLib_free(slot->name); + slot->name = (char *) malloc(sizeof(char) * (strlen(value) + 1)); + strcpy(slot->name, value); +} + +void uEspConfigLib::_copyDefault(uEspConfigLibList * slot, const char * value) { + uEspConfigLib_free(slot->defaultValue); + slot->defaultValue = (char *) malloc(sizeof(char) * (strlen(value) + 1)); + strcpy(slot->defaultValue, value); +} + +void uEspConfigLib::_copyValue(uEspConfigLibList * slot, const char * value) { + uEspConfigLib_free(slot->value); + slot->value = (char *) malloc(sizeof(char) * (strlen(value) + 1)); + strcpy(slot->value, value); +} + +void uEspConfigLib::_copyValue(uEspConfigLibList * slot, const String value) { + uEspConfigLib_free(slot->value); + slot->value = (char *) malloc(sizeof(char) * (value.length() + 1)); + value.toCharArray(slot->value, value.length() + 1); +} + +void uEspConfigLib::_copyDescription(uEspConfigLibList * slot, const char * value) { + uEspConfigLib_free(slot->description); + slot->description = (char *) malloc(sizeof(char) * (strlen(value) + 1)); + strcpy(slot->description, value); +} + + + +/** + * \brief Defines a configuration option + * + * @param name Name of configuration option + * @param description Description of the configuration option + * @param defaultValue Default value of the configuration option + */ +void uEspConfigLib::addOption(const char * name, const char * description, const char * defaultValue) { + if (list == 0) { + list = new uEspConfigLibList; + _copyName(list, name); + _copyDescription(list, description); + _copyDefault(list, defaultValue); + _copyValue(list, defaultValue); + list->next = 0; + return; + } + + uEspConfigLibList * prev = list; + for (uEspConfigLibList * slot = list; slot != 0; slot = slot->next) { + if (strcmp(slot->name, name) == 0) { + _copyDescription(slot, description); + _copyDefault(slot, defaultValue); + _copyValue(slot, defaultValue); + return; + } + prev = slot; + } + + prev->next = new uEspConfigLibList; + _copyName(prev->next, name); + _copyDescription(prev->next, description); + _copyDefault(prev->next, defaultValue); + _copyValue(prev->next, defaultValue); + prev->next->next = 0; +} + + +/** + * \brief Changes a configuration option current value + * + * @param name Name of configuration option + * @param value Default value of the configuration option + * @return False on error (name not defined previously) + */ +bool uEspConfigLib::set(const char * name, const char *value) { + if (list == 0) { + return false; + } + + for (uEspConfigLibList * slot = list; slot != 0; slot = slot->next) { + if (strcmp(slot->name, name) == 0) { + _copyValue(slot, value); + return true; + } + } + return false; +} + +/** + * \brief Gets a char pointer to the current value of a configuration option + * + * @param name Name of configuration option + * @return Char pointer. Null if not found. + */ +char * uEspConfigLib::getPointer(const char * name) { + for (uEspConfigLibList * slot = list; slot != 0; slot = slot->next) { + if (strcmp(slot->name, name) == 0) { + return slot->value; + } + } + return 0; +} + +/** + * \brief Changes a configuration option to its default value + * + * @param name Name of configuration option + * @return False on error (name not defined previously) + */ +bool uEspConfigLib::clear(const char *name) { + uEspConfigLibList *slot; + for (slot = list; slot != 0; slot = slot->next) { + if (strcmp(slot->name, name) == 0) { + _copyValue(slot, slot->defaultValue); + return true; + } + } + return false; +} + +/** + * \brief Handles a configuration HTML form request + * + * This will handle the request and serve an HTML page with a form with all configurations. + * + * @param server WebServer or ESP8266WebServer variable, depending on architecture + * @param path Path where the form will be sent + */ +void uEspConfigLib::handleConfigRequestHtml(uEspConfigLib_WebServer * server, const char *path) { + server->setContentLength(CONTENT_LENGTH_UNKNOWN); + yield(); + server->send(200, "text/html", ""); + yield(); + server->sendContent("IoT device config - uConfigLib
sendContent(path); + yield(); + server->sendContent("\">"); + yield(); + uEspConfigLibList *slot; + for (slot = list; slot != 0; slot = slot->next) { + server->sendContent(""); + yield(); + } + server->sendContent("

"); + yield(); + uEspConfigLib_WebServer_sendContent(slot->description); + yield(); + server->sendContent(":
"); + yield(); + uEspConfigLib_WebServer_sendContent(slot->name); + yield(); + server->sendContent(" (default: "); + yield(); + uEspConfigLib_WebServer_sendContent(slot->defaultValue); + yield(); + server->sendContent("):name); + yield(); + server->sendContent("\" value=\""); + yield(); + uEspConfigLib_WebServer_sendContent(slot->value); + yield(); + server->sendContent("\">

"); + yield(); +} + +/** + * \brief Handles a configuration JSON request + * + * This will handle the request and serve a JSON document with all configurations: + * + * { + * "data": [ + * { + * "name": "variable_name", + * "description": "variable_description", + * "defaultValue": "variable_default_value", + * "value": "variable_current_value" + * }, + * { + * "name": "variable_name", + * "description": "variable_description", + * "defaultValue": "variable_default_value", + * "value": "variable_current_value" + * }, + * { + * "name": "variable_name", + * "description": "variable_description", + * "defaultValue": "variable_default_value", + * "value": "variable_current_value" + * } + * ] + * } + * + * @param server WebServer or ESP8266WebServer variable, depending on architecture + */ +void uEspConfigLib::handleConfigRequestJson(uEspConfigLib_WebServer * server) { + server->setContentLength(CONTENT_LENGTH_UNKNOWN); + yield(); + server->send(200, "application/vnd.api+json", ""); + yield(); + server->sendContent("{\"data\":["); + yield(); + bool first = true; + for (uEspConfigLibList *slot = list; slot != 0; slot = slot->next) { + if (first) { + first = false; + } else { + server->sendContent(","); + yield(); + } + server->sendContent("{\"name\":\""); + yield(); + uEspConfigLib_WebServer_sendContent(slot->name); + yield(); + server->sendContent("\", \"description\":\""); + yield(); + uEspConfigLib_WebServer_sendContent(slot->description); + yield(); + server->sendContent("\", \"defaultValue\":\""); + yield(); + uEspConfigLib_WebServer_sendContent(slot->defaultValue); + yield(); + server->sendContent("\", \"value\":\""); + yield(); + uEspConfigLib_WebServer_sendContent(slot->value); + yield(); + server->sendContent("\"}"); + yield(); + } + server->sendContent("]}"); +} + + +/** + * \brief Handles a save configuration request + * + * This will handle the request and parameters, change any existing one and save the config file. + * If a config option is not set as parameter will be ignored. If a config option is empty it will be stored as empty. + * It usually will respond with a 302 redirect to /?saved=1, but if "format" paramer is passed with "json" value it will respond as JSON: + * { + * "data": { + * "result": 1 + * } + * } + * + * @param server WebServer or ESP8266WebServer variable, depending on architecture + */ +void uEspConfigLib::handleSaveConfig(uEspConfigLib_WebServer * server) { + String value; + bool isJson; + + value = server->arg("format"); + isJson = (value == "json"); + + for (uEspConfigLibList *slot = list; slot != 0; slot = slot->next) { + if (server->hasArg(slot->name)) { + value = server->arg(slot->name); + value.trim(); + _copyValue(slot, value.c_str()); + } + } + saveConfigFile(); + + server->setContentLength(CONTENT_LENGTH_UNKNOWN); + if (isJson) { + server->send(200, "application/vnd.api+json", ""); + server->sendContent("{\"data\":{\"result\": 1}}"); + } else { + server->sendHeader("Location", "/?saved=1", true); + server->send(302, "text/html",""); + } +} + + +void uEspConfigLib::_parseConfigLine(String line) { + int pos; + String variable, value; + line.trim(); + if (line.startsWith(";") || line.startsWith("#") || line.startsWith("//")) { // comment line + return; + } + pos = line.indexOf('='); + if (pos < 2) { // Not found or too short for sure, skip + return; + } + variable = line.substring(0, pos - 1); + value = line.substring(pos + 1); + variable.trim(); + value.trim(); + + set(variable.c_str(), value.c_str()); +} + + +/** + * \brief Loads config file from FileSystem and processes it + * + * @return False on error + */ +bool uEspConfigLib::loadConfigFile() { + bool result; + String line; + result = _fs->openToRead(); + if (!result) { + return false; + } + while (_fs->readLine(&line)) { + _parseConfigLine(line); + } + _fs->closeFile(); + return true; +} + +/** + * \brief Recreates and overwrites config file to FileSystem with current configurations + * + * @return False on error + */ +bool uEspConfigLib::saveConfigFile() { + bool result; + + result = _fs->openToWrite(); + if (!result) { + return false; + } + _fs->write("# uConfigLib Configuration file\n"); + yield(); + _fs->write("# Visit https://github.com/Naguissa/uEspConfigLib for details\n"); + yield(); + _fs->write("# Syntax:\n"); + yield(); + _fs->write("# variable = value\n"); + yield(); + _fs->write("# (spaces and empty lines doesn't care)\n"); + yield(); + _fs->write("# This file comments: lines starting with #, ; or //\n"); + yield(); + + for (uEspConfigLibList * slot = list; slot != 0; slot = slot->next) { + _fs->write("\n# "); + yield(); + _fs->write(slot->name); + yield(); + _fs->write(" -- "); + yield(); + _fs->write(slot->description); + yield(); + _fs->write("\n# Default value: "); + yield(); + _fs->write(slot->defaultValue); + yield(); + _fs->write("\n"); + yield(); + _fs->write(slot->name); + yield(); + _fs->write(" = "); + yield(); + _fs->write(slot->value); + yield(); + _fs->write("\n"); + yield(); + } + _fs->closeFile(); + yield(); + return true; +} + diff --git a/src/uEspConfigLib.h b/src/uEspConfigLib.h new file mode 100644 index 0000000..537cba0 --- /dev/null +++ b/src/uEspConfigLib.h @@ -0,0 +1,189 @@ +/** + * \class uEspConfigLib + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLib.h + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#pragma once + +#include +#ifdef ARDUINO_ARCH_ESP32 + #include + #include + #include "WebServer.h" +#else + #include "ESP8266WebServer.h" +#endif +#include "uEspConfigLibFSInterface.h" +#include "uEspConfigLibFSNone.h" +#include "uEspConfigLibFSSpiffs.h" +#include "uEspConfigLibFSLittlefs.h" +#include "uEspConfigLibFSSd.h" +#ifdef ARDUINO_ARCH_ESP32 + #include "WebServer.h" + #define uEspConfigLib_WebServer WebServer +#else + #include "ESP8266WebServer.h" + #define uEspConfigLib_WebServer ESP8266WebServer +#endif + + +struct uEspConfigLibList { + uEspConfigLibList() : next(0), name(0), description(0), defaultValue(0), value(0) {}; + uEspConfigLibList *next; + char * name; + char * description; + char * defaultValue; + char * value; +}; + +#define uEspConfigLib_free(field) if (field != 0) { free(field); field = 0; } +#define uEspConfigLib_WebServer_sendContent(data) if (*data != 0) { server->sendContent(data); } + +class uEspConfigLib { + public: + /** + * \brief Constructor + * + * @param fs Selected uEspConfigLibFSInterface to be used + */ + uEspConfigLib(uEspConfigLibFSInterface *); + + // Regular usage functions + /** + * \brief Defines a configuration option + * + * @param name Name of configuration option + * @param description Description of the configuration option + * @param defaultValue Default value of the configuration option + */ + void addOption(const char *, const char *, const char *); + + /** + * \brief Changes a configuration option current value + * + * @param name Name of configuration option + * @param value Default value of the configuration option + * @return False on error (name not defined previously) + */ + bool set(const char *, const char *); + + /** + * \brief Gets a char pointer to the current value of a configuration option + * + * @param name Name of configuration option + * @return Char pointer. Null if not found. + */ + char * getPointer(const char *); + + /** + * \brief Changes a configuration option to its default value + * + * @param name Name of configuration option + * @return False on error (name not defined previously) + */ + bool clear(const char *); + + // Web server functions + /** + * \brief Handles a configuration HTML form request + * + * This will handle the request and serve an HTML page with a form with all configurations. + * + * @param server WebServer or ESP8266WebServer variable, depending on architecture + * @param path Path where the form will be sent + */ + void handleConfigRequestHtml(uEspConfigLib_WebServer *, const char * = "/uConfigLib/saveConfig"); + + /** + * \brief Handles a configuration JSON request + * + * This will handle the request and serve a JSON document with all configurations: + * + * { + * "data": [ + * { + * "name": "variable_name", + * "description": "variable_description", + * "defaultValue": "variable_default_value", + * "value": "variable_current_value" + * }, + * { + * "name": "variable_name", + * "description": "variable_description", + * "defaultValue": "variable_default_value", + * "value": "variable_current_value" + * }, + * { + * "name": "variable_name", + * "description": "variable_description", + * "defaultValue": "variable_default_value", + * "value": "variable_current_value" + * } + * ] + * } + * + * @param server WebServer or ESP8266WebServer variable, depending on architecture + */ + void handleConfigRequestJson(uEspConfigLib_WebServer *); + + /** + * \brief Handles a save configuration request + * + * This will handle the request and parameters, change any existing one and save the config file. + * If a config option is not set as parameter will be ignored. If a config option is empty it will be stored as empty. + * It usually will respond with a 302 redirect to /?saved=1, but if "format" paramer is passed with "json" value it will respond as JSON: + * { + * "data": { + * "result": 1 + * } + * } + * + * @param server WebServer or ESP8266WebServer variable, depending on architecture + */ + void handleSaveConfig(uEspConfigLib_WebServer *); + + + // FS functions + + /** + * \brief Loads config file from FileSystem and processes it + * + * @return False on error + */ + bool loadConfigFile(); + + /** + * \brief Recreates and overwrites config file to FileSystem with current configurations + * + * @return False on error + */ + bool saveConfigFile(); + + private: + uEspConfigLib(); // 1 arg needed + void _copyName(uEspConfigLibList *, const char *); + void _copyDefault(uEspConfigLibList *, const char *); + void _copyValue(uEspConfigLibList *, const char *); + void _copyValue(uEspConfigLibList *, const String); + void _copyDescription(uEspConfigLibList *, const char *); + void _parseConfigLine(String); + uEspConfigLibList *list; + uEspConfigLibFSInterface * _fs; + +}; + diff --git a/src/uEspConfigLibFSInterface.h b/src/uEspConfigLibFSInterface.h new file mode 100644 index 0000000..09085aa --- /dev/null +++ b/src/uEspConfigLibFSInterface.h @@ -0,0 +1,101 @@ +/** + * \class uEspConfigLibFSInterface + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - FileSystem interface part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSInterface.h + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#pragma once + +#include + +/** + * \brief FileSystem class status: UNITIALIZED + */ +#define uEspConfigLibFS_STATUS_NOINIT 0 +/** + * \brief FileSystem class status: FILE CLOSED + */ +#define uEspConfigLibFS_STATUS_CLOSED 1 +/** + * \brief FileSystem class status: FILE OPEN TO READ + */ +#define uEspConfigLibFS_STATUS_OPEN_READ 2 +/** + * \brief FileSystem class status: FILE OPEN TO WRITE + */ +#define uEspConfigLibFS_STATUS_OPEN_WRITE 3 +/** + * \brief FileSystem class status: TEMPORARY ERROR + */ +#define uEspConfigLibFS_STATUS_ERROR 9 +/** + * \brief FileSystem class status: FATAL ERROR + */ +#define uEspConfigLibFS_STATUS_FATAL 10 + +class uEspConfigLibFSInterface { + public: + // Regular usage functions + /** + * \brief Opens the file for read + * + * @return False on error + */ + virtual bool openToRead() { return false; }; + + /** + * \brief Opens the file for write + * + * @return False on error + */ + virtual bool openToWrite() { return false; }; + + /** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ + virtual bool readLine(String *) { return false; }; + + /** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ + virtual bool write(const char *) { return false; }; + + /** + * \brief Closes current file + * + * @return False on error + */ + virtual bool closeFile() { return false; }; + + /** + * \brief Returns current status + * + * @return Current status + */ + uint8_t status() { return _status; } + + private: + uint8_t _status; + char * _path = 0; +}; + diff --git a/src/uEspConfigLibFSLittlefs.cpp b/src/uEspConfigLibFSLittlefs.cpp new file mode 100644 index 0000000..3dce308 --- /dev/null +++ b/src/uEspConfigLibFSLittlefs.cpp @@ -0,0 +1,165 @@ +/** + * \class uEspConfigLibFSLittlefs + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - Littlefs FileSystem interface implementation part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSLittlefs.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#include +#include "uEspConfigLibFSInterface.h" +#include "uEspConfigLibFSLittlefs.h" + + +/** + * \brief Constructor + * + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ +uEspConfigLibFSLittlefs::uEspConfigLibFSLittlefs(const bool init) { + uEspConfigLibFSLittlefs("/uEspConfig.ini", init); +} + +/** + * \brief Constructor + * + * @param path File path on filesystem + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ +uEspConfigLibFSLittlefs::uEspConfigLibFSLittlefs(const char *path, const bool init) { + _status = uEspConfigLibFS_STATUS_CLOSED; + + // Copy path + _path = (char *) malloc(sizeof(char) * (strlen(path) + 1)); + strcpy(_path, path); + + // Init FS if requested + if (init) { + _status = uEspConfigLibFS_STATUS_NOINIT; + bool correct = LittleFS.begin(uEspConfigLibFSLittlefs_begin_param); + yield(); + if (!correct) { + LittleFS.format(); + yield(); + correct = LittleFS.begin(); + yield(); + } + if (correct) { + _status = uEspConfigLibFS_STATUS_CLOSED; + } else { + _status = uEspConfigLibFS_STATUS_FATAL; + } + } +} + +/** + * \brief Opens the file for read + * + * @return False on error + */ +bool uEspConfigLibFSLittlefs::openToRead() { + if (_status == uEspConfigLibFS_STATUS_FATAL) { + return false; + } + + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + } + _dataFile = LittleFS.open(_path, "r"); + yield(); + if (!_dataFile) { + _status = uEspConfigLibFS_STATUS_ERROR; + return false; + } + _status = uEspConfigLibFS_STATUS_OPEN_READ; + return true; +} + + +/** + * \brief Opens the file for write + * + * @return False on error + */ +bool uEspConfigLibFSLittlefs::openToWrite() { + if (_status == uEspConfigLibFS_STATUS_FATAL) { + return false; + } + + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + } + _dataFile = LittleFS.open(_path, "w"); + yield(); + if (!_dataFile) { + _status = uEspConfigLibFS_STATUS_ERROR; + return false; + } + _status = uEspConfigLibFS_STATUS_OPEN_WRITE; + return true; +} + + +/** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ +bool uEspConfigLibFSLittlefs::readLine(String *line) { + if (_status != uEspConfigLibFS_STATUS_OPEN_READ) { + return false; + } + if (_dataFile.available()) { + yield(); + *line = _dataFile.readStringUntil('\n'); + yield(); + return true; + } + return false; +} + +/** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ +bool uEspConfigLibFSLittlefs::write(const char *data) { + if (_status != uEspConfigLibFS_STATUS_OPEN_WRITE) { + return false; + } + return (uEspConfigLibFSLittlefs_writeCasted(data) > 0); +} + +/** + * \brief Closes current file + * + * @return False on error + */ +bool uEspConfigLibFSLittlefs::closeFile() { + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + return true; + } + return false; +} + diff --git a/src/uEspConfigLibFSLittlefs.h b/src/uEspConfigLibFSLittlefs.h new file mode 100644 index 0000000..dc3ba02 --- /dev/null +++ b/src/uEspConfigLibFSLittlefs.h @@ -0,0 +1,96 @@ +/** + * \class uEspConfigLibFSLittlefs + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - Littlefs FileSystem interface implementation part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSLittlefs.h + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#pragma once + +#include +#include "uEspConfigLibFSInterface.h" +#include "FS.h" +#include "LittleFS.h" + +#ifdef ARDUINO_ARCH_ESP32 + #define uEspConfigLibFSLittlefs_writeCasted(data) _dataFile.write((uint8_t *) data, strlen(data)) + #define uEspConfigLibFSLittlefs_begin_param true +#else + #define uEspConfigLibFSLittlefs_writeCasted(data) _dataFile.write(data, strlen(data)) + #define uEspConfigLibFSLittlefs_begin_param +#endif + + +class uEspConfigLibFSLittlefs : public uEspConfigLibFSInterface { + public: + /** + * \brief Constructor + * + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ + uEspConfigLibFSLittlefs(const bool=false); + + /** + * \brief Constructor + * + * @param path File path on filesystem + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ + uEspConfigLibFSLittlefs(const char*, const bool=false); + + /** + * \brief Opens the file for read + * + * @return False on error + */ + bool openToRead(); + + /** + * \brief Opens the file for write + * + * @return False on error + */ + bool openToWrite(); + + /** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ + bool readLine(String *); + + /** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ + bool write(const char *); + + /** + * \brief Closes current file + * + * @return False on error + */ + bool closeFile(); + + private: + uint8_t _status; + char * _path = 0; + fs::File _dataFile; +}; + diff --git a/src/uEspConfigLibFSNone.cpp b/src/uEspConfigLibFSNone.cpp new file mode 100644 index 0000000..938a5b8 --- /dev/null +++ b/src/uEspConfigLibFSNone.cpp @@ -0,0 +1,76 @@ +/** + * \class uEspConfigLibFSNone + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - NO FileSystem interface implementation part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSNone.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#include +#include "uEspConfigLibFSInterface.h" +#include "uEspConfigLibFSNone.h" + +/** + * \brief Constructor + * + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ +uEspConfigLibFSNone::uEspConfigLibFSNone(const bool init = false) {} + +/** + * \brief Constructor + * + * @param unused File path on filesystem + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ +uEspConfigLibFSNone::uEspConfigLibFSNone(const char *unused, const bool init=false) {} + +/** + * \brief Opens the file for read + * + * @return False on error + */ +bool uEspConfigLibFSNone::openToRead() {return true;} + +/** + * \brief Opens the file for write + * + * @return False on error + */ +bool uEspConfigLibFSNone::openToWrite() {return true;} + +/** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ +bool uEspConfigLibFSNone::readLine(String *unused) {return false;} + +/** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ +bool uEspConfigLibFSNone::write(const char *unused) {return true;} + +/** + * \brief Closes current file + * + * @return False on error + */ +bool uEspConfigLibFSNone::closeFile() {return true;} + diff --git a/src/uEspConfigLibFSNone.h b/src/uEspConfigLibFSNone.h new file mode 100644 index 0000000..f5589cb --- /dev/null +++ b/src/uEspConfigLibFSNone.h @@ -0,0 +1,83 @@ +/** + * \class uEspConfigLibFSNone + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - NO FileSystem interface implementation part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSNone.h + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */#pragma once + +#include +#include "uEspConfigLibFSInterface.h" + +class uEspConfigLibFSNone : public uEspConfigLibFSInterface { + public: + /** + * \brief Constructor + * + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ + uEspConfigLibFSNone(const bool); + + /** + * \brief Constructor + * + * @param unused File path on filesystem + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ + uEspConfigLibFSNone(const char*, const bool); + + /** + * \brief Opens the file for read + * + * @return False on error + */ + bool openToRead(); + + /** + * \brief Opens the file for write + * + * @return False on error + */ + bool openToWrite(); + + /** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ + bool readLine(String *); + + /** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ + bool write(const char *); + + /** + * \brief Closes current file + * + * @return False on error + */ + bool closeFile(); + + private: + uint8_t _status; + char * _path = 0; +}; + diff --git a/src/uEspConfigLibFSSd.cpp b/src/uEspConfigLibFSSd.cpp new file mode 100644 index 0000000..39ff462 --- /dev/null +++ b/src/uEspConfigLibFSSd.cpp @@ -0,0 +1,158 @@ +/** + * \class uEspConfigLibFSSd + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - SD-card FileSystem interface implementation part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSSd.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#include +#include "uEspConfigLibFSInterface.h" +#include "uEspConfigLibFSSd.h" + + +/** + * \brief Constructor + * + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ +uEspConfigLibFSSd::uEspConfigLibFSSd(const bool init) { + uEspConfigLibFSSd("/uEspConfig.ini", init, SS); +} + +/** + * \brief Constructor + * + * @param path File path on filesystem + * @param init Set to true if you want to initialize and format (if needed) the filesystem + * @param pin CS pin, if not the standard one + */ +uEspConfigLibFSSd::uEspConfigLibFSSd(const char * path, const bool init, const uint8_t pin) { + _status = uEspConfigLibFS_STATUS_CLOSED; + + // Copy path + _path = (char *) malloc(sizeof(char) * (strlen(path) + 1)); + strcpy(_path, path); + + // Init FS if requested + if (init) { + if (SD.begin(pin)) { + _status = uEspConfigLibFS_STATUS_CLOSED; + } else { + _status = uEspConfigLibFS_STATUS_FATAL; + } + } +} + +/** + * \brief Opens the file for read + * + * @return False on error + */ +bool uEspConfigLibFSSd::openToRead() { + if (_status == uEspConfigLibFS_STATUS_FATAL) { + return false; + } + + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + } + + _dataFile = SD.open(_path, FILE_READ); + if (_dataFile.isDirectory()) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_FATAL; + return false; + } + _status = uEspConfigLibFS_STATUS_OPEN_READ; + return true; +} + + +/** + * \brief Opens the file for write + * + * @return False on error + */ +bool uEspConfigLibFSSd::openToWrite() { + if (_status == uEspConfigLibFS_STATUS_FATAL) { + return false; + } + + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + } + + _dataFile = SD.open(_path, FILE_WRITE); + if (!_dataFile) { + _status = uEspConfigLibFS_STATUS_ERROR; + return false; + } + _status = uEspConfigLibFS_STATUS_OPEN_WRITE; + return true; +} + + +/** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ +bool uEspConfigLibFSSd::readLine(String *line) { + if (_status != uEspConfigLibFS_STATUS_OPEN_READ) { + return false; + } + if (_dataFile.available()) { + yield(); + *line = _dataFile.readStringUntil('\n'); + yield(); + return true; + } + return false; +} + +/** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ +bool uEspConfigLibFSSd::write(const char *data) { + if (_status != uEspConfigLibFS_STATUS_OPEN_WRITE) { + return false; + } + return (uEspConfigLibFSSd_writeCasted(data) > 0); +} + +/** + * \brief Closes current file + * + * @return False on error + */ +bool uEspConfigLibFSSd::closeFile() { + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + return true; + } + return false; +} + diff --git a/src/uEspConfigLibFSSd.h b/src/uEspConfigLibFSSd.h new file mode 100644 index 0000000..c856978 --- /dev/null +++ b/src/uEspConfigLibFSSd.h @@ -0,0 +1,95 @@ +/** + * \class uEspConfigLibFSSd + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - SD-card FileSystem interface implementation part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSSd.h + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#pragma once + +#include +#include "uEspConfigLibFSInterface.h" +#include +#include + +#ifdef ARDUINO_ARCH_ESP32 + #define uEspConfigLibFSSd_writeCasted(data) _dataFile.write((uint8_t *) data, strlen(data)) +#else + #define uEspConfigLibFSSd_writeCasted(data) _dataFile.write(data, strlen(data)) +#endif + + +class uEspConfigLibFSSd : public uEspConfigLibFSInterface { + public: + /** + * \brief Constructor + * + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ + uEspConfigLibFSSd(const bool); + + /** + * \brief Constructor + * + * @param path File path on filesystem + * @param init Set to true if you want to initialize and format (if needed) the filesystem + * @param pin CS pin, if not the standard one + */ + uEspConfigLibFSSd(const char*, const bool = false, const uint8_t = SS); + + /** + * \brief Opens the file for read + * + * @return False on error + */ + bool openToRead(); + + /** + * \brief Opens the file for write + * + * @return False on error + */ + bool openToWrite(); + + /** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ + bool readLine(String *); + + /** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ + bool write(const char *); + + /** + * \brief Closes current file + * + * @return False on error + */ + bool closeFile(); + + private: + uint8_t _status; + char * _path = 0; + File _dataFile; +}; + diff --git a/src/uEspConfigLibFSSpiffs.cpp b/src/uEspConfigLibFSSpiffs.cpp new file mode 100644 index 0000000..4e74a3a --- /dev/null +++ b/src/uEspConfigLibFSSpiffs.cpp @@ -0,0 +1,164 @@ +/** + * \class uEspConfigLibFSSpiffs + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - SPIFFS FileSystem interface implementation part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSSpiffs.cpp + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */#include +#include "uEspConfigLibFSInterface.h" +#include "uEspConfigLibFSSpiffs.h" + + +/** + * \brief Constructor + * + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ +uEspConfigLibFSSpiffs::uEspConfigLibFSSpiffs(const bool init) { + uEspConfigLibFSSpiffs("/uEspConfig.ini", init); +} + +/** + * \brief Constructor + * + * @param path File path on filesystem + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ +uEspConfigLibFSSpiffs::uEspConfigLibFSSpiffs(const char *path, const bool init) { + _status = uEspConfigLibFS_STATUS_CLOSED; + + // Copy path + _path = (char *) malloc(sizeof(char) * (strlen(path) + 1)); + strcpy(_path, path); + + // Init FS if requested + if (init) { + _status = uEspConfigLibFS_STATUS_NOINIT; + bool correct = SPIFFS.begin(); + yield(); + if (!correct) { + SPIFFS.format(); + yield(); + correct = SPIFFS.begin(); + yield(); + } + if (correct) { + _status = uEspConfigLibFS_STATUS_CLOSED; + } else { + _status = uEspConfigLibFS_STATUS_FATAL; + } + } +} + +/** + * \brief Opens the file for read + * + * @return False on error + */ +bool uEspConfigLibFSSpiffs::openToRead() { + if (_status == uEspConfigLibFS_STATUS_FATAL) { + return false; + } + + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + } + _dataFile = SPIFFS.open(_path, "r"); + yield(); + if (!_dataFile) { + _status = uEspConfigLibFS_STATUS_ERROR; + return false; + } + _status = uEspConfigLibFS_STATUS_OPEN_READ; + return true; +} + + +/** + * \brief Opens the file for write + * + * @return False on error + */ +bool uEspConfigLibFSSpiffs::openToWrite() { + if (_status == uEspConfigLibFS_STATUS_FATAL) { + return false; + } + + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + } + _dataFile = SPIFFS.open(_path, "w"); + yield(); + if (!_dataFile) { + _status = uEspConfigLibFS_STATUS_ERROR; + return false; + } + _status = uEspConfigLibFS_STATUS_OPEN_WRITE; + return true; +} + + +/** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ +bool uEspConfigLibFSSpiffs::readLine(String *line) { + if (_status != uEspConfigLibFS_STATUS_OPEN_READ) { + return false; + } + if (_dataFile.available()) { + yield(); + *line = _dataFile.readStringUntil('\n'); + yield(); + return true; + } + return false; +} + +/** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ +bool uEspConfigLibFSSpiffs::write(const char *data) { + if (_status != uEspConfigLibFS_STATUS_OPEN_WRITE) { + return false; + } + return (uEspConfigLibFSSpiffs_writeCasted(data) > 0); +} + +/** + * \brief Closes current file + * + * @return False on error + */ +bool uEspConfigLibFSSpiffs::closeFile() { + if (_status == uEspConfigLibFS_STATUS_OPEN_READ || _status == uEspConfigLibFS_STATUS_OPEN_WRITE) { + _dataFile.close(); + _status = uEspConfigLibFS_STATUS_CLOSED; + yield(); + return true; + } + return false; +} + diff --git a/src/uEspConfigLibFSSpiffs.h b/src/uEspConfigLibFSSpiffs.h new file mode 100644 index 0000000..8de5975 --- /dev/null +++ b/src/uEspConfigLibFSSpiffs.h @@ -0,0 +1,94 @@ +/** + * \class uEspConfigLibFSSpiffs + * \brief The deffinitive ESP32 and ESP8266 configuration Arduino library, uEspConfigLib - SPIFFS FileSystem interface implementation part + * + * This library consist in 2 parts: + * + * One main library, uEspConfigLib, that manages configuration options, defaults, configuration site (HTML and JSON), configuration processing (from a POST of previous site) and configuration storage. + * + * One interface to manage different configuration storages. + * + * Currently storage classes are: SD-card, LittleFS, SPIFFS and none (values are lost after restart). + * + * + * @file uEspConfigLibFSSpiffs.h + * @copyright Naguissa + * @author Naguissa + * @see https://github.com/Naguissa/uEspConfigLib + * @see naguissa@foroelectro.net + * @version 1.0.0 + */ +#pragma once + +#include +#include "uEspConfigLibFSInterface.h" +#include "FS.h" + + +#ifdef ARDUINO_ARCH_ESP32 + #include "SPIFFS.h" + #define uEspConfigLibFSSpiffs_writeCasted(data) _dataFile.write((uint8_t *) data, strlen(data)) +#else + #define uEspConfigLibFSSpiffs_writeCasted(data) _dataFile.write(data, strlen(data)) +#endif + +class uEspConfigLibFSSpiffs : public uEspConfigLibFSInterface { + public: + /** + * \brief Constructor + * + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ + uEspConfigLibFSSpiffs(const bool=false); + + /** + * \brief Constructor + * + * @param path File path on filesystem + * @param init Set to true if you want to initialize and format (if needed) the filesystem + */ + uEspConfigLibFSSpiffs(const char*, const bool=false); + + /** + * \brief Opens the file for read + * + * @return False on error + */ + bool openToRead(); + + /** + * \brief Opens the file for write + * + * @return False on error + */ + bool openToWrite(); + + /** + * \brief Reads a whole line from current file + * + * @param line String pointer where line will be read + * @return False on error + */ + bool readLine(String *); + + /** + * \brief Writes content to current file + * + * @param data char array pointer to be written + * @return False on error + */ + bool write(const char *); + + /** + * \brief Closes current file + * + * @return False on error + */ + bool closeFile(); + + private: + uint8_t _status; + char * _path = 0; + fs::File _dataFile; +}; + diff --git a/src/~gvfM9dX.tmp b/src/~gvfM9dX.tmp new file mode 100644 index 0000000..e69de29