Using .h file #defines in platformio.ini?

I am using conditional compilation directives for compiling multiple versions of ESP32 CAM firmwares and that works well.

Since static IP address depends on the location (each router has different IP address) and URL for accessing each camera depends on camera number I’ve made a header file similar to:

#ifndef my_defines_header
#define my_defines_header

#define LOCATION_A 1
#define LOCATION_B 2

#define CAMERA1 1
#define CAMERA1_URL "/camera1"
#define CAMERA2 2
#define CAMERA2_URL "/camera2"

// choosing location
#define LOCATION LOCATION_A

// choosing camera number
#define FW_VER CAMERA1

#if FW_VER == CAMERA1
#define CAMERA_URL CAMERA1_URL
#elif FW_VER == CAMERA2
#define CAMERA_URL CAMERA2_URL
#endif

#endif

Then I can, after choosing location and camera number, in the code use something like:

#if FW_VER == CAMERA1
#if LOCATION == LOCATION_A
IPAddress ip(192,168,1,180);
#elif LOCATION == LOCATION_B
IPAddress ip(192,168,0,180);
#endif
#elif FW_VER == CAMERA2
#if LOCATION == LOCATION_A
IPAddress ip(192,168,1,181);
#elif LOCATION == LOCATION_B
IPAddress ip(192,168,0,181);
#endif
#endif

Now, the question is - is there a way to in platformio.ini configure upload_port for OTA programming depending on the location and camera number selected via #defines in the .h file?

In other words - is it possible to access #defines defined in header files from within platformio.ini?

Usually the platformio.ini configures the code – not the other way around.

Your code already uses macros, so if you remove

#define LOCATION LOCATION_A
#define FW_VER CAMERA1

from the code and instead make use of multiple environments as explained in the docs, together with build_flags, to reinject the values of the macros. So, you can have something like

; global options to prevent repeating
[env] 
platform = espressif32
board = esp32dev
framework = arduino

[env:location_1_camera_1]
build_flags = 
   -DLOCATION=LOCATION_A
   -DFW_VER=CAMERA1
upload_port = 192.168.1.181

[env:location_1_camera_2]
build_flags = 
   -DLOCATION=LOCATION_A
   -DFW_VER=CAMERA2
upload_port = 192.168.1.181

; etc

which will show up as different environments in the project task list.

grafik

Of course creating new environments can become cumbersome when the number of variables and possiblities for them increases.

However, if you chose to have one environment with values dynamically read out from the code, you will have to parse the header file somehow. You can DIY something there (e.g. reading the lines of the header file and searching for a specific string while excluding ‘commented out’ options), or you can use the compiler for it. E.g., g++ -std=c++11 -dM -E someHeaderfile.h > defines.txt will give you a list of evaluated defines. This is also the way Marlin does it.

In general, you can use Advanced scripting to accomplish this however you want, and dynamically set the env["UPLOAD_PORT"].

Also notice that your example here is particularly difficult to parse – since the IP address is stored in in the ip object surrounded by elif… you would have to first get all values of the macros and then check if the conditions hold to construct the object. You would have an easier time if you only activated a macro that sets the IP address (e.g. #define IP_ADDRESS_LIST 192,168,1,180) and then later construct the object IPAddress ip(IP_ADDRESS_LIST)), since if you have it as a macro, and the compiler can output you all the “final” evaluated macro values, you can use that to get the value of the IP address macro.

2 Likes

Yes, creating multiple environments and using build_flags instead of some of the #defines in the header file would work. However, as you said - that wouldn’t be usable for more than e.g. 2 locations + more than 5 cameras at each location. Especially when I am already using different environments for normal vs OTA firmware upload.

I will for now just leave everything as is and everytime change the upload_port in platformio.ini manually.

It is true usually platformio.ini configures the code but it would be a nice feature if OTA port could be configured according to some data from the source code because it really depends on what is written in the source.

Thank you very much for the reply!
Regards

I totally agree with you – have tried giving the readout-macros-using-the-compiler way a try? :slight_smile:

I havent’ tried that yet. Maybe I will when I’ll have more time. I am trying to finish an ESP32 CAM security system at the moment and I’d like to make it ready for using as soon as possible. I am trying to do remote access, upload to Google Drive, upload to Raspberry Pi in local network and save to SD card - all in the same time.