Sometimes you may need to wait for a certain condition to become true, but you don't want to wait forever: it may be awaiting for Serial, for the Wifi to connect to a network, or the response from a SoftwareSerial peripheral. The await construct lets you put an upper bound to the time you're willing to wait.

Most often, you see example code of this kind:

Serial.print("Attempting to connect to WiFi");

while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
}

If the connection doesn't succeed (maybe the AP is out of range or is down), you're stuck in an endless wait. A proper way for handling such situations is with a timeout that gets you out of the loop with an error status so you can handle the failure.
await is exactly this: a construct to await for a condition to become true until a timeout expires, returning true or false as a response.

Definition

#define await(condition, timeout) await_with_interval(condition, timeout, 10)
#define await_with_interval(condition, timeout, interval) \
  ([]() { \
    uint32_t start = millis(); \
    while (millis() - start <= timeout) { \
      if (condition) return true; \
      delay(interval); \
    } \
  return false; })()

How to use

await needs at least two arguments:

  1. the condition to await for
  2. the timeout, in milliseconds
// these are for greater code readability
#define Millis 
#define Second  *1000
#define Seconds *1000
bool wifiConnected = await(WiFi.status() == WL_CONNECTED, 10 Seconds)

The code above will wait 10 seconds for the wifi to connect: on failure, wifiConnected will be false and you can gently fail.

You can use it for any kind of check, like waiting for Serial.

bool serialReady = await(Serial, 5 Seconds)
bool serialHasCharacters = await(Serial.available(), 5 Seconds)

The default interval between checks is 10 milliseconds: if you need a custom delay interval you can use the more verbose await_with_interval:

// await WiFi for 10 seconds, check if connected every 500 millis
bool wifiConnected = await_with_interval(WiFi.status() == WL_CONNECTED, 10 Seconds, 500 Millis)

How it works

The await macro creates an inline function that loops until the timeout expires. At every loop it checks if the condition is true: if that's the case, it returns true. The inline function construct is needed to get a return value, so you can assign it to a variable or embed directly inside an if test. The following code sample gives you an idea of what's happening.

bool wifiConnected = await(WiFi.status() == WL_CONNECTED, 10 Seconds)

// conceptually translates to

bool inline_function() {
    uint32_t start = millis();

    while (millis() - start <= 10000) {
      if (WiFi.status() == WL_CONNECTED)
        return true;

      delay(10);
    }

   return false;
}

bool wifiConnected = inline_function();
Help the blow grow