2019年7月31日星期三

ESP32 cpplinq Tutorial: combining the skip and take operators

In this esp32 tutorial we will learn how to combine the cpplinq skip and take operators to be able to obtain a given section of an integer array. The tests shown on this tutorial were performed using an ESP32 board from DFRobot.

Introduction

In this esp32 tutorial we will learn how to combine the cpplinq skip and take operators to be able to obtain a given section of an integer array. We will be using the ESP32 and the Arduino core.

The technique we will use here is the same we can apply for pagination, using these two operators.

This might seem a feature that we don’t need on a microcontroller, but with the increase of the processing capabilities of these devices and the fact that we can setup a HTTP web server in a device such as the ESP32, being able to implement pagination might be useful when developing an API.

When we are doing pagination, we need to specify the offset from which we want to obtain our page, as we are going through the pages. Common approaches consist on allowing to specify either the index of the first element of the page or the page number.

The skip operator allows to specify the starting index of the range from which we want to start obtaining elements, thus serving this purpose.

Besides that, for pagination, we need to specify the number of elements we want per page, starting from the previously mentioned offset.

The take operator allows to obtain a given number of elements from a range and ignoring the remaining ones.

Thus, by using the skip operator followed by the take operator, we can specify the starting index and the number of elements we want to obtain from a sequence.

In this tutorial we are operating the pagination over a simple integer array, for illustration purposes. Naturally, for a real application scenario, we would most likely be applying the operators over an array of objects.

The tests shown on this tutorial were performed using an ESP32 board from DFRobot.

The code

As usual, the first thing we will do is including the cpplinq library. After that, we will declare the use of the cpplinq namespace.

#include "cpplinq.hpp"
   
using namespace cpplinq;

Moving on to the setup function, we will first open a serial connection, so we are able to output the results of our program. Then, we will declare an array of integers, over which we will apply the operators.

Serial.begin(115200);
     
int ints[] = {1,2,3,4,5,6,7,8,9};

Then, before we can apply the cpplinq operators, we need to convert our array to a range object. We do this by calling the from_array operator, passing as input our integer array.

from_array(ints)

Then we will apply the skip operator, which allows us to skip a given number of elements from our range. For illustration purposes, we will pass the value 4 to the operator, thus indicating that we want to skip the 4 first elements of the array.

skip(4)

Naturally, just by applying the skip operator, we would get all the remaining elements of the array. If we stopped here, the final range we would get would have the following elements:

[5,6,7,8,9]

Since, in our case, we want to get a fixed amount of elements (our page size), we need to keep processing the resulting range.

So, we then need to call the take operator. This operator allows to specify how many elements we want to take from the sequence, ignoring the remaining ones.

For this tutorial, we will assume a page size of 4 elements, meaning that we will get the first 4 elements of the already skipped sequence.

take(4)

After this, we expect to obtain the following sequence:

[5,6,7,8]

Then we need to convert the range back to a format we can iterate. Thus, we will use the to_vector function to convert it to a C++ vector. The full expression tree can be seen below.

auto result = from_array(ints)
               >> skip(4)
               >> take(4)
               >> to_vector();

To finalize, we will iterate through all the elements of the vector and print them to the serial port.

for(int i=0; i<result.size(); ++i){
    Serial.print(result[i]);
    Serial.print("|");
}

The complete code can be seen below.

#include "cpplinq.hpp"
   
using namespace cpplinq;
   
void setup() {
  Serial.begin(115200);
     
  int ints[] = {1,2,3,4,5,6,7,8,9};
     
  auto result = from_array(ints)
               >> skip(4)
               >> take(4)
               >> to_vector();
                  
  for(int i=0; i<result.size(); ++i){
    Serial.print(result[i]);
    Serial.print("|");
  }
}
   
void loop() {}

Testing the code

To test the code, simply compile it and upload it to your device using the Arduino IDE. After the procedure finishes, open the IDE serial monitor.

You should get an output similar to figure 1. As can be seen, the resulting sequence contains the expected elements.

Figure 1 – Output of the program, printed on the Arduino IDE serial monitor.

ESP32 ArduinoJSON: MessagePack Serialization

In this tutorial we will learn how to serialize content to the MessagePack format, using the ArduinoJson library and the ESP32. The tests shown here were performed using an ESP32 board from DFRobot.

Introduction

In this tutorial we will learn how to serialize content to the MessagePack format, using the ArduinoJson library and the ESP32.

MessagePack is an efficient binary serialization format that is more compact that JSON [1].

