Inspiration

My Mobi (莫比) elliptical has no resistance buttons. Resistance can only be changed from the Mobi app, which requires a login. Mobi closed and the servers went with it, so a machine worth thousands of yuan became a fixed-resistance exerciser. Many other owners are in the same situation. I had already written a small app that could connect, but resistance never behaved.

What it does

  • Connects to Mobi ellipticals over Bluetooth LE with no account and no internet.
  • Detects which of the four Mobi control boards the machine uses, in the same order as the official app.
  • Controls resistance with the exact commands the official app sent, and shows the level the machine reports back.
  • Tracks each workout: time, distance, calories, heart rate, cadence, averages and history, using the official formulas plus guards against over-counting.
  • Demo mode simulates a machine so anyone can try it without the hardware.

How I built it

Entirely in Kiro. A vibe session decompiled both versions of the official APK (3.5.9.1 and 4.5.17) with jadx and traced the obfuscated BLE layer. The findings became specs, steering files and hooks, and drove the Android implementation. See docs/KIRO_USAGE.md.

Challenges

  • Each control board changes resistance differently:
    • an unlock write plus a "decimal digit count" byte on the 2.0 box;
    • bytes echoed from the machine's own last frame on the 1.0 box;
    • a mandatory 1 Hz keep-alive on the HuanTong board;
    • a one-byte ×10 value over FTMS, with non-standard 2-byte data flags.
  • Android silently drops a GATT write issued before the previous one finishes, so everything goes through a serialized queue.
  • Calories: the official "old" formula reaches ~25 kcal/min at high levels, and accumulating per notification multiplies totals. The tracker integrates once per second from real elapsed time, ignores stale cadence, and adds only the increments of machine counters.

Accomplishments

  • One app covers four protocols, and every byte format is traced back to a location in the decompiled source.
  • The machine works again without the vendor.

What I learned

  • In reverse-engineering, the bugs hide in "obvious" details. The length byte turned out to be a digit count, and a constant was an ICU symbol the compiler reused.
  • Specs are most useful right after exploration, to turn discoveries into checkable commitments.

What's next

  • Test on more Mobi models with other owners, using the copyable GATT log.
  • A foreground service so the HuanTong keep-alive survives the screen turning off.

Built With

Share this project:

Updates

Submission history