Pass env variables at build time

Hello,
I am working on an open source project which however connects to some private cloud service.
I want the DSN string for the service (mqtt) to be “added” at build time, so my code on github doesn’t expose any credentials. Any idea how to achieve this?

Also, I see that even when working on arduino, I am not handling a .ino file anymore but a .cpp one. Can I use regular cpp syntax in platformio or am I still constrained to the C-like arduino language?

Thank you!

Thanks! Actually I found those pages before but how do I actually put those in my code? Those examples only have the .ini file…

See https://www.quora.com/What-are-macros-in-C

[env:myenv]
platform = ...
build_flags = -D SOME_ENV_VAR=${sysenv.ENV_VAR}

Thanks! Not sure tho, I have added those build flags but then in my code

#ifdef MQTT_HOSTNAME
    client.begin(MQTT_HOSTNAME, net);
#endif

I get an error at the comma in MQTT_HOSTNAME, with message “expression expected”.

Actually now I get this from the compiler:

:0:15: error: ‘m23’ was not declared in this scope
src/main.cpp:60:18: note: in expansion of macro ‘MQTT_HOSTNAME’
client.begin(MQTT_HOSTNAME, net);

Where m23 is part of my MQTT connection string (m23.xxx.xxx)

@valeros could you help here?

Hi @anon19416280! How did you set MQTT_HOSTNAME? I couldn’t reproduce the issue on Windows.

Hi @valeros, with some debugging I see that the env variables are set correctly.
However, the same firmware will connect to mqtt when compiled and uploaded via the Arduino IDE, and not connect via Platformio.

EDIT: if I define the vars as string in the code itself, everything will work. However via serial monitor I see that they’re defined also via env. Maybe a different type?

Solved! MQTT port was being passed as string instead of int. Sorry, I’m new to debugging embedded systems.

Thanks your for help!

This works but I wonder if it is possible to have a default value, when the environment variable is not set. Something like this:

build_flags = -D SOME_ENV_VAR=${sysenv.ENV_VAR:-someDefaultValue}

You can do that with Redirecting...

Thanks for quick response. Thats a solution alright, but it can easily create a lot of boilerplate code. I think it would be good to add this kind of functionality in PIO since it can be found in other modern frameworks as well.

In this case you can use Dynamic build flags.

build_flags = !python -c "import os; print('-DSOME_ENV_VAR=%s' % os.getenv('ENV_VAR', 'someDefaultValue'))"
1 Like

Hello!
And how can be passed some variables at build time, but from current environment?

Using !python script.py as dynamic build flags wont get access to environment (Import(“env”) can not be called).
If that variables would be global then this method can be used: Redirecting... but how to load PIO environment?

Could you show a simple configuration which does not work? I’m not sure that understand very well what you would like to achieve.

Hi Ivan,
Maybe I will tell what I want to achieve.

I need to store version string to be accessible both in C code and for extra scripts. I haven’t found working solution to have it in only one place. Ideally it would be somewhere in platformio.ini and easy accessible as build option and from python.

Currently I’m using version.txt in main directory and then read it from python and using dynamic build flag to read it. Is there some other way?

This approach is working as long You don’t need some environment based changes. For example if software version need to have language version included. Ideally would be to add platformio.ini entry lang and read it from scripts. In extra scripts it is possible - after Import(“env”) there is config object where it can be accessed, but not in script called as dynamic build flag, so Import(“env”) throws an error.

How to solve that?

You you need an exta script Redirecting... that will store version in Python and extend build environment with a custom macro.