This tutorial targets version 6 of ArduinoJSON. The library can be easily installed from the Arduino IDE library manager. The tests shown here were performed using an ESP32 board from DFRobot.

The code

We will start our code by including the ArduinoJson.h library. This way, we will have access to the functionalities to perform the message pack serialization.

#include <ArduinoJson.h>

Moving on to the Arduino setup, we will first open a serial connection, to later output the results of our program.

Serial.begin(115200);

Then, we will declare an object of class StaticJsonDocument. This object will hold the memory representation of our object. For a more detailed explanation on how the StaticJsonDocument works, please consult this previous tutorial.

When declaring an object of this class, we need to specify its capacity, in bytes. The value is specified as a template parameter. For this tutorial we will specify a capacity of 100 bytes, which is more than enough for the object we want to store.

For a more accurate estimation, the easiest way is use this assistant.

StaticJsonDocument<100> testDocument;

Next we will take care of adding the members to our StaticJsonDocument, to hold the actual data. We will be using the same structure we have been testing in previous tutorials:

{
    "sensorType": "temperature",
    "value": 10
}

To add these elements to the StaticJsonDocument, we simply need to use the [] operator, as shown below.

testDocument["sensorType"] = "Temperature";
testDocument["value"] = 10;

Now that we have the in memory representation of our object, we will take care of serializing it to the MessagePack format. The first thing we need to do is declaring a data buffer to hold the serialized content.

char buffer[100];

Then, to do the actual serialization, we need to call the serializeMsgPack function, passing as first input our StaticJsonDocument and as second input the destination buffer.

As output, the function will return the number of bytes written [2]. We will store this value in a variable.

int bytesWritten = serializeMsgPack(testDocument, buffer);

Then we will print to the serial port the number of bytes written to the buffer. After that, we will iterate through each byte of the array and print it in hexadecimal format.

Serial.print("Bytes written: ");
Serial.println(bytesWritten);
 
for(int i = 0; i<bytesWritten; i++){
    Serial.printf("%02X ",buffer[i]);
}

The final code can be seen below.

#include <ArduinoJson.h>
   
void setup() {
   
  Serial.begin(115200);
     
  StaticJsonDocument<100> testDocument;
     
  testDocument["sensorType"] = "Temperature";
  testDocument["value"] = 10;
   
  char buffer[100];
   
  int bytesWritten = serializeMsgPack(testDocument, buffer);
 
  Serial.print("Bytes written: ");
  Serial.println(bytesWritten);
 
  for(int i = 0; i<bytesWritten; i++){
    Serial.printf("%02X ",buffer[i]);
  }
}
 
void loop() {}

Testing the code

To test the code, simply compile it and upload it to your ESP32 using the Arduino IDE. When the procedure finishes, open the serial monitor tool. You should have an output similar to figure 1.

Figure 1 – Output of the program, showing the message serialized to MessagePack format.

To confirm that we have obtained the correct content, we will then deserialize the message back to JSON format, using this online tool.

To do it, simply copy the bytes of the message printed to the Arduino serial monitor. On the online tool, paste them on the right side text box. Make sure that you select the option “HEX” on the radio buttons over the text box.

Then, click the green “decode” button. The message should be decoded back to JSON format, as shown in figure 2. As can be seen, we obtained the original content we have stored in the StaticJsonDocument, in JSON format.

Figure 2 – Decoding the MessagePack message to JSON.

ESP32 ArduinoJson: Getting the length of the MessagePack serialization payload

In this tutorial we will check how to obtain the length of the MessagePack payload that is obtained when we serialize data to this format, using the ArduinoJson library. The tests shown here were performed using an ESP32 board from DFRobot.

Introduction

In this tutorial we will check how to obtain the length of the MessagePack payload that is obtained when we serialize data to this format, using the ArduinoJson library. We will be using the Arduino core, running on the ESP32.

For an introductory tutorial on how to serialize content to the MessagePack format, please check this previous tutorial.

The tests shown here were performed using an ESP32 board from DFRobot, using version 6 of ArduinoJson.

The code

As usual, we will start the code by including the ArduinoJson library.

#include <ArduinoJson.h>

Then, moving on to the Arduino setup function, we will start by opening a serial connection, so we can output the result of our program.

Serial.begin(115200);

After this, we will declare an object of class StaticJsonDocument, to hold the memory representation of our data.

StaticJsonDocument<100> testDocument;

