Czy wolisz polską wersję strony elektroda?
Nie, dziękuję Przekieruj mnie tamHow to migrate ESP32 Arduino projects to PlatformIO
To migrate an ESP32 Arduino project to PlatformIO, do not just open the old sketch folder and hope it builds unchanged. The reliable path is:
framework = arduino,src/,.ino into src/main.cpp,#include <Arduino.h> and any missing forward declarations,.cpp/.h modules,lib/ and declare external libraries in lib_deps,platformio.ini options such as board, upload_speed, monitor_speed, board_build.partitions, board_build.f_cpu, and board_build.flash_mode. (docs.platformio.org)Important correction: the main configuration file is platformio.ini, not platform.ini. Also, if you convert to .cpp, #include <Arduino.h> is required; one of the sample answers claimed the opposite, which is incorrect according to PlatformIO’s own documentation. (docs.platformio.org)
Arduino IDE hides several build details from you. PlatformIO is closer to normal C/C++ project structure. In particular, PlatformIO projects are centered around a root platformio.ini plus standardized folders such as src, include, lib, and test. The pio project init command creates that structure automatically. (docs.platformio.org)
The main conceptual difference is preprocessing. Arduino sketches use .ino files, and Arduino-style preprocessing hides missing includes and omitted function declarations. PlatformIO can compile .ino files inside src/, but its own documentation explicitly recommends manual .ino to .cpp conversion when you want proper code completion, linting, and standard C++ behavior. (docs.platformio.org)
A sound migration sequence is:
framework = arduino.src/.main.cpp..ino tabs into .cpp/.h.platformio.ini.You can initialize from CLI like this:
pio project init --board esp32dev
PlatformIO documents that pio project init creates platformio.ini, src, include, lib, and test, and can pre-fill platform, framework, and board when you pass a board ID. (docs.platformio.org)
This step matters more in PlatformIO than many Arduino users expect. Board manifests define defaults such as MCU, frequency, flash size, and other build parameters, and PlatformIO lets you override them with board_* options. PlatformIO also provides pio boards to list supported boards. (docs.platformio.org)
Examples of valid board IDs from the current PlatformIO documentation include:
esp32devesp32doit-devkit-v1esp32-c3-devkitm-1esp32-c6-devkitc-1 (docs.platformio.org)If your Arduino project used a nonstandard module or variant, choose the closest official board first, then override details such as CPU frequency, flash mode, partition table, and maximum size in platformio.ini. PlatformIO explicitly supports board-manifest overrides in the form board_{OBJECT.PATH}. (docs.platformio.org)
A typical migration looks like this:
Arduino IDE project
├── MyProject.ino
├── wifi.ino
├── sensors.ino
└── customlib/...
PlatformIO project
├── platformio.ini
├── src/
│ ├── main.cpp
│ ├── wifi.cpp
│ └── sensors.cpp
├── include/
│ ├── wifi.h
│ └── sensors.h
├── lib/
│ └── customlib/
└── test/
This aligns with PlatformIO’s documented directory layout: src for sources, include for headers, lib for project-specific private libraries, and test for tests. (docs.platformio.org)
.ino to main.cppThis is the most important code-side step. PlatformIO’s own FAQ states that Arduino files are not valid C/C++ source files in the usual sense because they commonly omit #include <Arduino.h> and function declarations. Its recommended fix is manual conversion to .cpp. (docs.platformio.org)
Minimal example:
#include <Arduino.h>
void blinkLed();
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
blinkLed();
}
void blinkLed() {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
}
Two migration rules are essential here:
#include <Arduino.h> at the top,In Arduino IDE, multiple .ino tabs are effectively merged before compilation. In a normal C++ build, each source file is compiled separately. That is why multi-tab Arduino projects often fail immediately after migration if you simply copy all files as-is. This is not a PlatformIO bug; it is the expected behavior of standard C/C++ compilation. The best fix is to split code into .cpp and .h files. The project structure and lib/include behavior documented by PlatformIO are designed for exactly this. (docs.platformio.org)
A typical module pair:
// include/wifi_manager.h
#pragma once
#include <Arduino.h>
#include <WiFi.h>
void wifiInit(const char* ssid, const char* pass);
bool wifiReady();
// src/wifi_manager.cpp
#include "wifi_manager.h"
void wifiInit(const char* ssid, const char* pass) {
WiFi.begin(ssid, pass);
}
bool wifiReady() {
return WiFi.status() == WL_CONNECTED;
}
// src/main.cpp
#include <Arduino.h>
#include "wifi_manager.h"
void setup() {
Serial.begin(115200);
wifiInit("ssid", "pass");
}
void loop() {
delay(1000);
}
lib/ versus lib_depsThis is where PlatformIO becomes much more reproducible than the Arduino IDE. PlatformIO’s dependency documentation states that platformio.ini and lib_deps are the place for declaring project dependencies. (docs.platformio.org)
Use two categories:
lib_deps.lib/YourLibrary/.... PlatformIO documents that lib/ is the private-library directory and has the highest priority for the Library Dependency Finder. (docs.platformio.org)Example:
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
bblanchon/ArduinoJson
knolleary/PubSubClient
If you previously depended on globally installed Arduino libraries in your user profile, this is the time to make them explicit. That is a major best-practice improvement because the build becomes reproducible on another PC or in CI. (docs.platformio.org)
platformio.iniThis is the part most ESP32 users underestimate. Arduino IDE stores many board-related choices in GUI menus; PlatformIO wants them declared as configuration.
A practical mapping is:
| Arduino IDE concept | PlatformIO setting |
|---|---|
| Board | board = ... |
| Framework | framework = arduino |
| Serial monitor baud | monitor_speed = ... |
| Upload speed | upload_speed = ... |
| Partition scheme | board_build.partitions = ... |
| CPU frequency | board_build.f_cpu = ... |
| Flash mode | board_build.flash_mode = ... |
| Max sketch size override | board_upload.maximum_size = ... |
| Debug macros | build_flags = -D ... |
These options are documented across PlatformIO’s ESP32 platform docs and general platform options docs. PlatformIO explicitly documents upload_speed, partition-table override via board_build.partitions, and generic board override syntax like board_build.f_cpu and board_build.flash_mode. (docs.platformio.org)
A good starting platformio.ini for many ESP32 Arduino migrations is:
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
monitor_filters = esp32_exception_decoder
upload_speed = 921600
; Add only if your old Arduino IDE project changed defaults
; board_build.partitions = huge_app.csv
; board_build.f_cpu = 240000000L
; board_build.flash_mode = qio
lib_deps =
; declare external libraries here
build_flags =
-D CORE_DEBUG_LEVEL=3
monitor_filters = esp32_exception_decoder is supported by PlatformIO’s device monitor and is particularly useful during ESP32 crash analysis. (docs.platformio.org)
Core commands after migration:
pio run
pio run -t upload
pio device monitor
These align with PlatformIO’s documented workflow for building, uploading, and monitoring a project. (docs.platformio.org)
Two very useful validation commands are:
pio project config --lint
pio pkg list
pio project config --lint checks platformio.ini, and pio pkg list shows installed packages and dependencies resolved from the project configuration. (docs.platformio.org)
A. “Cannot find Arduino.h” or broken IntelliSense
Usually caused by leaving the file as .ino when your editor integration expects .cpp, or by converting to .cpp but forgetting #include <Arduino.h>. PlatformIO’s FAQ explicitly calls out the missing include problem. (docs.platformio.org)
B. “undefined reference” for your own functions
Arduino preprocessing used to create prototypes for you. In .cpp, you must declare functions before use or place declarations in headers. (docs.platformio.org)
C. Library not found
Either the dependency was never added to lib_deps, or a private library was not moved into lib/. PlatformIO’s dependency and lib_dir docs describe both mechanisms. (docs.platformio.org)
D. Firmware builds but behaves differently from Arduino IDE
Most often a configuration mismatch: wrong board ID, wrong partition table, flash mode, CPU frequency, or maximum size. PlatformIO exposes these as explicit board_* settings rather than hidden menu choices. (docs.platformio.org)
E. OTA, SPIFFS/LittleFS, or filesystem issues
These often trace back to partition-table mismatch. PlatformIO documents that Arduino uses default.csv by default and lets you override it via board_build.partitions. It also warns that a SPIFFS partition must use Type=data and SubType=spiffs. (docs.platformio.org)
Current PlatformIO documentation, as accessed on May 12, 2026, is in the 6.1.x documentation stream. One useful relatively recent capability is pio project config --lint, documented as added in version 6.1.8, which makes configuration validation easier during migration. (docs.platformio.org)
A clear current best practice is reproducible builds: declare dependencies in lib_deps, keep private code in lib/, and pin platform versions when necessary. PlatformIO’s ESP32 platform docs explicitly support choosing specific stable platform versions via platform = espressif32@x.y.z or switching to an upstream platform source when needed. (docs.platformio.org)
Another practical trend is moving away from monolithic Arduino sketches toward modularized code in src/, include/, and lib/, because that structure naturally supports testing, code reuse, and cleaner dependency boundaries. PlatformIO’s project layout and shared-code guidance are aligned with that engineering style. (docs.platformio.org)
If your original Arduino sketch was:
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("Hello");
delay(1000);
}
The PlatformIO version should typically become:
#include <Arduino.h>
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("Hello");
delay(1000);
}
That extra include is not cosmetic; it is the key step in converting Arduino-style source into valid C++ source for normal IDE tooling. (docs.platformio.org)
project/
├── platformio.ini
├── src/
│ └── main.cpp
├── include/
│ └── config.h
├── lib/
│ └── MyPrivateDriver/
└── test/
This directly matches PlatformIO’s documented project structure and keeps the project maintainable as it grows. (docs.platformio.org)
A useful engineering rule is:
every hidden Arduino IDE setting must become visible either in code or in platformio.ini.
That means includes, prototypes, libraries, partition table, flash options, and board choice must all be made explicit. This is why PlatformIO feels stricter at first, but it is also why it is better for repeatable embedded builds. (docs.platformio.org)
From a software-engineering standpoint, the main ethical and legal issues in this migration are not about PlatformIO itself, but about project hygiene:
lib/, keep the original licenses intact and verify redistribution rights,pio run -t erase, because PlatformIO documents it as erasing the entire flash chip, which may destroy stored credentials, calibration values, or user data. (docs.platformio.org)For connected ESP32 products, also verify that migration does not silently change radio-related behavior due to different build defaults or partition settings. This is especially relevant if your deployed device uses OTA, NVS, SPIFFS/LittleFS, or manufacturing calibration data. The need to manage partition tables explicitly in PlatformIO is the technical reason this deserves attention. (docs.platformio.org)
.cpp over .ino for migrated code, even though PlatformIO can compile .ino from src/. This gives better tooling and fewer hidden behaviors. (docs.platformio.org)pio boards or the board explorer. Do not guess if your module has unusual flash or PSRAM. (docs.platformio.org)platformio.ini. For ESP32, pay special attention to partition tables, CPU frequency, flash mode, and maximum program size. (docs.platformio.org)lib_deps for external libraries and lib/ for private libraries. (docs.platformio.org)esp32_exception_decoder, during early migration testing. (docs.platformio.org)pio project config --lint before chasing phantom compiler errors. (docs.platformio.org)platform field. (docs.platformio.org)PlatformIO can compile .ino files in src/, so a “quick migration” is possible. However, that is not the best long-term engineering solution for a nontrivial ESP32 project, because code completion and linting are less robust with Arduino-style source files. (docs.platformio.org)
Exact binary equivalence with an old Arduino IDE build is not guaranteed on the first try. If your previous project depended on a specific board package revision or hidden menu settings, you may need to pin the PlatformIO platform version and explicitly reproduce the old board configuration. This is an engineering inference based on PlatformIO’s version-selection and board-override mechanisms. (docs.platformio.org)
If your original sketch used many global variables across tabs, expect some refactoring. That is normal when moving from Arduino’s concatenated-sketch model to modular C++. The result is usually cleaner and more testable code. This is an inference from the documented project structure and .ino-to-.cpp conversion model. (docs.platformio.org)
After the initial migration, the next worthwhile topics are:
lib/,If you want, a very productive next step is to take one real sketch and produce:
main.cpp, platformio.ini, and src/, include/, and lib/. That usually resolves 90% of migration difficulty in one pass.
The correct migration path is: create a real PlatformIO project, choose the exact ESP32 board, convert the main sketch to main.cpp, add #include <Arduino.h> and missing prototypes, split extra .ino tabs into standard C++ modules, move private code into lib/, declare external libraries in lib_deps, and recreate all Arduino IDE board settings in platformio.ini. (docs.platformio.org)
In practice, the biggest migration errors are not syntax errors; they are hidden-configuration errors. Once board ID, partition table, libraries, and flash/CPU settings are made explicit, ESP32 Arduino projects usually migrate cleanly and become much easier to maintain in a professional workflow. (docs.platformio.org)
If you want, I can next give you a template platformio.ini for a typical ESP32 Arduino sketch or help convert a specific .ino project tree.