Хранение любых данных в текстовом виде в формате "ключ":значение
- Быстрая и лёгкая реализация по сравнению с JSON
- Выделение буфера: статическое или динамическое (как у String)
- Реализован доступ (чтение и запись) через []
- Нативная конвертация из любых типов на запись, вывод в выбранный тип на чтение
- Отдельный инструмент для esp8266/esp32 - автоматическая запись и чтение в файл
- Аккуратная работа с памятью
Совместима со всеми Arduino платформами (используются Arduino-функции)
- Библиотеку можно найти по названию Pairs и установить через менеджер библиотек в:
- Arduino IDE
- Arduino IDE v2
- PlatformIO
- Скачать библиотеку .zip архивом для ручной установки:
- Распаковать и положить в C:\Program Files (x86)\Arduino\libraries (Windows x64)
- Распаковать и положить в C:\Program Files\Arduino\libraries (Windows x32)
- Распаковать и положить в Документы/Arduino/libraries/
- (Arduino IDE) автоматическая установка из .zip: Скетч/Подключить библиотеку/Добавить .ZIP библиотеку… и указать скачанный архив
- Читай более подробную инструкцию по установке библиотек здесь
- Рекомендую всегда обновлять библиотеку: в новых версиях исправляются ошибки и баги, а также проводится оптимизация и добавляются новые фичи
- Через менеджер библиотек IDE: найти библиотеку как при установке и нажать "Обновить"
- Вручную: удалить папку со старой версией, а затем положить на её место новую. "Замену" делать нельзя: иногда в новых версиях удаляются файлы, которые останутся при замене и могут привести к ошибкам!
Между парами ставится разделитель \n (перенос строки), после последней пары не ставится. Вид данных как текст:
"key0":value0
"key1":value1
"key2":value2
Во время редактирования через методы библиотеки (добавить, удалить, изменить) библиотека сама следит за корректным расположением разделителей.
Ключ и значение не должны содержать неэкранированных двойных кавычек " - это сломает чтение и запись! Библиотека не следит за этим и сама кавычки не экранирует! Если в поле значения нужен символ двойных кавычек - его нужно экранировать символом \:
"key0":val"ue0 - неправильно
"key1":val\"ue1 - правильно
data["key"] = "val\"ue"; // неправильно (равносильно значению val"ue)
data["key"] = "val\\\"ue"; // правильно (равносильно значению val\"ue)В документации ниже тип данных AnyText может принимать:
const char*,char*,"строковые константы"F("строки")- строки из PROGMEMString- строки
Тип AnyValue может принимать:
- Строки как в
AnyText - Все целые числа (8, 16, 32 бит)
doubleиfloat
Библиотека содержит в себе несколько классов для работы в разных сценариях:
PairsExt
Основной объект пар на основе статического внешнего char массива указанной длины.
// конструктор
PairsExt();
PairsExt(char* str, uint16_t size); // подключить внешний буфер размера size
// переменные
char* str; // строка для ручного доступа
uint16_t size; // указанный макс. размер
// методы
void setBuffer(char* str, uint16_t len);// подключить буфер
void clear(); // очистить строку
bool changed(); // было изменение данных. Само сбросится в false
bool contains(AnyText key); // проверка на существование
uint16_t length(); // фактическая длина строки
uint16_t amount(); // количество пар
void refresh(); // пересчитать длину строки и количество пар (после ручных изменений)
bool set(AnyText key, AnyValue value); // установить по ключу
bool setN(uint16_t idx, AnyValue value);// установить по индексу
Pair_t get(AnyText key); // получить по ключу
Pair_t getN(uint16_t idx); // получить по индексу
int32_t toInt(); // вывести в int
float toFloat(); // вывести в float
String toString(); // вывести в String
bool toChar(char* buf, uint16_t len); // вывести в char массив
bool remove(AnyText key); // удалить по ключу
bool removeN(uint16_t idx); // удалить по индексуPairs
Объект пар на основе динамической строки. Методы такие же как у PairsExt, за исключением setBuffer/reserve.
// конструктор
Pairs();
Pairs(uint16_t size); // с указанием резерва строки
// методы
bool reserve(uint16_t len); // зарезервировать строку
// наследует всё из PairsExtPairsStatic
Основан на PairsExt, но вместо внешнего массива создаёт свой, внутри объекта.
// конструктор
PairsStatic<макс. размер> ();
// методы
// наследует всё из PairsExtPairsFile
Автоматическое хранение и обновление базы пар для esp8266/esp32. Привязывается к файлу, записывает в него данные при изменении + выходе таймаута. Основано на динамическом классе Pairs.
// конструктор
// Установить файловую систему, имя файла и таймаут
PairsFile(fs::FS* nfs = nullptr, const char* path = nullptr, uint32_t tout = 10000);
// методы
// наследует всё из Pairs
// установить файловую систему и имя файла
void setFS(fs::FS* nfs, const char* path);
// установить таймаут записи, мс (умолч. 10000)
void setTimeout(uint32_t tout = 10000);
// прочитать данные в буфер. Опционально заразервировать дополнительное место. true если прочитаны
bool begin(uint16_t res = 0);
// обновить данные в файле
bool update();
// тикер, вызывать в loop. Сам обновит данные при изменении и выходе таймаута, вернёт true
bool tick();Pair_t
Объект пары, хранит указатели на ключ и значение и их длину, а также позволяет выводить данные в указанный тип.const char* key; // ключ
uint16_t key_len; // длина ключа
const char* val; // значение
uint16_t val_len; // длина значения
// вывести значение в char массив
bool toChar(char* buf, uint16_t len);
int32_t toInt(); // вывести значение в int
float toFloat(); // вывести значение в float
String toString(); // вывести значение в StringУ разных классов по сути отличается только инициализация:
// PairsExt
char str[100] = {0};
PairsExt p(str, 100);
// PairsExt
Pairs p;
// PairsExt
PairsStatic<100> p;
// PairsFile
PairsFile p(&LittleFS, "/data.dat");
// перед вызовом begin() файловая система должна быть запущена!В чтении-записи всё одиаково, из предыдущего примера объект p:
// запись. Типы данных в любых сочетаниях
p["key0"] = "val0";
p[F("key1")] = 1234;
p[0] = F("abcd");
p.set("key2", 3.14);
p.setN(0, ("new val 0"));
// чтение
Serial.println(p["key0"]); // авто-каст в String
int i = p["key1"].toInt();
float f = p.get("key2").toFloat();
// удаление
p.remove(F("key1"));
p.removeN(0);
// работа со String. Вот так - тоже будет работать
String val = "value";
p[String("key") + 1] = val;
// но нужно помнить, что это может создавать фрагментацию памяти
// если используется динамический PairsПри ручных изменениях в буфере (данные скопированы откуда-то извне) нужно вызвать .refresh() для пересчёта базы данных!
PairsFile data(&LittleFS, "/data.dat", 3000);
void setup() {
LittleFS.begin();
data.begin(); // прочитать из файла
data["key"] = "value"; // изменили
}
void loop() {
data.tick(); // тикаем тут. Само обновится после таймаута
}- v1.0
- v1.1
- Динамическая String реализация заменена на свою
- Добавлена возможность задавать значения из PROGMEM
- Библиотека облегчена и ускорена
- Больше безопасности
При нахождении багов создавайте Issue, а лучше сразу пишите на почту alex@alexgyver.ru
Библиотека открыта для доработки и ваших Pull Request'ов!
При сообщении о багах или некорректной работе библиотеки нужно обязательно указывать:
- Версия библиотеки
- Какой используется МК
- Версия SDK (для ESP)
- Версия Arduino IDE
- Корректно ли работают ли встроенные примеры, в которых используются функции и конструкции, приводящие к багу в вашем коде
- Какой код загружался, какая работа от него ожидалась и как он работает в реальности
- В идеале приложить минимальный код, в котором наблюдается баг. Не полотно из тысячи строк, а минимальный код