4.2 KiB
CLAUDE.md — OpusBike
Project P-000014 · Company C-000001 (ProActys GmbH) Live: https://monitor.proactys.swiss/opusbike/
What is this
PWA webapp that connects to a Bosch Smart System eBike via Web Bluetooth and displays live telemetry: Speed, Torque, Ride Time, Total Kilometer, Mode (OFF/ECO/TOUR/eMTB/TURBO).
Architecture
/opt/opusbike/
├── webapp/ Static PWA (HTML/CSS/JS, no framework)
│ ├── index.html Single page — connect view + ride dashboard
│ ├── manifest.json PWA manifest (start_url: ".", scope: ".")
│ ├── css/style.css Brand-compliant styling
│ ├── js/
│ │ ├── app.js Main UI logic + Demo mode
│ │ ├── bleService.js Web Bluetooth connection to Bosch
│ │ ├── boschProtocol.js Bosch BLE protocol decoder (varint TLV)
│ │ ├── wsRelay.js WebSocket relay client (source/viewer)
│ │ ├── sw.js Service worker (cache-first)
│ │ └── qrcode.js Inline QR code generator
│ └── icons/ PWA icons (192, 512, apple-touch, favicon.svg)
├── server/
│ ├── relay.js Node.js WebSocket relay (ws library, port 3030)
│ └── package.json
├── Dockerfile nginx:alpine serving /usr/share/nginx/html on port 8080
├── Dockerfile.relay Node 20 alpine running relay.js on port 3030
├── docker-compose.yml Two services: nginx + relay, network: shared
└── nginx.conf Static file serving config
How it works
Three connection modes
-
Direct BLE — Chrome (desktop/Android) or Bluefy (iOS) connects directly to the Bosch Smart System via Web Bluetooth. Data is also forwarded to the WS relay for other viewers.
-
WebSocket Relay — Devices without Web Bluetooth (Safari, Firefox) auto-connect to the relay as viewers. They see the same live dashboard streamed from the BLE source.
-
Demo Mode — Simulates realistic riding data. Also broadcasts via WS relay so all connected devices see the demo.
iOS / iPhone support
Safari does NOT support Web Bluetooth. The app detects iOS and shows a banner recommending Bluefy (free App Store app) which adds Web Bluetooth to iOS. URL: https://apps.apple.com/app/bluefy-web-ble-browser/id1492822055
Once Bluefy is installed, open https://monitor.proactys.swiss/opusbike/ in Bluefy → tap "Connect via Bluetooth" → pair with the Bosch system → ride.
Bosch BLE Protocol
- Service UUID:
0000fee7-0000-1000-8000-00805f9b34fb - Characteristic UUID:
00000011-0000-1000-8000-00805f9b34fb - Encoding: varint TLV (tag 0x01=speed/10, 0x02=torque, 0x03=totalKm/1000, 0x04=mode)
- Filter names:
smart system,Bosch,BRC
WebSocket relay protocol
- URL:
wss://monitor.proactys.swiss/opusbike/ws - Register:
{ type: "register", role: "source" | "viewer" } - Telemetry:
{ type: "telemetry", data: { speed, torque, totalKm, mode } } - Server broadcasts:
source_connected,source_disconnectedto viewers
Caddy routing (in /home/ubuntu/monitoring/Caddyfile)
monitor.proactys.swiss {
handle /opusbike/ws → opusbike-relay:3030 (WebSocket)
handle_path /opusbike/* → opusbike-nginx:8080 (static, prefix stripped)
handle → gitea:3000 (Gitea at root)
}
Deploy
cd /opt/opusbike
docker compose up -d --build # rebuild both containers
docker restart monitoring-proxy-1 # reload Caddy (bind mount inode issue)
Important: After editing the Caddyfile, you MUST docker restart monitoring-proxy-1 (not just caddy reload) because the Edit tool creates a new file inode which breaks the bind mount.
Brand
- Skill S-000007 (ProActys brand charter)
- Colors: Primary #4285F4, Dark #364052, Navy #051229, Ice #E1E8F0
- Font: Segoe UI, Arial, Helvetica, sans-serif
- Always: capital P capital A in "ProActys"
TODO / Known issues
- Bosch BLE protocol needs real-device validation (UUIDs + TLV tags are estimated)
- Test Bluefy on real iPhone + real Bosch Smart System
- Add battery level if available in BLE data
- Add cadence (RPM) if available
- Consider adding ride history / local storage