Skip to content

ESP32-S3: Watchdog timer expired running polling loop #9460

Open
@mMerlin

Description

@mMerlin

Adafruit CircuitPython 9.1.1 on 2024-07-22; Adafruit-Qualia-S3-RGB666 with ESP32S3
Board ID:adafruit_qualia_s3_rgb666

I have a script to explore working with SSE. It «seems to» work. I can connect and disconnect browser sessions. However, if I then just leave it running with no connections, and come back later (maybe an hour), the app is frozen. ctrl+c in the serial window aborts and gives:

192.168.20.105 -- "GET /sse" 360 -- "200 OK" 101 -- 126ms
192.168.20.105 -- "GET /favicon.ico" 390 -- "404 Not Found" 90 -- 18ms
client ('192.168.20.105', 8332) went away: code 32
client ('192.168.20.108', 47266) went away: code 32
client ('192.168.20.108', 11392) went away: code 32

Adafruit CircuitPython 9.1.1 on 2024-07-22; Adafruit-Qualia-S3-RGB666 with ESP32S3
>>> 
>>> 
soft reboot

Auto-reload is off.
Running in safe mode! Not running saved code.

You are in safe mode because:
Internal watchdog timer expired.
Press reset to exit safe mode.

The first part of that is the final log messages while it was running. This has occurred several times with different versions of the code. Including (I think) the httpserver_sse.py example in the repo that I started from. I don't know if it it total run time, or total idle time that triggers this.

Adafruit CircuitPython 9.1.1 on 2024-07-22; Adafruit-Qualia-S3-RGB666 with ESP32S3
Board ID:adafruit_qualia_s3_rgb666

Here is code that 'almost' matches what produced the above log. Almost, because the sequence has been: run the script, do some testing, then edit the offline version. In this case, the edit was cleanup to remove some debug messages, tweak the remaining, then start working on a more full html file. Got called away for awhile, when returned, found it locked up. again. Some of those lockup resulted in CIRCUITPY becoming read only. I had to do the file system erase to get it back.

# SPDX-FileCopyrightText: 2024 H Phil Duby
# SPDX-License-Identifier: MIT

"""
HTTP Server with SSE request handling for ambient environment data
"""

from time import monotonic_ns
try:
    # not used at runtime, useful for IDE and documentation
    from typing import NoReturn, Dict, Tuple
except ImportError:
    pass
import microcontroller  #type:ignore
import socketpool  #type:ignore
import wifi  #type:ignore
from adafruit_httpserver import FileResponse, Request, Route, Server, SSEResponse, GET

class AmbientHTTPServer:
    """Serve ambient environment information to clients"""
    def __init__(self):
        print('Initializing server...')  # TRACE
        pool = socketpool.SocketPool(wifi.radio)
        self.server = Server(pool, debug=True)
        self.sse_response: Dict[Tuple[str, int], SSEResponse] = {}
        self.next_event_time_ns = monotonic_ns()
        self.setup_routes()

    def client(self, request: Request) -> FileResponse:
        """Return HTML page that initiates SSE communication"""
        print(f'Serving HTML to {request.client_address}')  # DEBUG
        return FileResponse(request, 'index.html', '/client')

    def sse_client(self, request: Request) -> SSEResponse:
        """Establish SSE communication with client"""
        if request.client_address in self.sse_response:
            raise NameError(f'Client {request.client_address} already connected')
        print(f'Connecting client {request.client_address}')  # DEBUG
        response = SSEResponse(request)
        self.sse_response[request.client_address] = response
        print(f'SSE response created for {request.client_address}')  # DEBUG
        return response

    def setup_routes(self) -> None:
        """Create web server routes for application"""
        self.server.add_routes([
            Route('/client', GET, self.client),
            Route('/sse', GET, self.sse_client)
        ])

    def send_event_to_clients(self) -> None:
        """Send fresh data to all connected SSE clients"""
        if self.sse_response and self.next_event_time_ns < monotonic_ns():
            cpu_temp = round(microcontroller.cpu.temperature, 2)
            for client_id, client in list(self.sse_response.items()):
                # print(f'Sending event {cpu_temp} to client {client_id} for {client._request}')  # DEBUG pylint:disable=protected-access
                try:
                    client.send_event(str(cpu_temp))  # send data to client
                except BrokenPipeError as be:
                    print(f'Client {client_id} disconnected: code {be}')
                    del self.sse_response[client_id]
            self.next_event_time_ns = monotonic_ns() + 1000000000  # 1 second

    def start(self) -> NoReturn:
        """Start the application web server"""
        self.server.start(str(wifi.radio.ipv4_address))
        # Except: RuntimeError: Cannot start server on None:5000
        # Except: gaierror: (-2, 'Name or service not known')
        while True:
            self.server.poll()  # watch for new connection or page requests
            self.send_event_to_clients()

if __name__ == "__main__":
    instance = AmbientHTTPServer()
    print('Server instantiated')  # TRACE
    instance.start()

When it locks up, the only thing it is doing is polling, because self.sse_response is empty.

The index.html file referenced is:

<html lang="en">
    <head>
        <title>Server-Sent Events Client</title>
    </head>
    <body>
        <p>CPU temperature: <strong>-</strong>&deg;C</p>
        <script>
            const eventSource = new EventSource('/sse');
            const cpuTemp = document.querySelector('strong');

            eventSource.onmessage = event => cpuTemp.textContent = event.data;
            eventSource.onerror = error => cpuTemp.textContent = error;
        </script>
    </body>
</html>

I'm not setup to create a debug version of circuitpython, but with a little guidance, I probably could add some logging (with timestamps) to a local copy of HTTPServer.Server

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions