fix(sim): desktop QEMU sims use injected sidecar URL; fix nano-button-led wiring

- ESP32 / Raspberry Pi / STM32 / Pico-W bridges built their WebSocket URL
  from a bespoke API_BASE() that read only VITE_API_BASE (fallback
  localhost:8001) and ignored the desktop shell's runtime-injected
  window.__VELXIO_API_BASE__. On the desktop the sidecar runs on a random
  127.0.0.1 port, so the sim WebSocket dialed localhost:8001 and never
  connected: compile succeeded but the simulation never started. Honor
  __VELXIO_API_BASE__ first; web (/api) and dev (localhost:8001) unchanged.
- nano-button-led example: button was wired D2->1a and 1b->GND (same
  terminal), tying D2 to GND permanently. Rewire D2->1.l and GND->2.l
  (opposite terminals), matching the other examples.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
David Montero 2026-06-02 03:24:19 +02:00
parent 6c35a6ea7f
commit daa46c6724
5 changed files with 58 additions and 10 deletions

View File

@ -5026,7 +5026,7 @@ void loop() {
{
id: 'w-btn',
start: { componentId: 'arduino-uno', pinName: '2' },
end: { componentId: 'btn1', pinName: '1a' },
end: { componentId: 'btn1', pinName: '1.l' },
color: '#00aaff',
},
{
@ -5043,7 +5043,7 @@ void loop() {
},
{
id: 'w-btn-gnd',
start: { componentId: 'btn1', pinName: '1b' },
start: { componentId: 'btn1', pinName: '2.l' },
end: { componentId: 'arduino-uno', pinName: 'GND' },
color: '#000000',
},

View File

@ -48,8 +48,20 @@ export function toQemuBoardType(kind: BoardKind): 'esp32' | 'esp32-s3' | 'esp32-
return 'esp32'; // esp32, esp32-devkit-c-v4, esp32-cam, wemos-lolin32-lite
}
const API_BASE = (): string =>
(import.meta.env.VITE_API_BASE as string | undefined) ?? 'http://localhost:8001/api';
const API_BASE = (): string => {
// The desktop shell injects the sidecar URL at runtime (random port) via
// window.__VELXIO_API_BASE__; honor it first so the QEMU-board WebSocket
// reaches the local Python sidecar instead of the build-time / dev
// default. Without this, ESP32 / Pi / STM32 simulations never start in
// the desktop app (the WS dialed localhost:8001, not the sidecar port).
if (typeof window !== 'undefined') {
const injected = (window as { __VELXIO_API_BASE__?: string }).__VELXIO_API_BASE__;
if (typeof injected === 'string' && injected) {
return injected.replace(/\/+$/, '');
}
}
return (import.meta.env.VITE_API_BASE as string | undefined) ?? 'http://localhost:8001/api';
};
/** Returns a stable UUID for this browser tab (persists across reloads, resets on new tab). */
export function getTabSessionId(): string {

View File

@ -27,8 +27,20 @@
* { type: 'error', data: { message: string } }
*/
const API_BASE = (): string =>
(import.meta.env.VITE_API_BASE as string | undefined) ?? 'http://localhost:8001/api';
const API_BASE = (): string => {
// The desktop shell injects the sidecar URL at runtime (random port) via
// window.__VELXIO_API_BASE__; honor it first so the QEMU-board WebSocket
// reaches the local Python sidecar instead of the build-time / dev
// default. Without this, ESP32 / Pi / STM32 simulations never start in
// the desktop app (the WS dialed localhost:8001, not the sidecar port).
if (typeof window !== 'undefined') {
const injected = (window as { __VELXIO_API_BASE__?: string }).__VELXIO_API_BASE__;
if (typeof injected === 'string' && injected) {
return injected.replace(/\/+$/, '');
}
}
return (import.meta.env.VITE_API_BASE as string | undefined) ?? 'http://localhost:8001/api';
};
export class RaspberryPi3Bridge {
readonly boardId: string;

View File

@ -27,8 +27,20 @@
import type { BoardKind } from '../types/board';
import { generateUUID } from '../utils/uuid';
const API_BASE = (): string =>
(import.meta.env.VITE_API_BASE as string | undefined) ?? 'http://localhost:8001/api';
const API_BASE = (): string => {
// The desktop shell injects the sidecar URL at runtime (random port) via
// window.__VELXIO_API_BASE__; honor it first so the QEMU-board WebSocket
// reaches the local Python sidecar instead of the build-time / dev
// default. Without this, ESP32 / Pi / STM32 simulations never start in
// the desktop app (the WS dialed localhost:8001, not the sidecar port).
if (typeof window !== 'undefined') {
const injected = (window as { __VELXIO_API_BASE__?: string }).__VELXIO_API_BASE__;
if (typeof injected === 'string' && injected) {
return injected.replace(/\/+$/, '');
}
}
return (import.meta.env.VITE_API_BASE as string | undefined) ?? 'http://localhost:8001/api';
};
export function getTabSessionId(): string {
if (typeof sessionStorage === 'undefined') return generateUUID();

View File

@ -35,8 +35,20 @@ export interface WifiStatus {
export interface PacketOutFrame { ether: Uint8Array; }
export interface PacketInFrame { ether: Uint8Array; }
const API_BASE = (): string =>
(import.meta.env.VITE_API_BASE as string | undefined) ?? 'http://localhost:8001/api';
const API_BASE = (): string => {
// The desktop shell injects the sidecar URL at runtime (random port) via
// window.__VELXIO_API_BASE__; honor it first so the QEMU-board WebSocket
// reaches the local Python sidecar instead of the build-time / dev
// default. Without this, ESP32 / Pi / STM32 simulations never start in
// the desktop app (the WS dialed localhost:8001, not the sidecar port).
if (typeof window !== 'undefined') {
const injected = (window as { __VELXIO_API_BASE__?: string }).__VELXIO_API_BASE__;
if (typeof injected === 'string' && injected) {
return injected.replace(/\/+$/, '');
}
}
return (import.meta.env.VITE_API_BASE as string | undefined) ?? 'http://localhost:8001/api';
};
export class Cyw43Bridge {
readonly boardId: string;