For this tutorial we will be using the same structure we have used in previous tutorials:

{
    "sensorType": "temperature",
    "value": 10
}

So, to add these elements to our StaticJsonDocument, we simply need to use the [] operator.

testDocument["sensorType"] = "Temperature";
testDocument["value"] = 10;

Then, to obtain the length of the payload produced by the MessagePack serialization, we simply need to call the measureMsgPackfunction. As input, we will pass our StaticJsonDocument. As output, the function will return the length, which we will print to the serial port.

int expectedBytesToWrite = measureMsgPack(testDocument);
 
Serial.print("Expected Bytes: ");
Serial.println(expectedBytesToWrite);

For comparison, we will now do the actual serialization of the data to the MessagePack format, like we have done in the previous tutorial.

So, we start by declaring a data buffer to hold the result and then we simply call the serializeMsgPack function to do the actual serialization.

Note that this function returns the number of bytes written to the output buffer, which corresponds to the length of the payload. Thus, we will also print this value to the serial port, to confirm it matches the value returned by the measureMsgPack function.

char buffer[100];
 
int bytesWritten = serializeMsgPack(testDocument, buffer);
  
Serial.print("Bytes written: ");
Serial.println(bytesWritten);

The final source code can be found below.

#include <ArduinoJson.h>
    
void setup() {
    
  Serial.begin(115200);
      
  StaticJsonDocument<100> testDocument;
      
  testDocument["sensorType"] = "Temperature";
  testDocument["value"] = 10;
 
  int expectedBytesToWrite = measureMsgPack(testDocument);
 
  Serial.print("Expected Bytes: ");
  Serial.println(expectedBytesToWrite);
    
  char buffer[100];
 
  int bytesWritten = serializeMsgPack(testDocument, buffer);
  
  Serial.print("Bytes written: ");
  Serial.println(bytesWritten);
 
}
  
void loop() {}

Testing the code

To test the code, simply compile it and upload it to your ESP32, using the Arduino IDE. After the procedure is finished, open the Arduino IDE serial monitor.

You should obtain a result similar to figure 1. As can be seen, the lengths printed to the serial match, as expected.

Figure 1 – Output of the program, showing the expected and the actual length of the MessagePack payload.

2019年7月30日星期二

Raspberry Pi HTTP/2 server: Receiving GET request from a ESP32

In this tutorial we will check how to send a HTTP/2 GET request from an ESP32 to a Node.js server running on the Raspberry Pi 3.


Introduction

In this tutorial we will check how to send a HTTP/2 GET request from an ESP32 to a Node.js server running on the Raspberry Pi 3.

This will be a slightly more complex tutorial that works on top of the knowledge built on other previous tutorials. So, I’ll leave the links for those below.

The ESP32 will be programmed using the Arduino core. You can check in detail how to perform an HTTP/2 GET request from the ESP32 on this previous tutorial.

In sum, we will be using a wrapper called sh2lib from IDF. This wrapper works on top of NGHTTP2, offering easier to use functions. The sh2lib will be used as an Arduino library. The installation procedure is really simple and it can be checked on this previous post.

On the Raspberry Pi side, we will need to host a HTTP/2 server. This was already covered on this previous tutorial. The tutorial explains how to generate the server certificate and private keys needed and contains a step by step analysis of all the code.

This tutorial was tested on a Raspberry Pi 3 model B+, running version 4.9 of Raspbian. Additionally, a DFRobot’s ESP32 moduleintegrated in a ESP32 development board was used.


The Node.js code

The first thing we will do in our code is importing the HTTP/2 module. This module will expose the features we need to configure our HTTP/2 server.

We will also need the file system module, so we can read the content of the private key and certificate files.

const http2 = require('http2');
const fs = require('fs');
After the imports we will define a function that will be executed every time a HTTP/2 request is received. The function will be invoked with two arguments:

an object of class Http2ServerRequest;

an object of class Http2ServerResponse.

In our code, we will only make use of the second object, which will allow us to send a response back to the client.

To do it, we simply need to call the end method on the mentioned object, passing as input the content we want to return to the client.

Additionally, it’s important to take in consideration that this method also signals that all the content was sent by the server and that the message should be considered complete.

The full function implementation can be seen below. We will simply send a “Hello World” message back, that should be received by the client (in our case, the ESP32).

function onRequest (req, resp) {
    resp.end("Hello World from the RPI3,via HTTP2");
}
After this, we need to create the server by calling the createSecureServer from the imported HTTP/2 module.

