importScripts("https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js"); let sensorData = {}; // ✅ Store sensor values async function initializePyodide() { self.pyodide = await loadPyodide({ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.23.4/full/" }); self.pyodide.globals.set("send_to_main", (event, data) => { self.postMessage({ type: event, data: data }); }); // ✅ Expose sensor data to Python self.pyodide.globals.set("get_sensor_data", (name) => { return sensorData[name] ?? null; }); // ✅ Run Python initialization await self.pyodide.runPythonAsync(` import sys import pyodide import asyncio import time class RobotModule: def get_sensor(self, name): return get_sensor_data(name) robot = RobotModule() def fire(): send_to_main("fire", None) def turn(deg): send_to_main("turn", deg) class ConsoleOutput: def write(self, text): if text.strip(): send_to_main("console", text) def flush(self): pass sys.stdout = ConsoleOutput() sys.stderr = ConsoleOutput() sys.modules["robot"] = robot # ✅ Override time.sleep() with an async version _original_sleep = time.sleep # Backup original sleep async def async_sleep(seconds): await asyncio.sleep(seconds) # ✅ Allows JavaScript to process events while sleeping time.sleep = async_sleep # ✅ Monkey-patch time.sleep() `); self.postMessage({ type: "ready" }); // ✅ Notify main thread that Pyodide is ready } initializePyodide(); self.onmessage = async (event) => { if (!self.pyodide) { self.postMessage({ type: "error", message: "Pyodide not initialized yet." }); return; } if (event.data.type === "sensor_update") { // ✅ Update sensor data Object.assign(sensorData, event.data.data); } else if (event.data.type === "execute") { try { let result = await self.pyodide.runPythonAsync(event.data.code); if (result !== undefined && result !== null && result !== "") { self.postMessage({ type: "console", data: result }); } } catch (error) { self.postMessage({ type: "error", message: error.toString() }); } } };