5#include "ustd_platform.h"
11#include <Arduino_JSON.h>
13#ifndef MAX_FRICKEL_DEPTH
14#define MAX_FRICKEL_DEPTH 9
70 bool forcenew =
false;
71 bool autocommit =
true;
77 jsonfile(
bool auto_commit =
true,
bool force_new =
false, String path =
"/")
78 : forcenew(force_new), autocommit(auto_commit), path(path) {
87 obj = JSON.parse(
"{}");
90 void clear(
bool auto_commit =
true,
bool force_new =
false) {
98 obj = JSON.parse(
"{}");
99 autocommit = auto_commit;
100 forcenew = force_new;
104 bool init(String basename, JSONVar &value,
bool auto_commit =
true) {
115 autocommit = auto_commit;
118 return autocommit ?
commit() :
true;
121 bool init(String basename, String value,
bool auto_commit =
true) {
129 JSONVar jv = JSON.parse(value);
130 return init(basename, jv, auto_commit);
133 bool initFromFile(String basename, String fn,
bool auto_commit =
true) {
141 bool result = loadFile(basename, fn);
143 autocommit = auto_commit;
145 return autocommit ?
commit() :
true;
154 return JSON.stringify(obj);
163 if (filename ==
"") {
164 DBG(
"Cannot commit uninitialized object");
167 String jsonString = JSON.stringify(obj);
169 DBG2(
"Writing file: " + path + filename +
".json, content: " + jsonString);
171 fs::File f =
fsOpen(path + filename +
".json",
"w");
173 DBG(
"File " + path + filename +
".json can't be opened for write, failure.");
176 f.print(jsonString.c_str());
188 ustd::array<String> keyparts;
190 if (prepareRead(key, keyparts, subobj)) {
191 DBG2(
"From " + key +
", element found.");
212 if (!prepareWrite(key, target)) {
216 return autocommit ?
commit() :
true;
236 ustd::array<String> keyparts;
237 if (!prepareRead(key, keyparts, value)) {
263 ustd::array<String> keyparts;
265 if (!prepareRead(key, keyparts, subobj)) {
268 if (JSON.typeof(subobj) !=
"array") {
269 DBG(
"From " + key +
", element has wrong type '" + JSON.typeof(subobj) +
270 "' - expected 'array'");
273 values.resize(subobj.length());
274 for (
int i = 0; i < subobj.length(); i++) {
275 JSONVar element(subobj[i]);
303 ustd::array<String> keyparts;
305 if (!prepareRead(key, keyparts, subobj)) {
308 if (JSON.typeof(subobj) !=
"array") {
309 DBG(
"From " + key +
", element has wrong type '" + JSON.typeof(subobj) +
310 "' - expected 'array'");
315 for (
int i = 0; i < subobj.length(); i++) {
316 if (JSON.typeof(subobj[i]) !=
"string") {
317 DBG(
"From " + key +
", array element " + String(i) +
" has wrong type '" +
318 JSON.typeof(subobj[i]) +
"' - expected 'string'");
323 values.resize(subobj.length());
324 for (
int i = 0; i < subobj.length(); i++) {
325 values[i] = String((
const char *)subobj[i]);
331 bool strict =
false) {
345 bool readBoolArray(String key, ustd::array<bool> &values,
bool strict =
false) {
355 ustd::array<String> keyparts;
357 if (!prepareRead(key, keyparts, subobj)) {
360 if (JSON.typeof(subobj) !=
"array") {
361 DBG(
"From " + key +
", element has wrong type '" + JSON.typeof(subobj) +
362 "' - expected 'array'");
367 for (
int i = 0; i < subobj.length(); i++) {
368 if (JSON.typeof(subobj[i]) !=
"boolean") {
369 DBG(
"From " + key +
", array element " + String(i) +
" has wrong type '" +
370 JSON.typeof(subobj[i]) +
"' - expected 'boolean'");
375 values.resize(subobj.length());
376 for (
int i = 0; i < subobj.length(); i++) {
377 values[i] = (bool)subobj[i];
406 ustd::array<String> keyparts;
408 if (!prepareRead(key, keyparts, subobj)) {
411 if (JSON.typeof(subobj) !=
"array") {
412 DBG(
"From " + key +
", element has wrong type '" + JSON.typeof(subobj) +
413 "' - expected 'array'");
418 for (
int i = 0; i < subobj.length(); i++) {
419 if (JSON.typeof(subobj[i]) !=
"number") {
420 DBG(
"From " + key +
", array element " + String(i) +
" has wrong type '" +
421 JSON.typeof(subobj[i]) +
"' - expected 'number'");
426 values.resize(subobj.length());
427 for (
int i = 0; i < subobj.length(); i++) {
428 values[i] = (double)subobj[i];
434 bool strict =
false) {
448 bool readLongArray(String key, ustd::array<long> &values,
bool strict =
false) {
458 ustd::array<String> keyparts;
460 if (!prepareRead(key, keyparts, subobj)) {
463 if (JSON.typeof(subobj) !=
"array") {
464 DBG(
"From " + key +
", element has wrong type '" + JSON.typeof(subobj) +
465 "' - expected 'array'");
470 for (
int i = 0; i < subobj.length(); i++) {
471 if (JSON.typeof(subobj[i]) !=
"number") {
472 DBG(
"From " + key +
", array element " + String(i) +
" has wrong type '" +
473 JSON.typeof(subobj[i]) +
"' - expected 'number'");
478 values.resize(subobj.length());
479 for (
int i = 0; i < subobj.length(); i++) {
480 values[i] = (long)subobj[i];
505 ustd::array<String> keyparts;
507 if (!prepareRead(key, keyparts, subobj)) {
510 if (JSON.typeof(subobj) !=
"boolean") {
511 DBG(
"From " + key +
", element has wrong type '" + JSON.typeof(subobj) +
512 "' - expected 'boolean'");
515 bool result = (bool)subobj;
516 DBG2(
"From " + key +
", value: " + (result ?
"true" :
"false"));
527 return jf.
readBool(key, defaultVal);
536 ustd::array<String> keyparts;
538 if (!prepareRead(key, keyparts, subobj)) {
541 if (JSON.typeof(subobj) !=
"string") {
542 DBG(
"From " + key +
", element has wrong type '" + JSON.typeof(subobj) +
543 "' - expected 'string'");
546 String result = (
const char *)subobj;
547 DBG2(
"From " + key +
", value: " + result);
561 String
readString(String key,
unsigned int minLength, String defaultVal =
"") {
569 return val.length() < minLength ? defaultVal : val;
572 static String
atomicReadString(String key,
unsigned int minLength, String defaultVal =
"") {
580 return jf.
readString(key, minLength, defaultVal);
589 ustd::array<String> keyparts;
591 if (!prepareRead(key, keyparts, subobj)) {
594 if (JSON.typeof(subobj) !=
"number") {
595 DBG(
"From " + key +
", element has wrong type '" + JSON.typeof(subobj) +
596 "' - expected 'number'");
599 double result = (double)subobj;
600 DBG2(
"From " + key +
", value: " + String(result));
614 double readDouble(String key,
double minVal,
double maxVal,
double defaultVal) {
624 return (val < minVal || val > maxVal) ? defaultVal : val;
627 static double atomicReadDouble(String key,
double minVal,
double maxVal,
double defaultVal) {
637 return jf.
readDouble(key, minVal, maxVal, defaultVal);
646 return (
long)
readDouble(key, (
double)defaultVal);
656 return jf.
readLong(key, defaultVal);
659 long readLong(String key,
long minVal,
long maxVal,
long defaultVal) {
668 long val =
readLong(key, defaultVal);
669 return (val < minVal || val > maxVal) ? defaultVal : val;
672 static long atomicReadLong(String key,
long minVal,
long maxVal,
long defaultVal) {
682 return jf.
readLong(key, minVal, maxVal, defaultVal);
692 if (!prepareWrite(key, target)) {
696 return autocommit ?
commit() :
true;
715 JSONVar jv = JSON.parse(value);
716 if (JSON.typeof(jv) ==
"undefined") {
717 DBG(
"Invalid JSON-value " + value);
722 if (!prepareWrite(key, target)) {
726 return autocommit ?
commit() :
true;
746 if (!prepareWrite(key, target)) {
749 target = (
const char *)value.c_str();
750 return autocommit ?
commit() :
true;
770 if (!prepareWrite(key, target)) {
773 target = JSON.parse(
"[]");
774 for (
unsigned int i; i < values.length(); i++) {
775 target[i] = (
const char *)values[i].c_str();
777 return autocommit ?
commit() :
true;
797 if (!prepareWrite(key, target)) {
801 return autocommit ?
commit() :
true;
821 if (!prepareWrite(key, target)) {
824 target = JSON.parse(
"[]");
825 for (
unsigned int i; i < values.length(); i++) {
826 target[i] = values[i];
828 return autocommit ?
commit() :
true;
848 if (!prepareWrite(key, target)) {
852 return autocommit ?
commit() :
true;
872 if (!prepareWrite(key, target)) {
875 target = JSON.parse(
"[]");
876 for (
unsigned int i; i < values.length(); i++) {
877 target[i] = values[i];
879 return autocommit ?
commit() :
true;
899 if (!prepareWrite(key, target)) {
903 return autocommit ?
commit() :
true;
923 if (!prepareWrite(key, target)) {
926 target = JSON.parse(
"[]");
927 for (
unsigned int i; i < values.length(); i++) {
928 target[i] = values[i];
930 return autocommit ?
commit() :
true;
944 bool loadFile(String basename, String fn) {
946 fs::File f =
fsOpen(fn,
"r");
951 if (!f.available()) {
952 DBG2(
"Opened " + fn +
", but no data in file!");
955 while (f.available()) {
957 String line = f.readStringUntil(
'\n');
961 JSONVar content = JSON.parse(jsonstr);
962 if (JSON.typeof(content) ==
"undefined") {
963 DBG(
"Parsing input file " + fn +
"failed, invalid JSON!");
964 DBG2(
"Content: " + jsonstr);
967 DBG2(
"Input file " + fn +
" successfully parsed");
968 DBG3(
"Content: " + jsonstr);
974 bool checkLoad(String basename) {
975 if (basename != filename) {
979 if (loaded || forcenew) {
982 return loadFile(basename, path + basename +
".json");
985 bool prepareRead(String key, ustd::array<String> &keyparts, JSONVar &subobj,
986 bool objmode =
false) {
989 if (keyparts.length() < (objmode ? 1 : 2)) {
990 DBG(
"Key-path too short, minimum needed is filename/topic, got: " + key);
993 if (!checkLoad(keyparts[0])) {
996 JSONVar iterator(obj);
997 for (
unsigned int i = 1; i < keyparts.length() - 1; i++) {
998 JSONVar tmpCopy(iterator[keyparts[i]]);
1000 if (JSON.typeof(iterator) ==
"undefined") {
1001 DBG2(
"From " + key +
", element " + keyparts[i] +
" not found.");
1005 String lastKey = keyparts[keyparts.length() - 1];
1006 if (!iterator.hasOwnProperty(lastKey)) {
1007 DBG2(
"From " + key +
", element " + lastKey +
" not found.");
1010 JSONVar tmpCopy(iterator[lastKey]);
1016 bool prepareWrite(String key, JSONVar &target,
bool objmode =
false) {
1017 ustd::array<String> keyparts;
1021 if (keyparts.length() < (objmode ? 1 : 2)) {
1022 DBG(
"Key-path too short, minimum needed is filename/topic, got: " + key);
1025 if (keyparts.length() > MAX_FRICKEL_DEPTH) {
1026 DBG(
"Key-path too long, maxdepth is " + String(MAX_FRICKEL_DEPTH) +
", got: " + key);
1029 if (!checkLoad(keyparts[0]) && forcenew) {
1030 DBG(
"Creating new file /" + keyparts[0] +
".json");
1034 switch (keyparts.length()) {
1040 target = obj[keyparts[1]];
1043 target = obj[keyparts[1]][keyparts[2]];
1046 target = obj[keyparts[1]][keyparts[2]][keyparts[3]];
1049 target = obj[keyparts[1]][keyparts[2]][keyparts[3]][keyparts[4]];
1052 target = obj[keyparts[1]][keyparts[2]][keyparts[3]][keyparts[4]][keyparts[5]];
1056 obj[keyparts[1]][keyparts[2]][keyparts[3]][keyparts[4]][keyparts[5]][keyparts[6]];
1059 target = obj[keyparts[1]][keyparts[2]][keyparts[3]][keyparts[4]][keyparts[5]]
1060 [keyparts[6]][keyparts[7]];
1063 target = obj[keyparts[1]][keyparts[2]][keyparts[3]][keyparts[4]][keyparts[5]]
1064 [keyparts[6]][keyparts[7]][keyparts[8]];
1067 DBG(
"SERIOUS PROGRAMMING ERROR - MAX_FRICKEL_DEV higher than implemented support "
1068 "in " __FILE__
" line number " +
1074 static void normalize(String &src) {
1075 if (src.c_str()[0] ==
'/') {
1076 src = src.substring(1);
muwerk JSON File Class
Definition jsonfile.h:67
bool readDoubleArray(String key, ustd::array< double > &values, bool strict=false)
Definition jsonfile.h:396
bool writeDouble(String key, double value)
Definition jsonfile.h:841
static double atomicReadDouble(String key, double minVal, double maxVal, double defaultVal)
Definition jsonfile.h:627
static bool atomicReadDoubleArray(String key, ustd::array< double > &values, bool strict=false)
Definition jsonfile.h:433
static bool atomicWriteBool(String key, bool value)
Definition jsonfile.h:804
String readString(String key, unsigned int minLength, String defaultVal="")
Definition jsonfile.h:561
static bool atomicWriteBoolArray(String key, ustd::array< bool > &values)
Definition jsonfile.h:831
static bool atomicReadJsonVar(String key, JSONVar &value)
Definition jsonfile.h:243
bool remove(String key)
Definition jsonfile.h:206
static bool atomicWriteJsonVar(String key, String value)
Definition jsonfile.h:729
double readDouble(String key, double minVal, double maxVal, double defaultVal)
Definition jsonfile.h:614
long readLong(String key, long defaultVal)
Definition jsonfile.h:640
static bool atomicWriteStringArray(String key, ustd::array< String > &values)
Definition jsonfile.h:780
static long atomicReadLong(String key, long defaultVal)
Definition jsonfile.h:649
bool writeLongArray(String key, ustd::array< long > &values)
Definition jsonfile.h:916
static bool atomicReadJsonVarArray(String key, ustd::array< JSONVar > &values)
Definition jsonfile.h:281
bool init(String basename, JSONVar &value, bool auto_commit=true)
Definition jsonfile.h:104
bool readStringArray(String key, ustd::array< String > &values, bool strict=false)
Definition jsonfile.h:293
static bool atomicReadBool(String key, bool defaultVal)
Definition jsonfile.h:520
bool readBoolArray(String key, ustd::array< bool > &values, bool strict=false)
Definition jsonfile.h:345
bool writeJsonVar(String key, JSONVar &value)
Definition jsonfile.h:685
bool writeDoubleArray(String key, ustd::array< double > &values)
Definition jsonfile.h:865
bool writeString(String key, String value)
Definition jsonfile.h:739
static bool atomicExists(String key)
Definition jsonfile.h:197
bool writeBoolArray(String key, ustd::array< bool > &values)
Definition jsonfile.h:814
static bool atomicWriteLong(String key, long value)
Definition jsonfile.h:906
bool readJsonVarArray(String key, ustd::array< JSONVar > &values)
Definition jsonfile.h:255
bool exists(String key)
Definition jsonfile.h:183
bool writeLong(String key, long value)
Definition jsonfile.h:892
bool readLongArray(String key, ustd::array< long > &values, bool strict=false)
Definition jsonfile.h:448
bool initFromFile(String basename, String fn, bool auto_commit=true)
Definition jsonfile.h:133
static long atomicReadLong(String key, long minVal, long maxVal, long defaultVal)
Definition jsonfile.h:672
jsonfile(bool auto_commit=true, bool force_new=false, String path="/")
Definition jsonfile.h:77
static bool atomicWriteString(String key, String value)
Definition jsonfile.h:753
bool commit()
Definition jsonfile.h:157
static String atomicReadString(String key, String defaultVal="")
Definition jsonfile.h:551
static bool atomicWriteDouble(String key, double value)
Definition jsonfile.h:855
bool init(String basename, String value, bool auto_commit=true)
Definition jsonfile.h:121
double readDouble(String key, double defaultVal)
Definition jsonfile.h:583
static bool atomicWriteLongArray(String key, ustd::array< long > &values)
Definition jsonfile.h:933
void clear(bool auto_commit=true, bool force_new=false)
Definition jsonfile.h:90
long readLong(String key, long minVal, long maxVal, long defaultVal)
Definition jsonfile.h:659
static bool atomicRemove(String key)
Definition jsonfile.h:219
bool readJsonVar(String key, JSONVar &value)
Definition jsonfile.h:228
static double atomicReadDouble(String key, double defaultVal)
Definition jsonfile.h:604
String readString(String key, String defaultVal="")
Definition jsonfile.h:530
static bool atomicWriteJsonVar(String key, JSONVar &value)
Definition jsonfile.h:699
static String atomicReadString(String key, unsigned int minLength, String defaultVal="")
Definition jsonfile.h:572
static bool atomicReadStringArray(String key, ustd::array< String > &values, bool strict=false)
Definition jsonfile.h:330
bool readBool(String key, bool defaultVal)
Definition jsonfile.h:499
static bool atomicReadLongArray(String key, ustd::array< long > &values, bool strict=false)
Definition jsonfile.h:485
static bool atomicReadBoolArray(String key, ustd::array< bool > &values, bool strict=false)
Definition jsonfile.h:382
bool writeStringArray(String key, ustd::array< String > &values)
Definition jsonfile.h:763
String toString() const
Definition jsonfile.h:150
bool writeJsonVar(String key, String value)
Definition jsonfile.h:709
bool writeBool(String key, bool value)
Definition jsonfile.h:790
static bool atomicWriteDoubleArray(String key, ustd::array< double > &values)
Definition jsonfile.h:882
The muwerk namespace.
Definition console.h:15
fs::File fsOpen(String filename, String mode)
Definition filesystem.h:113
void split(String &src, char delimiter, array< String > &result)
Definition muwerk.h:62