As the first input, this function receives an object containing two properties (key and cert), which contain the content of the private key and certificate files, respectively.

We will make use of the readFileSync function from the File System module to get the content of these files. Note that, as input, the function receives the path to the files. On the code below, I’m assuming that both the files and the Node.js script are running in the same directory, which is why only the file names is used.

As the second parameter, the createSecureServer function receives a function to be executed when a request is received. Naturally, we should pass the onRequest callback function we have defined earlier.

const server = http2.createSecureServer({
  key: fs.readFileSync('localhost-privkey.pem'),
  cert: fs.readFileSync('localhost-cert.pem')
}, onRequest);
To finalize, we simply need to call the listen method on our server object. As input, we pass the number of the port where it should listen to incoming HTTP/2 requests. We will be using port 8443.
server.listen(8443);
The final code can be seen below
const http2 = require('http2');
const fs = require('fs');
  
function onRequest (req, resp) {
    resp.end("Hello World from the RPI3,via HTTP2");
}
  
const server = http2.createSecureServer({
  key: fs.readFileSync('localhost-privkey.pem'),
  cert: fs.readFileSync('localhost-cert.pem')
}, onRequest);
  
server.listen(8443);


The ESP32 code

We will also start the ESP32 Arduino code with the library includes. We will need to include the WiFi.h, so we can connect the device to a WiFi network, and the sh2lib.h, which is a wrapper built on top of the NGHTTP2 library, making it easier to use the HTTP/2 features.

#include "WiFi.h"
  
extern "C" {
#include "sh2lib.h"
}

In order to be able to connect the ESP32 to a WiFi network, we will also need its credentials, which we will store as two global variables. Note that we will need both the network name and password.

const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";

To finalize the global variables declaration, we will also need a flag that will signal when the request sent to the server is complete. Naturally, we will set its initial value to false.
bool request_finished = false;
Moving on to the setup function, we will start by opening a serial connection and then connecting the ESP32 to the WiFi network, using the previously declared credentials.

After that, we will launch the FreeRTOS task that will take care of the HTTP/2 related function calls.

The whole setup function can be seen below.
void setup() {
  Serial.begin(115200);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
  
  xTaskCreate(http2_task, "http2_task", (1024 * 32), NULL, 5, NULL);
  
}
Moving on to the FreeRTOS task implementation, we will start by declaring a sh2lib_handle struct. This struct will be needed for the HTTP/2 related function calls we will do below.
struct sh2lib_handle hd;
Then we will connect the ESP32 to the HTTP/2 server, with a call to the sh2lib_connect function.

As first parameter, we should pass the address of the sh2lib handle we have just created. As the second parameter we should pass the URL of the server.

In our case, the URL has the format shown below, where you should change #yourRaspberryIp# by the IP of your device. For an explanation o how to get the local IP of your Raspberry Pi, please check here.
https://#yourRaspberryIp#:8443
The code for establishing the connection to the server can be seen below, using the local IP address of my Raspberry Pi. We will also do an error check to confirm we could successfully connect to the server.
if (sh2lib_connect(&hd, "https://192.168.1.92:8443") != ESP_OK) {
    Serial.println("Error connecting to HTTP2 server");
    vTaskDelete(NULL);
}
  
Serial.println("Connected");
After establishing the connection to the server, we will setup the HTTP/2 GET request with a call to the sh2lib_do_get function. Recall from the previous tutorial that this function only does the setup of the request, and later we need to invoke an additional function to actually exchange the data with the server.

As first input, the sh2lib_do_get receives the address of our handle, as second input the relative path of the server that we want to reach, and as third parameter a callback function that will be called to handle the server response. We will take care of defining this function later.

Note that we are using an endpoint called “/test” but we could use any other value since the HTTP/2 server will always return a “Hello World” message back to the client.
sh2lib_do_get(&hd, "/test", handle_get_response);
As already mentioned, we need to call an additional function to do the actual exchange of data with the server. This function is called sh2lib_execute and it receives as only input our handle address.

Note that this function needs to be called periodically until the response from the server is received and the stream is closed. Thus, we will do it in an infinite loop that will break only when the request_finished flag is set to true.

It will be the responsibility of the server response handling function to set this flag to true as soon as the request is finished.

while (1) {
  
    if (sh2lib_execute(&hd) != ESP_OK) {
      Serial.println("Error in send/receive");
      break;
    }
  
    if (request_finished) {
      break;
    }
  
    vTaskDelay(10);
}
After the loop breaks, we know that the request is finished, so we can disconnect from the server and then delete the FreeRTOS task, which will no longer be needed.
sh2lib_free(&hd);
Serial.println("Disconnected");
  
