importScripts("https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js"); let sensorData = {}; // ✅ Declare sensorData globally async function initializePyodide() { self.pyodide = await loadPyodide({ indexURL: "https://cdn.jsdelivr.net/pyodide/v0.23.4/full/" }); // ✅ Explicitly define send_to_main before running Python self.pyodide.globals.set("send_to_main", (event, data) => { self.postMessage({ type: event, data: data }); }); // ✅ Now set get_sensor_data AFTER Pyodide is initialized self.pyodide.globals.set("get_sensor_data", (name) => { return sensorData[name] ?? null; // Return sensor value or null if not set }); // ✅ Define the robot module in Python self.pyodide.runPython(` import sys import pyodide class RobotModule: def get_sensor(self, name): return get_sensor_data(name) # ✅ This should now work! 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(): # Avoid empty writes send_to_main("console", text) # ✅ send_to_main is now properly defined return None def flush(self): pass sys.stdout = ConsoleOutput() sys.stderr = ConsoleOutput() # ✅ Register robot module in sys.modules sys.modules["robot"] = robot `); 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 sensorData when receiving a sensor update Object.assign(sensorData, event.data.data); } else { 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() }); } } };