diff --git a/.circleci/config.yml b/.circleci/config.yml index e5427994..fa6af4e9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -34,6 +34,7 @@ jobs: - run: platformio ci ./examples/SingleButton --board=esp01_1m --board=nodemcuv2 --board=esp32dev - run: platformio ci ./examples/SonoffDualShutters --board=esp01_1m --board=nodemcuv2 --board=esp32dev - run: platformio ci ./examples/TemperatureSensor --board=esp01_1m --board=nodemcuv2 --board=esp32dev + - run: platformio ci ./examples/Broadcast -O "build_flags = -D HOMIE_LITTLEFS" --board=esp01_1m --board=nodemcuv2 --board=esp32dev lint: working_directory: ~/code diff --git a/library.json b/library.json index 904a3fcc..ea0965e1 100644 --- a/library.json +++ b/library.json @@ -42,6 +42,12 @@ }, { "name": "ESP Async WebServer" + }, + { + "owner": "lorol", + "name": "LittleFS_esp32", + "version": "^1.0.5", + "platforms": ["espressif32"] } ], "export": { diff --git a/src/Homie/Boot/BootConfig.cpp b/src/Homie/Boot/BootConfig.cpp index 6e39152f..615c1527 100644 --- a/src/Homie/Boot/BootConfig.cpp +++ b/src/Homie/Boot/BootConfig.cpp @@ -285,15 +285,15 @@ void BootConfig::_onCaptivePortal(AsyncWebServerRequest *request) { Interface::get().getLogger() << F("Proxy") << endl; _proxyHttpRequest(request); } - } else if (request->url() == "/" && !SPIFFS.exists(CONFIG_UI_BUNDLE_PATH)) { + } else if (request->url() == "/" && !_fs.exists(CONFIG_UI_BUNDLE_PATH)) { // UI File not found String msg = String(F("UI bundle not loaded. See Configuration API usage: http://homieiot.github.io/homie-esp8266")); Interface::get().getLogger() << msg << endl; request->send(404, F("text/plain"), msg); - } else if (request->url() == "/" && SPIFFS.exists(CONFIG_UI_BUNDLE_PATH)) { + } else if (request->url() == "/" && _fs.exists(CONFIG_UI_BUNDLE_PATH)) { // Respond with UI Interface::get().getLogger() << F("UI bundle found") << endl; - AsyncWebServerResponse *response = request->beginResponse(SPIFFS.open(CONFIG_UI_BUNDLE_PATH, "r"), F("index.html"), F("text/html")); + AsyncWebServerResponse *response = request->beginResponse(_fs.open(CONFIG_UI_BUNDLE_PATH, "r"), F("index.html"), F("text/html")); request->send(response); } else { // Faild to find request diff --git a/src/Homie/Boot/BootConfig.hpp b/src/Homie/Boot/BootConfig.hpp index 552ab194..9d6c5743 100644 --- a/src/Homie/Boot/BootConfig.hpp +++ b/src/Homie/Boot/BootConfig.hpp @@ -10,7 +10,6 @@ #include #include #include -#include #elif defined(ESP8266) #include #include @@ -40,6 +39,7 @@ class BootConfig : public Boot { void loop(); private: + FS _fs; AsyncWebServer _http; HTTPClient _httpClient; DNSServer _dns; diff --git a/src/Homie/Config.cpp b/src/Homie/Config.cpp index da37f6d6..c0db86c7 100644 --- a/src/Homie/Config.cpp +++ b/src/Homie/Config.cpp @@ -2,36 +2,24 @@ using namespace HomieInternals; +HomieInternals::FS Config::_fs = HomieInternals::FS(); + Config::Config() : _configStruct() - , _spiffsBegan(false) , _valid(false) { } -bool Config::_spiffsBegin() { - if (!_spiffsBegan) { -#ifdef ESP32 - _spiffsBegan = SPIFFS.begin(true); -#elif defined(ESP8266) - _spiffsBegan = SPIFFS.begin(); -#endif - if (!_spiffsBegan) Interface::get().getLogger() << F("✖ Cannot mount filesystem") << endl; - } - - return _spiffsBegan; -} - bool Config::load() { - if (!_spiffsBegin()) { return false; } + if (!_fs.begin()) { return false; } _valid = false; - if (!SPIFFS.exists(CONFIG_FILE_PATH)) { + if (!_fs.exists(CONFIG_FILE_PATH)) { Interface::get().getLogger() << F("✖ ") << CONFIG_FILE_PATH << F(" doesn't exist") << endl; return false; } - File configFile = SPIFFS.open(CONFIG_FILE_PATH, "r"); + File configFile = _fs.open(CONFIG_FILE_PATH, "r"); if (!configFile) { Interface::get().getLogger() << F("✖ Cannot open config file") << endl; return false; @@ -148,7 +136,7 @@ bool Config::load() { } char* Config::getSafeConfigFile() const { - File configFile = SPIFFS.open(CONFIG_FILE_PATH, "r"); + File configFile = _fs.open(CONFIG_FILE_PATH, "r"); size_t configSize = configFile.size(); char buf[MAX_JSON_CONFIG_FILE_SIZE]; @@ -170,19 +158,19 @@ char* Config::getSafeConfigFile() const { } void Config::erase() { - if (!_spiffsBegin()) { return; } + if (!_fs.begin()) { return; } - SPIFFS.remove(CONFIG_FILE_PATH); - SPIFFS.remove(CONFIG_NEXT_BOOT_MODE_FILE_PATH); + _fs.remove(CONFIG_FILE_PATH); + _fs.remove(CONFIG_NEXT_BOOT_MODE_FILE_PATH); } void Config::setHomieBootModeOnNextBoot(HomieBootMode bootMode) { - if (!_spiffsBegin()) { return; } + if (!_fs.begin()) { return; } if (bootMode == HomieBootMode::UNDEFINED) { - SPIFFS.remove(CONFIG_NEXT_BOOT_MODE_FILE_PATH); + _fs.remove(CONFIG_NEXT_BOOT_MODE_FILE_PATH); } else { - File bootModeFile = SPIFFS.open(CONFIG_NEXT_BOOT_MODE_FILE_PATH, "w"); + File bootModeFile = _fs.open(CONFIG_NEXT_BOOT_MODE_FILE_PATH, "w"); if (!bootModeFile) { Interface::get().getLogger() << F("✖ Cannot open NEXTMODE file") << endl; return; @@ -195,9 +183,9 @@ void Config::setHomieBootModeOnNextBoot(HomieBootMode bootMode) { } HomieBootMode Config::getHomieBootModeOnNextBoot() { - if (!_spiffsBegin()) { return HomieBootMode::UNDEFINED; } + if (!_fs.begin()) { return HomieBootMode::UNDEFINED; } - File bootModeFile = SPIFFS.open(CONFIG_NEXT_BOOT_MODE_FILE_PATH, "r"); + File bootModeFile = _fs.open(CONFIG_NEXT_BOOT_MODE_FILE_PATH, "r"); if (bootModeFile) { int v = bootModeFile.parseInt(); bootModeFile.close(); @@ -208,11 +196,11 @@ HomieBootMode Config::getHomieBootModeOnNextBoot() { } void Config::write(const JsonObject config) { - if (!_spiffsBegin()) { return; } + if (!_fs.begin()) { return; } - SPIFFS.remove(CONFIG_FILE_PATH); + _fs.remove(CONFIG_FILE_PATH); - File configFile = SPIFFS.open(CONFIG_FILE_PATH, "w"); + File configFile = _fs.open(CONFIG_FILE_PATH, "w"); if (!configFile) { Interface::get().getLogger() << F("✖ Cannot open config file") << endl; return; @@ -222,7 +210,7 @@ void Config::write(const JsonObject config) { } bool Config::patch(const char* patch) { - if (!_spiffsBegin()) { return false; } + if (!_fs.begin()) { return false; } StaticJsonDocument patchJsonDoc; @@ -232,7 +220,7 @@ bool Config::patch(const char* patch) { } JsonObject patchObject = patchJsonDoc.as(); - File configFile = SPIFFS.open(CONFIG_FILE_PATH, "r"); + File configFile = _fs.open(CONFIG_FILE_PATH, "r"); if (!configFile) { Interface::get().getLogger() << F("✖ Cannot open config file") << endl; return false; diff --git a/src/Homie/Config.hpp b/src/Homie/Config.hpp index 437f08ea..8304a836 100644 --- a/src/Homie/Config.hpp +++ b/src/Homie/Config.hpp @@ -3,10 +3,7 @@ #include "Arduino.h" #include -#ifdef ESP32 -#include -#endif // ESP32 -#include "FS.h" +#include "FS.hpp" #include "Datatypes/Interface.hpp" #include "Datatypes/ConfigStruct.hpp" #include "Utils/DeviceId.hpp" @@ -34,7 +31,7 @@ class Config { private: ConfigStruct _configStruct; - bool _spiffsBegan; + static FS _fs; bool _valid; bool _spiffsBegin(); diff --git a/src/Homie/Constants.hpp b/src/Homie/Constants.hpp index ed93903d..150f11a3 100644 --- a/src/Homie/Constants.hpp +++ b/src/Homie/Constants.hpp @@ -10,6 +10,28 @@ #define HOMIE_CONFIG 1 #endif +// config mode requires SPIFFS as ESP Async Webserver only works with SPIFFS +#if HOMIE_CONFIG +#ifndef HOMIE_SPIFFS +#define HOMIE_SPIFFS +#endif +#endif + +// default should be SPIFFS, except using LittleFS is explicitely defined +#ifndef HOMIE_LITTLEFS +#ifndef HOMIE_SPIFFS +#define HOMIE_SPIFFS +#endif +#endif + +// fail if none or both are defined +#if defined(HOMIE_SPIFFS) && defined(HOMIE_LITTLEFS) +#error "Only one of HOMIE_SPIFFS and HOMIE_LITTLEFS must be defined. HOMIE_CONFIG requires HOMIE_SPIFFS." +#endif +#if !(defined(HOMIE_SPIFFS) || defined(HOMIE_LITTLEFS)) +#error "At least one of HOMIE_SPIFFS or HOMIE_LITTLEFS needs to be defined." +#endif + namespace HomieInternals { const char HOMIE_VERSION[] = "3.0.1"; const char HOMIE_ESP8266_VERSION[] = "3.0.0"; diff --git a/src/Homie/FS.cpp b/src/Homie/FS.cpp new file mode 100644 index 00000000..924f4c79 --- /dev/null +++ b/src/Homie/FS.cpp @@ -0,0 +1,47 @@ +#include "FS.hpp" + +#include "Datatypes/Interface.hpp" + +HomieInternals::FS::FS() + : _began(false) { +} + +bool HomieInternals::FS::begin() { + if (!_began) { +#if defined(HOMIE_SPIFFS) +#if defined(ESP8266) + _began = SPIFFS.begin(); +#elif defined(ESP32) + _began = SPIFFS.begin(true); +#endif +#elif defined(HOMIE_LITTLEFS) + _began = LittleFS.begin(); +#endif + if (!_began) Interface::get().getLogger() << F("✖ Cannot mount filesystem") << endl; + } + return _began; +} + +bool HomieInternals::FS::exists(const char *filepath) { +#if defined(HOMIE_SPIFFS) + return SPIFFS.exists(filepath); +#elif defined(HOMIE_LITTLEFS) + return LittleFS.exists(filepath); +#endif +} + +File HomieInternals::FS::open(const char* path, const char* mode) { +#if defined(HOMIE_SPIFFS) + return SPIFFS.open(path, mode); +#elif defined(HOMIE_LITTLEFS) + return LittleFS.open(path, mode); +#endif +} + +bool HomieInternals::FS::remove(const char* path) { +#if defined(HOMIE_SPIFFS) + return SPIFFS.remove(path); +#elif defined(HOMIE_LITTLEFS) + return LittleFS.remove(path); +#endif +} diff --git a/src/Homie/FS.hpp b/src/Homie/FS.hpp new file mode 100644 index 00000000..4fa0fe54 --- /dev/null +++ b/src/Homie/FS.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "Constants.hpp" + +#if defined(HOMIE_SPIFFS) +#if defined(ESP8266) +#include +#elif defined(ESP32) +#include +#endif +#elif defined(HOMIE_LITTLEFS) +#if defined(ESP8266) +#include +#elif defined(ESP32) +#include +#endif +#endif + +namespace HomieInternals { +class FS { + public: + FS(); + bool begin(); + bool exists(const char *filepath); + File open(const char* path, const char* mode); + bool remove(const char* path); + + private: + bool _began; +}; +} // namespace HomieInternals