filesystem + Config
This commit is contained in:
parent
e517e3d717
commit
e8a73463bb
@ -2,8 +2,8 @@
|
|||||||
platform = espressif32
|
platform = espressif32
|
||||||
board = esp32dev
|
board = esp32dev
|
||||||
framework = arduino
|
framework = arduino
|
||||||
lib_deps =
|
board_build.filesystem = littlefs
|
||||||
knolleary/pubsubclient@2.8
|
lib_deps = knolleary/pubsubclient@2.8
|
||||||
bblanchon/ArduinoJson@7.3.0
|
bblanchon/ArduinoJson@7.3.0
|
||||||
me-no-dev/ESPAsyncWebServer@1.2.4
|
me-no-dev/ESPAsyncWebServer@1.2.4
|
||||||
build_flags = -DWIFI_SSID=\"HappyNet\" -DWIFI_PKEY=\"1Grausame!Sackratte7\" -DWIFI_HOST=\"PatrixTest\"
|
build_flags = -DWIFI_SSID=\"HappyNet\" -DWIFI_PKEY=\"1Grausame!Sackratte7\" -DWIFI_HOST=\"PatrixTest\"
|
||||||
@ -1,11 +1,14 @@
|
|||||||
#ifndef PATRIX_NODE_TEST_H
|
#ifndef PATRIX_NODE_TEST_H
|
||||||
#define PATRIX_NODE_TEST_H
|
#define PATRIX_NODE_TEST_H
|
||||||
|
|
||||||
|
#include <patrix/core/Config.h>
|
||||||
#include <patrix/display/DisplayMatrix.h>
|
#include <patrix/display/DisplayMatrix.h>
|
||||||
#include <patrix/node/PatrixNode.h>
|
#include <patrix/node/PatrixNode.h>
|
||||||
|
|
||||||
DisplayMatrix<32, 8> display;
|
DisplayMatrix<32, 8> display;
|
||||||
|
|
||||||
|
Config config("/test.json");
|
||||||
|
|
||||||
class NodeTest final : public PatrixNode {
|
class NodeTest final : public PatrixNode {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -15,9 +18,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void setup() override {
|
void setup() override {
|
||||||
|
config.read();
|
||||||
display.printf("Test");
|
display.printf("Test");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loop() override {
|
||||||
|
config.loop();
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
106
src/patrix/core/Config.h
Normal file
106
src/patrix/core/Config.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#ifndef PATRIX_CONFIG_H
|
||||||
|
#define PATRIX_CONFIG_H
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <LittleFS.h>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#define CONFIG_WRITE_DELAY_MILLIS (30 * 1000)
|
||||||
|
|
||||||
|
class Config final {
|
||||||
|
|
||||||
|
const String path;
|
||||||
|
|
||||||
|
JsonDocument config;
|
||||||
|
|
||||||
|
unsigned long dirty = 0;
|
||||||
|
|
||||||
|
bool doForceNextHexBuffer = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
explicit Config(String path) : path(std::move(path)) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
~Config() = default;
|
||||||
|
|
||||||
|
void read() {
|
||||||
|
fsMount();
|
||||||
|
auto file = LittleFS.open(path, "r");
|
||||||
|
if (!file) {
|
||||||
|
error("failed to open file for config: %s", path.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!deserialize(file)) {
|
||||||
|
config.clear();
|
||||||
|
config = config.to<JsonObject>();
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write() const {
|
||||||
|
fsMount();
|
||||||
|
auto write = LittleFS.open(path, "w");
|
||||||
|
if (!write) {
|
||||||
|
error("failed to open file for config write: %s", path.c_str());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto size = measureJson(config);
|
||||||
|
if (serializeJson(config, write) == size) {
|
||||||
|
char buffer[256];
|
||||||
|
serializeJson(config, buffer, sizeof buffer);
|
||||||
|
info("config written: %s => %s", path.c_str(), buffer);
|
||||||
|
} else {
|
||||||
|
error("failed to write config: %s", path.c_str());
|
||||||
|
}
|
||||||
|
write.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
if (dirty != 0 && millis() - dirty > CONFIG_WRITE_DELAY_MILLIS) {
|
||||||
|
dirty = 0;
|
||||||
|
write();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T get(const char *key, T fallback) {
|
||||||
|
if (config[key].is<T>()) {
|
||||||
|
return config[key].as<T>();
|
||||||
|
}
|
||||||
|
warn("config key \"%s\" not found!", key);
|
||||||
|
return fallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void set(const char *key, T value) {
|
||||||
|
config[key] = value;
|
||||||
|
dirty = max(1UL, millis()); // avoid special value zero (=> not dirty)
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
bool deserialize(File file) {
|
||||||
|
if (deserializeJson(config, file) != DeserializationError::Ok) {
|
||||||
|
error("failed to deserialize config: %s", file.path());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!config.is<JsonObject>()) {
|
||||||
|
error("config not a json-object: %s", file.path());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char buffer[256];
|
||||||
|
serializeJson(config, buffer, sizeof buffer);
|
||||||
|
info("config loaded: %s => %s", path.c_str(), buffer);
|
||||||
|
config = config.as<JsonObject>();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
64
src/patrix/core/filesystem.cpp
Normal file
64
src/patrix/core/filesystem.cpp
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#include "filesystem.h"
|
||||||
|
|
||||||
|
#include <FS.h>
|
||||||
|
#include <LittleFS.h>
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
auto fsMounted = false;
|
||||||
|
|
||||||
|
bool fsMount() {
|
||||||
|
if (!fsMounted) {
|
||||||
|
fsMounted = LittleFS.begin(true);
|
||||||
|
}
|
||||||
|
if (fsMounted) {
|
||||||
|
info("filesystem mounted: %3d%% used (%d bytes)", static_cast<int>(round(100.0 * LittleFS.usedBytes() / LittleFS.totalBytes())), LittleFS.usedBytes());
|
||||||
|
} else {
|
||||||
|
error("failed to mount filesystem");
|
||||||
|
}
|
||||||
|
return fsMounted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fsIsMounted() {
|
||||||
|
return fsMounted;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fsList(FS& fs, const char *path, const String& indent) { // NOLINT(*-no-recursion)
|
||||||
|
auto dir = fs.open(path);
|
||||||
|
if (!dir) {
|
||||||
|
error("not found: %s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!dir.isDirectory()) {
|
||||||
|
error("not a directory: %s", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info("LS: %s %4s %s", indent.c_str(), "", dir.name());
|
||||||
|
|
||||||
|
const auto indent2 = indent + " ";
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
auto file = dir.openNextFile();
|
||||||
|
if (!file) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
fsList(fs, file.path());
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.rewindDirectory();
|
||||||
|
while (true) {
|
||||||
|
auto file = dir.openNextFile();
|
||||||
|
if (!file) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!file.isDirectory()) {
|
||||||
|
info("LS: %s %4d %s", indent2.c_str(), file.size(), file.name());
|
||||||
|
}
|
||||||
|
file.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
dir.close();
|
||||||
|
}
|
||||||
13
src/patrix/core/filesystem.h
Normal file
13
src/patrix/core/filesystem.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef PATRIX_FILESYSTEM_H
|
||||||
|
#define PATRIX_FILESYSTEM_H
|
||||||
|
|
||||||
|
#include <FS.h>
|
||||||
|
#include <WString.h>
|
||||||
|
|
||||||
|
bool fsMount();
|
||||||
|
|
||||||
|
bool fsIsMounted();
|
||||||
|
|
||||||
|
void fsList(FS& fs, const char *path, const String& indent = "");
|
||||||
|
|
||||||
|
#endif
|
||||||
Loading…
Reference in New Issue
Block a user