ESP8266/ESP32

What are the ESP32 DAC output pins?

  • Pin IO25 is connected to DAC_1
  • Pin IO26 is connected to DAC_2

Source: ESP32 technical reference manual, Table 4-4

Posted by Uli Köhler in Analog, ESP8266/ESP32

ESP32 minimal httpd_uri_t example (ESP-IDF)

This httpd_uri_t handler just answers Hello World!:

static const httpd_uri_t rootHandler = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = [](httpd_req_t *req) {
        httpd_resp_set_type(req, "text/html");
        httpd_resp_send(req, "<h1>Hello World!</h1>", HTTPD_RESP_USE_STRLEN);

        return ESP_OK;
    }
};

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32

Automated script to build MicroPython for the ESP32

The following script installs esp-idf, the required dependencies and then builds MicroPython for the ESP32.

apt -y update && apt -y install python3 python3-pip cmake
# Install esp-idf
git clone --depth 1 -b v4.4.3 https://github.com/espressif/esp-idf.git /opt/esp-idf
cd /opt/esp-idf && git submodule update --init --recursive && ./install.sh

# Clone micropython
git clone --depth 1 -b v1.19.1 https://github.com/micropython/micropython.git /opt/micropython

# Build micropython
cd /opt/micropython/ && make -C mpy-cross
# Build micropython@esp32
cd /opt/micropython/ports/esp32 && source /opt/esp-idf/export.sh && make submodules && make -j4

 

Posted by Uli Köhler in Embedded, ESP8266/ESP32, MicroPython

ESP32 Arduino HTTPS webserver example using certificate from LittleFS

The following example reads a HTTPS/TLS certificate from LittleFS (cert.pem and privkey.pem – these are just standard X.509 PEM files) and uses those to initialize a HTTPS server. Most of this example is based on the esp-idf https_server example.

Our code to initialize the HTTPS server uses code from the following posts:

The core initialization sequence works like this:

// These need to be GLOBAL variables, they still need to exist
// after initialization!
std::string cert;
std::string privkey;

httpd_ssl_config_t conf = HTTPD_SSL_CONFIG_DEFAULT();
httpd_handle_t server = nullptr;

void InitializeHTTPServer() {
        std::string cert = ReadFileToString("/cert.pem");
        std::string privkey = ReadFileToString("/privkey.pem");

        conf.cacert_pem = (const uint8_t*)this->cert.c_str();
        conf.cacert_len = this->cert.size() + 1;

        conf.prvtkey_pem = (const uint8_t*)this->privkey.c_str();
        conf.prvtkey_len = this->privkey.size() + 1;

        esp_err_t ret = httpd_ssl_start(&server, &conf);
        if (ESP_OK != ret) {
            ESP_LOGI(TAG, "Error starting server!");
            return;
        }
}

However it is typically far more convenient to use our HTTPSServer class:

class HTTPSServer {
public:

    HTTPSServer(): conf(HTTPD_SSL_CONFIG_DEFAULT()) {
    }

    void ReadCertificateInfoFromFilesystem() {
        cert = ReadFileToString("/cert.pem");
        privkey = ReadFileToString("/privkey.pem");
    }

    void StartServer() {
        // Start the httpd server
        ESP_LOGI(TAG, "Starting server");

        ReadCertificateInfoFromFilesystem();

        conf.cacert_pem = (const uint8_t*)this->cert.c_str();
        conf.cacert_len = this->cert.size() + 1;

        conf.prvtkey_pem = (const uint8_t*)this->privkey.c_str();
        conf.prvtkey_len = this->privkey.size() + 1;

        esp_err_t ret = httpd_ssl_start(&server, &conf);
        if (ESP_OK != ret) {
            ESP_LOGI(TAG, "Error starting server!");
            return;
        }
    }

    void RegisterHandler(const httpd_uri_t *uri_handler) {
        httpd_register_uri_handler(this->server, uri_handler);
    }

    httpd_handle_t server = nullptr;

    httpd_ssl_config_t conf;
    std::string cert;
    std::string privkey;
};

Usage example:

void setup() {
    InitFilesystem();

    // TODO setup wifi network

    httpsServer.StartServer();
    // Register your 
    httpsServer.RegisterHandler(&root);
}

Full example:

#include <Arduino.h>
#include <WiFi.h>
#include <LittleFS.h>
#include <string>
#include <esp_https_server.h>
#include "esp_tls.h"

//AsyncWebServer server(80);
static const char *TAG = "https-littlefs-example";

