Reputation: 49
I am building an app with the Flutter framework that would benefit from being able to pull data from various fitness devices including Fitness Machines. I'm using Flutter Blue Plus to search for devices and subscribe to characteristics. At my local GYM I encountered 4 machines whose Fitness Machine Characteristic Data does not match the Specification from the Bluetooth SIG. All the machines were made by Star Trac and I believe the machines are older/cheaper models. The machines include a Treadmill, Elliptical, Upright Bike, and a Recumbent Bike.
As far as I know I followed the standard documentation, read the Flag Data and used it to parse the raw data for the individual features. So now I have turned off my original data extraction and altered my app to collect Raw Data. I then tried it out by doing a retest with a treadmill on a real workout where I changed both speed and elevation to get as much of the Octets to have non-zero data as possible. I also took pictures of the machine display. I got 3449 data points and was able to match up the Raw Data to the different Treadmill Data Fields and according to the Standard BLE Documentation the data I received should have had 34 octets but only 32 octets were sent in each transmission, further the flag bit 0 was 0.
The flags octets were 254, 23 ( or 0x17FE in hex ) across all 3449 data points.
I was able to match up Octets 3 to 15 as Instantaneous Speed, Average Speed, Total Distance, Inclination, Ramp Angle, and Positive Elevation Gain which agrees with the standard.
However, I was also able to match up Octets 20 to Octets 32 as Total Energy, Energy/Hour, Energy/Minute, Heart Rate, Metabolic Equivalent, Elapsed Time, Force on Belt, and Power output and according to the standard this data is coming four octets early but at least in the expected order.
I cannot determine what Octets 16, 17, 18, and 19 are actually doing because my values were 0 in every data point . According to the standard these four Octets should contain Negative Elevation Gain (2 octets), Instantaneous Pace (2 Octets), and Average Pace (2 Octets). But 6 octets is not 4 octets.
So if anyone reading this has experience obtaining data from the BLE Fitness Machine Service ( especially Treadmills ... extra especially Treadmills made by Star Trac ) will you please share some of you knowledge and experience about what is causing the data discrepancy.
Is the machine not following the standard, or is the standard documentation that is online right now not actually correct, or am I just missing something?
Upvotes: 0
Views: 244
Reputation: 49
I have determined the source of the irregularities in the treadmill data as well as some of the irregularities in the bikes and elliptical.
So apparently way back in 2017 (please remember I am very new to all this still ) Bluetooth SIG put out XML files describing the standard and they have what might be called errors in the description of the standard. I found these XML files via a conversation following a Blog post by James Taylor (https://jjmtaylor.com/post/fitness-machine-service-ftms/).
In case you've never seen these XML files here is a link: https://github.com/oesmith/gatt-xml
So the treadmills in question are following the standard in those XML files, specifically the Treadmills are using one uint8 octet for Instantaneous Pace and one unit8 octet for Average Pace. The standard (as published today) is to use a uint16 (in two octets) for each of those. I programmed my app to follow today's published standard so I got less data than I expected. Though the treadmills do report Pace measurements on their screens this data is not actually transmitted in the TreadmillData Characteristic, the Pace octets are always 0. That's not a big deal for my application but it might be for someone else's.
Now Here are some other things I've learned in this process:
I also learned that in the 2017 xml documents, Resistance is said to be sint16 delivered in 2 octets with a precision of 0.1 but in the published standard of today it is a unitless uint8 delivered in 1 octet. The elliptical and bikes at my Gym both follow the 2017 xml document.
There is an egregious error in the 2017 xml document for IndoorBikeData. I have heard about this bug a few times as I've scoured the internet but now I've seen it. The document simultaneously says the "Flag Bit 1 means Inst. Cadence Present and Flag Bit 2 means Avg. Speed Present" in the "Flag" section and "Inst. Cadence requires Bit 2 while Avg. Speed required Bit 1" in the remaining field sections. I'm pretty sure that's a Grand Father Paradox.
Testing the bikes at my Gym with both the FlutterBluePlus Sample App and nRF Connect (thanks again ukBaz). I received IndoorBikeData in two packets. The first packet had a 1 in Flag Bit 1 and 0 in Flag Bit 2. The second packet had a 0 in Flag Bit 1 and a 1 in Flag Bit 2. By the published standard of today, that means Average Cadence should have been in the first packet and Inst. Cadence should have been in the second packet. But what I actually got from both tests was that Inst. Cadence followed by Average Cadence were both in that first packet and the second packet contained no Cadence information. This means the first packet is longer than what is expected and the 2nd packet is shorter than what is expected. I'm not sure why the makers of the Bikes originally did this.
nRF Connect did not have any trouble with the Treadmills that I could tell, so I believe it has accounted for the discrepancy with the Pace values.
On the elliptical nRF was reporting Resistance values that were scaled up by 10 compared to what the machine's screen said. I also noticed this in the Raw data from the FlutterBluePlus sample app. This makes sense, as in the 2017 xml docs it says that is value is given in 0.1 precision so a resistance of 2 on the machine would be 20 in the Bluetooth data. So nRF is not away of this discrepancy in the precision, though it must be aware of the size discrepancy as the remaining entries were all correct.
On the bikes nRF reported "invalid data characteristic" on packets with with FlagBit 2 set to 1 and it had messed up data for packets with FlagBit 1 set 1, specifically the total distance were huge values as a results of being calculated from the wrong octets. So it confirmed that the Bluetooth data coming out these Bikes is just not right and it appears to be unaware of what this kind of of data is supposed to look like. I also notice that inst. and average speed in the Bluetooth data appears to be non-sensical and does not match what the bike's screen reported.
So I'm happy that I know why most of the data is weird now but I don't really yet know where to go from here. Its unsettling to know that there are probably a lot of machines that don't follow the standard and are also not going to get updated or repaired to match that standard. So if want my app to be useable to anyone then I have to find a way to accommodate the incorrectly formatted data.
If anyone would like to see data from my tests I have multiple spread sheets, screen shots, and video recordings. Feel free to ask.
I hope my experience helps someone in the future.
Upvotes: 2