# 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 1. **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. 2. **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. 3. **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_disconnected` to 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 ```bash 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