A web-based remote control for a "deadrail" (battery-powered, DCC-free) model train engine. It connects directly to the engine's onboard controller over Bluetooth Low Energy (BLE) using the Web Bluetooth API — no app install required, just a browser.
- Wireless control over BLE — start/stop, speed up/down, direction, and emergency shutdown
- Live status display (speed and direction) via BLE notifications
- Connection log showing BLE events and raw TX messages for debugging
- React 19
- Vite for dev server and bundling
- Web Bluetooth API for BLE communication (no external BLE libraries)
- Node.js and npm
- A browser with Web Bluetooth support (Chrome or Edge on desktop/Android). Web Bluetooth is not supported in Safari or Firefox.
- Web Bluetooth requires a secure context —
localhostworks for local dev, otherwise the app must be served over HTTPS (e.g. the Vercel deployment). - An engine controller advertising a BLE GATT service with the UUIDs below.
npm install
npm run devThen open the dev server URL in a supported browser, click Connect to Engine, and select your device from the browser's Bluetooth pairing prompt.
Other scripts:
npm run build # production build
npm run preview # preview the production build locally
npm run lint # run ESLintThe app expects a GATT service (a Nordic UART Service-style UUID) exposing three characteristics, defined in src/ble.js:
| Characteristic | UUID | Direction | Purpose |
|---|---|---|---|
| RX | 6e400002-b5a3-f393-e0a9-e50e24dcca9e |
App → Engine | Write plain-text commands |
| TX | 6e400003-b5a3-f393-e0a9-e50e24dcca9e |
Engine → App | Notify with debug/log text |
| STATUS | 6e400004-b5a3-f393-e0a9-e50e24dcca9e |
Engine → App | Read/notify JSON { speed, direction } |
Commands sent on RX (see src/components/Controls.jsx):
START/STOPINC/DEC(speed step up/down)FORWARD/REVERSESHUTDOWN
src/
App.jsx # BLE connection lifecycle and top-level layout
ble.js # GATT service/characteristic UUIDs
components/
Controls.jsx # Command buttons
StatusPanel.jsx # Live speed/direction display
This project is configured for Vercel (see .vercel/). Since Web Bluetooth requires HTTPS, deploying to Vercel (or any HTTPS host) is required for use outside of localhost.
- The Hidden Quirks of Web Bluetooth on the Raspberry Pi Pico — gotchas encountered when implementing the BLE peripheral side on a Pico, relevant if the engine controller is Pico-based.