# HomeSpan Watchdog Timer

The ESP32 operating system supports a task-based watchdog timer (TWDT) that checks to ensure tasks (or any select section of code) that subscribes to the task watchdog is being periodically run.  If not, then after a pre-specified period of time, the device automatically reboots.

Typically, it is only the background IDLE processes that subscribe to the TWDT, but by default the Arduino-ESP32 library does NOT enable the IDLE task watchdog for single-core chips (ESP32-S2, C3, and C6) and only enables the IDLE task watchdog associated with Core-0 for dual-core chips (ESP32 and ESP32-S3).  The Arduino-ESP32 library default is to set the TWDT timeout to 5 seconds.

Based on these defaults, if the your sketch hangs, or otherwise goes into an infinite loop, the device will be frozen indefinitely until you manually reset it or cycle the power.

Fortunately, you can add an optional watchdog to the TWDT that specifically checks to ensure all needed HomeSpan tasks and functions are running as expected.  To do so, simply call the homeSpan  method `enableWatchdog(uint16_t nSeconds)` near the top of the `setup()` portion of your sketch.   Once enabled, the TWDT will time-out and automatically reboot the device after *nSeconds* unless the HomeSpan watchdog has been reset.  HomeSpan resets its watchdog automatically upon reaching the very end of the HomeSpan `poll()` function.  As long as the end of the `poll()` function is reached every *nSeconds* seconds, the TWDT will be silent.  But if the `poll()` function hangs, or another process blocks the `poll()` function from even being called, the TWDT will trigger after *nSeconds* seconds and the device will reboot.

By setting *nSeconds* to a time that is sufficiently long to allow all of your setup process to run (perhaps 10-20 seconds), you can be assured that if any of the HomeSpan process are caught in an infinite loop, the device will reboot on its own.  This is particularly helpful when used in conjunction with OTA Rollbacks since you can configure things such that if you upload a new sketch via OTA and it hangs on start-up, it will reboot after a short period of time and rollback to the prior working version of the sketch.  See the [HomeSpan OTA](OTA.md) page for details on how to enable rollbacks.

If for whatever reason you need to perform a function within the HomeSpan framework that will prevent the `poll()` task from running for an extended period of time (i.e. longer than *nSeconds*) you can call `homeSpan.disableWatchdog()` to temporarily disable the HomeSpan watchdog and prevent a reboot.  Then simply call `homeSpan.enableWatchdog(nSeconds)` once again when your function is complete to re-enable the HomeSpan watchdog.  See the [HomeSpan API Reference](Reference.md) for details on the `enableWatchdog()` and `disableWatchdog()` methods.

### Implementation Notes

* Internally, HomeSpan calls the homeSpan `resetWatchdog()` method to reset its watchdog at the end of the `poll()` function.  HomeSpan also embeds calls to `resetWatchdog()` at the end of any other HomeSpan function that, by design, temporarily blocks the `poll()` function, such as when HomeSpan is waiting for you to type your WiFi Credentials into the Serial Monitor, when you've used the Control Button to place HomeSpan into Command Mode, or when you've started the HomeSpan Setup Access Point.  These extra embedded calls to `resetWatchdog()` ensure the TWDT will not trigger while these other functions are running, but the TWDT will indeed trigger and reboot the device if those functions themselves hang.
  
* The `resetWatchdog()` method serves two purposes:  it resets the HomeSpan watchdog (if it is enabled) and it calls `vTaskDelay(1)` (regardless of whether or not the HomeSpan watchdog is enabled).  The call to `vTaskDelay` allows HomeSpan to yield for 1 ms so that other separate tasks with the same or lower priority (such as the IDLE tasks) get an opportunity to run.

* The homeSpan `resetWatchdog()` method is public and you can call it yourself from within your sketch if needed.  For example, if your sketch runs the HomeSpan `poll()` function by calling `homeSpan.poll()` from within the main Arduino `loop()` and you add code into the `loop()` that takes more than *nSeconds* seconds to run, you should either call `homeSpan.disableWatchdog()` before that code is run, or repeatedly call `resetWatchdog()` from within your long-running code at a point that is only reached if your code is running correctly, but will not be called if your code hangs.  This effectively allows the TWDT to monitor your long-running code and trigger a reboot if it hangs.

* If instead of calling `homeSpan.poll()` from within the Arduino `loop()` your sketch calls `homeSpan.autoPoll()` at the end of the Arduino `setup()` function to launch HomeSpan polling in a separately-running task, then the HomeSpan polling task will be unaffected by delays in any code you may add to the Arduino `loop()`.

* However, even if you use `homeSpan.autoPoll()` to run HomeSpan polling in its own task, you still need to make sure you don't add any long-running code to the Arduino `setup()` function that delays the initial launch of polling by more than *nSeconds* seconds from the point you call `homeSpan.enableWatchdog(nSeconds)`.  If you do add any initializaiton code to the Arduino `setup()` function that takes a long time to run, you can either wait to call `enableWatchdog(nSeconds)` until after that code completes, or even better you can still call `enableWatchdog(nSeconds)` at the top of the Arduino `setup()` function and then periodicially call `resetWatchdog()` from within your long-running code.  This ensures the HomeSpan watchdog will trigger a reboot after *nSeconds* seconds if your code hangs.

* Note that to avoid triggerring the HomeSpan watchdog, the HomeSpan `poll()` function needs to reach its **end** every *nSeconds* seconds.  This means you need to make sure the `poll()` function does not get delayed running any code you use to implement HomeSpan Service structures (e.g., the SpanService constructor, the `update()`, `button()`, and `loop()` methods, etc.) or any code you use to implement HomeSpan callbacks.  Similar to above, if you do need to add code to a Service structure or callback that takes a long time to run, make sure to periodically call `homeSpan.resetWatchdog()` within that code so it is properly protected by the HomeSpan watchdog.

* Enabling the HomeSpan watchdog only protects *your sketch* from hanging indefinitely by triggering a reboot after *nSeconds* seconds if the watchdog is not reset.  But the HomeSpan watchdog does nothing to create any sort of "heartbeat" to keep alive connections to HomeKit or your Home App if your sketch contains long delays that do not trigger the watchdog.  This means that even with HomeSpan watchdog protection enabled, delays that prevent the HomeSpan `poll()` function from running in a timely fashion will cause HomeKit to display the dreaded "No Response" message in your Home App.

* The HomeSpan watchdog is implemented as part of the ESP32's *task* watchdog timer, which is completely separate from the ESP32's *interrupt* watchdog timer (IWDT) used by various operating system functions.

---

[↩️](../README.md) Back to the Welcome page
