NVS

If you have any data that you want to store in kublet permanently, you can save that in the kublet’s Non-Volatile Storage Library (NVS). This data is preserved in the event of a power reset, but erased if a new app is flashed.

Non-volatile storage (NVS) library is designed to store key-value pairs in flash. They are useful for storing sensitive information such as API keys, certs.

NVS is a simpler way of storing a small amount of data, like e.g. a struct, instead of a full-blown filesystem.

How to use

We use the Preferences.h library that comes with Arduino to store data in NVS. The basic flow of using NVS looks like this:

#include <Preferences.h>

Preferences preferences;

void setup() {
  preferences.begin("app", false);
  preferences.putString("ipaddr", "198.168.20.2");
  preferences.end();

  preferences.begin("app", false);
  String ipaddr = preferences.getString("ipaddr");
  // do something
  preferences.end();
}

All key value pairs are stored in namespaces. For published Krates on Kublet, all key value pairs must be stored in the namespace app. To store key value pairs, you would need to first open/create the storage space with the namespace app:

preferences.begin("app", false);

The false opens the namespace in read/write mode. Use true to open the namespace in read-only mode.

After reading or writing to the namespace, close it with:

preferences.end();

The code for writing to the namespace looks like this:

preferences.putString("ipaddr", "198.168.20.2");

string is not the only data type you can save. NVS supports multiple data types, and you would write to NVS like this:

TypeFunction
CharputChar(const char* key, int8_t value)
Unsigned CharputUChar(const char* key, int8_t value)
ShortputShort(const char* key, int16_t value)
Unsigned ShortputUShort(const char* key, uint16_t value)
IntputInt(const char* key, int32_t value)
Unsigned IntputUInt(const char* key, uint32_t value)
LongputLong(const char* key, int32_t value)
Unsigned LongputULong(const char* key, uint32_t value)
Long64putLong64(const char* key, int64_t value)
Unsigned Long64putULong64(const char* key, uint64_t value)
FloatputFloat(const char* key, const float_t value)
DoubleputDouble(const char* key, const double_t value)
BoolputBool(const char* key, const bool value)
StringputString(const char* key, const String value
BytesputBytes(const char* key, const void* value, size_t len)

To read a value from the namespace, after opening the namespace, you would write:

String ipaddr = preferences.getString("ipaddr");

Similarly, you would call different methods depending on the data type you want to read:

TypeFunction
ChargetChar(const char* key, const int8_t defaultValue)
Unsigned ChargetUChar(const char* key, const uint8_t defaultValue)
ShortgetShort(const char* key, const int16_t defaultValue
Unsigned ShortgetUShort(const char* key, const uint16_t defaultValue)
IntgetInt(const char* key, const int32_t defaultValue)
Unsigned IntgetUInt(const char* key, const uint32_t defaultValue)
LonggetLong(const char* key, const int32_t defaultValue)
Unsigned LonggetULong(const char* key, const uint32_t defaultValue)
Long64getLong64(const char* key, const int64_t defaultValue)
Unsigned Long64getULong64(const char* key, const uint64_t defaultValue)
FloatgetFloat(const char* key, const float_t defaultValue)
DoublegetDouble(const char* key, const double_t defaultValue)
BoolgetBool(const char* key, const bool defaultValue)
StringgetString(const char* key, const String defaultValue)
StringgetString(const char* key, char* value, const size_t maxLen)
BytesgetBytes(const char* key, void * buf, size_t maxLen)

To clear all key value pairs within a namespace, call:

preferences.begin("app", false);
preferences.clear();
preferences.end();

To remove a key from the namespace:

preferences.begin("app", false);
preferences.remove(key);
preferences.end();