I am programming on the Arduino platform for ESP8266 IoT devices and I tend to use env sections in the platformio.ini file in order to separate settings between the various variants I make.
But what about settings I want to be global for all env:s?
Is it possible to put them before the first env section and then they will be used by all env:s?
And if I want one env to override a specific setting is that possible by just having the same setting in the env section with a different value?
For example to use a âlatestâ version of a platform globally but specify a different version on one env?
Say to globally use
platform = espressif8266
but specify a specific version for one env:
[env:esp01_serial-aspo]
platform = espressif8266@2.5.2
Or vice versa, to use the specific version globally unless the platform is specified in the env section without version number?
I am trying to tidy up my ini file to avoid duplication as much as possible.
Right now I have to duplicate these in every single env section:
board = esp01
framework = arduino
board_upload.maximum_size = 1048576
upload_speed = 115200
upload_port = COM8
monitor_speed = 115200
monitor_port = COM8
It seems like a waste of space and is easy to overlook a change for instance of the serial port to use.
Hereâs an example of one of my platformio.ini
files where I have extracted the common stuff to the [env]
environment, which means that it is common to every other environment in the file.
There are 5 environments in my file. the [env]
one is common to the other four. They, in turn allow me to program the code for my Uno or my Duemilanove (2009) and in both cases, I can upload using the Arduino bootloader or my USBtiny ICSP device.
HTH
Cheers,
Norm.
; Settings common to *all* environments.
[env]
platform = atmelavr
framework = arduino
; Duemilanove settings using the Arduino bootloader.
[env:2009]
board = diecimilaatmega328
; Uno settings using the Arduino bootloader.
[env:uno]
board = uno
; Duemilanove settings using the USBTiny.
[env:2009_icsp]
board = diecimilaatmega328
upload_protocol = usbtiny
; Uno settings using the USBTiny.
[env:uno_icsp]
board = uno
upload_protocol = usbtiny
Thanks.
before I posted I looked at this documentation page and then I was confused because they use a section [common]
for the settings used in the env sections.
But then in each such env they showed that you had to refer to the common setting like this:
${common.build_flags}
This totally defeats the concept of a common setting that it has to be repeated in each section even though the value is not.
So you suggest to put all common settings into an [env]
section and then it will be used in all actual environments named like [env:env_name]
?
I donât understand the logic behind thisâŚ
But if it works then so be it.
Question:
What happens to settings inside the platformio.ini file without any section name before?
Like if you just enter the various settings at the top before any [env.xxx]
section?
UPDATE:
I now found the proper doc page for env and it explains it allâŚ
So it works like I hoped such that whatever is in [env] gets included into all [env:envname] unless the same setting is present also here in which case the local version âwinsâ.
Perfect!

Not exactly. You can combine them per Interpolation of Values â PlatformIO latest documentation
That should be the solution you really want to have.
1 Like
I donât understand the Interpolation part but what I have done is the following:
I have a basic config that contains everything needed for all the versions I deal with. These settings are in section [env]
Then I have 4 different variations:
2 different locations and for each location both an AP and a MainRouter connection separated by their MAC addresses and SSID. Password is the same on all 4.
So I also have 4 sections named say [env:location_x]
where location is the name of the target and x is the name of the AP to use.
Each of these sections just hold the specific data for the connection by WiFi and the MQTT topic to use.
This way all configs entries are in one place only and I have 4 different environments I can build.
This seems to be what I need.
With Interpolation you can inherit settings from another environment so you donât have to rewrite them. Example for build-flags:
[env]
platform = espressif32
board = esp32dev
framework = arduino
build_flags =
'-DWIFI_SSID="mywifissid"'
'-DWIFI_PASS="mypass"'
[env:server]
build_flags =
${env.build_flags}
'-DMODE="server"'
[env:client]
build_flags =
${env.build_flags}
'-DMODE="client"'
The build_flags
from env
are âinheritedâ to env:server
and env:client
so the
WIFI_SSID
and WIFI_PASS
will be available to the server and client environment.
2 Likes
Thanks,
that sounds more understandable rather than the strange word âInterpolationâ, which indicates some kind of calculated âmean valueââŚ
I have now updated my platformio.ini file according to these findings to reduce its size considerably.