volatile bool filesystemOK = false;

void InitFilesystem() {
  // Initialize LittleFS
  if (!LittleFS.begin(false /* false: Do not format if mount failed */)) {
    Serial.println("Failed to mount LittleFS");
    if (!LittleFS.begin(true /* true: format */)) {
      Serial.println("Failed to format LittleFS");
    } else {
      Serial.println("LittleFS formatted successfully");
      filesystemOK = true;
    }
  } else { // Initial mount success
    filesystemOK = true;
  }
}

/* An HTTP GET handler */
static esp_err_t root_get_handler(httpd_req_t *req)
{
    httpd_resp_set_type(req, "text/html");
    httpd_resp_send(req, "<h1>Hello Secure World!</h1>", HTTPD_RESP_USE_STRLEN);

    return ESP_OK;
}

static const httpd_uri_t root = {
    .uri       = "/",
    .method    = HTTP_GET,
    .handler   = root_get_handler
};

size_t LittleFSFilesize(const char* filename) {
  auto file = LittleFS.open(filename, "r");
  size_t filesize = file.size();
  // Don't forget to clean up!
  file.close();
  return filesize;
}

std::string ReadFileToString(const char* filename) {
  auto file = LittleFS.open(filename, "r");
  size_t filesize = file.size();
  // Read into temporary Arduino String
  String data = file.readString();
  // Don't forget to clean up!
  file.close();
  return std::string(data.c_str(), data.length());
}

class HTTPSServer {
public:

    HTTPSServer(): conf(HTTPD_SSL_CONFIG_DEFAULT()) {
    }

    void ReadCertificateInfoFromFilesystem() {
        cert = ReadFileToString("/cert.pem");
        privkey = ReadFileToString("/privkey.pem");
    }

    void StartServer() {
        // Start the httpd server
        ESP_LOGI(TAG, "Starting server");

        ReadCertificateInfoFromFilesystem();

        conf.cacert_pem = (const uint8_t*)this->cert.c_str();
        conf.cacert_len = this->cert.size() + 1;

        conf.prvtkey_pem = (const uint8_t*)this->privkey.c_str();
        conf.prvtkey_len = this->privkey.size() + 1;

        esp_err_t ret = httpd_ssl_start(&server, &conf);
        if (ESP_OK != ret) {
            ESP_LOGI(TAG, "Error starting server!");
            return;
        }

        // Set URI handlers
        ESP_LOGI(TAG, "Registering URI handlers");
        httpd_register_uri_handler(server, &root);
        return;
    }

    void RegisterHandler(const httpd_uri_t *uri_handler) {
        httpd_register_uri_handler(this->server, uri_handler);
    }

    httpd_handle_t server = nullptr;

    httpd_ssl_config_t conf;
    std::string cert;
    std::string privkey;
};

HTTPSServer httpsServer;

