How to put settings in platformio.ini to be used by all env sections?

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!

:grinning:

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.
:grinning:

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 :wink:

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 ?? :smiley:

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) :wink:

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 :rofl: