From 835ca6d7a87887ba9c55b618bfc57dc0352788f8 Mon Sep 17 00:00:00 2001 From: David Montero Date: Sat, 23 May 2026 23:13:20 +0200 Subject: [PATCH] fix(esp32): stub network + ntptime modules for MicroPython in QEMU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Inject a compat shim into the raw-REPL prelude that replaces sys.modules["network"] and sys.modules["ntptime"] with no-op stubs BEFORE user main.py runs. Why: the picsimlab QEMU fork's esp32_wifi NIC emulation handles Arduino's lightweight WiFi.h but not MicroPython's full esp_wifi_init path. Calling network.WLAN(STA_IF) (which is what every network-using MP sketch does) drives the firmware to wait on peripheral status bits QEMU never sets, eventually tripping the FreeRTOS task watchdog (TG1WDT_SYS_RESET ~26s after boot, or TG0WDT ~14s if the NIC is partially attached). With the stub: network.WLAN(STA_IF).isconnected() -> False network.WLAN(STA_IF).connect(...) -> no-op ntptime.settime() -> raises OSError Sketches that already have try/except around sync_time (which is most of the 100-days examples) now degrade gracefully: WELCOME + EYES screens run, TIME and WEATHER screens show their fallback behaviour, no panic, no reboot. Doesn't affect Arduino C++ — sketches that #include use real WiFi.begin() and the existing esp32_wifi NIC handles those fine. A proper fix is to extend the picsimlab WiFi emulation to support the full ESP-IDF API, but that's a multi-day project. This stub unblocks the 31 MicroPython examples shipping with network imports. --- frontend/src/store/useSimulatorStore.ts | 45 +++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/frontend/src/store/useSimulatorStore.ts b/frontend/src/store/useSimulatorStore.ts index 186f9be2..161b9556 100644 --- a/frontend/src/store/useSimulatorStore.ts +++ b/frontend/src/store/useSimulatorStore.ts @@ -1278,9 +1278,48 @@ export const useSimulatorStore = create((set, get) => { const path = JSON.stringify(f.name); return `with open(${path},'w') as _f:\n _f.write(${lit})`; }); - const prelude = preludeLines.length - ? preludeLines.join('\n') + '\n' - : ''; + + // WiFi compat shim: replace `network` and `ntptime` with no-op + // stubs BEFORE user main.py imports them. The picsimlab QEMU + // fork's esp32_wifi NIC emulation is sufficient for Arduino's + // lightweight WiFi.h but not for MicroPython's full esp_wifi_init + // path — calling `network.WLAN(STA_IF)` hangs forever waiting + // for peripheral status bits that QEMU never sets, tripping the + // FreeRTOS task watchdog (TG1WDT_SYS_RESET ~26s after boot). + // The stubs let sketches degrade gracefully: + // wlan.isconnected() → False + // wlan.connect(...) → no-op + // ntptime.settime() → raises OSError (most sketches already + // catch and print "Sync Failed") + const wifiStub = [ + 'import sys', + 'class _StubWLAN:', + ' def __init__(self, *a, **k): pass', + ' def active(self, on=None): return False', + ' def connect(self, ssid=None, pwd=None): pass', + ' def disconnect(self): pass', + ' def isconnected(self): return False', + ' def ifconfig(self, c=None): return ("0.0.0.0", "0.0.0.0", "0.0.0.0", "0.0.0.0")', + ' def config(self, *a, **k): return None', + ' def status(self, *a): return -1', + ' def scan(self): return []', + 'class _StubNetwork:', + ' STA_IF = 0', + ' AP_IF = 1', + ' WLAN = _StubWLAN', + 'sys.modules["network"] = _StubNetwork()', + 'class _StubNTP:', + ' host = "pool.ntp.org"', + ' timeout = 1', + ' @staticmethod', + ' def settime(): raise OSError("WiFi unavailable in simulator")', + ' @staticmethod', + ' def time(): raise OSError("WiFi unavailable in simulator")', + 'sys.modules["ntptime"] = _StubNTP()', + ].join('\n'); + + const prelude = wifiStub + '\n' + + (preludeLines.length ? preludeLines.join('\n') + '\n' : ''); esp32Bridge.setPendingMicroPythonCode(prelude + mainFile.content); } } else {