PlatformIO

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

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 add extra include directory to PlatformIO project

In platformio.ini, add the following build flags:

build_flags = -I../my-extra-include-dir

By using this method, you can also add multiple include directories:

build_flags = -I../my-first-include-dir -I../my-second-include-dir

All paths are relative to the directory where platformio.ini resides in.

Posted by Uli Köhler in PlatformIO

How to fix PlatformIO ValueError: Invalid simple block ‘^0.4.6.4’

Problem:

You want to build your PlatformIO project which has library dependency like

lib_deps =
    nanopb/Nanopb@^0.4.6.4

but you see an error message like

Error: Traceback (most recent call last):
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/__main__.py", line 102, in main
    cli()  # pylint: disable=no-value-for-parameter
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/click/core.py", line 1130, in __call__
    return self.main(*args, **kwargs)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/click/core.py", line 1055, in main
    rv = self.invoke(ctx)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/cli.py", line 71, in invoke
    return super().invoke(ctx)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/click/core.py", line 1657, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/click/core.py", line 1404, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/click/core.py", line 760, in invoke
    return __callback(*args, **kwargs)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/click/decorators.py", line 26, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/run/cli.py", line 144, in cli
    process_env(
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/run/cli.py", line 201, in process_env
    result = {"env": name, "duration": time(), "succeeded": ep.process()}
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/run/processor.py", line 83, in process
    install_project_env_dependencies(
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/package/commands/install.py", line 132, in install_project_env_dependencies
    _install_project_env_libraries(project_env, options),
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/package/commands/install.py", line 241, in _install_project_env_libraries
    spec = PackageSpec(library)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/package/meta.py", line 184, in __init__
    self._parse(self.raw)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/package/meta.py", line 291, in _parse
    raw = parser(raw)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/package/meta.py", line 316, in _parse_requirements
    self.requirements = tokens[1].strip()
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/platformio/package/meta.py", line 231, in requirements
    else semantic_version.SimpleSpec(str(value))
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/semantic_version/base.py", line 647, in __init__
    self.clause = self._parse_to_clause(expression)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/semantic_version/base.py", line 1043, in _parse_to_clause
    return cls.Parser.parse(expression)
  File "/home/uli/.platformio/penv/lib/python3.10/site-packages/semantic_version/base.py", line 1063, in parse
    raise ValueError("Invalid simple block %r" % block)
ValueError: Invalid simple block '^0.4.6.4'

Solution:

You are using the library version 0.4.6.4 but the library version specifier does not support versions with 4 levels (a.b.c.d) – the correct version specifier is just using the first three digits: a.b.c. In our example, this would be

lib_deps =
  nanopb/Nanopb@^0.4.6

After that, you have to delete your .pio directory in the project folder in order to fix the issue:

rm -rf .pio

When that is done, rebuild and the issue will be gone.

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

How to link Angular project dist directory to PlatformIO SPIFFS data directory

For tips how to make the Angular build small enough to fit into the SPIFFS image, see How to make Angular work with ESP32 SPIFFS / ESPAsyncWebserver

When you are building a PlatformIO image, you can easily make the dist/[project_name] directory from the Angular project directory appear in the SPIFFS image by using a symlink.

My config tells the server to serve from the www subdirectory.

server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("index.html");

Therefore, we first need to create the data directory in the same directory where platformio.ini is located:

mkdir data

Now we can create a symlink from the angular dist directory to data/www, for example:

ln -s ../MyUI/dist/myui data/www

PlatformIO will automatically handle the symlink, if the directory exists.

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

How to make Angular work with ESP32 SPIFFS / ESPAsyncWebserver

The main issue when using Angular web UIs is that the resulting files get too large, hence building the filesystem image will fail with SPIFFS_write error(-10001): File system is full.

Using these tips, I could get an Angular PrimeNG app to fit into a 4MB flash ESP32 module without any custom partition table and without any other crazy hacks! Even the fonts & PrimeNG icons fit into the SPIFFS easily, with a total of only 380 kB of the approximately 1.5 MB being consumed.

File compression

The number one most important tip is that you can just gzip -9 the files from the angular dist directory and ESPAsyncWebserver will automatically handle decompressing them!

This is my platformio.ini:

[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.3
board = esp32dev
framework = arduino
board_build.filesystem = littlefs
lib_deps =
    esphome/AsyncTCP-esphome@^1.2.2
    esphome/ESPAsyncWebServer-esphome@^2.1.0
    [email protected]
upload_speed = 460800
monitor_speed = 115200

This is my angular build script:

#!/bin/sh
ng build --aot --build-optimizer --optimization --progress --output-hashing none
gzip -9 dist/**/*

This is where I tell ESPAsyncWebserver (note that you should use the esphome fork) to serve files statically:

server.serveStatic("/", SPIFFS, "/www/").setDefaultFile("index.html");

Other tips

In order to make your life easier managing the data directory with both Angular files and other files, see How to link Angular project dist directory to PlatformIO SPIFFS data directory

You can use purgecss but compression works so well that it isn’t really worth both the risk of accidentally removing some CSS rules which you manually need to whitelist. Before discovering how well compression worked, I started to manually remove CSS rules from the PrimeNG theme file. This worked fine, but the SPIFFS still wasn’t small enough.

Often you can save space by deleting.

For example, primeicons.svg and primeicons.ttf are two different formats with the same content. Note that some (especially older, and some mobile) browsers don’t support all formats, hence it’s rather risky to remove them if you need to support multiple platforms.

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

How to fix SPIFFS_write error(-10001): File system is full.

Are you using Angular and seeing this error message? See How to make Angular work with ESP32 SPIFFS / ESPAsyncWebserver

The error message

SPIFFS_write error(-10001): File system is full.

should be mostly self-explanatory:

The files you are trying to put into the image exceed the maximum size of the filesystem image.

There are two possible solutions:

  • Decrease the size of the files, either by minifying files where this is possible, or removing some files altogether.
  • Increase the allowable size of the filesystem image e.g. by using a ESP32 module with more flash (e.g. 8MB instead of 4MB), and/or using a partition table with a larger file partition.
Posted by Uli Köhler in ESP8266/ESP32, PlatformIO

How to fix SPIFFS_write error(-10010): unknown

Problem:

When trying to build a SPIFFS image, you see an error message like

SPIFFS_write error(-10010): unknown
error adding file!
Error for adding content from www!
/www/Inter-Light.27083fa6375bb9ef.woff2

Solution:

SPIFFS_write error(-10010): unknown means that the filename is too long. SPIFFS only supports filenames with a maximum of 32 characters.

In our example, Inter-Light.27083fa6375bb9ef.woff2 is 32 characters long.

Hence, the solution is to shorten the filename of every file with a filename (including extension) of 32+ characters.

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

How to fix ESPAsyncWebserver undefined reference to `SHA1Init’

Problem:

When using ESPAsyncWebserver with websockets, you see the following error messages while linking:

Linking .pio/build/esp32dev/firmware.elf
/home/uli/.platformio/packages/[email protected]+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/lib67a/libESP Async WebServer.a(AsyncWebSocket.cpp.o):(.literal._ZN22AsyncWebSocketResponseC2ERK6StringP14AsyncWebSocket+0x10): undefined reference to `SHA1Init'
/home/uli/.platformio/packages/[email protected]+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/lib67a/libESP Async WebServer.a(AsyncWebSocket.cpp.o):(.literal._ZN22AsyncWebSocketResponseC2ERK6StringP14AsyncWebSocket+0x18): undefined reference to `SHA1Update'
/home/uli/.platformio/packages/[email protected]+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/lib67a/libESP Async WebServer.a(AsyncWebSocket.cpp.o):(.literal._ZN22AsyncWebSocketResponseC2ERK6StringP14AsyncWebSocket+0x1c): undefined reference to `SHA1Final'
/home/uli/.platformio/packages/[email protected]+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/lib67a/libESP Async WebServer.a(AsyncWebSocket.cpp.o): in function `AsyncWebSocketResponse::AsyncWebSocketResponse(String const&, AsyncWebSocket*)':
/home/uli/dev/My-Firmware/.pio/libdeps/esp32dev/ESP Async WebServer/src/AsyncWebSocket.cpp:1269: undefined reference to `SHA1Init'
/home/uli/.platformio/packages/[email protected]+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: /home/uli/dev/My-Firmware/.pio/libdeps/esp32dev/ESP Async WebServer/src/AsyncWebSocket.cpp:1270: undefined reference to `SHA1Update'
/home/uli/.platformio/packages/[email protected]+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: /home/uli/dev/My-Firmware/.pio/libdeps/esp32dev/ESP Async WebServer/src/AsyncWebSocket.cpp:1271: undefined reference to `SHA1Final'
/home/uli/.platformio/packages/[email protected]+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/lib67a/libESP Async WebServer.a(WebAuthentication.cpp.o):(.literal._ZL6getMD5PhtPc+0x4): undefined reference to `mbedtls_md5_starts'
/home/uli/.platformio/packages/[email protected]+2021r2-patch3/bin/../lib/gcc/xtensa-esp32-elf/8.4.0/../../../../xtensa-esp32-elf/bin/ld: .pio/build/esp32dev/lib67a/libESP Async WebServer.a(WebAuthentication.cpp.o): in function `getMD5(unsigned char*, unsigned short, char*)':
/home/uli/dev/My-Firmware/.pio/libdeps/esp32dev/ESP Async WebServer/src/WebAuthentication.cpp:73: undefined reference to `mbedtls_md5_starts'

Solution:

This is a bug in the ESPAsyncWebserver official library, which is not regularly maintained. But you can use use the esphome fork of ESPAsyncWebserver and their fork of AsyncTCP instead.

In platformio.ini, instead of

lib_deps =
    ESP Async [email protected]

use the esphome fork and AsyncTCP:

lib_deps =
    esphome/AsyncTCP-esphome@^1.2.2
    esphome/ESPAsyncWebServer-esphome@^2.1.0

After that, try to build / upload, the linking errors should be gone.

Full platformio.ini example

[env:esp32dev]
platform = espressif32
platform_packages = framework-arduinoespressif32 @ https://github.com/espressif/arduino-esp32.git#2.0.3
board = esp32dev
framework = arduino
lib_deps =
    esphome/AsyncTCP-esphome@^1.2.2
    esphome/ESPAsyncWebServer-esphome@^2.1.0
    [email protected]
upload_speed = 460800
monitor_speed = 115200

 

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

How to fix PlatformIO No such file or directory bootloader__80m.bin/bootloader__40m.bin

Problem:

While trying to upload/flash an ESP32(S2/S3) project using PlatformIO with a platformio.ini like this:

[env:esp32-s2-saola-1]
platform = espressif32
board = esp32-s2-saola-1
framework = arduino

you see an error message like

esptool write_flash: error: argument <address> <filename>: [Errno 2] No such file or directory: '/home/uli/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32s2/bin/bootloader__80m.bin'
*** [upload] Error 2

or

esptool write_flash: error: argument <address> <filename>: [Errno 2] No such file or directory: '/home/uli/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/bin/bootloader__40m.bin'

Solution:

This is a bug in version 2.0.4 of the arduino-espressif32 framework. In order to work around it, use version 2.0.3 until this bux is fixed. You can do this by appending

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

to platformio.ini. Full example:

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

 

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

How to initialize struct sockaddr_in using initializer lists

This way of initializing a struct sockaddr_in uses modern C and avoids all the raw of days that should long be forgotten, at least for most applications. I use this approach successfully e.g. for ESP32 microcontrollers.

struct sockaddr_in server_addr = {
    .sin_family = AF_INET,
    .sin_port = htons(46118),
    .sin_addr = {.s_addr = htonl(INADDR_ANY)}
};

 

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

How to run PlatformIO serial monitor from the command line

First, activate the PlatformIO virtual environment which will give you access to the pio script:

source ~/.platformio/penv/bin/activate

Now, if you have – for example – an environment called esp32dev listed in platformio.ini:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino

you can build & upload using the following code:

pio run -e esp32dev -t monitor

You can also combine both commands (the virtual env activation and the pio run command) into a single line of shell script:

source ~/.platformio/penv/bin/activate && pio run -e esp32dev -t monitor
Posted by Uli Köhler in PlatformIO

How to run PlatformIO build & upload from the command line

First, activate the PlatformIO virtual environment which will give you access to the pio script:

source ~/.platformio/penv/bin/activate

Now, if you have – for example – an environment called esp32dev listed in platformio.ini:

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino

you can build & upload using the following code:

pio run -e esp32dev -t upload

You can also combine both commands (the virtual env activation and the pio run command) into a single line of shell script:

source ~/.platformio/penv/bin/activate && pio run -e esp32dev -t upload
Posted by Uli Köhler in PlatformIO

How to see PlatformIO actual commands during build or upload

Having a look at the actual commands being used by PlatformIO is pretty easy:

Instead of clicking Build or Upload, open the Advanced folder and select Verbose Build or Verbose Upload.

This will show you all raw commands such as esptool.py commands that are being run.

Posted by Uli Köhler in PlatformIO

How to flash Marlin 2.x to BTT SKR 1.4 using PlatformIO

The best way to flash Marlin via PlatformIO onto the LPC1768 MCU on a BTT SKR v1.4 board is to insert an SD card into it, connect the computer via USB and use the mbed as upload_protocol.

In order to do this, edit ini/lpc176x.ini from within Visual Studio Code and add the following new code to [env:LPC1768]:

upload_protocol = mbed
upload_port=/media/uli/A87B-A154/

with upload_port being the directory where the SD card is mounted (while you can do this using an SD card reader, it is so much easier by just connecting the BTT SKR v1.4 via USB directly to your computer, allowing both serial port and SD card access at the same time).

Full example of the [env:LPC1768] section:

[env:LPC1768]
platform = ${common_LPC.platform}
extends  = common_LPC
board    = nxp_lpc1768
upload_protocol = mbed
upload_port=/media/uli/A87B-A154/

In the PlatformIO menu, choose LPC1768/Upload. There is no special configuration for the BTT SKR v1.4 but of course you need to configure Configuration.h etc correctly – see https://www.makenprint.uk/3d-printing/3d-printing-guides/skr-v1-4-configuration-h-marlin-2-setup-part-2/

After uploading, press the reset button on the Board to apply the firmware update. You can use picocom to connect to your printer, see How to connect to your 3D printer using picocom, e.g.:

picocom -b 115200 /dev/ttyACM0 --imap lfcrlf --ech

Enter M115 to check if you have correctly updated the fiwa

You might need to manually re-mount the SD card using your file manager after a firmware update in order to enabled PlaformIO doing another update.

Posted by Uli Köhler in 3D printing, Embedded, PlatformIO

How to fix PlatformIO ArduinoJSON .pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp:43:5: error: static assertion failed: To use 64-bit integers with ArduinoJson, you must set ARDUINOJSON_USE_LONG_LONG to 1

Problem:

While trying to compile your PlatformIO project, you see an error message like

.pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp:43:5: error: static assertion failed: To use 64-bit integers with ArduinoJson, you must set ARDUINOJSON_USE_LONG_LONG to 1. See https://arduinojson.org/v6/api/config/use_long_long/
     ARDUINOJSON_ASSERT_INTEGER_TYPE_IS_SUPPORTED(T);
     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from .pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson.hpp:30,
                 from .pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson.h:9,
                 from include/MQTT/StatusMessage.hpp:2,
                 from src/MQTT/StatusMessage.cpp:1:
.pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Variant/ConverterImpl.hpp: In instantiation of 'static void ArduinoJson6185_1::Converter<T, Enable>::toJson(const T&, ArduinoJson6185_1::VariantRef) [with T = long long int (*)(); Enable = void]':
.pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Variant/VariantRef.hpp:98:27:   required from 'bool ArduinoJson6185_1::VariantRef::set(T*) const [with T = long long int()]'
.pio/libdeps/ESP32/ArduinoJson/src/ArduinoJson/Object/MemberProxy.hpp:58:5:   required from 'ArduinoJson6185_1::MemberProxy<TParent, TStringRef>::this_type& ArduinoJson6185_1::MemberProxy<TParent, TStringRef>::operator=(TChar*) [with TChar = long long int(); TObject = ArduinoJson6185_1::JsonDocument&; TStringRef = const char*; ArduinoJson6185_1::MemberProxy<TParent, TStringRef>::this_type = ArduinoJson6185_1::MemberProxy<ArduinoJson6185_1::JsonDocument&, const char*>]'

Solution

Add -DARDUINOJSON_USE_LONG_LONG=1 to the build_flags in platformio.ini. If build_flags does not exist in platformio.ini, create it after [env:...]

build_flags = -DARDUINOJSON_USE_LONG_LONG=1

 

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

ESP32 Wireguard example with HTTP access over Wireguard (PlatformIO)

In this example we will use Wireguard-ESP32-Arduino in order to make HTTP requests over Wireguard on the ESP32.

[env:esp32-gateway]
platform = espressif32
board = esp32-gateway
framework = arduino
monitor_speed = 115200
lib_deps =
    ciniml/WireGuard-ESP32@^0.1.5
#include <WiFi.h>
#include <WireGuard-ESP32.h>

// WiFi configuration --- UPDATE this configuration for your WiFi AP
char ssid[] = "MyWifiESSID";
char password[] = "my-wifi-password";

// WireGuard configuration --- UPDATE this configuration from JSON
char private_key[] = "gH2YqDa+St6x5eFhomVQDwtV1F0YMQd3HtOElPkZgVY=";
IPAddress local_ip(10, 217, 59, 2);
char public_key[] = "X6NJW+IznvItD3B5TseUasRPjPzF0PkM5+GaLIjdBG4=";
char endpoint_address[] = "192.168.178.133"; // IP of Wireguard endpoint to connect to.
int endpoint_port = 19628;

static WireGuard wg;

void setup()
{
    Serial.begin(115200);
    Serial.println("Connecting to the AP...");
    WiFi.begin(ssid, password);
    while( !WiFi.isConnected() ) {
        delay(100);
    }
    Serial.println(WiFi.localIP());
    Serial.println("Adjusting system time...");
    configTime(9 * 60 * 60, 0, "ntp.jst.mfeed.ad.jp", "ntp.nict.jp", "time.google.com");

    Serial.println("Connected. Initializing WireGuard...");
    wg.begin(
        local_ip,
        private_key,
        endpoint_address,
        public_key,
        endpoint_port);
}

void loop()
{
    WiFiClient client;

    /**
     * Connect to
     * python3 -m http.server
     */
    if( !client.connect("10.217.59.1", 8000) ) {
        Serial.println("Failed to connect...");
        delay(1000);
        return;
    } else { // Client connected successfully. Send dummy HTTP request.
        client.write("GET /wireguard-test HTTP/1.1\r\n");
        client.write("Host: wireguard.test.com\r\n");
        client.write("\r\n\r\n");
    }

}

Remember to replace 192.168.238.133 by the IP address of the computer your ESP32 should connect to (i.e. the computer running WireGuard). You also need to enter the correct Wifi credentials.

On the computer, deploy this WireGuard config:

[Interface]
# Name = Computer
PrivateKey = ONj6Iefel47uMKtWRCSMLan2UC5eW3Fj9Gsy9bqcyEc=
Address = 10.217.59.1/24
ListenPort = 19628

[Peer]
# Name = ESP32
PublicKey = H3KaL/X94984cLDNWFsM4Hx6Rs/Ku0bW2ECkDUn7wFw=
AllowedIPs = 10.217.59.2/32
PersistentKeepalive = 60

which is auto-generated by the following GuardMyWire config:

{
    "rules": {
        "Node": {
            "connect_to": ["*"],
            "keepalive": 60
        }
    },
    "peers": [
        {
            "name": "Computer",
            "endpoint": "192.168.178.233:19628",
            "addresses": [
                "10.217.59.1/24"
            ],
            "type": "Node",
            "interface_name": "wg0"
        }, {
            "name": "ESP32",
            "addresses": [
                "10.217.59.2/24"
            ],
            "type": "Node",
            "interface_name": "wg0"
        }
    ]
}

Enable this config and start a Python HTTP server to receive the requests using

python3 -m http.server

Now flash the firmware on the ESP32.

Using wg show you should see the ESP connecting:

interface: Computer
  public key: X6NJW+IznvItD3B5TseUasRPjPzF0PkM5+GaLIjdBG4=
  private key: (hidden)
  listening port: 19628

peer: H3KaL/X94984cLDNWFsM4Hx6Rs/Ku0bW2ECkDUn7wFw=
  endpoint: 10.9.1.108:19628
  allowed ips: 10.217.59.2/32
  latest handshake: 5 seconds ago
  transfer: 11.71 MiB received, 10.43 MiB sent
  persistent keepalive: every 1 minute

Look for the

latest handshake: 5 seconds ago

line.

On the shell running python3 -m http.server you should see the dummy HTTP requests:

10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
10.217.59.2 - - [31/Dec/2021 02:36:48] "GET /wireguard-test HTTP/1.1" 404 -
10.217.59.2 - - [31/Dec/2021 02:36:48] code 404, message File not found
Posted by Uli Köhler in ESP8266/ESP32, PlatformIO, Wireguard

FreeRTOS task queue minimal example

This is how you create and use a task queue in FreeRTOS:

Global declaration

Declare the structure of a task (I recommend to use a task type enum class in order to keep the flexibility of using multiple task types:

#include <freertos/queue.h>

enum class I2CTaskType : uint8_t {
    MyTaskType = 0
};

struct I2CTask {
    I2CTaskType type;
    // Parameters
    int16_t value;
};
static QueueHandle_t i2cTaskQueue;

Initialization code

Call this once, before using it:

// Create task queue
i2cTaskQueue = xQueueCreate(8 /* Number of queue slots */, sizeof(I2CTask));

In the thread processing the queue

if (xQueueReceive(i2cTaskQueue, (void *)&task, portMAX_DELAY /* Wait infinitely for new tasks */) == pdTRUE) {
    if(task.type == I2CTaskType::MyTaskType) {
        // TODO process task
        Serial.printf("My task type: %d\r\n", task.value);
    }
}

How to add a task to the queue

void AddTask(int16_t val) {
    I2CTask task;
    task.type = I2CTaskType::MyTaskType;
    task.value = val;
    xQueueSend(i2cTaskQueue, (void*)&task, 10 / portTICK_PERIOD_MS /* timeout */);
}

 

Posted by Uli Köhler in C/C++, Embedded, FreeRTOS, PlatformIO