Jump to content

Reverse Engineering Bluetooth Data for fun

super_teabag

Hey all!

 

This isn't a "hey please help I've fallen and can't get up" kind of post, but rather one that's imho dense with computer science topics. 

My hope is that it will genuinely peek someone's interest in computer science, programming, reverse engineering and genuinely inspire people.

 

Any who, recently got this exercise bike with Bluetooth functionality, right. now I didn't want to pay oodles of money a month for some fitness app.

So, I was like "I can write my own and it'll work on all my devices"... at least that's the goal.

 

Starting out I had to connect to the bike's Bluetooth with the caveat being I wanted to do this using a web browser then leverage PWAs (progressive web apps) to install on any of my devices with this very basic exercise app.

Learned there's an experimental standard for Bluetooth available on 

navigator.bluetooth

 

Connecting to the bike was relatively easy. I used a Bluetooth discovery app on my phone to figure out what "services" were available on the bike's Bluetooth server.

It got a little tricky as the data I would get back from the Bluetooth device was 88 bits, or 11 bytes. With no indication of endianess, and no headers were on the data to see where things may be in this arbitrary bundle of bites.

 

I thereby devised a plan to log the data and see where it changed and using the Bluetooth and with the assistance of Bluetooth discovery apps I learned roughly what the shape of the data would be 

thing.PNG

 

In the highlighted area, I knew that wheel rev, last crank even time, last wheel event time, and crank revolutions would be 16 bit unsigned numbers. Why? Because as I pedaled the bike what my app would read was "rolling over"

a concept that instead of continuing to count past 16 bits of information. The bike instead resets to 0

 

Now, where in that 88 bit payload were these 16 bit unsigned numbers? Well, I did some logging of the information which you can see from the included text file of my log.

Using that I deduced where about 4 of these numbers were in the payload as they also lined up with my Bluetooth sniffing application told me.

 

The following is what gives me the correct data readout from my bike on the web! Now, I have to do some math to calculate RPM and KPH or MPH.

 

	private readonly parseCadenceWheelSpeedWheelTime = (event: { target: { value: DataView } }) => {
		const { value: dataView } = event?.target;
		const littleEndian = true;
		// wheel revolutions in unsigned 16 bit numbers.
		this.wheelRevolutions$.next(dataView.getUint32(1, littleEndian));
		// last wheel event time in unsigned 16 bit numbers.
		this.lastWheelEventTime$.next(dataView.getUint16(5, littleEndian));
		// amount of times the wheel went around in unsigned 16 bit numbers.
		this.crankRevolutions$.next(dataView.getUint16(7, littleEndian));
		// last crank event time in unsigned 16 bit numbers.
		this.lastCrankEventTime$.next(dataView.getUint16(9, littleEndian));
	};

 

 

bluetooth-logging.txt

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×