Skip to content

pselvana/peloton-overlay

 
 

Repository files navigation

grupetto: workout data for Gen 2 Peloton Bikes Dougmeister

   

grupetto is an app that creates a system-wide overlay with live statistics about your ride:

Dougmeister

You can use it to watch media from sources like Netflix and Youtube while viewing your current power output, cadence, resistance, and speed.

Note: This project is wholly unaffiliated with Peloton. Please do not approach them for support with this app. It relies on undocumented interfaces that are subject to change with any update.

For developers: When forking this project, be sure to update the ReleaseChecker to point to your repository


Installation

grupetto must be side-loaded onto the Peloton, follow this guide to learn how to sideload an APK.

After following those steps, the APK for grupetto can be found on the Releases tab above.

Youtube instructions

Note: Gen 2 tablets might have additional hurdles solved by this when trying to authorize ADB connections:

@blairkenvin
Just as a heads up, it looks like there's another barrier that must've gotten added with a recent update.
When attempting to enable USB debugging I was getting an error message saying
"Because an app is obscuring a permission request, Settings can't verify your response".
In order to fix this, just go into Settings->Device Settings->Apps, click the gear in the top-right,
then go to Special Access->Draw over other apps, then unselect both apps that are checked.
You can then reconnect your USB cable, and enable USB debugging.
Make sure you check 'remember this device', and then immediately check both of the apps again.
After that you can then install any apps you want :)

Note: Unfortunately, sideloading functionality was recently locked behind a valid subscription. At the time of writing, once the overlay has been installed its continued function is not tied to a subscription. (this is subject to change). A factory reset may enable the functionality; it may also be available after the first update completes and before the bike is shutdown.

Local Development

The app can be built and run on a standard Android emulator without any Peloton hardware. When not running on a Peloton device, it automatically uses a built-in DummySensorInterface that generates synthetic sine-wave data (~200W power, ~150 RPM cadence, ~110 resistance), so the full UI can be exercised locally.

Prerequisites

1. Android Studio

Download and install Android Studio. It includes the Android SDK, emulator, and build tools. On first open, it will prompt you to install any missing SDK components.

2. JDK 11

The project requires JDK 11. Check your version with java -version.

  • macOS (Homebrew): brew install temurin@11
  • Other: Download from Adoptium

After installing, configure Android Studio to use it: Preferences → Build, Execution, Deployment → Build Tools → Gradle → Gradle JDK → select JDK 11

3. Android SDK Components

Install these via Android Studio → SDK Manager:

  • SDK Platform: API 33 (Android 13)
  • Build Tools: 33.x.x
  • Android Emulator + system image for API 33

Minimum supported API is 24 (Android 7.0), so any emulator image API 24+ will work, though API 33 is recommended.

Build & Run

Open the project

Open the project root in Android Studio and wait for Gradle sync to complete. All library dependencies are downloaded automatically — no manual installation needed. The Gradle 7.5 wrapper (gradlew) is included, so no separate Gradle install is required.

Create an emulator (AVD)

  1. Tools → Device Manager → Create Virtual Device
  2. Select any phone hardware profile (e.g. Pixel 6)
  3. Choose system image: API 33 (Android 13) — download it if not already present
  4. Finish and launch the emulator

Run the app

  • In Android Studio: select the emulator as the target device and click Run (▶)
  • Or from the terminal:
./gradlew assembleDebug
adb install app/build/outputs/apk/debug/app-debug.apk

Granting the Overlay Permission

SYSTEM_ALERT_WINDOW (Draw over other apps) is required for the overlay to function. On first launch the app will redirect you to Android Settings to grant it. Alternatively, grant it via ADB:

adb shell appops set com.spop.poverlay SYSTEM_ALERT_WINDOW allow

Notes

  • No secrets needed for debug builds. The keystore environment variables (KEYSTORE_PASSWORD, KEY_ALIAS, KEY_PASSWORD) are only required for release builds.
  • Fake sensor data is automatic. The app checks Build.BRAND == "Peloton" at runtime; on any other device or emulator it falls back to DummySensorInterface with no configuration needed.

Usage

  • When first run, grupetto will ask for permission to draw over other apps. This permission is required for the app to function.

Permissions Screenshot

  • By default the overlay is shown in its expanded form.

    Pressing and holding on power graph will shrink it, and the overlay be dragged around the screen to position it:

Example of Dragging Overlay

  • Clicking once on either edge of the overlay enters minimized mode. In this mode the overlay can no longer be relocated, but it continues to show updated values. Click on it again to re-enter the exapnded mode

Minimized Mode Gif Minimized Mode Static

  • The timer can only be controlled in expanded mode. Click once on the timer to start it. Click again to pause, and hold down for 3 seconds to restart it. There is a configuration option on the main screen to show or hide the timer when minimized

Shows Timer Operation

Implementation

Getting access to sensor data

Exploring SerialPort

This project was greatly helped by the work done by @ihaque on the Pelomon project: https://ihaque.org/tag/pelomon.html

My initial attempt was to directly interface with the serial port via the SerialPort API (which would rely on reflection). But the OS is locked down quite extensively, and there was no clear way for a non-system app to access the serial port directly. Additionally there is no (known) way to get a system application onto the bike, which heavily limits our options, as many permissions used internally are marked as system level permissions.

I explored trying to leverage the built-in updater services, but it seems unlikely that there is no verification of installed packages, and they are also likely behind similar system level permissions to the serial port.

Establishing system service connection

After establishing the direct-access method was a non-starter, there I pulled APKs from my production Generation 2 bike and decompiled them via JADX. They were heavily obfuscated, but using the Pelomon project as a reference, I was able to track down an internal system service that provides communication with a Generation 2 bike.

By leveraging that system service, we're able to "leapfrog" the restriction on direct access, since technically the internal system service is accessing the Serial Port, not our application.

This also provides an ergonomic interface to build against (all the serial port resource handling is done for us), but drastically increases the odds of this being broken by an update.


I also explored a backup approach by using reflection to instantiate internal classes and manipulate their APIs, but it's a much tricker approach since we're running any code found under the current app's UID (meaning anything that was locked off to system-apps

Android App Architecture

Grupetto is an example of implementing a system service with a rich UI. Jetpack Compose was leveraged for rapid iteration.

A service acts as a LifecycleOwner to provide the scaffolding Compose expects outside of a normal activity (see LifecycleEnabledService.kt)

Due to the nature of this project relying on an undocumented interface that may break without notice, effort that has been put into organization of the composables themselves is somewhat limited, and I would not use them as a reference for what a well-built Compose app looks like

However, the patterns used to provide them with data are generally sound, and could be used as a reference for how a Service can provide data for a complex UI

Other hardware

The app is intentionally designed to not necessarily rely on data from the Peloton. The app could be expanded to support other tablets and sensor sources, such as ANT+ power meters.

Reporting Issues

Please do not approach Peloton with issues related to this. They have no duty to support a reverse engineered service.

Please use the Github issue tab, and mention which version of the OS you're running if possible ( this is displayed at the bottom of screen before the overlay is started)

Unimplemented features

I've limited this project's scope due to the fact it could easily be broken by an update.

Features I would consider out-of-scope are mostly related to workout session tracking, and interfacing directly with other apps.

What's with the name?

https://en.wikipedia.org/wiki/Autobus_(cycling)

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • Kotlin 88.5%
  • Java 11.5%