vTaskDelete(NULL);
The full FreeRTOS task can be seen below.
void http2_task(void *args)
{
  struct sh2lib_handle hd;
  
  if (sh2lib_connect(&hd, "https://192.168.1.92:8443") != ESP_OK) {
    Serial.println("Error connecting to HTTP2 server");
    vTaskDelete(NULL);
  }
  
  Serial.println("Connected");
  
  sh2lib_do_get(&hd, "/test", handle_get_response);
  
  while (1) {
  
    if (sh2lib_execute(&hd) != ESP_OK) {
      Serial.println("Error in send/receive");
      break;
    }
  
    if (request_finished) {
      break;
    }
  
    vTaskDelay(10);
  }
  
  sh2lib_free(&hd);
  Serial.println("Disconnected");
  
  vTaskDelete(NULL);
}
Finally, we just need to check the implementation of the server response callback function. In its implementation we will imply check if there is data available to read and, in case some is available, print it to the serial port.

Additionally, we will check if we received the flag that indicates the HTTP/2 stream is closed, thus indicating the request is completed. In case it is, we set the request_finished flag to true, to break the loop of the FreeRTOS task.

The full callback function code can be seen below. You can read a more detailed explanation of all its parameters on this previous tutorial.
int handle_get_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)
{
    if (len > 0) {
        Serial.printf("%.*s\n", len, data);
    }
  
    if (flags == DATA_RECV_RST_STREAM) {
        request_finished = true;
        Serial.println("STREAM CLOSED");
    }
    return 0;
}
The final source code can be seen below.
#include "WiFi.h"
  
extern "C" {
#include "sh2lib.h"
}
  
const char* ssid = "yourNetworkName";
const char* password =  "yourNetworkPass";
  
bool request_finished = false;
  
int handle_get_response(struct sh2lib_handle *handle, const char *data, size_t len, int flags)
{
    if (len > 0) {
        Serial.printf("%.*s\n", len, data);
    }
  
    if (flags == DATA_RECV_RST_STREAM) {
        request_finished = true;
        Serial.println("STREAM CLOSED");
    }
    return 0;
}
  
void http2_task(void *args)
{
  struct sh2lib_handle hd;
  
  if (sh2lib_connect(&hd, "https://192.168.1.92:8443") != ESP_OK) {
    Serial.println("Error connecting to HTTP2 server");
    vTaskDelete(NULL);
  }
  
  Serial.println("Connected");
  
  sh2lib_do_get(&hd, "/test", handle_get_response);
  
  while (1) {
  
    if (sh2lib_execute(&hd) != ESP_OK) {
      Serial.println("Error in send/receive");
      break;
    }
  
    if (request_finished) {
      break;
    }
  
    vTaskDelay(10);
  }
  
  sh2lib_free(&hd);
  Serial.println("Disconnected");
  
  vTaskDelete(NULL);
}
  
void setup() {
  Serial.begin(115200);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }
  
  xTaskCreate(http2_task, "http2_task", (1024 * 32), NULL, 5, NULL);
  
}
  
void loop() {
  vTaskDelete(NULL);
}


Testing the code

To test the whole system, the first thing we need to do is launching the HTTP/2 server on the Raspberry Pi.

To do it, simply run the Node.js code from this post from the command line. You can check here how to run a Node.js script from the command line.

After the server is running, you should do a quick test from the Raspberry Pi web browser to confirm it is correctly receiving the HTTP/2 requests and returning an answer. You can check how to test the server from a browser on this previous post.

After confirming the Node.js code is running correctly and you are being able to reach it locally, it is also a good ideia to check if you can reach it from another computer on the same WiFi network.

To do it, you just need to access it from a web browser on a computer. Nonetheless, this time you will need to use the local IP address of the Raspberry Pi on the WiFi network, which should be the one you have obtained to use on the ESP32 code.

If everything is working correctly, we can proceed to test the integration between the ESP32 and the server. To do it, we first need to compile and upload the code to the ESP32, using the Arduino IDE.

As soon as it finishes, open the IDE serial monitor tool. You should get an output similar to figure 1. As can be seen, the ESP32 was able to connect to the server and then it received the message we set on the Node.js code. After that, the connection was closed, as expected.

Figure 1 – Output of the program, with the response from the Raspberry Pi HTTP/2 server.

