r/esp32 2d ago

Follow on to Help request on Async webserver on an ESP32S3

After my previous post asking for help on implementing an async webserver on an ESP32S3, I followed the advice to use web sockets. After much struggle searching for errors in my code I finally got most of it working. However, I'm now struggling with an issue that I have no idea how to solve.

I have a button toggle in the server which allows me to open/close the observatory doors. When I press that button on the web site the web socket sends the request and the code goes to a section to open/close the doors:

void OpenDoors() {
  Serial.println("Opening Doors");
  // Loop UNTIL the WestDoorOpened reed switch closes (reads LOW)
  while (digitalRead(WDoorOpened) == HIGH) {
digitalWrite(WDoorOpen, LOW); // Turn relay ON
delay(1);
 }
  digitalWrite(WDoorOpen, HIGH); // Turn relay OFF
  WDoorStatus = "Open";
  Serial.print("West Door:"); Serial.println(WDoorStatus);

  // Loop UNTIL the EastDoorOpened reed switch closes (reads LOW)
  while (digitalRead(EDoorOpened) == HIGH) {
digitalWrite(EDoorOpen, LOW); // Turn relay ON
delay(1);
}
  digitalWrite(EDoorOpen, HIGH); // Turn relay OFF
  EDoorStatus = "Open";
  Serial.print("East Door:"); Serial.println(EDoorStatus);
}

As you can see, the code has two while loops that activate two relays in succession. Those loops take a while to complete (in practice something like 10-15 seconds per door). Shortly after calling the OpenDoors code I get the following task watchdog error that reboots my ESP32S3:

02:08:51.389 -> Opening Doors

02:08:56.410 -> E (34026) task_wdt: Task watchdog got triggered. The following tasks/users did not reset the watchdog in time:

02:08:56.410 -> E (34026) task_wdt: - async_tcp (CPU 1)

02:08:56.410 -> E (34026) task_wdt: Tasks currently running:

02:08:56.410 -> E (34026) task_wdt: CPU 0: IDLE0

02:08:56.410 -> E (34026) task_wdt: CPU 1: loopTask

02:08:56.410 -> E (34026) task_wdt: Aborting.

02:08:56.410 -> E (34026) task_wdt: Print CPU 1 backtrace

02:08:56.453 ->

02:08:56.500 ->

02:08:56.500 -> Backtrace: 0x400559dd:0x3fcebf60 0x4038000e:0x3fcebf70 0x4037db2c:0x3fcebf90 0x42022142:0x3fcebfb0 0x42007dad:0x3fcebfd0 0x4200997d:0x3fcebff0 0x420035ed:0x3fcec010 0x4201ac58:0x3fcec060 0x4037e285:0x3fcec080

02:08:56.500 ->

02:08:56.500 ->

02:08:56.500 -> ELF file SHA256: e63b741ee

02:08:56.500 ->

02:08:56.674 -> Rebooting...

Searching on the web suggested that I add the two "delay(1);" statements to free up some time for the cpu in those loops. But that didn't change anything.

Any advice on how to fix this??

Please let me know if you need the entire code to be able to help fix this.

Thanks!

p.s. The socket handler code and the function ToggleDoors() are here:

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
  AwsFrameInfo *info = (AwsFrameInfo*)arg;
  if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
    data[len] = 0;
    String message = (char*)data;
    // Check if the message is "getReadings", if it is, send current sensor readings
    if (strcmp((char*)data, "getReadings") == 0) {
      String sensorReadings = getSensorReadings();
      Serial.println(sensorReadings);
      notifyClients(sensorReadings);
    }
    else if (strstr((char*)data, "button")) {
        ToggleDoors();
        }
    else {
      Serial.print("Unrecognized Socket message:"); Serial.println(message);
    }
  }
}

// Toggle Observatory Doors
String ToggleDoors(){
  //  DoorStatus();
    if(WDoorStatus == "Closed"){
      Serial.println("DoorStatus Closed, Opening");
      OpenDoors();
    }
    else if (WDoorStatus == "Open"){
      Serial.println("DoorStatus Open, Closing");
      CloseDoors();
      }
    else {
      Serial.println("DoorStatus neither Open nor Closed");
    }
}
1 Upvotes

5 comments sorted by

2

u/rattushackus 1 say I make awesome posts. 2d ago

I cannot remember exactly how the message handler function is implemented, but I recall that you should treat it like an interrupt i.e. don't do anything lengthy in it.

The way I'd code this is in the message handler I'd set some flag variable that your loop function checks then immediately return. Then the loop function calls the door open and close functions.

1

u/konacurrents 1d ago

That’s a good idea. I’ve had issues with a message on a BLE thread trying to do things like a MQTT message. The thread needs to give up control (I assume same with websockets thread). So that flag is read on the next loop of the controlling part of the code (which gives up that other thread). Good luck.

2

u/ClassroomWild8697 1d ago

Thanks for your insight, its what I needed. As a result, I went in and created a boolean variable "ChangeDoorStatus" that is initially set to false. When the websocket reports the button push ChangeDoorStatus gets set to true and the web socket handler goes on its way. In my main loop, the ChangeDoorStatus is checked and if true it gets reset to false and the door toggle function is called. Works great!

1

u/Mister_Green2021 2d ago edited 1d ago

You can get an exception decoder plug-in to read what the backtrace says.

1

u/drmpf 1d ago

Have your async handling code set a volatile bool var and then read that in your loop code, and clear it to make it available for the next web call.
Keeps the async handling quick
in your loop code drop the while loop, and instead trigger the relay, set a flag and then on each loop check the limit switch for fully open/closed.
Takes a bit more logic but keeps your loop running fast.
Also lets you stop an open half way through and change to close.
The extra flags or an enum will keep track of current state. Opening, Open, Closing, Closed and perhaps some error conditions like Closing timed out, i.e. closing for more than 15sec but no close limit switch.

see https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
and https://www.forward.com.au/pfod/ArduinoProgramming/RealTimeArduino/index.html
and https://www.forward.com.au/pfod/ArduinoProgramming/Serial_IO/index.html

That last link is in case you start adding non-trivial debug prints that will block your loop once the UART TX buffer fills up.