How to connect an ESP32 to Thinger.io using ESP-IDF

Picture of Jaime Bautista Salinero
Jaime Bautista Salinero

In Thinger.io we do our best to listen to what our community needs, that is why when this week a user asked us if Thinger.io could be integrated with ESP-IDF framework we jumped to the opportunity of trying it out and provide a viable solution for anyone that wants to dive into Espressif’s low level development framework or even provide a cloud infrastructure to already existing project running with ESP-IDF.

For easy integration of the most common consumer microcontrollers, we developed years back within Thinger.io an Arduino Library to provide easy connection to our Cloud IoT Platform with the most used framework at the time.

With time and innovation comes new opportunities, and this is one. That why in this post we will explain how use ESP-IDF framework to connect an ESP32 to Thinger.io by using our Arduino Library alongside the arduino-esp32 core component for ESP-IDF.


ESP-IDF installation

The first step is to have the ESP-IDF framework installed on your environment. There is no better way to do this than to install it by following Espressif’s official documentation. Just note that for this post we will be using a Linux environment, as well as the version of ESP-IDF 4.4.5 (at the time of writing of this post, the latest ESP-IDF compatible version with Arduino Core ESP32 is v4.4).

Example project

Before starting, set the correct FreeRTOS Tick Rate (Hz).

All right, with ESP-IDF installed, now what? Let’s start by following the First Steps on ESP-IDF of the installation guide, which copies an example project, try to build it and flash it into your microcontroller to verify that everything is working correctly.

cd ~/esp
cp -r $IDF_PATH/examples/get-started/hello_world .
cd hello_world
idf.py -p PORT flash monitor

To exit the monitor press Ctrl + ]. More keyboard shortcuts here

Once verified, lets go ahead and add Arduino as an ESP-IDF component by following again their official documentation. It is important to understand the basics of the build systems of an ESP-IDF project, and visually understand the file and directory structure.

Add Thinger.io Library as component

This step is very similar to adding the arduino-esp32 core as component of the ESP-IDF project.

cd ~/esp/hello_world/components
git clone https://github.com/thinger-io/Arduino-Library.git thinger
cd ..
idf.py menuconfig

At this point, it is important to take two things into consideration.

The first one is to know which structure for the main file you’ll be using, and configure your project accordingly, if you’ll be using Arduino setup() and loop() or ESP-IDF appmain(). In this case, this is subject to personal preference, as below we will provide an example code for both methods. The principal difference between these two is that by using the Arduino approach, the code in the setup and loop functions are executed in CPU number 1 leveraging FreeRTOS, with an stack size of 8192 bytes, while the ESP-IDF appmain approach lets you use the CPU 0 for this task while being able to launch additional tasks, which means additional control of the execution flow.

The second point to have into consideration is the possibility that a linker error may occur when using WiFiClientSecure, easily solved by Enabling PSK Verification in the menuconfig, found under Component Config → ESP-TLS. You can find more information in this GitHub issue.

Main file of the project

Now that everything is installed and configured, lets go ahead and tackle the last steps of this integration.

Create a new main.cpp file under ~/esp/hello_world/main/ and change the main CMakeLists.txt to make use of this file:

idf_component_register(SRCS "main.cpp"
                    INCLUDE_DIRS "")

Depending on which structure for the main file you’ve chosen, here goes the same example in both alternatives.

Using Arduino setup() and loop()

With this option the main file looks very similar to Arduino’s sketches:

//file: main.cpp

// Uncomment when one needs to troubleshoot authentication and Wi-Fi connectivity issues
//#define THINGER_SERIAL_DEBUG

// Uncomment to point to your private Thinger.io instance
//#define THINGER_SERVER "<subdomain>.aws.thinger.io"

#include "Arduino.h"

#include "ThingerESP32.h"

#define USERNAME "your_user_name"
#define DEVICE_ID "your_device_id"
#define DEVICE_CREDENTIAL "your_device_credential"

#define SSID "your_wifi_ssid"
#define SSID_PASSWORD "your_wifi_ssid_password"

ThingerESP32 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);

void setup(){

  Serial.begin(115200);

  thing.add_wifi(SSID, SSID_PASSWORD);

  thing["in_out"] = [](pson& in, pson& out){
    out["sum"] = (long)in["value1"] + (long)in["value2"];
    out["mult"] = (long)in["value1"] * (long)in["value2"];
  };

  while(!Serial){
    ; // wait for serial port to connect
  }

}

void loop(){

    thing.handle();

}

As mentioned before, this will execute in and additional task in the CPU 1 by leveraging FreeRTOS.

Using ESP-IDF appmain()

In this case the flow is single execution, so the setup and loop functions are not available.

This approach needs an additional configuration. By default the Main Stack Size is set to 3584 bytes, due to the use of secure TLS connection this size is insufficient for our needs, and will put the microcontroller in a boot loop. We would need to increase this size to, for example, 8192 bytes, the same size that the Arduino approach uses for the execution of the setup and loop functions.

For that, in menuconfig, go to Component config > ESP System Settings and set CONFIG_ESP_MAIN_TASK_STACK_SIZE to 8192.

//file: main.c or main.cpp

// Uncomment when one needs to troubleshoot authentication and Wi-Fi connectivity issues
//#define THINGER_SERIAL_DEBUG

// Uncomment to point to your private Thinger.io instance
//#define THINGER_SERVER "<subdomain>.aws.thinger.io"

#include "Arduino.h"

#include "ThingerESP32.h"

#define USERNAME "your_user_name"
#define DEVICE_ID "your_device_id"
#define DEVICE_CREDENTIAL "your_device_credential"

#define SSID "your_wifi_ssid"
#define SSID_PASSWORD "your_wifi_ssid_password"

ThingerESP32 thing(USERNAME, DEVICE_ID, DEVICE_CREDENTIAL);

extern "C" void app_main()
{
  initArduino();

  // Arduino-like setup()
  Serial.begin(115200);

  thing.add_wifi(SSID, SSID_PASSWORD);

  thing["in_out"] = [](pson& in, pson& out){
    out["sum"] = (long)in["value1"] + (long)in["value2"];
    out["mult"] = (long)in["value1"] * (long)in["value2"];
  };

  while(!Serial){
    ; // wait for serial port to connect
  }

  // Arduino-like loop()
  while(true) {

    thing.handle();

  }

  // WARNING: if program reaches end of function app_main() the MCU will restart.
}

Now, regardless of the approach you’ve used. Build and flash the software into the ESP32.

cd ~/esp/hello_world
idf.py build
idf.py -p /dev/ttyACM0 flash monitor

You should also see that the micro controller has been connected to the Thinger.io Platform and are able to execute the resources.


Conclusion

By leveraging the Espressif Arduino core as a component of ESP-IDF, we are able to integrate almost any Arduino library, one of them being our own developed Thinger.io library, as well as being able to have full control and low level codification of Espressif’s micro controllers.

This project could go even further, by mimicking what Espressif defines as the main entrypoint in the Arduino approach (checkout a simpler but older version here or the most recent here), and integrating your own needs alongside a connection to Thinger.io.

If you have any questions, or would like to comment further on this integration join us at our community forum!

Do you have any doubts? Contact us!

Discover how Thinger can help your business with our All-in-One platform. 

Start building your IoT products

With the All-in-One Best Leading IoT Platform