Fun with Async and Promises - ESP8266

I’ve built an ESP8266 using a WEMOS D1 Mini Pro and relay that I need to trigger a momentary connection.

This is being accessed as a web service using ‘ESPAsyncWebServer’. I’m happy with the aspects of using the web service, setting up the config over WiFi, saving it to SPIFFS etc. but the frustration comes when trying to trigger the momentary relay connection.

const int relayPin = D1;
const long interval = 500;

void togglePower() {
  Serial.println("Relay triggered!");
  digitalWrite(relayPin, HIGH);
  digitalWrite(D4, LOW);
  delay(interval);
  digitalWrite(relayPin, LOW);
  digitalWrite(D4, HIGH);
}

What happens is the relay gets triggered, but then sticks in that triggered state.

I think it’s because the Async web service is not waiting (as per) for the relay to toggle back after the delay. At the point of delay() we get no further in the code.

My main thrust is to act on an api call:

AsyncCallbackJsonWebHandler* handler = new AsyncCallbackJsonWebHandler("/api", [](AsyncWebServerRequest *request, JsonVariant &json) {
  togglePower();
}

There’s some more clever stuff around it that checks the authenticity of the call etc, but as the togglePower() is called Asynchronously it fails as control is returned to the loop I guess.

In the worlds of of JavaScript I’d use Async/Await or promises. I tried to look at using future and promises, but all the c++ reference material I found is a different syntax and compiling my code fails.

Can someone point me to a source where I can get a working example of future/promises on Arduino?

I’ve attached the full .ino if any one is interested. It’s going to end up public on Github when I get it working anyhow.

Many thanks for looking.

scorpion-lite.ino (7.4 KB)

In the asynchronous callbacks you must not use delay(). They should be as short as possible (almost the same as interrupt handlers but the callbacks allow more). If you need timed stuff, just set a flag variable in the callback and do the rest in the main loop.

pylon:
In the asynchronous callbacks you must not use delay(). They should be as short as possible (almost the same as interrupt handlers but the callbacks allow more). If you need timed stuff, just set a flag variable in the callback and do the rest in the main loop.

Thanks for the reply.

That's pretty much what I mean. If I were to use a delay() it should be in another thread or promise that is independent. But I don't know how to call that from c++/Arduino.

Hmm, I was putting a variable in the loop that looked like this:

void loop() {
  if (power == 1) {
    power = 0;
    togglePower();
  }
}

But I thought that a bit of a cowardly solution.

But I thought that a bit of a cowardly solution.

No, that's exactly how it's intended to be used.

it should be in another thread or promise that is independent.

These devices don't know the concept of a thread or process. I guess by promise you mean simply callbacks. These terms are used in the PC/Web world, embedded devices are usually much simpler and don't have all the capabilities of a full-fledged PC.

pylon:
No, that's exactly how it's intended to be used.

These devices don't know the concept of a thread or process. I guess by promise you mean simply callbacks. These terms are used in the PC/Web world, embedded devices are usually much simpler and don't have all the capabilities of a full-fledged PC.

Well that works I guess, thank you :slight_smile:

Just tested it out an now it does what I need. On to the next challenge.

In the world of PC's and JavaScript promises are more like callbacks++ and even then we're moving onto Async/await functions instead. I was obviously overthinking it on the tiny boards.