Skip to Content

← All functionalities

Hydraulic moving floor (BLE app)ESP32 PLC 38RGPIOResilience / OTA

A hardware watchdog that keeps an unattended ESP32 PLC alive

Firmware on a machine in the field will eventually hang — a blocked BLE stack, a deadlock, an unbounded loop. The question is what happens next. In this real mobile hydraulic machine deployment, the ESP32 task watchdog answers it: if the main loop stops feeding esp_task_wdt for 20 seconds, the PLC reboots itself and the machine is operational again before anyone climbs up to power-cycle a cabinet.

Three lines to become self-healing

esp_task_wdt_init(20, true) arms the watchdog, esp_task_wdt_add(NULL) subscribes the current task, and a single esp_task_wdt_reset() at the top of every loop iteration feeds it. The true flag is the one that matters: it triggers a panic and a full reboot instead of just printing a warning to a serial port nobody is watching. Pick a timeout comfortably above your longest legitimate blocking operation, such as flash writes or BLE reconnections.

Know why you rebooted

A watchdog that silently hides crashes breeds zombie firmware: the machine keeps running while a real bug goes unreported for months. On boot the example reads esp_reset_reason() and, when the cause was the task watchdog, increments a persistent counter in NVS — the same Preferences pattern used for the machine's cycle counters. A rising watchdog count in the field is your early warning that some code path needs fixing before it becomes a support call.

Prove it works before you ship

The example sketch includes a "hang" button that deliberately enters an infinite loop without feeding the watchdog: the heartbeat LED freezes and roughly 20 seconds later the PLC restarts on its own. Testing recovery on the bench is the difference between hoping the watchdog works and knowing it does — afterwards the BLE server re-advertises and the mobile app reconnects automatically.

A snippet from the implementation

Straight from the example as deployed on the ESP32 PLC 38R — copy it freely:

void setup() {
  Serial.begin(115200);
  pinMode(BTN_HANG, INPUT);
  pinMode(LED_ALIVE, OUTPUT);

  // 1. Diagnostics: why did we boot?
  esp_reset_reason_t reason = esp_reset_reason();
  Serial.print("Reason of the last reboot: ");
  Serial.println(resetReasonText(reason));

  // 2. Persistent counter of watchdog reboots (NVS pattern)
  prefs.begin("nvdata", false);
  wdtResets = prefs.getInt("wdt_resets", 0);
  if (reason == ESP_RST_TASK_WDT) {
    wdtResets++;
    prefs.putInt("wdt_resets", wdtResets);
  }
  prefs.end();
  Serial.println("Accumulated watchdog reboots: " + String(wdtResets));

  // 3. Arm the watchdog: 20 s and panic=true (reboots instead of just warning)
  esp_task_wdt_init(WDT_TIMEOUT, true);
  esp_task_wdt_add(NULL);              // watches the current task (loop)
  Serial.println("Watchdog armed: " + String(WDT_TIMEOUT) + " s");
}

The full example is a complete program — wiring header, setup and main loop — ready to adapt to your application.

Frequently asked questions

What watchdog timeout should I choose?

Several times longer than your worst-case legitimate loop iteration, including flash writes and BLE operations. The 20 seconds used here is conservative for a machine controller whose loop normally turns in milliseconds.

Does the watchdog protect against every kind of failure?

No. It catches software hangs of the monitored task, not logic bugs that keep the loop spinning, nor hardware faults. Combine it with brownout detection, sane output defaults on boot and the reset-reason logging shown here.

Do outputs reset to a safe state after a watchdog reboot?

Yes, on reboot all GPIO return to their default state and your setup() runs again, so design setup() to start with every valve and motor output off — exactly what the valve state machine in this series does.

Related functionalities