Repository navigation
Feature/mech dog - #5
Conversation
forward = Right down = Left
Added new blocks (Move and Color) Only Forward command is working with vex WORK IN PROGRESS
Previous block functionality still working on new block functions
Found problem: the number for the muscle energy window and the raw data doesn't match up
- need to connect the vex through AP before starting the application
This reverts commit ceb24df.
- fixed colors
…into feature/ganglion
- no longer degrees for turn block (for kids) - Shortcut is ready to be used (Neuroscope-EMG) -Updated gitignore (pycache)
* src/main/index.js: - Fixed production build path from loadURL to loadFile with correct relative path - Added Python process spawning with virtual environment detection - Implemented WebSocket connection validation with 10s timeout - Added proper process cleanup on app quit and window close - Updated hardcoded references from Muse to Ganglion devices - Fixed port configuration from 3000 to 3002 * src/renderer/js/muse-client.js: - Fixed duplicate filters property that was overriding device name filters - Added Ganglion service (0xfe84) to optionalServices for proper discovery * package.json: - Updated electron-builder config to include build/renderer directory - Added extraResources for Python executable bundling - Enhanced build scripts with python:build for PyInstaller integration - Updated serve script to use port 3002 - Added build:local script for complete build process * VEXServer.spec (new): - PyInstaller specification for Python server executable - Proper dependency handling for websockets and asyncio - Console executable configuration for debugging * resources/python/VEXServer_dev.py (new): - Created simulation mode WebSocket server for development - Mock VEX robot with full command protocol (led_on, move, turn_left, turn_right) - Enables testing without physical VEX robot hardware - Runs on ws://127.0.0.1:8777 with JSON command interface * requirements.txt: - Added PyInstaller>=5.0 for standalone executable creation **Key Improvements:** - Enables successful Windows executable creation with integrated Python server - Two-process architecture provides reliable communication in both dev and production - Fixed Bluetooth device scanning to properly detect Ganglion devices instead of Muse - Automatic virtual environment detection in development mode - Production builds now bundle Python server as standalone executable - Enhanced development workflow with simulation server for hardware-free testing
…rking WebSocket management **New Features:** * Console UI: Replace frequency bands display with clean console output * VEX Reconnect: Add functional reconnect button to restart VEX connection without app restart * Enhanced Testing: Complete VEX simulation server with comprehensive test suite * Robust WebSocket Management: Proper connection handling with reconnection support **Console System (NEW):** * src/renderer/js/console.js: Clean terminal-like console without timestamps/emojis * src/renderer/index.html: Replace bands display with console container * src/renderer/js/main.js: Integrate Console class replacing BandPowerVis * src/renderer/js/wrapper-functions.js: Connect blockly_print to console output **VEX Reconnect System (FULLY FUNCTIONAL):** * src/main/index.js: Complete WebSocket connection management with proper scoping - Added stopPythonServer() and reconnectVEX() process management - Moved WebSocket variables and functions to global scope for proper access - Implemented createWebSocketConnection() with timeout and error handling - Fixed function scoping issues that prevented reconnection * src/main/preload.js: Expose vexReconnect IPC method to renderer * src/renderer/index.html: Add VEX reconnect button in sidebar (orange refresh icon) * src/renderer/js/events.js: Implement reconnect button handler with visual feedback **Enhanced VEX Testing:** * resources/python/VEXServer_dev.py: Complete simulation server with full command support * test_vex_server.py: Comprehensive WebSocket test suite for validation **Key Technical Improvements:** - Fixed variable scoping: ws and createWebSocketConnection now accessible globally - Proper WebSocket lifecycle management: Close old connections before creating new ones - Enhanced error handling with timeout protection and graceful fallbacks - Clean console replaces cluttered frequency bands display - Robust reconnection process with proper server restart sequence - Enhanced print blocks accept any data type and output to console **WebSocket Reconnection Flow:** 1. Close existing WebSocket connection 2. Stop Python VEX server gracefully (SIGTERM with SIGKILL fallback) 3. Wait 2 seconds for cleanup 4. Restart Python VEX server 5. Wait 3 seconds for server initialization 6. Re-establish WebSocket connection with timeout protection 7. Resume VEX command functionality
**Block-to-Text Converter:** * src/renderer/js/simple-text-view.js: Text coding environment using Blockly's built-in code generation * src/renderer/index.html: Add toggle buttons for block/text modes and export functionality * src/renderer/js/main.js: Integrate text view with existing Blockly system
… app rename Python (resources/python): Add resilient AIM connection loop; server stays alive and retries when robot is offline Add reconnect_robot action to reset robot connection without restarting server Add disconnect_robot cleanup to close websocket threads and sockets before re-init Add status action reporting robot_connected for UI Improve connection logs (attempting / connected / retry) Electron main (src/main): Detect and spawn bundled VEXServer.exe in production Replace waitOn websocket probe with lightweight TCP port polling Guard reconnectVEX against overlap and clear force-kill timer to avoid killing new process Periodically poll server status and relay to renderer via vex-status Fix false-positive connected state by distinguishing wsConnected vs robotConnected Add lazy-init UDP sockets for Tello (no bind to 9000/8890 until needed) Renderer: Add connectivity status dot showing wsConnected (grey/yellow) and robotConnected (green) Add onVexStatus and requestVexStatus to preload for UI updates Packaging/build: Ensure PyInstaller bundle includes vex module/resources and fix spec path resolution Use process.resourcesPath/python/VEXServer.exe in production and improve spawn/path logging Naming/branding: Rename app to "NeuroBlock EMG for VEX" (productName/appId, window title, HTML title) Docs: Update README with "Adding a New Blockly Block (Example: VEX Kicker)" section and build notes Notes: Reconnect button sends reconnect_robot when local websocket is up; only restarts Python process if websocket is down Status dot: grey = websocket down, yellow = websocket up/robot down, green = robot connected Avoid binding to port 9000 unless Tello is actively used
This reverts commit b031569.
…X integration ### Application Branding & Identity - Rename app from 'NeuroBlock EMG for VEX' → 'NeuroBlock EEG for VEX' - Update package.json productName, window title, and HTML title - Update appId to reflect EEG focus: com.htil.neuroblock-emg-vex ### EEG Signal Processing (Muse Headset) - Restore Signal class for real-time EEG data buffering (512-sample buffer) - Restore BandPowerVis for frequency band visualization (delta, theta, alpha, beta, gamma) - Restore FeatureExtractor for band power computation from raw EEG samples - Restore BLE (Bluetooth Low Energy) integration for Muse headset connection - Wire Muse eegReadings callback → Signal.add_data() for live data streaming ### UI Layout - Two-Panel Design - Left panel (45% width): * Top card (40vh): 4 EEG channel graphs (channels 0-3 from Muse) * Bottom card (40vh): Band power frequency spectrum visualization - Right panel (55% width): * Blockly visual programming editor for robot control * VEX AIM robot command center and status display * Console output and device connection status
…band power metrics and fixing controls_if handler
There was a problem hiding this comment.
Pull request overview
This PR migrates “mech-dog” (MechDog/VEX) support into the main Electron app by adding a Python robot backend, IPC bridges, new Blockly blocks/categories, and a blocks↔text-code view/export flow.
Changes:
- Add a Python WebSocket backend (MechDog + VEX AIM) and wire it into the Electron main process with reconnect/status polling.
- Expand Blockly with MechDog/VEX control + telemetry blocks and add validation improvements.
- Add text-mode/editor/conversion utilities and export tooling, plus assorted test/demo assets and build scripts.
Reviewed changes
Copilot reviewed 39 out of 52 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
test_vex_server.py |
Adds a simple Python WebSocket smoke-test script for the dev server. |
test-reconnect.js |
Adds a Node.js script to test WebSocket reconnection behavior. |
test-converter.html |
Adds a browser test page for the block-to-text converter. |
src/renderer/js/wrapper-functions.js |
Adds safer band-power getters, MechDog telemetry getters, and VEX/MechDog command wrappers. |
src/renderer/js/text-editor.js |
Adds a Monaco-based text editor component with Python completions. |
src/renderer/js/simple-text-view.js |
Adds a simple blocks→text display/export controller. |
src/renderer/js/muse-client.js |
Adjusts Bluetooth request options (services) for Muse/Ganglion connections. |
src/renderer/js/main.js |
Adds global telemetry/band-power initialization and VEX status handling for UI readouts. |
src/renderer/js/interpreter-api.js |
Exposes new wrapper functions (MechDog/VEX + kicker + muscle energy) to js-interpreter. |
src/renderer/js/feature-extractor.js |
Hardens relative band power calculation (avoids divide-by-zero/undefined). |
src/renderer/js/events.js |
Adds export + MechDog reconnect UI event handlers and sends a stop command on stop. |
src/renderer/js/customblock.js |
Adds MechDog telemetry blocks, muscle energy block, and multiple VEX/MechDog control blocks. |
src/renderer/js/console.js |
Adds an in-app console UI and API (window.neuroConsole usage). |
src/renderer/js/coding-mode-manager.js |
Adds a “blocks vs text” mode manager (Monaco + Blockly sync/export). |
src/renderer/js/categories.js |
Adds a MechDog category and includes muscle energy in Data category. |
src/renderer/js/blockly-main.js |
Adds block validation UX, adds MechDog category to toolbox, improves run flow and error reporting. |
src/renderer/js/block-to-text-converter.js |
Adds a Blockly workspace → Python-like text converter module. |
src/renderer/index.html |
Updates UI for text mode/editor, adds export/reconnect controls, adds MechDog sonar readout. |
src/main/tello.js |
Lazily instantiates the Tello controller to avoid initializing unless needed. |
src/main/preload.js |
Exposes new IPC APIs for VEX/MechDog commands, status, reconnect, and generic sendCommand. |
src/main/index.js |
Adds Python backend process management, WebSocket client, IPC routing, polling, and packaging path changes. |
src/main/index copy.js |
Minor formatting tweak in dev reloader try/catch. |
setup-venv.sh |
Adds a helper script to create/activate a Python venv and install requirements. |
resources/python/vex/vex_types.py |
Adds VEX AIM API type definitions and constants. |
resources/python/vex/vex_messages.py |
Adds VEX AIM WebSocket message definitions. |
resources/python/vex/vex_globals.py |
Adds VEXcode-style globals to mirror VEX API ergonomics. |
resources/python/vex/settings.py |
Adds settings loader for VEX AIM configuration. |
resources/python/vex/settings.json |
Adds default VEX connection settings (host). |
resources/python/vex/__pycache__/vex_globals.cpython-313.pyc |
Adds a compiled Python bytecode artifact (should not be tracked). |
resources/python/vex/__pycache__/settings.cpython-313.pyc |
Adds a compiled Python bytecode artifact (should not be tracked). |
resources/python/vex/__pycache__/__init__.cpython-313.pyc |
Adds a compiled Python bytecode artifact (should not be tracked). |
resources/python/vex/__init__.py |
Adds VEX package init re-exporting AIM/types. |
resources/python/VexTest.py |
Adds a Python WebSocket test script for VEX server commands. |
resources/python/VEXServer_dev.py |
Adds a mock VEX server for development without hardware. |
resources/python/VEXServer.py |
Adds a VEX AIM WebSocket server with reconnect/status/kicker support. |
resources/python/MechDogServer.py |
Adds a BLE-backed MechDog WebSocket server with telemetry and action commands. |
requirements.txt |
Adds Python dependencies for servers (websockets, bleak, pyinstaller, etc.). |
programs/maze_program_emg.xml |
Adds a sample Blockly program using muscle energy + VEX movement. |
package.json |
Updates dev server port, adds python build scripts, updates Electron builder config/resources, adds deps. |
block-text-demo.html |
Adds a standalone demo page for block-to-text conversion. |
VEXServer.spec |
Adds PyInstaller spec (currently building MechDogServer.exe). |
README.md |
Replaces placeholder README with detailed usage/build/docs (incl. VEX kicker pattern). |
Neuroscope.bat |
Adds a Windows batch helper to activate venv and run the app. |
Neuroscope-EMG.lnk |
Adds a Windows shortcut artifact (should not be tracked). |
.gitignore |
Adds ignores for Python bytecode and venv-related paths. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (window.electronAPI && typeof window.electronAPI.vexKicker === 'function') { | ||
| window.electronAPI.vexKicker(k); | ||
| } else { | ||
| // Fallback to generic command if alias missing (defensive) | ||
| window.electronAPI.sendCommand({ action: "kicker", type: k }); | ||
| } |
There was a problem hiding this comment.
vex_kicker() checks window.electronAPI only in the if branch, but the else branch still calls window.electronAPI.sendCommand(...) and will throw if electronAPI is undefined. Guard sendCommand as well (or no-op / log) so this stays truly defensive.
| toast.innerHTML = ` | ||
| <i class="close icon" onclick="this.parentElement.remove()"></i> | ||
| <div class="header">${type.charAt(0).toUpperCase() + type.slice(1)}</div> | ||
| <p>${message}</p> | ||
| `; |
There was a problem hiding this comment.
showMessage() builds the toast using innerHTML and interpolates message directly into the HTML. Since message can include error.message (and could contain user-controlled content), this creates an XSS injection path. Prefer building DOM nodes and setting textContent for the message body/header instead of using innerHTML.
| '''A percentage unit that represents a value from 0% to 100%''' | ||
| LEFT = TurnType.LEFT | ||
| '''A turn unit that is defined as left turning.''' | ||
| RIGHT = TurnType.LEFT |
There was a problem hiding this comment.
RIGHT is incorrectly assigned to TurnType.LEFT, so any code using the global RIGHT constant will behave like a left turn. This should reference TurnType.RIGHT.
| RIGHT = TurnType.LEFT | |
| RIGHT = TurnType.RIGHT |
| let dr // 1. Define the block's JSONks_color = 70; | ||
|
|
There was a problem hiding this comment.
Line 5 is a corrupted variable declaration (let dr // ... ks_color = 70;) which makes this file invalid JavaScript and will break the renderer build at import time. Restore the original drone_blocks_color declaration (or otherwise fix the declaration) so the module parses.
| const button = document.getElementById("vex-reconnect"); | ||
| const originalHTML = button.innerHTML; | ||
| button.innerHTML = '<i class="spinner loading icon"></i>'; | ||
| button.disabled = true; |
There was a problem hiding this comment.
reconnect_vex() assumes document.getElementById("vex-reconnect") always exists; if it’s missing, button.innerHTML will throw and break the handler. Add a null check (or use the existing eById helper) before reading/modifying the button.
| // Resize Blockly | ||
| if (this.blocklyWorkspace) { | ||
| Blockly.svgResize(this.blocklyWorkspace); | ||
| } |
There was a problem hiding this comment.
This file calls Blockly.svgResize(...) but does not import Blockly, so switching modes will throw a ReferenceError: Blockly is not defined. Import Blockly (e.g. from blockly/core) or route resizing through an injected dependency.
| handlePrint(block) { | ||
| const value = this.getFieldOrInputValue(block, 'VALUE', '"Hello World"'); | ||
| this.addLine(`print(${value})`); | ||
| } |
There was a problem hiding this comment.
The converter’s handlers don’t match the actual custom block input names/types. For example, the print block’s input is named val (see customblock.js), but handlePrint() looks for VALUE, so conversions will always fall back to the default string. Align the converter’s field/input names with the real Blockly block definitions so the generated text reflects the workspace accurately.
| vex_kicker: this.wrapperFunctions.vex_kicker, | ||
|
|
||
| // ← NEW: expose muscle energy from window.filteredSample | ||
| getMuscleEnergy: () => window.filteredSample | ||
| }; |
There was a problem hiding this comment.
getMuscleEnergy returns window.filteredSample, but that global is not defined anywhere else in the codebase right now, so this will always be undefined. Either define/update window.filteredSample where the EMG feature is computed, or make this function return a numeric default (and/or compute muscle energy directly) so the muscle_energy block reliably outputs a Number.
| <div style="position: absolute; right: 5px; top: 260px; z-index: 100"> | ||
| <button id="exportCode" class="huge circular ui teal icon button" style="display: inherit; margin-left: auto" | ||
| title="Export code as Python file"> | ||
| <i class="download icon"></i> | ||
| </button> | ||
| </div> | ||
|
|
||
| <!-- File Upload--> | ||
| <input type="file" id="file_handler" style="display: none" /> | ||
| <div style="position: absolute; right: 5px; top: 260px; z-index: 100"> | ||
| <button id="bluetooth" class="huge circular ui blue icon button" style="display: inherit; margin-left: auto"> | ||
| <i class="bluetooth icon"></i> | ||
| </button> | ||
| </div> |
There was a problem hiding this comment.
The new Export and Bluetooth buttons are both positioned at top: 260px, so they will overlap and one will be unclickable depending on z-index/DOM order. Adjust the layout so each button has a unique position (or use a vertical button group) to avoid UI collision.
| # Activate the venv | ||
| echo "Activating virtual environment..." | ||
| source venv/Scripts/activate | ||
|
|
There was a problem hiding this comment.
This script is named setup-venv.sh but activates the venv using the Windows path (venv/Scripts/activate). On macOS/Linux the activation script is typically venv/bin/activate, so the current script will fail. Update it to detect platform/shell and use the correct activate path (and consider aligning the venv dir name with .venv used elsewhere).
Moving mech-dog updates to main repo