Riders Hub is an independent, open-source Android ride companion for electric skateboards. It records board telemetry locally, presents current and past ride information, and uses Android's companion-device support for low-power background detection.
The first supported hardware integration is for compatible Backfire boards and
their BF_* remotes. The project is designed as Riders Hub—not as an official
Backfire application or a product tied to that brand.
Riders Hub is an independent community project. Its authors and contributors are not affiliated with, associated with, sponsored by, or endorsed by Backfire or Backfire Boards. Backfire does not provide support for this software. Backfire and related product names and trademarks belong to their respective owners.
- Board battery percentage, pack voltage, odometer, and a confidence-labelled remaining-range estimate.
- Current-trip distance, moving time, top speed, five-kilometre-per-hour speed buckets, and recent ride summaries.
- Automatic background detection through Android's Companion Device Manager, without a permanent foreground service or continuous custom scanning.
- Short-disconnect continuity: reconnecting within two minutes resumes the same logical ride and telemetry log.
- A configurable low-board-battery warning and notification, with a 20% default and five-point adjustment steps.
- Local ride archives that preserve decoded telemetry and original BLE frames in compact, verified files.
- Battery Longevity tracking with a speed-normalized full-charge estimate, observed charge windows, and an adaptive daily-to-yearly capacity chart.
- Optional self-hosted API channels for core metrics, one-hertz live speed/GPS, and consent-gated raw archive synchronization.
- Optional Shelly Plus Plug S Gen2 observation with confirmation-only charger start/stop, power-based safety cutoffs, and a separate local evidence archive.
- A Wear OS companion dashboard for live speed, board battery, trip distance, estimated remaining range, and ride mode, with clearly subdued last-known values while disconnected.
A separate remote-battery field has not been identified, so Riders Hub shows that value as unavailable instead of presenting an inferred reading.
Riders Hub's visual language is inspired by Nothing's product design: a high-contrast monochrome palette, dot-matrix typography, generous open space, modular information, and restrained red accents for state and warnings. It is an independent interpretation and is not affiliated with or endorsed by Nothing Technology.
The launcher uses the same longboard mark for its regular, round, and Android themed-icon variants. The launch screen and system bars remain black so startup matches the dashboard instead of flashing a light background.
The current adapter connects to the remote, not directly to the skateboard
ESC. The remote must already be connected to the board and advertising with a
name beginning with BF_.
Charger observation is a separate integration for a stock Shelly Plus Plug S Gen2 with BLE RPC enabled. Presence alone never energizes the outlet. This first test version still requires physical validation with the intended plug and charger before its automatic completion behavior should be relied on.
The Backfire G3 is the only board tested so far, which is why the UI displays
G3; Riders Hub should also work with boards using second-generation or newer
black-plastic remotes with the index-finger opening, but those combinations
remain unverified. The BLE transport and core telemetry fields are also
corroborated by community work on a Zealot S, but other board and remote
revisions may differ.
See the BLE API notes for the current protocol details, confidence levels, and known unknowns.
Riders Hub's normal operation subscribes to telemetry notifications from the paired remote.
Charger control is experimental. Keep the charger and board on a nonflammable, well-ventilated surface and do not leave the first physical tests unattended. The app uses a 12-hour plug-side automatic-off request as a backstop, not as a substitute for the charger's own protections or supervision.
This project is experimental and is based on community and independent reverse engineering. Keep the board's drive wheels clear of the ground during physical testing.
- Associate a supported remote once through Android's system chooser.
- Android watches for that device while Riders Hub is closed.
- When the remote appears, the companion service connects and records telemetry.
- When the remote leaves, BLE work stops. A reconnect within two minutes continues the same ride; otherwise Android finalizes it with a one-shot alarm.
BLE detection does not require an activity, custom BLE scanner, wake lock, or permanent foreground notification. Opt-in API GPS uses a location foreground service during the logical ride, and durable API uploads use WorkManager.
Range estimates the kilometres remaining at the current battery level. Its bar shows how much useful ride data supports the estimate—not battery level or distance. An estimate appears after a usable 5% battery-depletion window and at least 1 km, and becomes Ready after 20 km and 10%. Between rides it uses the common speed-bucket distribution of the latest 100 km; during a ride it adapts to that ride's accumulated speed mix.
Battery Longevity compares speed-normalized kilometres per full charge over inferred charging cycles. It needs at least 0.5 km and 5% battery use for a data point. The chart starts daily; pinch to group by week, month, or year, and tap a bar to inspect it more closely. Local voltage statistics support future analysis, but these estimates are not a measured capacity or battery-health diagnosis.
After each ride, Riders Hub moves the complete log into a local archive. Archive files are compressed and verified at roughly 10 MiB or when the paired remote changes; existing rides are never overwritten. Interrupted final writes are ignored without losing earlier entries.
Archives contain ride data and a device identifier, so exported files are sensitive. See the Android app guide for the technical format.
The optional integration targets any server implementing the published v1 contract. Configure one base URL and sign in through the server's OIDC provider under Device → Self-hosted API. The app uses browser Authorization Code + PKCE and exchanges the short-lived access token for a source-bound device credential. A legacy bearer key remains available for migration. Capability discovery enables metrics, realtime, and analytics independently. HTTPS/WSS is preferred; HTTP/WS requires explicit confirmation and remains visibly marked as unencrypted.
Core snapshots are best-effort every ten seconds while riding, while ride start and end events use a durable SQLite outbox. Realtime sends only the newest frame at most once per second. Optional precise GPS follows the logical ride through the reconnect grace period. Raw RHA and charger-observation synchronization share separate explicit consent scoped to both the URL and authenticated server identity. Charger COA files use their own endpoint and durable delivery ledger; they are never mixed into ride archives.
See the HTTP contract, WebSocket contract, and server implementer guide.
The API integration is off until configured. Its base URL and device or legacy bearer credential are encrypted at rest with Android Keystore and excluded from backup. OIDC access tokens are used only for registration and are not persisted. Decoded API messages use random export identifiers and never include Bluetooth names, addresses, local paths, raw bytes, or non-finite measurements.
GPS is separately off by default and requires precise foreground plus background location permission. While enabled for an active ride, a location foreground service shows a persistent notification. Full fixes enter the local raw archive; the realtime projection contains only fix time, coordinates, and optional altitude. Raw archive uploads require a separate per-destination disclosure because RHA data can include device identifiers, exact activity times, frames, diagnostics, and full GPS records.
Charger COA files contain exact observation times, generated identifiers, decisions, relay state, power and protection evidence. They exclude BLE/Wi-Fi identifiers and raw Shelly RPC, remain local unless the same raw-analytics consent is approved, and are retained until explicitly deleted.
The optional Wear OS companion receives only connection state, live speed, board battery, current trip distance, the phone's aggregate estimated remaining range, ride mode, and the update time through Google's private paired-device Data Layer. Bluetooth addresses, remote names, odometer totals, ride history, locations, and raw telemetry are not sent to the watch.
Exported logs can contain ride data and a stable Bluetooth address. Local captures, signing material, and build outputs are ignored by Git; review any file carefully before forcing it into a public commit.
- Android 14 or newer
- Wear OS 3 or newer for the optional watch companion
- A compatible board and Bluetooth remote
- JDK 17 or newer for development
- Android SDK API 36 for building
./gradlew testDebugUnitTest lintDebug assembleDebug
adb -s PHONE_SERIAL install -r app/build/outputs/apk/debug/app-debug.apk
adb -s WATCH_SERIAL install -r wear/build/outputs/apk/debug/wear-debug.apkThe application ID is at.themrcodes.ridershub. Installation, association,
lifecycle details, log extraction, and the JSONL schema are documented in the
Android app guide.
The watch build is a non-standalone companion and uses the same application ID as the phone build. For Google Play distribution, publish both form-factor artifacts under the same listing and signing key. Modern Wear OS installs its artifact through Play on the compatible watch; a directly sideloaded phone APK does not embed or automatically sideload the watch APK.
- Open the repository root in Android Studio and let the Gradle sync finish.
- On the watch, enable ADB debugging and Wireless debugging under Developer options. The watch and workstation must be on the same Wi-Fi network.
- Pair the watch with the workstation. When pairing manually, use the address
under Pair new device only with
adb pair. Then use the separate address on the main Wireless debugging screen withadb connect. - Select the shared Riders Hub - Watch run configuration and the watch in Android Studio's target-device menu, then click Run.
Android Studio builds :wear:assembleDebug, installs the watch APK, and starts
the launcher activity. To test real phone-to-watch data, install :app on the
paired phone from the same checkout so both debug APKs use the same signing
certificate. Wear OS 3 and newer does not support ADB debugging through the
phone's Bluetooth connection; deployment requires a direct Wi-Fi or supported
USB ADB connection to the watch.
During an active ride, the watch posts a low-priority Ongoing Activity after notification permission is granted. This keeps the dashboard available through the system's second inactivity timeout. Ambient mode redraws only on the Wear OS minute tick, buffers faster phone updates between ticks, and shows only current trip kilometres, board battery, and estimated kilometres remaining. Devices that request burn-in protection receive a small four-position layout shift. Swipe sideways to the gear page to optionally keep the live dashboard awake during active rides instead; this uses more battery and does not enter ambient mode until the ride is no longer active.
The watch listens for telemetry through a narrowly filtered Data Layer service and stores only the latest privacy-minimized payload. Phone updates can wake the watch app while its dashboard is backgrounded, and a recreated dashboard restores that last state without a continuously running foreground service.
The debug Wear APK includes an ADB-only synthetic telemetry receiver. It is
protected by Android's DUMP permission and is not compiled into release
artifacts. With the debug APK running on a watch emulator, inject a live sample:
adb -s WATCH_SERIAL shell am broadcast \
-n at.themrcodes.ridershub/at.themrcodes.ridershub.wear.SyntheticTelemetryReceiver \
-a at.themrcodes.ridershub.wear.DEBUG_TELEMETRY \
--es connection LIVE \
--ef speed_kmh 24.5 \
--ei battery_percent 78 \
--ef trip_km 4.25 \
--ef estimated_range_km 12.75 \
--es mode SPORTUse RECONNECTING for connection to verify retained-but-dimmed values, add
--el age_ms 60000 to a LIVE sample to verify the stale-update state, or
send --ez clear true to restore the waiting-for-phone state.
Debug phone APKs also include an ADB-only sender for checking the real paired device Data Layer without producing a ride record:
adb -s PHONE_SERIAL shell am broadcast \
-n at.themrcodes.ridershub/at.themrcodes.ridershub.WearDataLayerTestReceiver \
-a at.themrcodes.ridershub.DEBUG_WEAR_TELEMETRYIt publishes fixed synthetic values through the production telemetry path. To
remove the test item afterward, repeat the command with --ez clear true.
The receiver and sample values are absent from release builds.
app/contains the Android application, resources, and JVM tests.wear/contains the Wear OS dashboard.wear-shared/contains the versioned, privacy-minimized phone-to-watch telemetry contract.gradle/and the root Gradle files provide the reproducible build.docs/contains protocol evidence, lifecycle documentation, and capture analysis.
- Android app, lifecycle, and log schema
- Backfire BLE API and evidence levels
- Moving telemetry capture analysis
Special thanks to the community-maintained Swift project
djensenius/Backfire for documenting
the Backfire BLE interface. Its findings about the F1 transport and telemetry
frame fields provided important groundwork that was reused and independently
validated in Riders Hub. The project's
protocol issue #26 also
documents the 25-byte frame reassembly, multi-byte fields, odometer, voltage,
and CRC-16/MODBUS behavior.
Riders Hub is professionally vibe-coded: it is developed with AI assistance under professional software-engineering oversight, but remains a side project. It may contain bugs, incorrect assumptions, or security issues. Please review it carefully, report problems responsibly, and—if you have the time—help make it better. Contributions and support are always appreciated. ❤️
Riders Hub is available under the MIT License. Dependency licensing is listed in Third-party notices.
0 comments
log in to comment.