Hi there,
I am using the IRremoteESP8266 library that accepts options set in the PlatformIO.ini.
The flags in the ini file are:
-D IR_ENABLE_DEFAULT=false
-D SEND_NEC=true
(first line disables all send and receive protocols,
second line enables only the NEC sending protocol)
This works if I inlcude those flags in every environment
I want to enable quite a few more protocols, and I have 3 different âenvironmentsâ in my ini-file. So i googled the same question as bobswede did.
The solution with inherited settings doesnât seem to work for me.
Does it perhaps only work for predefined PlatformIO build_flag ?
[env]
platform = espressif32
; for the IR library
build_flags=
'-D_IR_ENABLE_DEFAULT_=false' ; this gets evaluated before code ?? IRremoteESP8266.h
; '-DDECODE_NEC=true'
'-DSEND_NEC=true'
and
[env:PURPLE]
platform = espressif32
board = esp32-s3-t-qt-4R2
framework = arduino
lib_deps = bblanchon/ArduinoJson@^6.1.0
lib_ldf_mode = chain+
build_flags =
${env.build_flags}
-I include
-D BOARD_HAS_PSRAM
I donât get compile errors, but the flag isnt interpreted correcty when compiling (resulting in a function between #if and #endif in the library, not being available.
I donât know the IRremoteESP8266 library, so i created a small test project for this case:
.
âââ .pio
âââ lib
â âââ LibA
â âââ src
â â âââ LibA.h
â âââ library.json
âââ src
â âââ main.cpp
âââ platformio.ini
/lib/LibA/src/LibA.h
#pragma once
#ifdef LIBA_OPTION1
#pragma message("LibA: Option 1 is enabled")
#endif
#ifdef LIBA_OPTION2
#pragma message("LibA: Option 2 is enabled")
#endif
#ifdef LIBA_OPTION3
#pragma message("LibA: Option 3 is enabled")
#endif
/lib/LibA/library.json
{
"name": "LibA",
"version": "1.0.0"
}
/src/main.cpp
#include <Arduino.h>
#include <LibA.h>
void setup() {
Serial.begin(115200);
Serial.println("Hello World");
}
void loop() {
}
/platformio.ini
[env]
platform = espressif32
framework = arduino
board = esp32dev
monitor_speed = 115200
build_flags =
-DLIBA_OPTION1=1
[env:PURPLE]
build_flags =
${env.build_flags}
-DLIBA_OPTION2=1
[env:GREEN]
build_flags =
${env.build_flags}
-DLIBA_OPTION3=1
Output during build âPURPLEâ:
In file included from src/main.cpp:2:
lib/LibA/src/LibA.h:4:44: note: '#pragma message: LibA: Option 1 is enabled'
4 | #pragma message("LibA: Option 1 is enabled")
| ^
lib/LibA/src/LibA.h:8:44: note: '#pragma message: LibA: Option 2 is enabled'
8 | #pragma message("LibA: Option 2 is enabled")
|
Output during build âGREENâ:
In file included from src/main.cpp:2:
lib/LibA/src/LibA.h:4:44: note: '#pragma message: LibA: Option 1 is enabled'
4 | #pragma message("LibA: Option 1 is enabled")
| ^
lib/LibA/src/LibA.h:12:44: note: '#pragma message: LibA: Option 3 is enabled'
12 | #pragma message("LibA: Option 3 is enabled")
| ^
So in general this should work.
This defines the macro âIR_ENABLE_DEFAULT
â and a thus #ifdef IR_ENABLE_DEFAULT
will be true
, even if the value of the macro itself is set to âfalse
â
What you need for such a case is this:
build_unflags=
-D IR_ENABLE_DEFAULT
Thanks for your fast and detailed reply.
Its getting late here though, so I will look at it sometime next week.
You do scare me a bit.
How do you know the other environment in my ini file is called [env:GREEN] ?
Thanks⌠I will let you know if this helped. (next week)
Quick first reply to your last remark.
I will have a further look, but I think the logic in the library as downloaded is:
IRremoteESP8266.h
#ifndef _IR_ENABLE_DEFAULT_
#define _IR_ENABLE_DEFAULT_ true // Unless set externally, the default is on.
#endif // _IR_ENABLE_DEFAULT_
I define and set the value of IR_ENABLE_DEFAUL to false in the platform.ini
Then:
#ifndef DECODE_NEC
#define DECODE_NEC _IR_ENABLE_DEFAULT_
#endif // DECODE_NEC
#ifndef SEND_NEC
#define SEND_NEC _IR_ENABLE_DEFAULT_
#endif // SEND_NEC
So if I do not define SEND_NEC in platform.ini , then it will be defined in the IRremoteESP8266.h and have the value IR_ENAVLE_DEFAULT , which is now false
That was just a guess.
Red is to close to Purple, so I thought green would be next 
In the meantime, I took a look at the IRremoteESP8266 library to better understand the context. The following works for me:
[env]
platform = espressif32 @ 6.10.0
framework = arduino
board = esp32dev
monitor_speed = 115200
lib_deps =
IRremoteESP8266
build_flags =
-D_IR_ENABLE_DEFAULT_=false
[env:PURPLE]
build_flags =
${env.build_flags}
-DDECODE_HASH=true
-DSEND_RAW=true
[env:GREEN]
build_flags =
${env.build_flags}
-DDECODE_NEC=true
-DSEND_NEC=true
Looking at the IRremoteESP8266.h with the different environments selected results in
PURPLE
DECODE_HASH
and SEND_RAW
expands to true
GREEN
DECODE_NEC
and SEND_NEC
exoabds to true
When hovering over _IR_ENABLE_DEFAULT_
in line 103 I can see that the macro expands to false
:
Where and what exactly did you see?
Sorry man, I really appreciate your effort, but its 01:30 am here.
What I saw was the compile error (yeah⌠i said i didnt get a compile error)
class âIRsendâ has no member named âsendNECâ
when i browse the file IRsend.h and IRsend.cpp, which have the function SendNEC like this:
IRsend.h
#if (SEND_NEC || SEND_SHERWOOD || SEND_AIWA_RC_T501 || SEND_SANYO || \
SEND_MIDEA24)
void sendNEC(uint64_t data, uint16_t nbits = kNECBits,
uint16_t repeat = kNoRepeat);
uint32_t encodeNEC(uint16_t address, uint16_t command);
#endif
and IRsend.cpp
#if SEND_NEC
case NEC:
case NEC_LIKE:
sendNEC(data, nbits, min_repeat);
break;
#endif
but in both files SEND_NEC appears false.
(I donât know how PlatformIO knows to show GREEN or PURPLE between compiles. Is it just showing the values evaluated in the last compile attempt?)
In summary with environments as below:
GREEN compiles (uploads, works)
PURPLE does not compile because:
âclass IRsendâ has no member named âsendNECâ; did you mean âsendRawâ?
[env]
platform = espressif32
; for the IR library
build_flags=
'-D_IR_ENABLE_DEFAULT_=false'
'-DSEND_NEC=true'
[env:GREEN]
platform = espressif32
board = esp32-s3-t-qt-N8
framework = arduino
lib_deps = bblanchon/ArduinoJson@^6.1.0
lib_ldf_mode = chain+
build_flags =
-I include
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D GreenBox=1
; for the IR library
-D_IR_ENABLE_DEFAULT_=false
-DSEND_NEC=true
[env:PURPLE]
platform = espressif32
board = esp32-s3-t-qt-4R2 ; is a Json file with board specifications?
framework = arduino
lib_deps = bblanchon/ArduinoJson@^6.1.0
lib_ldf_mode = chain+
build_flags =
${env.build_flags}
-I include
-D BOARD_HAS_PSRAM
-D ARDUINO_USB_MODE=1
-D ARDUINO_USB_CDC_ON_BOOT=1
-D PurpleBox=1
-D_IR_ENABLE_DEFAULT_=false ;
The reason it works in your case, perhaps, is that you donât have a mains.cpp (or some other function) that actually calls SendNEC(code, bits, repeats)
If I remove SendNEC(0x1200, 12,2 ) from my code, it compiles correctly.
I didnât compile at all because I have no real project.
But I check which macros gets activated. Example a new BLUE environment which activates the sections (highlighted code) for Samsung and LG:
If you could share your project (on github), it would be much easier to support you, analyze your project and find a possible issue.
A quick lunchtime read of your latest reply.
I donât quite know how platformIO chooses which environment to apply when you are just looking through the files to see which macros are active.
I never asked myself this until I started to add seperate environments in the ini-files and thats just a recent thing for me.
I see in your example that SEND_LG and SEND_SAMSUNG are active, but why didnât it pick SEND_NEC (from GREEN) did you activate the BLUE environment before checking in the files?
I might put my code on github, or just make a quick and easy test with less clutter to see if I can reproduce your observations.
My code is rather cluttered. Making it succeptable for something not going like it is on your side, but also making it hard for anyone else to check whats going on.
Have to run home now, they are installing Airconditioning at home in an hour.
Thanks for all your effort.
The user (you) select the environment to be used in the âProject Environment Switcherâ located in the bottom bar:
Because I had the BLUE
environment selected in the projects environment switcher. So only the BLUE
(and the general env
) settings are applied.
Were you waiting for me ?? 
When I checked my files yesterday, the macros did not behave as yours did.
But this bit of info is great, I will check it again.
Sometimes⌠(joke) 
If you didnât choose a specific environment, the âdefaultâ will be used. So all settings which are available in the env
setting will be applied.
Well then this info about the environment switch will make troubleshooting a bit easier. The more you know,!
Thanks⌠and I will be back ⌠donât wait up for me⌠Hahahaha 