├── _config.yml ├── keywords.txt ├── .clang-format ├── library.properties ├── .github ├── workflows │ ├── platformio.yml │ └── Arduino.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .gitignore ├── CONTRIBUTING.md ├── platformio.ini ├── LICENSE ├── CODE_OF_CONDUCT.md ├── examples └── Effortless_Spiffs_Basic │ └── Effortless_Spiffs_Basic.ino ├── README.md └── src └── Effortless_SPIFFS.h /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-midnight -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | Effortless_SPIFFS KEYWORD1 2 | eSPIFFS KEYWORD1 3 | 4 | checkFlashConfig KEYWORD2 5 | getFileSize KEYWORD2 6 | openFile KEYWORD2 7 | saveFile KEYWORD2 8 | openFromFile KEYWORD2 9 | saveToFile KEYWORD2 10 | 11 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | IndentWidth: 2 3 | TabWidth: 2 4 | ColumnLimit: 0 5 | AccessModifierOffset: -1 6 | AllowShortIfStatementsOnASingleLine: true 7 | IndentCaseLabels: false 8 | NamespaceIndentation: All 9 | 10 | PointerAlignment : Left 11 | AlignConsecutiveDeclarations : true 12 | AlignAfterOpenBracket : true 13 | 14 | SortIncludes : false -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=Effortless-SPIFFS 2 | version=2.3.0 3 | author=thebigpotatoe 4 | maintainer=thebigpotatoe 5 | sentence=A class designed to make reading and storing data on the ESP8266 and ESP32 effortless. 6 | paragraph=Supports all basic types plus String, std::string, and ArduinoJSON. 7 | category=Data Storage 8 | url=https://thebigpotatoe.github.io/Effortless-SPIFFS/ 9 | architectures=esp8266,esp32 10 | license=MIT 11 | -------------------------------------------------------------------------------- /.github/workflows/platformio.yml: -------------------------------------------------------------------------------- 1 | name: PlatformIO CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Set up Python 13 | uses: actions/setup-python@v1 14 | - name: Install dependencies 15 | run: | 16 | python -m pip install --upgrade pip 17 | pip install platformio 18 | - name: Run PlatformIO 19 | run: platformio run 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Folders 35 | .vscode 36 | /.pio 37 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: thebigpotatoe 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 16 | -------------------------------------------------------------------------------- /platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; https://docs.platformio.org/page/projectconf.html 10 | 11 | [platformio] 12 | src_dir = examples/Effortless_Spiffs_Basic 13 | lib_dir = . 14 | test_dir = test 15 | 16 | [common] 17 | lib_deps = 18 | ArduinoJson 19 | 20 | [env:nodemcuv2] 21 | platform = espressif8266 22 | board = nodemcuv2 23 | framework = arduino 24 | monitor_speed = 115200 25 | lib_deps = ${common.lib_deps} 26 | 27 | [env:ESP32] 28 | platform = espressif32 29 | framework = arduino 30 | board = esp32dev 31 | lib_deps = 32 | ${common.lib_deps} 33 | 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: thebigpotatoe 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **Environment** 14 | - Arduino/PlatformIO 15 | - Versions of any libraries 16 | 17 | **Desktop (please complete the following information):** 18 | - OS: [e.g. iOS] 19 | - Browser [e.g. chrome, safari] 20 | - Version [e.g. 22] 21 | 22 | **To Reproduce** 23 | Steps to reproduce the behavior: 24 | 1. Go to '...' 25 | 2. Click on '....' 26 | 3. Scroll down to '....' 27 | 4. See error 28 | 29 | **Expected behavior** 30 | A clear and concise description of what you expected to happen. 31 | 32 | **Screenshots** 33 | If applicable, add screenshots to help explain your problem. 34 | 35 | 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/workflows/Arduino.yml: -------------------------------------------------------------------------------- 1 | name: Arduino 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | env: 11 | PLATFORM_DEFAULT_URL: https://arduino.esp8266.com/stable/package_esp8266com_index.json,https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json 12 | REQUIRED_LIBRARIES: ArduinoJSON 13 | strategy: 14 | matrix: 15 | arduino-boards-fqbn: 16 | - esp8266:esp8266:nodemcuv2:xtal=80,vt=flash,exception=disabled,eesz=4M1M,ip=lm2f,dbg=Disabled,lvl=None____,wipe=none 17 | - esp32:esp32:esp32 18 | 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v2 22 | 23 | - name: Compile all examples 24 | uses: ArminJo/arduino-test-compile@v2 25 | with: 26 | arduino-board-fqbn: ${{ matrix.arduino-boards-fqbn }} 27 | platform-url: ${{ env.PLATFORM_DEFAULT_URL }} 28 | required-libraries: ${{ env.REQUIRED_LIBRARIES }} 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 thebigpotatoe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /examples/Effortless_Spiffs_Basic/Effortless_Spiffs_Basic.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2019 thebigpotatoe 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | */ 14 | 15 | // #define USE_SERIAL_DEBUG_FOR_eSPIFFS // Uncomment to use Serial for debug in eSIFFS library 16 | // #include // Uncomment this to include ArduinoJson. Make sure to have it installed first 17 | #include 18 | 19 | /* A Word of Warning! 20 | The ESP SPIFFS class and consequently this library 21 | only suports a file name size of 31 characters, it 22 | is up to you to manage this. You may get away with 23 | having more characters, but this could lead to 24 | undefined behaviour 25 | */ 26 | 27 | void setup() { 28 | // Start Serial 29 | Serial.begin(115200); 30 | Serial.println(); 31 | 32 | // Small delay for startup 33 | delay(1000); 34 | 35 | // Create a eSPIFFS class 36 | #ifndef USE_SERIAL_DEBUG_FOR_eSPIFFS 37 | // Create fileSystem 38 | eSPIFFS fileSystem; 39 | 40 | // Check Flash Size - Always try to incorrperate a check when not debugging to know if you have set the SPIFFS correctly 41 | if (!fileSystem.checkFlashConfig()) { 42 | Serial.println("Flash size was not correct! Please check your SPIFFS config and try again"); 43 | delay(100000); 44 | ESP.restart(); 45 | } 46 | #else 47 | // Create fileSystem with debug output 48 | eSPIFFS fileSystem(&Serial); // Optional - allow the methods to print debug 49 | #endif 50 | 51 | // This will change value through reboots 52 | bool writeToFlash = false; // default value will be overriden by opening file 53 | fileSystem.openFromFile("/writeToFlash.txt", writeToFlash); // This will open the value of writeToFlash 54 | writeToFlash = !writeToFlash; // Flip value 55 | fileSystem.saveToFile("/writeToFlash.txt", writeToFlash); // This will save the value of writeToFlash 56 | 57 | if (writeToFlash) { 58 | Serial.println(); 59 | Serial.println("** Setting a random value to each variable and saving it **"); 60 | } else { 61 | Serial.println(); 62 | Serial.println("** Opening last saved state of variables **"); 63 | } 64 | 65 | // Booleans 66 | bool newBool; 67 | if (writeToFlash) { 68 | newBool = random(0, 1); 69 | fileSystem.saveToFile("/Boolean.txt", newBool); 70 | } else { 71 | fileSystem.openFromFile("/Boolean.txt", newBool); 72 | } 73 | Serial.print("Boolean value is: "); 74 | Serial.println(newBool); 75 | 76 | // floats and doubles 77 | double newFloat = 0.0; 78 | if (writeToFlash) { 79 | newFloat = (float)random(1, 1000) / (float)random(1000, 65563); 80 | fileSystem.saveToFile("/Float.txt", newFloat); 81 | } else { 82 | fileSystem.openFromFile("/Float.txt", newFloat); 83 | } 84 | Serial.print("Float value is: "); 85 | Serial.println(newFloat, 15); 86 | 87 | // Signed Int Values 88 | signed int newSignedInt = 0; 89 | if (writeToFlash) { 90 | newSignedInt = random(-100000, 100000); 91 | fileSystem.saveToFile("/SignedInt.txt", newSignedInt); 92 | } else { 93 | fileSystem.openFromFile("/SignedInt.txt", newSignedInt); 94 | } 95 | Serial.print("Signed Int value is: "); 96 | Serial.println(newSignedInt); 97 | 98 | // Signed Long Values 99 | signed long newSignedLong = 0; 100 | if (writeToFlash) { 101 | newSignedLong = random(-100000, 100000); 102 | fileSystem.saveToFile("/SignedLong.txt", newSignedLong); 103 | } else { 104 | fileSystem.openFromFile("/SignedLong.txt", newSignedLong); 105 | } 106 | Serial.print("Signed Long value is: "); 107 | Serial.println(newSignedLong); 108 | 109 | // Unsigned Int Values 110 | unsigned long newUnsignedInt = 0; 111 | if (writeToFlash) { 112 | newUnsignedInt = random(0, 100000); 113 | fileSystem.saveToFile("/UnsignedInt.txt", newUnsignedInt); 114 | } else { 115 | fileSystem.openFromFile("/UnsignedInt.txt", newUnsignedInt); 116 | } 117 | Serial.print("UnsignedInt value is: "); 118 | Serial.println(newUnsignedInt); 119 | 120 | // Unsigned Long Values 121 | unsigned long newUnsignedLong = 0; 122 | if (writeToFlash) { 123 | newUnsignedLong = random(0, 100000); 124 | fileSystem.saveToFile("/UnsignedLong.txt", newUnsignedLong); 125 | } else { 126 | fileSystem.openFromFile("/UnsignedLong.txt", newUnsignedLong); 127 | } 128 | Serial.print("Unsigned Long value is: "); 129 | Serial.println(newUnsignedLong); 130 | 131 | // Char buffers 132 | const char* newCharBuffer; 133 | if (writeToFlash) { 134 | newCharBuffer = "Hello World"; 135 | fileSystem.saveToFile("/CharBuffer.txt", newCharBuffer); 136 | } else { 137 | fileSystem.openFromFile("/CharBuffer.txt", newCharBuffer); 138 | } 139 | Serial.print("Char Buffer is: "); 140 | Serial.println(newCharBuffer); 141 | 142 | // Strings 143 | String newString; 144 | if (writeToFlash) { 145 | newString = "Hello World"; 146 | fileSystem.saveToFile("/String.txt", newString); 147 | } else { 148 | fileSystem.openFromFile("/String.txt", newString); 149 | } 150 | Serial.print("String is: "); 151 | Serial.println(newString); 152 | 153 | // std::strings 154 | std::string newStdString; 155 | if (writeToFlash) { 156 | newStdString = "Hello World"; 157 | fileSystem.saveToFile("/stdString.txt", newStdString); 158 | } else { 159 | fileSystem.openFromFile("/stdString.txt", newStdString); 160 | } 161 | Serial.print("std::string is: "); 162 | Serial.println(newStdString.c_str()); 163 | 164 | // Arduino JSON documents - currently only dynamic documents 165 | #if defined ARDUINOJSON_VERSION_MAJOR && ARDUINOJSON_VERSION_MAJOR == 6 166 | DynamicJsonDocument jsonDocument(1024); 167 | if (writeToFlash) { 168 | jsonDocument["Value"] = random(0, 100000); 169 | fileSystem.saveToFile("/json.txt", jsonDocument); 170 | } else { 171 | fileSystem.openFromFile("/json.txt", jsonDocument); 172 | } 173 | Serial.print("JSON Document is: "); 174 | serializeJson(jsonDocument, Serial); 175 | Serial.println(); 176 | 177 | JsonObject jobject = jsonDocument.to(); 178 | if (writeToFlash) { 179 | jobject["Value"] = random(0, 100000); 180 | fileSystem.saveToFile("/jsonObject.txt", jobject); 181 | } else { 182 | fileSystem.openFromFile("/jsonObject.txt", jsonDocument); 183 | } 184 | Serial.print("JSON Object is: "); 185 | serializeJson(jobject, Serial); 186 | Serial.println(); 187 | 188 | JsonArray jarray = jsonDocument.to(); 189 | if (writeToFlash) { 190 | jarray[0] = random(0, 100000); 191 | fileSystem.saveToFile("/jsonArray.txt", jarray); 192 | } else { 193 | fileSystem.openFromFile("/jsonArray.txt", jsonDocument); 194 | } 195 | Serial.print("JSON Array is: "); 196 | serializeJson(jarray, Serial); 197 | Serial.println(); 198 | #endif 199 | 200 | // Reboot to see what values are stored 201 | if (writeToFlash) { 202 | Serial.println("Rebooting..."); 203 | ESP.restart(); 204 | } 205 | } 206 | 207 | void loop() {} 208 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Effortless-SPIFFS 2 | 3 | [![GitHub release](https://img.shields.io/github/release/thebigpotatoe/Effortless-SPIFFS.svg)](https://github.com/thebigpotatoe/Effortless-SPIFFS/releases) 4 | [![arduino-library-badge](https://www.ardu-badge.com/badge/Effortless-SPIFFS.svg?)](https://www.ardu-badge.com/Effortless-SPIFFS) 5 | [![PlatformIO Build Status](https://github.com/thebigpotatoe/Effortless-SPIFFS/workflows/PlatformIO%20CI/badge.svg)](https://github.com/thebigpotatoe/Effortless-SPIFFS/actions?query=workflow%3A%22PlatformIO+CI%22) 6 | [![Arduino Build Status](https://github.com/thebigpotatoe/Effortless-SPIFFS/workflows/Arduino/badge.svg)](https://github.com/thebigpotatoe/Effortless-SPIFFS/actions?query=workflow%3A%22PlatformIO+CI%22) 7 | [![GitHub License](https://img.shields.io/github/license/mashape/apistatus.svg)](https://github.com/thebigpotatoe/Effortless-SPIFFS/blob/master/LICENSE) 8 | 9 | A class designed to make reading and storing data on the __ESP8266__ and __ESP32__ effortless. This library aims to make access to SPIFFS much easier to allow users to get on with writing the important stuff rather than debugging why storage isn't working. 10 | 11 | ## :exclamation: IMPORTANT :exclamation: 12 | 13 | When using in a project or exploring the example make sure to set your SPIFFS size correctly for your project/board. While the library will not fail when trying to open files from a non existent SPIFFS partition, failure to set the size will mean the library and hence project will not work as intended. 14 | 15 | The library has a very handy method `checkFlashConfig()` to check this for you. Using this method at the start of your sketch with a meaningful `Serial.print()` statement will save you a lot of time wondering why things are not working in production. 16 | 17 | For more info on setting the SPIFFS size see: 18 | 19 | - [ESP8266 SPIFFS in Arduino](https://cdn.instructables.com/ORIG/FST/OP12/IZT6TEBJ/FSTOP12IZT6TEBJ.png?auto=webp&frame=1&width=1024&fit=bounds&md=f16daccb8697a6bd8728838feb18d9de) 20 | - [ESP8266 SPIFFS in PlatformIO](https://docs.platformio.org/en/latest/platforms/espressif8266.html#flash-size) 21 | - [ESP32 SPIFFS in Arduino](https://user-images.githubusercontent.com/26627719/44614648-d76f9980-a852-11e8-8383-d6ae74a2ff5b.png) 22 | - [ESP32 SPIFFS in PlatformIO](https://docs.platformio.org/en/latest/platforms/espressif32.html#partition-tables) 23 | 24 | ## Quick Start 25 | 26 | The example below is all you need to get going with opening and saving data from a variable. Be sure to also check out the example `Effortless_Spiffs_Basic.ino` for detailed understanding of how to use this library with all data types. 27 | 28 | ``` c++ 29 | #include 30 | 31 | eSPIFFS fileSystem; 32 | float myVariable; 33 | 34 | void setup(){ 35 | Serial.begin(115200); 36 | Serial.println(); 37 | } 38 | 39 | void loop() { 40 | // Open the storage file and save data to myVariable 41 | if (fileSystem.openFromFile("/Float.txt", myVariable)) { 42 | Serial.print("Successfully read file and parsed data: "); 43 | Serial.println(myVariable, 6); 44 | } 45 | 46 | // Set myVariable to a random value 47 | myVariable = (float)random(1, 1000) / (float)random(1000, 65563); 48 | Serial.print("myVariable is now: "); 49 | Serial.println(myVariable, 6); 50 | 51 | // Write the data back to the SPIFFS 52 | if (fileSystem.saveToFile("/Float.txt", myVariable)) { 53 | Serial.println("Successfully wrote data to file"); 54 | } 55 | 56 | // Delay between loops 57 | delay(10000); 58 | } 59 | ``` 60 | 61 | ## Usage 62 | 63 | ### As an Object 64 | 65 | This library can be used directly by creating an object using the eSIFFS class. When declaring the class there is an optional input for a reference to a Print object to help with debugging. 66 | 67 | ``` c++ 68 | // Definition 69 | eSPIFFS(); 70 | eSPIFFS(&Print); 71 | 72 | // Usage 73 | eSPIFFS fileSystem; 74 | eSPIFFS fileSystem(&Print); 75 | ``` 76 | 77 | ### Extending a Class 78 | 79 | Each method in the class definition of eSPIFFS is defined as virtual so that it can be overriden by a child class if desired. The definitions of these are described below. 80 | 81 | ``` c++ 82 | virtual inline bool checkFlashConfig() 83 | virtual inline bool getFileSize(const char* _filename) 84 | virtual bool openFile(const char* _filename, char* _output, size_t _len = 0) 85 | virtual bool saveFile(const char* _filename, const char* _input) 86 | ``` 87 | 88 | There are two functions however which are not virtual; `openFromFile` and `saveToFile`. These are instead template functions which rely on an implementation of `std::enable_if` and `std::is_same`. These functionality provided by these can be extended to new types by using the same format template function as the eSPIFFS class. 89 | 90 | ``` c++ 91 | template 92 | typename Effortless_SPIFFS_Internal::enable_if::value, __NewTypeHere__>::type 93 | eSPIFFS::openFromFile(const char* _filename, NewType& _output) 94 | ``` 95 | 96 | ## Helper Methods 97 | 98 | ### Check that SPIFFS size is correct 99 | 100 | eSPIFFS checks if the SPIFFS system is correct in the Arduino IDE using `checkFlashConfig` each time `saveFile` and `openFile` are called. This is to ensure that SPIFFS can be read and written to before doing any useful work. This method uses Serial debug outputs to tell the user how to set up spiffs if passed a serial reference. This function is public and inline to optimise for frequent calls. 101 | 102 | ``` c++ 103 | // Definition 104 | inline bool checkFlashConfig() 105 | 106 | // Usage 107 | eSPIFFS fileSystem(); 108 | bool spiffsSetCorrectly = fileSystem.checkFlashConfig(); 109 | ``` 110 | 111 | #### Getting the file size 112 | 113 | The eSPIFFS class will get the file size of any file given a path. Th method `getFileSize` is used internally and is extended to the public API to make finding the length of a file easy. If a file is not found or not able to be read, the value will be 0. 114 | 115 | ``` c++ 116 | // Definition 117 | inline size_t getFileSize(const char* fileName) 118 | 119 | // Usage 120 | eSPIFFS fileSystem(); 121 | size_t fileSize = fileSystem.getFileSize("/Example.file"); 122 | ``` 123 | 124 | ## Saving data to files 125 | 126 | The eSPIFFS API allows users to store data to the SPIFFS two possible methods; by passing a const char* or a variable reference of your choice. 127 | 128 | ### Saving data to file from a const char* C String 129 | 130 | The first method `saveFile` is used to store data into SPIFFS is via a const char* C string. The function takes a filename and a const char* pointer to a string which is then printed to SPIFFS. The file will return true if the data was written and false if there was an issue. 131 | 132 | ``` c++ 133 | // Definition 134 | bool saveFile(const char* _filename, const char* _input) 135 | 136 | // Usage 137 | eSPIFFS fileSystem(); 138 | const char* myString = "Hello World"; 139 | fileSystem.saveFile("Example.file", myString); 140 | ``` 141 | 142 | #### Saving data to file using a variable 143 | 144 | The second method `saveToFile` is used to store data is to use a reference to a variable of the users choice. This function wraps `saveFile` by parsing the users variable to a C String and saving that. The arguments it takes are filename and a reference value to any standard type. It also supports String, std::string, and ArduinoJson DynamicJsonDocuments. This method will also return true on a successful write to SPIFFS and false if there is an error. 145 | 146 | ``` c++ 147 | // Definition 148 | bool saveToFile(const char*, &bool); 149 | bool saveToFile(const char*, &float); 150 | bool saveToFile(const char*, &double); 151 | bool saveToFile(const char*, &signed char); 152 | bool saveToFile(const char*, &unsigned char); 153 | bool saveToFile(const char*, &signed int); 154 | bool saveToFile(const char*, &unsigned int); 155 | bool saveToFile(const char*, &signed short); 156 | bool saveToFile(const char*, &unsigned short); 157 | bool saveToFile(const char*, &signed long); 158 | bool saveToFile(const char*, &unsigned long); 159 | bool saveToFile(const char*, &char*); 160 | bool saveToFile(const char*, &const char*); 161 | bool saveToFile(const char*, &String); 162 | bool saveToFile(const char*, &std::string); 163 | bool saveToFile(const char*, &ArduinoJson::DynamicJsonDocument); 164 | 165 | // Usage 166 | eSPIFFS fileSystem(); 167 | float myVariable = 324.890; 168 | fileSystem.saveToFile("Example.file", myVariable); 169 | ``` 170 | 171 | ## Opening data from files 172 | 173 | The eSPIFFS API extends access to the SPIFFS of your ESP8266 in two ways; by modifying a C String or by storing a parsed value to a passed variable reference. 174 | 175 | ### Opening files as a string 176 | 177 | The first method `openFile` accesses data stored in the SPIFFS is through a modified const char* value. This method takes a filename, a char pointer to an output C String buffer, and the size of the number of bytes to read from the file. The function will return true if it stored the data in the char pointer and false if it failed for any reason. 178 | 179 | > It should be noted that if the number of bytes asked to read will be automatically limited to the size of the file. Using the getFileSize() method before this is useful to set a char array of the correct size. 180 | 181 | ``` c++ 182 | // Definition 183 | bool openFile(const char* filename, char* outputString, size_t numBytesToRead = 0); 184 | 185 | // Usage 186 | eSPIFFS fileSystem(); 187 | size_t fileSize = getFileSize("/Example.file"); 188 | char* fileContents[fileSize + 1]; // Dont forget about the null terminator for C Strings 189 | fileSystem.openFile("/Example.file", fileContents, fileSize); 190 | Serial.print("Data stored in fileContents is: ") 191 | Serial.println(fileContents); 192 | ``` 193 | 194 | ### Opening Files with a Variable Reference 195 | 196 | The second method `openFromFile` wraps `openFile` to return a parsed value to a variable of your choice. It takes a file name as well as a reference to your variable where it will store parsed data. The method returns true if a value was parsed and stored correctly and false if it failed at any point. If the function failed it will not modify the original data in the variable reference. This method supports all basic types plus String, std::string, and ArduinoJson DynamicJsonDocuments 197 | 198 | ``` c++ 199 | // Definitions 200 | bool openFromFile(const char*, &bool); 201 | bool openFromFile(const char*, &float); 202 | bool openFromFile(const char*, &double); 203 | bool openFromFile(const char*, &signed char); 204 | bool openFromFile(const char*, &unsigned char); 205 | bool openFromFile(const char*, &signed int); 206 | bool openFromFile(const char*, &unsigned int); 207 | bool openFromFile(const char*, &signed short); 208 | bool openFromFile(const char*, &unsigned short); 209 | bool openFromFile(const char*, &signed long); 210 | bool openFromFile(const char*, &unsigned long); 211 | bool openFromFile(const char*, &char*); 212 | bool openFromFile(const char*, &const char*); 213 | bool openFromFile(const char*, &String); 214 | bool openFromFile(const char*, &std::string); 215 | bool openFromFile(const char*, &ArduinoJson::DynamicJsonDocument); 216 | 217 | // Usage 218 | eSPIFFS fileSystem(); 219 | float myVariable; 220 | fileSystem.openFromFile("/Example.file", myVariable); 221 | Serial.print("Data stored in myVariable is: ") 222 | Serial.println(myVariable, 6); 223 | ``` 224 | 225 | ## Contributing and Feedback 226 | 227 | This is my first Arduino library and while I have tried to optimise it there is most likely room for improvement. Any feedback in the form of issues or pull request are welcome. 228 | -------------------------------------------------------------------------------- /src/Effortless_SPIFFS.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | 5 | // Check for arduino env here 6 | // Arduino Libraries 7 | #include 8 | 9 | #include "FS.h" 10 | 11 | // Architecture Specific Libraries 12 | #if defined(ESP8266) 13 | #include 14 | #define EFFORTLESS_SPIFFS_TYPE LittleFS 15 | #elif defined(ESP32) 16 | #include "SPIFFS.h" 17 | #define EFFORTLESS_SPIFFS_TYPE SPIFFS 18 | #else 19 | #error Effortless SPIFFS does not work on the selected architecture 20 | #endif 21 | 22 | // Standard c++ libraries 23 | #include 24 | 25 | #ifndef Effortless_SPIFFS_h 26 | #define Effortless_SPIFFS_h 27 | 28 | #define EFFORTLESS_SPIFFS_VERSION_MAJOR 2 29 | #define EFFORTLESS_SPIFFS_VERSION_MINOR 1 30 | #define EFFORTLESS_SPIFFS_VERSION_PATCH 2 31 | 32 | // Effortless SPIFFS Constants 33 | #ifndef Effortless_SPIFFS_CHAR_SIZE 34 | #define Effortless_SPIFFS_CHAR_SIZE 1024 35 | #endif 36 | 37 | #ifndef Effortless_SPIFFS_PRECISION 38 | #define Effortless_SPIFFS_PRECISION 15 39 | #endif 40 | 41 | // Effortless SPIFFS Debug Macros 42 | #define ESPIFFS_DEBUG(x) \ 43 | if (printer) printer->print(x) 44 | #define ESPIFFS_DEBUGLN(x) \ 45 | if (printer) printer->println(x) 46 | 47 | // Effortless SPIFFS internal namespace 48 | namespace Effortless_SPIFFS_Internal { 49 | template 50 | struct enable_if {}; 51 | 52 | template 53 | struct enable_if { typedef T type; }; 54 | 55 | template 56 | struct is_same { 57 | static const bool value = false; 58 | }; 59 | template 60 | struct is_same { 61 | static const bool value = true; 62 | }; 63 | } // namespace Effortless_SPIFFS_Internal 64 | 65 | // Main Effortless SPIFFS Class 66 | class eSPIFFS { 67 | public: // constructors 68 | eSPIFFS(Print* _debug = nullptr) : printer(_debug) {} 69 | ~eSPIFFS() {} 70 | 71 | public: // spiffs access methods 72 | virtual inline bool checkFlashConfig() { 73 | #if defined(ESP8266) 74 | if (!flashSizeCorrect) { 75 | // Get actual flash size and size set in IDE 76 | uint32_t realSize = ESP.getFlashChipRealSize(); 77 | uint32_t ideSize = ESP.getFlashChipSize(); 78 | 79 | // Compare the two sizes 80 | if (realSize >= ideSize) { 81 | // Get info about the LittleFS 82 | if (EFFORTLESS_SPIFFS_TYPE.begin()) { 83 | FSInfo fs_info; 84 | EFFORTLESS_SPIFFS_TYPE.info(fs_info); 85 | if (fs_info.totalBytes != 0) { 86 | // Change the boolean to true if the config is ok 87 | flashSizeCorrect = true; 88 | } else { 89 | ESPIFFS_DEBUGLN("[checkFlashConfig] - LittleFS size was set to 0, please select a LittleFS size from the \"tools->flash size:\" menu"); 90 | } 91 | } else { 92 | ESPIFFS_DEBUGLN("[checkFlashConfig] - LittleFS size was set to 0, please select a LittleFS size from the \"tools->flash size:\" menu"); 93 | } 94 | } else { 95 | // Tell the user the flash is incorrect if it is not 96 | ESPIFFS_DEBUGLN("[checkFlashConfig] - Flash chip set to the incorrect size, correct size is; " + String(realSize)); 97 | } 98 | } 99 | 100 | #elif defined(ESP32) 101 | if (EFFORTLESS_SPIFFS_TYPE.begin()) { 102 | if (EFFORTLESS_SPIFFS_TYPE.totalBytes() > 0) { 103 | flashSizeCorrect = true; 104 | } else { 105 | ESPIFFS_DEBUGLN("[checkFlashConfig] - SPIFFS size was set to 0, please select a SPIFFS size from the \"tools->flash size:\" menu or partition a SPIFFS"); 106 | } 107 | } else { 108 | ESPIFFS_DEBUGLN("[checkFlashConfig] - Failed to start SPIFFS"); 109 | } 110 | #endif 111 | 112 | // Return the boolean 113 | return flashSizeCorrect; 114 | } 115 | virtual inline int getFileSize(const char* _filename) { 116 | // Check if the flash config is set correctly 117 | if (checkFlashConfig()) { 118 | // Check if the spiffs starts correctly 119 | if (EFFORTLESS_SPIFFS_TYPE.begin()) { 120 | // Check if the file exists 121 | if (EFFORTLESS_SPIFFS_TYPE.exists(_filename)) { 122 | // Open the dir and check if it is a file 123 | File currentFile = EFFORTLESS_SPIFFS_TYPE.open(_filename, "r"); 124 | if (currentFile) { 125 | // Return the file size 126 | return currentFile.size(); 127 | } else { 128 | ESPIFFS_DEBUG("[getFileSize] - File did not open correctly: "); 129 | ESPIFFS_DEBUGLN(_filename); 130 | } 131 | } else { 132 | ESPIFFS_DEBUG("[getFileSize] - File does not exist: "); 133 | ESPIFFS_DEBUGLN(_filename); 134 | } 135 | } else { 136 | ESPIFFS_DEBUGLN("[getFileSize] - Failed to start file system"); 137 | } 138 | } 139 | return 0; 140 | } 141 | virtual File getFile(const char* _filename, const char* _readWrite) { 142 | // Check if the flash config is set correctly 143 | if (checkFlashConfig()) { // 5us 144 | // Check if the spiffs starts correctly 145 | if (EFFORTLESS_SPIFFS_TYPE.begin()) { // 5us 146 | // Check if the file exists 147 | if (strcmp(_readWrite, "r") == 0 ? EFFORTLESS_SPIFFS_TYPE.exists(_filename) : true) { // 49us 148 | // Open it in read mode and check if its ok 149 | File currentFile = EFFORTLESS_SPIFFS_TYPE.open(_filename, _readWrite); // 115us 150 | if (currentFile) { 151 | return currentFile; 152 | } else { 153 | ESPIFFS_DEBUG("[openFile] - Failed to open file"); 154 | ESPIFFS_DEBUGLN(_filename); 155 | } 156 | } else { 157 | ESPIFFS_DEBUG("[openFile] - File does not exist: "); 158 | ESPIFFS_DEBUGLN(_filename); 159 | } 160 | } else { 161 | ESPIFFS_DEBUGLN("[openFile] - Failed to start LittleFS"); 162 | } 163 | } 164 | return File(); 165 | } 166 | virtual bool openFile(const char* _filename, char* _output, size_t _len = 0) { 167 | // Open it in read mode and check if its ok 168 | File currentFile = getFile(_filename, "r"); // 115us 169 | if (currentFile) { 170 | // Read the desired number of bytes from the array to the output buffer 171 | size_t numBytesToRead = (_len > 0 && _len <= currentFile.size()) ? _len : currentFile.size(); 172 | if (currentFile.readBytes(_output, numBytesToRead)) { // readBytes - 300us, readBytesUntil - 465us - goes up with larger strings 173 | return true; 174 | } else { 175 | ESPIFFS_DEBUG("[openFile] - Failed to read any bytes from file: "); 176 | ESPIFFS_DEBUGLN(_filename); 177 | } 178 | } 179 | return false; 180 | } 181 | virtual bool saveFile(const char* _filename, const char* _input) { // Total time is about 6000us for small strings 182 | // Open the file in write mode and check if open 183 | File currentFile = getFile(_filename, "w"); 184 | if (currentFile) { 185 | // Print the input string to the file 186 | if (currentFile.print(_input)) { 187 | currentFile.close(); 188 | return true; 189 | } else { 190 | ESPIFFS_DEBUG("[saveFile] - Failed to write any bytes to file: "); 191 | ESPIFFS_DEBUGLN(_filename); 192 | } 193 | } 194 | 195 | return false; 196 | } 197 | virtual bool appendFile(const char* _filename, const char* _input) { 198 | // Open the file in write mode and check if open 199 | File currentFile = getFile(_filename, "a"); 200 | if (currentFile) { 201 | // Print the input string to the file 202 | if (currentFile.print(_input)) { 203 | currentFile.close(); 204 | return true; 205 | } else { 206 | ESPIFFS_DEBUG("[saveFile] - Failed to append any bytes to file: "); 207 | ESPIFFS_DEBUGLN(_filename); 208 | } 209 | } 210 | return false; 211 | } 212 | 213 | public: 214 | void setDebugOutput(Print* _debug) { 215 | if (_debug) printer = _debug; 216 | } 217 | void clearDebugOutput() { 218 | printer = nullptr; 219 | } 220 | 221 | public: // open value templates 222 | template 223 | typename Effortless_SPIFFS_Internal::enable_if::value, bool>::type 224 | openFromFile(const char* _filename, T& _output) { 225 | size_t fileSize = getFileSize(_filename); 226 | char fileContents[fileSize + 1]; 227 | memset(fileContents, 0x00, fileSize + 1); 228 | 229 | if (openFile(_filename, fileContents, fileSize)) { 230 | char* ptr; 231 | _output = (strtol(fileContents, &ptr, 10)); 232 | return true; 233 | } 234 | return false; 235 | } 236 | template 237 | typename Effortless_SPIFFS_Internal::enable_if::value || 238 | Effortless_SPIFFS_Internal::is_same::value, 239 | bool>::type 240 | openFromFile(const char* _filename, T& _output) { 241 | size_t fileSize = getFileSize(_filename); 242 | char fileContents[fileSize + 1]; 243 | memset(fileContents, 0x00, fileSize + 1); 244 | 245 | if (openFile(_filename, fileContents, fileSize)) { 246 | char* ptr; 247 | _output = strtod(fileContents, &ptr); 248 | return true; 249 | } 250 | return false; 251 | } 252 | template 253 | typename Effortless_SPIFFS_Internal::enable_if::value || 254 | Effortless_SPIFFS_Internal::is_same::value || 255 | Effortless_SPIFFS_Internal::is_same::value || 256 | Effortless_SPIFFS_Internal::is_same::value, 257 | bool>::type 258 | openFromFile(const char* _filename, T& _output) { 259 | size_t fileSize = getFileSize(_filename); 260 | char fileContents[fileSize + 1]; 261 | memset(fileContents, 0x00, fileSize + 1); 262 | 263 | if (openFile(_filename, fileContents, fileSize)) { 264 | char* ptr; 265 | _output = strtol(fileContents, &ptr, 10); //80us 266 | return true; 267 | } 268 | return false; 269 | } 270 | template 271 | typename Effortless_SPIFFS_Internal::enable_if::value || 272 | Effortless_SPIFFS_Internal::is_same::value || 273 | Effortless_SPIFFS_Internal::is_same::value || 274 | Effortless_SPIFFS_Internal::is_same::value, 275 | bool>::type 276 | openFromFile(const char* _filename, T& _output) { 277 | size_t fileSize = getFileSize(_filename); 278 | char fileContents[fileSize + 1]; 279 | memset(fileContents, 0x00, fileSize + 1); 280 | 281 | if (openFile(_filename, fileContents, fileSize)) { 282 | char* ptr; 283 | _output = strtoul(fileContents, &ptr, 10); 284 | return true; 285 | } 286 | return false; 287 | } 288 | template 289 | typename Effortless_SPIFFS_Internal::enable_if::value || 290 | Effortless_SPIFFS_Internal::is_same::value, 291 | bool>::type 292 | openFromFile(const char* _filename, T& _output) { 293 | size_t fileSize = getFileSize(_filename); 294 | if (Effortless_SPIFFS_CHAR_SIZE > fileSize) { 295 | static char fileContents[Effortless_SPIFFS_CHAR_SIZE]; 296 | memset(fileContents, 0x00, Effortless_SPIFFS_CHAR_SIZE); 297 | 298 | if (openFile(_filename, fileContents, fileSize)) { 299 | _output = fileContents; 300 | return true; 301 | } 302 | } else { 303 | ESPIFFS_DEBUGLN("[openFromFile] - Internal static char buffer to small for file contents, set Effortless_SPIFFS_CHAR_SIZE larger if required (default 1024)"); 304 | } 305 | 306 | return false; 307 | } 308 | template 309 | typename Effortless_SPIFFS_Internal::enable_if::value || 310 | Effortless_SPIFFS_Internal::is_same::value, 311 | bool>::type 312 | openFromFile(const char* _filename, T& _output) { 313 | size_t fileSize = getFileSize(_filename); 314 | char fileContents[fileSize + 1]; 315 | memset(fileContents, 0x00, fileSize + 1); 316 | 317 | if (openFile(_filename, fileContents, fileSize)) { 318 | _output = fileContents; 319 | return true; 320 | } 321 | return false; 322 | } 323 | #if defined ARDUINOJSON_VERSION_MAJOR && ARDUINOJSON_VERSION_MAJOR == 6 324 | template 325 | typename Effortless_SPIFFS_Internal::enable_if::value, bool>::type 326 | openFromFile(const char* _filename, T& _output) { 327 | File file = getFile(_filename, "r"); 328 | if (file) { 329 | DeserializationError jsonError = deserializeJson(_output, file); 330 | if (!jsonError) { 331 | return true; 332 | } else { 333 | ESPIFFS_DEBUG("[openFromFile] - Failed to parse JSON: "); 334 | ESPIFFS_DEBUG(jsonError.c_str()); 335 | ESPIFFS_DEBUG(" for file "); 336 | ESPIFFS_DEBUGLN(_filename); 337 | } 338 | } 339 | return false; 340 | } 341 | #endif 342 | 343 | public: // save value templates 344 | template 345 | typename Effortless_SPIFFS_Internal::enable_if::value, bool>::type 346 | saveToFile(const char* _filename, T& _input) { 347 | char inputString[2]; // Bool string will be: "0" + \0 348 | if (sprintf(inputString, "%d", _input)) { 349 | if (saveFile(_filename, inputString)) { 350 | return true; 351 | } 352 | } 353 | return false; 354 | } 355 | template 356 | typename Effortless_SPIFFS_Internal::enable_if::value || 357 | Effortless_SPIFFS_Internal::is_same::value, 358 | bool>::type 359 | saveToFile(const char* _filename, T& _input) { 360 | char inputString[Effortless_SPIFFS_PRECISION + 7]; // precision + decimal() + notation(4) + sign(1) + null(1) 361 | if (sprintf(inputString, "%.*g", Effortless_SPIFFS_PRECISION, _input)) { 362 | if (saveFile(_filename, inputString)) { 363 | return true; 364 | } 365 | } 366 | return false; 367 | } 368 | template 369 | typename Effortless_SPIFFS_Internal::enable_if::value || 370 | Effortless_SPIFFS_Internal::is_same::value || 371 | Effortless_SPIFFS_Internal::is_same::value || 372 | Effortless_SPIFFS_Internal::is_same::value, 373 | bool>::type 374 | saveToFile(const char* _filename, T& _input) { 375 | char inputString[15]; // signed long string will be 11 digits + \0 376 | if (sprintf(inputString, "%li", (signed long)_input)) { 377 | if (saveFile(_filename, inputString)) { 378 | return true; 379 | } 380 | } 381 | return false; 382 | } 383 | template 384 | typename Effortless_SPIFFS_Internal::enable_if::value || 385 | Effortless_SPIFFS_Internal::is_same::value || 386 | Effortless_SPIFFS_Internal::is_same::value || 387 | Effortless_SPIFFS_Internal::is_same::value, 388 | bool>::type 389 | saveToFile(const char* _filename, T& _input) { 390 | char inputString[15]; // unsigned long string will be 10 digits + \0 391 | if (sprintf(inputString, "%lu", (unsigned long)_input)) { 392 | if (saveFile(_filename, inputString)) { 393 | return true; 394 | } 395 | } 396 | return false; 397 | } 398 | template 399 | typename Effortless_SPIFFS_Internal::enable_if::value || 400 | Effortless_SPIFFS_Internal::is_same::value, 401 | bool>::type 402 | saveToFile(const char* _filename, T _input) { 403 | if (saveFile(_filename, _input)) { 404 | return true; 405 | } 406 | return false; 407 | } 408 | template 409 | typename Effortless_SPIFFS_Internal::enable_if::value || 410 | Effortless_SPIFFS_Internal::is_same::value, 411 | bool>::type 412 | saveToFile(const char* _filename, T& _input) { 413 | if (saveFile(_filename, _input.c_str())) { 414 | return true; 415 | } 416 | return false; 417 | } 418 | #if defined ARDUINOJSON_VERSION_MAJOR && ARDUINOJSON_VERSION_MAJOR == 6 419 | template 420 | typename Effortless_SPIFFS_Internal::enable_if::value || 421 | Effortless_SPIFFS_Internal::is_same::value || 422 | Effortless_SPIFFS_Internal::is_same::value, 423 | bool>::type 424 | saveToFile(const char* _filename, T& _input) { 425 | File file = getFile(_filename, "w"); 426 | if (file) { 427 | if (serializeJson(_input, file)) { 428 | file.close(); 429 | return true; 430 | } else { 431 | ESPIFFS_DEBUG("[saveToFile] - Failed to serialize JSON for file "); 432 | ESPIFFS_DEBUGLN(_filename); 433 | } 434 | } 435 | return false; 436 | } 437 | #endif 438 | 439 | public: // save value templates 440 | template 441 | typename Effortless_SPIFFS_Internal::enable_if::value, bool>::type 442 | appendToFile(const char* _filename, T& _input) { 443 | char inputString[2]; // Bool string will be: "0" + \0 444 | if (sprintf(inputString, "%d", _input)) { 445 | if (appendFile(_filename, inputString)) { 446 | return true; 447 | } 448 | } 449 | return false; 450 | } 451 | template 452 | typename Effortless_SPIFFS_Internal::enable_if::value || 453 | Effortless_SPIFFS_Internal::is_same::value, 454 | bool>::type 455 | appendToFile(const char* _filename, T& _input) { 456 | char inputString[Effortless_SPIFFS_PRECISION + 7]; // precision + decimal() + notation(4) + sign(1) + null(1) 457 | if (sprintf(inputString, "%.*g", Effortless_SPIFFS_PRECISION, _input)) { 458 | if (appendFile(_filename, inputString)) { 459 | return true; 460 | } 461 | } 462 | return false; 463 | } 464 | template 465 | typename Effortless_SPIFFS_Internal::enable_if::value || 466 | Effortless_SPIFFS_Internal::is_same::value || 467 | Effortless_SPIFFS_Internal::is_same::value || 468 | Effortless_SPIFFS_Internal::is_same::value, 469 | bool>::type 470 | appendToFile(const char* _filename, T& _input) { 471 | char inputString[15]; // signed long string will be 11 digits + \0 472 | if (sprintf(inputString, "%li", (signed long)_input)) { 473 | if (appendFile(_filename, inputString)) { 474 | return true; 475 | } 476 | } 477 | return false; 478 | } 479 | template 480 | typename Effortless_SPIFFS_Internal::enable_if::value || 481 | Effortless_SPIFFS_Internal::is_same::value || 482 | Effortless_SPIFFS_Internal::is_same::value || 483 | Effortless_SPIFFS_Internal::is_same::value, 484 | bool>::type 485 | appendToFile(const char* _filename, T& _input) { 486 | char inputString[15]; // unsigned long string will be 10 digits + \0 487 | if (sprintf(inputString, "%lu", (unsigned long)_input)) { 488 | if (appendFile(_filename, inputString)) { 489 | return true; 490 | } 491 | } 492 | return false; 493 | } 494 | template 495 | typename Effortless_SPIFFS_Internal::enable_if::value || 496 | Effortless_SPIFFS_Internal::is_same::value, 497 | bool>::type 498 | appendToFile(const char* _filename, T _input) { 499 | if (appendFile(_filename, _input)) { 500 | return true; 501 | } 502 | return false; 503 | } 504 | template 505 | typename Effortless_SPIFFS_Internal::enable_if::value || 506 | Effortless_SPIFFS_Internal::is_same::value, 507 | bool>::type 508 | appendToFile(const char* _filename, T& _input) { 509 | if (saveFile(_filename, _input.c_str())) { 510 | return true; 511 | } 512 | return false; 513 | } 514 | #if defined ARDUINOJSON_VERSION_MAJOR && ARDUINOJSON_VERSION_MAJOR == 6 515 | template 516 | typename Effortless_SPIFFS_Internal::enable_if::value || 517 | Effortless_SPIFFS_Internal::is_same::value || 518 | Effortless_SPIFFS_Internal::is_same::value, 519 | bool>::type 520 | appendToFile(const char* _filename, T& _input) { 521 | File file = getFile(_filename, "a"); 522 | if (file) { 523 | if (serializeJson(_input, file)) { 524 | file.close(); 525 | return true; 526 | } else { 527 | ESPIFFS_DEBUG("[saveToFile] - Failed to serialize JSON for file "); 528 | ESPIFFS_DEBUGLN(_filename); 529 | } 530 | } 531 | return false; 532 | } 533 | #endif 534 | 535 | private: // storage 536 | bool flashSizeCorrect = false; 537 | Print* printer = nullptr; 538 | }; 539 | 540 | #endif 541 | 542 | #else 543 | #error Effortless_SPIFFS requires a C++ compiler 544 | #endif --------------------------------------------------------------------------------