ESPHome lambdas and C(++) for beginners

ESPHome is absolutely brilliant for people who wish to build their own smart home gadgets.

The recent acquisition of the project by Nabu Casa, the company behind Home Assistant has kicked some life in the previously stagnant project. Doing even complex things with it is quite easy, but as with all powerful frameworks going outside what the framework builders intended can be a rough ride.

This page collects all the things I wish I had been told about working with C(++) around ESPHome as a web developer and a human.

Be warned though, I found the below by trial and error, I have very limited C background.

Quick examples

Using lambdas

Lambdas are a way of running arbitrary C code

Getting a sensor value

lambda / included source file
id(api_key).state

The ID function can be used to access the sensors defined in YAML and the .state attribute contains the current state of the sensor.

For this to work, a sensor must be defined and an ID given to it in YAML.

project.yaml

text_sensor:
- platform: template
name: "API Key"
id: api_key

Construct a JSON string

lambda / included source file

char buf[256];
sprintf(buf, "{\"device\":{\"api_key\": \"%s\",
\"temperature\": \"%%1.3f\" }}", id(api_key).state.c_str(), id(temperature).state );
return ((std::string) buf);

This creates a C style character array of max 256 characters, and constructs a string by inserting a string and floating point value to the string.

The last line returns the value as a C++ standard library string, which is the less capability challenged string data type common with embedded projects, which ESPHome uses.

Including external files

ESPHome allows you to include external C source files to be compiled into the firmware. The example includes a header file functions.h

project.yaml

esphome:
...
includes:
- functions.h

You can build anything in the included files, the most useful thing I found is to define reusable functions in the file.

Note though, that all the includes directive does, is copy the named file to
<projecdir>/.esphome/build/<projectname>/src

If you remove or rename the include, it will not remove the file!

Converting values to strings

Newer versions of C++ provide the ability to call std::to_string(12345); to convert floating point values to std::string, but this functionality is not available in ESPHome. Instead, I use the following function defined in an external header file:

functions.h

template <typename T>

std::string ToString(T val)

{

std::stringstream stream;

stream << val;

return stream.str();

}


Other tips

  • Arduino examples work, but only when not dealing with strings, as the Arduino framework has its own String implementation which offers yet another bad alternative in an already crowded market. See below for more information.

  • A full reference of ESPHome's internal functions is available here. Unfortunately, it mostly contains the name of the function, along with parameters and return value types. The rest is left as an exercise to the reader.

  • Skimming through the header file for helper functions can be interesting, it contains many functions for things like getting the MAC address, various type conversions and lighting-related calculations.

What is going on with char*, char, String and std::string?!

A reasonable person might assume that a good computer system has an object for storing text. If the developers of the system have been particularly misanthrophic, it might have two. In embedded C projects you are likely to encounter four. Here they are:

  • char* aka. "C-style string". A variable length character array.

  • char another C style string with static length

  • String Arduino framework's own attempt at fixing C strings

  • std::string C++ style string, used by ESPHome

To make things extra confusing, in addition to these, there are numerous other options for various types of encodings (8, 16 and 32 bit), string buffers and all manner of excitement.

Which one should you use?

  • std:string when you can

  • char* when you must

  • Other things if you really can't live without them