void setup() {
    Serial.begin(115200);
    delay(500);

    InitFilesystem();

    // Connect Wifi, restart if not connecting
    // https://techoverflow.net/2021/01/21/how-to-fix-esp32-not-connecting-to-the-wifi-network/
    WiFi.begin("MyWifi", "Lobae1tie5achokef8riequohgohx");

    uint32_t notConnectedCounter = 0;
    while (WiFi.status() != WL_CONNECTED) {
        delay(100);
        Serial.println("Wifi connecting...");
        notConnectedCounter++;
        if(notConnectedCounter > 150) { // Reset board if not connected after 5s
            Serial.println("Resetting due to Wifi not connecting...");
            ESP.restart();
        }
    }
    Serial.print("Wifi connected, IP address: ");
    Serial.println(WiFi.localIP());

    httpsServer.StartServer();
    httpsServer.RegisterHandler(&root);
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(1000);
}
[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.5
board = esp32dev
framework = arduino
board_build.filesystem = littlefs
monitor_speed = 115200

 

Posted by Uli Köhler in Arduino, ESP8266/ESP32, Networking, PlatformIO

How to read LittleFS file to std::string (using Arduino/PlatformIO)

The following utility function reads . As a prerequisite, you need to initialize the LittleFS filesystem and configure PlatformIO to use LittleFS as filesystem when uploading the filesystem image.

NoteBefore using any of the functions below, you need to call InitFilesystem() in setup() in order to mount the filesystem. You can find this function in our previous post on how to initialize LittleFS.

#include <string>

std::string ReadFileToString(const char* filename) {
  auto file = LittleFS.open(filename, "r");
  size_t filesize = file.size();
  // Read into temporary Arduino String
  String data = file.readString();
  // Don't forget to clean up!
  file.close();
  return std::string(data.c_str(), data.length());
}

Example usage:

std::string cert = ReadFileToString("/cert.pem");

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32, PlatformIO

How to configure PlatformIO for LittleFS (ESP32)

You can configure PlatformIO to use the LittleFS filesystem as opposed to the default SPIFFS using

board_build.filesystem = littlefs

If you are ussing arduino-esp32, you might also need to specify to use a recent arduino-esp32 framework version, but I suggest to first try it out without using that option:

platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.5

Full platformio.ini example

[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.5
board = esp32dev
framework = arduino
board_build.filesystem = littlefs
monitor_speed = 115200

 

Posted by Uli Köhler in ESP8266/ESP32, PlatformIO

How to fix esp-tls-mbedtls: mbedtls_x509_crt_parse returned -0x2180

Problem:

While trying to use TLS on the ESP32, you are using a certificate and private key e.g. from NVS or from the filesystem. However when you try to connect using SSL, you see error messages like

E (9774) esp-tls-mbedtls: mbedtls_x509_crt_parse returned -0x2180
E (9775) esp-tls-mbedtls: Failed to set server pki context
E (9775) esp-tls-mbedtls: Failed to set server configurations, returned [0x8015] (ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED)
E (9786) esp-tls-mbedtls: create_ssl_handle failed, returned [0x8015] (ESP_ERR_MBEDTLS_X509_CRT_PARSE_FAILED)
E (9795) esp_https_server: esp_tls_create_server_session failed

Solution:

-0x2180 means MBEDTLS_ERR_X509_INVALID_FORMAT

The most common issue here is that conf.cacert_len and conf.prvtkey_len must include the NUL terminator in the length.

Working Example:

conf.cacert_pem = (const uint8_t*)cert.c_str();
conf.cacert_len = this->cert.size() + 1;

conf.prvtkey_pem = (const uint8_t*)privkey.c_str();
conf.prvtkey_len = this->privkey.size() + 1;

Note the + 1 here: Without the + 1, you’ll see the mbedtls_x509_crt_parse returned -0x2180

Other causes:

If the length isn’t the issue, you likely have a malformed certificate. I suggest to print out the certificate’s content via the serial port, saving it to file we’ll call cert_esp32.pem and then running

openssl x509 -in cert_esp32.pem -noout -text

to verify that the certificate is correct. You can do the same for the private key, but typically either both the private key and the certificate are fine or both are not.

Posted by Uli Köhler in C/C++, Embedded, ESP8266/ESP32, Networking

How to initialize LittleFS in Arduino on the ESP32 (PlatformIO)

In order to use the LittleFS library that comes with Arduino on the ESP32, use the following function

#include <LittleFS.h>

bool filesystemOK = false;

void InitFilesystem() {
  // Initialize LittleFS
  if (!LittleFS.begin(false /* false: Do not format if mount failed */)) {
    Serial.println("Failed to mount LittleFS");
    if (!LittleFS.begin(true /* true: format */)) {
      Serial.println("Failed to format LittleFS");
    } else {
      Serial.println("LittleFS formatted successfully");
      filesystemOK = true;
    }
  } else { // Initial mount success
    filesystemOK = true;
  }
}

Additionally, you need to configure PlatformIO to use LittleFS:

board_build.filesystem = littlefs

Now, in setup(), call

InitFilesystem();

If you have errors including LittleFS.h, you might need to explicitly use a recent arduino-esp32 version in platformio.ini:

platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.5

In case you absolutely need to use an older arduino-esp32 version that doesn’t support LittleFS out of the box, you can use the lorol/LittleFS library as outlined in our previous post: How to initialize LittleFS in PlatformIO on the ESP32 using the lorol/LittleFS library

Full platformio.ini example:

[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.5
board = esp32dev
framework = arduino
board_build.filesystem = littlefs
monitor_speed = 115200

 

Posted by Uli Köhler in Arduino, Embedded, ESP8266/ESP32, PlatformIO

Does ESP32 (ESP-IDF/Arduino/mbed-tls) support secp384r1 certificates?

Yes, I verified that mbed-tls (which is used in the esp-idf framework, which is in turn used by Arduino/PlatformIO) works fine when using a secp384r1-keyed Let’s encrypt TLS server certificate.

The version used in arduino-esp32 v2.0.5 with PlatformIO 6.1.5.

Posted by Uli Köhler in ESP8266/ESP32, mbed

Should you use SPIFFS oder LittleFS?

For new projects, you should exclusively use LittleFS, period.

The only reason why you would you SPIFFS at all if you have data stored on SPIFFS and can’t easily migrate to LittleFS.

LittleFS is just better than SPIFFS in every regard and SPIFFS will at some point in time be deprecated anyways.

Posted by Uli Köhler in Embedded, ESP8266/ESP32, PlatformIO

How to get filesize in LittleFS (ESP32/PlatformIO)

After you have initialized LittleFS (see ESP32 Filesystem initialization code example (LittleFS)) you can get the filesize by first opening the file, and then calling .size() on the opened file. Don’t forget to close the file afterwards.

auto file = LittleFS.open(filename, "r");
size_t filesize = file.size();
// Don't forget to clean up!
file.close();

Utility function to get the size of a file stored on LittleFS:

size_t LittleFSFilesize(const char* filename) {
  auto file = LittleFS.open(filename, "r");
  size_t filesize = file.size();
  // Don't forget to clean up!
  file.close();
  return filesize;
}

Example usage:

Serial.println(LittleFSFilesize("/cert.pem"));

 

Posted by Uli Köhler in C/C++, ESP8266/ESP32, PlatformIO

How to fix ESP32 PlatformIO esp_https_server.h: No such file or directory

Problem:

When compiling your PlatformIO project, you see a compiler error like

src/main.cpp:6:10: fatal error: esp_https_server.h: No such file or directory

at the following line:

#include <esp_https_server.h>

Solution:

The ESP32 HTTPS server library is not included with the older versions of arduino-espressif32. The solution therefore is to use a more recent version of the platform library such as version 2.0.4. In order to do that, add the following line to your platformio.ini:

platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.4

Complete platformio.ini example:

[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.4
board = esp32dev
framework = arduino
monitor_speed = 115200

 

Posted by Uli Köhler in Embedded, ESP8266/ESP32, PlatformIO

How to set static IP address on ESP32

TL;DR

Before you call WiFi.begin(...), call this:

if (!WiFi.config(
      IPAddress(192, 168, 19, 5), // ESP's IP address
      IPAddress(192, 168, 19, 1), // Gateway
      IPAddress(255, 255, 255, 0), // IP Address
      IPAddress(192, 168, 19, 1) // DNS server
    )) {
  Serial.println("Failed to set static IP");
}

and replace the IP address etc with the static

Full example

This is based on our previous post on How to fix ESP32 not connecting to the Wifi network:

#include <Arduino.h>
#include <WiFi.h>

void setup() {
  Serial.begin(115200);
  WiFi.begin("MyWifiSSID", "MyWifiPassword");

  // Set static IP
  if (!WiFi.config(
        IPAddress(192, 168, 19, 5), // ESP's IP address
        IPAddress(192, 168, 19, 2), // Gateway
        IPAddress(255, 255, 255, 0), // IP Address
        IPAddress(192, 168, 19, 1) // DNS server
      )) {
    Serial.println("Failed to set static IP");
  }

  // Wait for wifi to be connected
  uint32_t notConnectedCounter = 0;
  while (WiFi.status() != WL_CONNECTED) {
      delay(100);
      Serial.println("Wifi connecting...");
      notConnectedCounter++;
      if(notConnectedCounter > 150) { // Reset board if not connected after 5s
          Serial.println("Resetting due to Wifi not connecting...");
          ESP.restart();
      }
  }
  Serial.print("Wifi connected, IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  // put your main code here, to run repeatedly:
}

 

Posted by Uli Köhler in Embedded, ESP8266/ESP32, Networking

How to install ESP32 espota.py on Linux

Currently there is no pip install ... way of installing espota.py. The easiest way of installing it is to download it from GitHub:

wget https://raw.githubusercontent.com/espressif/arduino-esp32/master/tools/espota.py

 

Posted by Uli Köhler in Embedded, ESP8266/ESP32, Networking

How to fix ESP32 esptool.py Running stub… StopIteration

Problem:

When flashing an ESP32, especially when flashing remotely, you see the following log message

Serial port rfc2217://10.1.2.3.105:4418
Connecting...
Device PID identification is only supported on COM and /dev/ serial ports.
..
Chip is ESP32-S2
Features: WiFi, No Embedded Flash, No Embedded PSRAM, ADC and temperature sensor calibration in BLK2 of efuse V2
Crystal is 40MHz
MAC: 60:55:f9:f0:3a:16
Uploading stub...
Running stub...
Traceback (most recent call last):
  File "/usr/local/bin/esptool.py", line 34, in <module>
    esptool._main()
  File "/usr/local/lib/python3.8/dist-packages/esptool/__init__.py", line 1004, in _main
    main()
  File "/usr/local/lib/python3.8/dist-packages/esptool/__init__.py", line 684, in main
    esp = esp.run_stub()
  File "/usr/local/lib/python3.8/dist-packages/esptool/loader.py", line 912, in run_stub
    p = self.read()
  File "/usr/local/lib/python3.8/dist-packages/esptool/loader.py", line 307, in read
    return next(self._slip_reader)
StopIteration

Solution:

This issue occurs not because of a hardware defect but because the latency of the connection is quite high and therefore the timeout occurs before the communication between the script and the bootloader can happen.

In order to fix it, you need to edit the hard-coded default timeout in the esptool.py installation!

First, you need to identify the location of loader.py in your installation. You can simply do that from the following part of the stack trace:

File "/usr/local/lib/python3.8/dist-packages/esptool/loader.py", line 912, in run_stub p = self.read()

In this case, loader.py is located at

/usr/local/lib/python3.8/dist-packages/esptool/loader.py

You need to edit the following line:

MEM_END_ROM_TIMEOUT = 0.05  # short timeout for ESP_MEM_END, as it may never respond

and increase the timeout – my recommendation is to increase it to 2.5 seconds.

… or you can simply change the timeout using the following command:

sed -i -e 's/MEM_END_ROM_TIMEOUT = 0.05/MEM_END_ROM_TIMEOUT = 2.5/g' /usr/local/lib/python3.8/dist-packages/esptool/loader.py

After that, your upload should work just fine.

Posted by Uli Köhler in Electronics, Embedded, ESP8266/ESP32, Networking

How to write std::string to ESP32 NVS

Also see: How to read ESP32 NVS value into std::string

Writing a std::string into NVS is pretty easy. You can just use .c_str() to obtain a const char* pointer and then proceed as shown in How to write string (const char*) to ESP32 NVS

You can use this utility function to write a string (const char*) into the NVS:

bool NVSWriteString(nvs_handle_t nvs, const std::string& key, const std::string& value) {
    esp_err_t err;
    if((err = nvs_set_blob(nvs, key.c_str(), value.data(), value.size())) != ESP_OK) {
        Serial.printf("Failed to write NVS key %s: %srn", key, esp_err_to_name(err));
        return false;
    }
    return true;
}

Usage example

This example is based on How to initialize NVS on ESP32. Most importantly, it assumes you have already initialized the NVS and myNVS exists and is valid.

char mySerialNo[128] = {0};

_NVS_WriteString(myNVS, "SerialNo", "0000001");

This will write the value 0000001 to the NVS with key SerialNo

Note that NVS strings are length-delimited (as in: The length is stored in the NVS) and not neccessarily NUL-terminated. This code does not store the NUL terminator in NVS.

Posted by Uli Köhler in ESP8266/ESP32

How to read ESP32 NVS value into std::string

In our previous post, we discussed How to get the length / size of NVS value on ESP32. Based on that, we can read a NVS value into a std::string.

Strategy

  1. Determine size of value in NVS
  2. Allocate temporary buffer of the determined size
  3. Read value from NVS into temporary buffer
  4. Create std::string from value
  5. Cleanup temporary buffer

Utility function to read NVS value as std::string

In case the key does not exist in NVS, this function will return the empty string ("").

#include <nvs.h>
#include <string>

std::string ReadNVSValueAsStdString(nvs_handle_t nvs, const char* key) {
    /**
     * Strategy:
     *  1. Determine size of value in NVS
     *  2. Allocate temporary buffer of determined size
     *  3. Read value from NVS into temporary buffer
     *  4. Create std::string from value
     *  5. Cleanup
     */
    // Step 1: Get size of key
    esp_err_t err;
    size_t value_size = 0;
    if((err = nvs_get_str(nvs, _key.c_str(), nullptr, &value_size)) != ESP_OK) {
        if(err == ESP_ERR_NVS_NOT_FOUND) {
            // Not found, no error
            return "";
        } else {
            printf("Failed to get size of NVS key %s: %s\r\n", key, esp_err_to_name(err));
            return;
        }
    }
    // Step 2: Allocate temporary buffer to read from
    char* buf = (char*)malloc(value_size);
    // Step 3: Read value into temporary buffer.
    esp_err_t err;
    if((err = nvs_get_str(nvs, _key.c_str(), buf, &value_size)) != ESP_OK) {
        // "Doesn't exist" has already been handled before, so this is an actual error.
        // We assume that the value did not change between reading the size (step 1) and now.
        // In case that assumption is value, this will fail with ESP_ERR_NVS_INVALID_LENGTH.
        // This is extremely unlikely in all usage scenarios, however.
        printf("Failed to read NVS key %s: %s\r\n", key, esp_err_to_name(err));
        free(buf);
        return "";
    }
    // Step 4: Make string
    std::string value = std::string(buf, value_size);
    // Step 5: cleanup
    free(buf);
    
    return value;
}

Usage example

This assumes that you have setup myNvs as we have shown in our previous post How to initialize NVS on ESP32

std::string value = ReadNVSValueAsStdString(myNvs, "MyKey");

C++17 optimizations

Starting from C++17, you can possibly create a std::string directly instead of using the temporary buffer, since there is an overload of .data() that returns a non-const pointer – so you can write directly to the std::string‘s buffer.

However, since my PlatformIO-based toolchain currently doesn’t support that, I have not written that code yet.

Posted by Uli Köhler in C/C++, ESP8266/ESP32

How to get length / size of NVS value on ESP32

You can find the size of a value stored in ESP32 NVS by running nvs_get_blob() with length set to a pointer to a variable with content 0, and out_value set to nullptrnvs_get_str() works as well, the only difference is the type of the out_value argument, which does not matter at all.

It’s easier to understand if you look at this example function:

size_t NVSGetSize(nvs_handle_t nvs, const char* key) {
    esp_err_t err;
    size_t valueSize = 0;
    if((err = nvs_get_str(nvs, key, nullptr, &valueSize)) != ESP_OK) {
        if(err == ESP_ERR_NVS_NOT_FOUND) {
            // Not found, no error
            return 0;
        } else {
             // Actual error, log & return 0
            printf("Failed to get size of NVS key %s: %s\r\n", key, esp_err_to_name(err));
            return 0;
        }
    }
    return valueSize;
}

Usage example

This assumes that you have setup myNvs as we have shown in our previous post How to initialize NVS on ESP32

size_t myKeySize = NVSGetSize(myNvs, "MyKey");

 

Posted by Uli Köhler in ESP8266/ESP32

How to write string (const char*) to ESP32 NVS

Also see: How to read string (const char*) from ESP32 NVS

You can use this utility function to write a string (const char*) into the NVS:

bool _NVS_WriteString(nvs_handle_t nvs, const char* key, const char* value) {
    esp_err_t err;
    if((err = nvs_set_str(nvs, key, value)) != ESP_OK) {
        Serial.printf("Failed to write NVS key %s: %s\r\n", key, esp_err_to_name(err));
        return false;
    }
    return true;
}

Usage example

This example is based on How to initialize NVS on ESP32. Most importantly, it assumes you have already initialized the NVS and myNVS exists and is valid.

char mySerialNo[128] = {0};

_NVS_WriteString(myNVS, "SerialNo", "0000001");

This will write the value 0000001 to the NVS with key SerialNo

Note that NVS strings are length-delimited (as in: The length is stored in the NVS) and not neccessarily NUL-terminated. This code does not store the NUL terminator in NVS.

Posted by Uli Köhler in ESP8266/ESP32

How to read string (const char*) from ESP32 NVS

Also see: How to write string (const char*) to ESP32 NVS

 

You can use this utility function to read a string:

bool _NVS_ReadString(nvs_handle_t nvs, const char* key, char* value, size_t maxSize) {
    esp_err_t err;
    if((err = nvs_get_str(nvs, key, value, &maxSize)) != ESP_OK) {
        Serial.printf("Failed to read NVS key %s: %s\r\n", key, esp_err_to_name(err));
        return false;
    }
    return true;
}

Usage example

This example is based on How to initialize NVS on ESP32. Most importantly, it assumes you have already initialized the NVS and myNVS exists and is valid.

char mySerialNo[128] = {0};

_NVS_ReadString(myNVS, "SerialNo", mySerialNo, 128-1);

This will read the NVS entry with key SerialNo into the buffer mySerialNo. Note that we are using 128-1 as size, even though the buffer has a size of 128. This is to ensure that there is ALWAYS a terminating NUL character at the last value of the buffer.

Note that NVS strings are length-delimited (as in: The length is stored in the NVS) and not neccessarily NUL-terminated. I recommend to not store the NUL terminator in the NVS.

Posted by Uli Köhler in ESP8266/ESP32