ESP8266 SPIFFS: Reading a file

In this tutorial we will learn how to read the content of file from the ESP8266 SPIFFS file system, using the Arduino core. The tests shown on this tutorial were performed on a DFRobot’s ESP8266 FireBeetle board.

The code

In this tutorial we will learn how to read the content of file from the ESP8266 SPIFFS file system, using the Arduino core.

We will create the file beforehand, to make sure we have content available to read. The procedure on how to create a file on the ESP8266 file system was covered in detail on the previous tutorial.

The tests shown on this tutorial were performed on a DFRobot’s ESP8266 FireBeetle board.


Introduction

The first thing we will do is importing the FS.h library, like we have been doing in previous tutorials. This way, we will have access to the SPIFFS extern variable, which we can use to interact with the ESP8266 file system.

#include <FS.h>

Then we will move on to the Arduino Setup function, where we will start by opening a serial connection. We will use it to later output the results of our program.

Serial.begin(115200);
Serial.println();
After this we will mount the SPIFFS file system. This procedure always needs to be executed before we start to interact with the file system.

if (!success) {
    Serial.println("Error mounting the file system");
    return;
}
Then we will write a file in the file system, to make sure we have some content to read. The procedure on how to write a file was covered in detail on this previous article.

In short, to write a file to the SPIFFS file system of the ESP8266, we first need to open it in writing mode. This is done with a call to the openmethod on the SPIFFS variable, passing as first input the name of the file and as second input the opening mode.

Note that we will call our file /file.txt, which means that we need to use this same name when later opening it for reading.

After opening the file in writing mode and checking that no error occurred during the procedure, we can write some content to it with a call to the print method on our File object.

This method takes as argument a string with the content to write to the file and returns as output the number of bytes written. We can use the returned value to perform an error check.

Finally, once the content is written to the file, we can close it with a call to the close method, also on the File object.

The full code for writing the file can be seen below.

File file = SPIFFS.open("/file.txt", "w");
 
if (!file) {
    Serial.println("Error opening file for writing");
    return;
}
 
int bytesWritten = file.print("TEST SPIFFS");
 
if (bytesWritten == 0) {
    Serial.println("File write failed");
    return;
}
 
file.close();

Now that we have handled the creation of the file, we can read its content and print it to the serial port.

The first thing we need to do is opening the file with a call to the open method on the SPIFFS object. We should use the file name mentioned before (“/file.txt”) and this time we should open it in reading mode.

So, to open a file in reading mode, we need to pass the value “r” as second input of the open method.

We will store in a variable the File object returned by the open method and then perform an error check to make sure the opening procedure did not fail.

File file2 = SPIFFS.open("/file.txt", "r");
 
if (!file2) {
    Serial.println("Failed to open file for reading");
    return;
}

Now we will take care of reading the content of the file. To do it, we can leverage the available method of the File object, which returns the number of bytes left to read from the file.

The value returned by this method can be used as stopping condition of a loop where we will read the content of the file byte by byte.

To read a byte from the file, we simply need to call the read method on the File object. We can directly print the returned value to the serial port.

while (file2.available()) {
 
    Serial.write(file2.read());
}

To finalize we just need to close the file with a call to the close method.

file2.close();
The final source code can be seen below.

#include <FS.h>
 
void setup() {
 
  Serial.begin(115200);
  Serial.println();
 
  bool success = SPIFFS.begin();
 
  if (!success) {
    Serial.println("Error mounting the file system");
    return;
  }
 
  File file = SPIFFS.open("/file.txt", "w");
 
  if (!file) {
    Serial.println("Error opening file for writing");
    return;
  }
 
  int bytesWritten = file.print("TEST SPIFFS");
 
  if (bytesWritten == 0) {
    Serial.println("File write failed");
    return;
  }
 
  file.close();
 
 
  File file2 = SPIFFS.open("/file.txt", "r");
 
  if (!file2) {
    Serial.println("Failed to open file for reading");
    return;
  }
 
  Serial.println("File Content:");
 
  while (file2.available()) {
 
    Serial.write(file2.read());
  }
 
  file2.close();
 
}
 
void loop() {}

Testing the code

To test the code, simply compile it and upload it to your device, using the Arduino IDE. Once the procedure ends, open the Arduino IDE serial monitor.

You should get an output similar to figure 1. As can be seen, the content we had previously written to the file was printed to the serial port, as expected.

Figure 1 – Output of the program, showing the content of the file.