Skip to content

Code Portability Between IDEs

Code Portability Between IDEs

This section covers how to transfer ESP32 code between PlatformIO and Arduino IDE. By the end of this section, you will be able to:

  • Understand the structural differences between PlatformIO and Arduino IDE projects
  • Convert a PlatformIO multi-file project to Arduino IDE format
  • Identify and fix common portability issues (function prototypes, file extensions)
  • Maintain a single codebase that works in both environments
  • PlatformIO project structure (01-05)
  • Arduino IDE setup (01-04)

This course’s code examples are developed in PlatformIO (VS Code), but some users prefer the Arduino IDE. The two environments have structural differences:

AspectPlatformIOArduino IDE
Main Filesrc/main.cppsketch_folder/sketch_name.ino
Additional Filessrc/*.cpp, src/*.h, include/*.h.ino files in the same folder
Library Managementplatformio.ini (declarative)Library Manager (GUI)
Function PrototypesRequiredAuto-generated (not required)
File Extensions.cpp, .h.ino
Configurationplatformio.iniTools → Board menu
platformio_project/
├── platformio.ini # Configuration
├── src/
│ ├── main.cpp # Main code
│ ├── wifi_mqtt.h # Wi-Fi/MQTT code (header with implementation)
│ └── credentials.h # SSID, password
├── include/ # Additional headers
├── lib/ # Private libraries
└── .pio/ # Build artifacts
arduino_sketch/
├── sketch.ino # Main file (same name as the folder)
├── wifi_mqtt.ino # Additional code tab
├── credentials.ino # Credentials tab
└── (no configuration file — settings in IDE menu)
  1. Locate your PlatformIO project folder
  2. Copy the contents of the src/ directory:
    • main.cpp
    • wifi_mqtt.h
    • credentials.h

Step 2: Create the Arduino IDE Folder Structure

Section titled “Step 2: Create the Arduino IDE Folder Structure”
  1. Create a new folder (e.g., ESP32_Basic_Sketch)
  2. Create an .ino file with the same name as the folder: ESP32_Basic_Sketch.ino
  3. Copy the content from main.cpp into this .ino file

Step 3: Convert Main File (main.cpp → .ino)

Section titled “Step 3: Convert Main File (main.cpp → .ino)”

Before (PlatformIO main.cpp):

#include <Arduino.h>
#include <WiFi.h>
#include "credentials.h"
#include "wifi_mqtt.h"
void setup() {
Serial.begin(115200);
// ...
}
void loop() {
// ...
}

After (Arduino IDE .ino):

#include <WiFi.h>
// PlatformIO includes become standard includes
// The .h files need to be converted to .ino tabs
void setup() {
Serial.begin(115200);
// ...
}
void loop() {
// ...
}

Key changes:

  • Remove #include <Arduino.h> (Arduino IDE adds this automatically)
  • Remove #include "credentials.h" — these will become separate .ino tabs
  • Remove #include "wifi_mqtt.h" — this will also become a separate .ino tab

wifi_mqtt.h → Create a new tab in Arduino IDE (Ctrl+Shift+N or the dropdown arrow) named wifi_mqtt.ino:

// wifi_mqtt.ino — Paste the content from wifi_mqtt.h
#include <WiFi.h>
#include <PubSubClient.h>
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);
void connectToWiFi() {
Serial.print("Connecting to Wi-Fi");
WiFi.begin(ssid, password);
// ...
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
// ... same content as wifi_mqtt.h
}
void connectToMQTT() {
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(mqttCallback);
// ...
}

credentials.h → Create another tab named credentials.ino:

credentials.ino
const char* ssid = "YourWiFiSSID";
const char* password = "YourWiFiPassword";
const char* mqttServer = "192.168.1.100";
const int mqttPort = 1883;

Step 5: Handle Function Prototypes (PlatformIO vs Arduino IDE)

Section titled “Step 5: Handle Function Prototypes (PlatformIO vs Arduino IDE)”

PlatformIO requires explicit function prototypes:

// PlatformIO: prototypes required
void connectToWiFi();
void connectToMQTT();
void mqttCallback(char* topic, byte* payload, unsigned int length);
void sendSensorData();
void setup() {
// ...
connectToWiFi(); // OK — prototype declared above
}
void connectToWiFi() {
// implementation
}

Arduino IDE auto-generates prototypes for .ino files, so explicit prototyping is optional:

// Arduino IDE: prototypes auto-generated
// You can still add them, but they are not required
void setup() {
connectToWiFi(); // OK — Arduino IDE creates prototype automatically
}
void connectToWiFi() {
// implementation
}

For cross-platform compatibility, add prototypes with a conditional:

#ifdef PLATFORMIO
// Explicit prototypes for PlatformIO's strict compiler
void connectToWiFi();
void connectToMQTT();
void mqttCallback(char* topic, byte* payload, unsigned int length);
#endif

Alternatively, place function definitions before setup() in the main file:

// This works in both environments — define before setup()
void connectToWiFi() {
// implementation
}
void setup() {
connectToWiFi(); // Works — function already defined
}

Step 6: Update platformio.ini Dependencies — Manual Arduino IDE Installation

Section titled “Step 6: Update platformio.ini Dependencies — Manual Arduino IDE Installation”

PlatformIO auto-downloads libraries declared in lib_deps. In Arduino IDE, you must install them manually via Library Manager.

platformio.ini (source):

lib_deps =
knolleary/PubSubClient @ ^2.8
bblanchon/ArduinoJson @ ^7.0
adafruit/DHT sensor library @ ^1.4

Arduino IDE installation:

  1. Tools → Manage Libraries (Ctrl+Shift+I)
  2. Search each library name and click Install
  3. Ensure versions match the PlatformIO specification

For code that must behave differently in each environment:

// Platform detection
#if defined(PLATFORMIO)
const char* projectVersion = "2.0.0 (PlatformIO)";
#elif defined(ARDUINO_ARCH_ESP32)
const char* projectVersion = "2.0.0 (Arduino IDE)";
#endif
void setup() {
Serial.begin(115200);
Serial.println(projectVersion);
#if defined(PLATFORMIO)
// PlatformIO-specific: maybe different pin mapping
const int ledPin = 2;
#else
// Arduino IDE-specific fallback
const int ledPin = 13; // Some boards have LED on pin 13
#endif
pinMode(ledPin, OUTPUT);
}

Step 8: Complete Arduino IDE Conversion Checklist

Section titled “Step 8: Complete Arduino IDE Conversion Checklist”
  • #include <Arduino.h> removed (causes compile error in Arduino IDE)
  • All .h files converted to .ino tabs (same folder as main .ino)
  • #include "filename.h" changed to match .ino tab names
  • Required libraries installed via Library Manager
  • Board selected correctly (Tools → Board → ESP32 Arduino)
  • Port selected correctly
  • Upload speed set (Tools → Upload Speed → 921600)
  • Sketch compiles without errors
  • The same code compiles and runs in both PlatformIO and Arduino IDE
  • Arduino IDE does not report “missing function prototype” errors
  • Library versions match between both environments
  • Serial output is identical from both builds
  • MQTT and Wi-Fi behavior is identical

”Arduino.h: No such file or directory”

Section titled “”Arduino.h: No such file or directory””

Cause: #include <Arduino.h> is used in the .ino file.

Solution: Remove #include <Arduino.h> from the main .ino file. The Arduino IDE prepends it automatically.

“‘credentials_h’ was not declared in this scope”

Section titled ““‘credentials_h’ was not declared in this scope””

Cause: The #include "credentials.h" directive expects a .h file, but the Arduino IDE tab is named credentials.ino.

Solutions:

  1. Rename the tab to credentials.h (Arduino IDE supports .h tabs)
  2. Or remove the #include — Arduino IDE automatically includes all .ino tabs in the sketch folder
  3. Or use #include "credentials.ino" (not conventional but works)

“Function not declared in this scope” in PlatformIO but works in Arduino IDE

Section titled ““Function not declared in this scope” in PlatformIO but works in Arduino IDE”

Cause: PlatformIO requires function prototypes before first use.

Solution: Add prototypes at the top of main.cpp:

// Add these before setup()
void connectToWiFi();
void connectToMQTT();
void mqttCallback(char* topic, byte* payload, unsigned int length);

Or rearrange functions so the callee appears before the caller.

  • Develop in PlatformIO, test in Arduino IDE: PlatformIO is faster and has better tooling, but verify portability
  • Use conditional compilation sparingly: It’s better to write compatible code than to use #ifdef everywhere
  • Keep the file structure identical: If your PlatformIO project has credentials.h, create a credentials.h tab in Arduino IDE (not .ino)
  • Document library versions: Note the library versions used in PlatformIO so they can be matched in Arduino IDE
  • Test early, test often: After major code changes, verify the sketch compiles in both environments
  • Use .h extensions in Arduino IDE tabs: Arduino IDE supports .h files as tabs, making the transition more natural
  1. PlatformIO uses src/main.cpp + *.h files; Arduino IDE uses .ino files in a single folder
  2. Main conversion steps: rename main.cpp to .ino, convert *.h to .ino or .h tabs
  3. Remove #include <Arduino.h> and #include "filename.h" for Arduino IDE
  4. Add function prototypes for PlatformIO’s stricter compiler
  5. Install libraries manually in Arduino IDE that PlatformIO auto-downloads
  6. PlatformIO offers faster compilation and better code organization; Arduino IDE offers simplicity and broad compatibility