Keiser® M3i

Development Guide for the M3i Bluetooth Smart enabled bike.

Changes Increases broadcast rate to overcome scan latency issues.

The Keiser M3i offers the ability for any Bluetooth® Smart Ready device to receive data from the bike detailing the current rider’s performance. The information can be used for supplemental real time data, performance tracking, group training, or even caloric burn tracking.

Transmission

The Keiser M3i’s Bluetooth® radio utilizes the 4.0 specification for Low Energy devices and operates in a TX-only mode. This allows the bike to communicate with more than one device simultaneously, as well as allowing the bike to use less power.

The transmission from the bike is a non-connectible unidirectional advertisement packet set to transmit the bikes current statistics once every 357 milliseconds. Bike versions previous to 6.30 use a broadcast period of 2 seconds, but this was changed in version 6.30 to overcome issues with detecting broadcasts on devices using shared antennas. The broadcast is non-connectible and will therefore not be visible to most applications using Bluetooth® pairing designed for GATT devices. The broadcast is only visible while performing a Low Energy scan, so the recommendation is to perform a scan on a small window around the expected transmission period. The capability to perform a Low Energy scan is not yet available on all devices and platforms, but has been adopted by Apple for use in the iBeacon technology, which will likely push the adoption on platforms that do not yet support it.

Platform Notes

iOS: Bluetooth Smart is supported by iOS SDK versions 5.0 and greater. Due to the energy management built into the Core Bluetooth API, running a continuous scan will often result in intermittent reception of data. The best approach for working with iOS is to toggle the scan after the receipt of a packet from the targeted device.

OnNewPacket(data){
    if (IsTargetDevice(data)){
        StopScan();
        StartScan();
        RecordData(data);
    }
}

Android: Bluetooth Smart is supported on Android versions 4.4 and greater. There is an API break at version 5.0, and due to the number of issues with the Bluetooth LE portion of Bluedroid it is recommended to target platforms 5.0+.

Broadcast Packet Data Structure

The bikes data is held in the body of the advertisement broadcast, in the section designated for advertising data. Most Bluetooth® APIs will extrapolate this data from the full broadcast packet and may make it available as a byte array. The advertising packet also includes a six byte advertising address, which is a globally unique identifier, similar to a MAC address (though there is no designation for manufacturers).

Broadcast Packet

d6 be 89 8e 42 25 7e 75 29 3b 78 db 03 09 4d 33 03 19 00 00 02 01 04 13 ff 02 01 06 13 00 38 38 03 46 05 73 00 0D 00 04 27 01 00 0A 62 41 7f
  • d6 be 89 8e The access address will likely be hidden by most APIs and is not necessary.
  • 42 25 The packet header will also likely be extrapolated by the API. This includes information about the type of transmission address, packet type, and the length of the transmission.
  • 7e 75 29 3b 78 db The advertising address will likely be extrapolated by the API, but is needed for quickly sorting Low Energy scan responses. The address is transmitted as little-endian, so the address parsed correctly resolves to db:78:3b:29:75:7e. This address will be referred to as the device UUID.
  • 03 09 4d … 01 00 0A The advertising data contains the majority of the data and may be accessible as a byte array, or may be broken down further by the API.
  • 62 41 7f The CRC is used for verifying validity of the data transmitted and will likely not be accessible via an API.

Advertising Data Structure

Within the advertising data section are several sections of structured and unstructured data. Some APIs will process the structured data portions while others will require manual parsing of this section.

Advertising Data

03 09 4d 33 03 19 00 00 02 01 04 13 ff 02 01 06 13 00 38 38 03 46 05 73 00 0D 00 04 27 01 00 0A
  • 03 09 4d 33 The local name contains the length, type, and actual name of the transmitting device. The M3i as well as the M3 TBT and M5 will display as “M3”.
  • 03 19 00 00 The appearance section is unused by Keiser, so it will always appear as 0000.
  • 02 01 04 The flags portion contains information regarding the capabilities of the device broadcasting. The M3i operates as non-discoverable, non-connectible, so the flag will always be 0x04.
  • 13 ff 02 … 01 00 0A The manufacturer specific data section is where the bike’s data is stored. The first byte is the length and will likely be hidden by most APIs; however, the remainder will typically be exposed as a byte array for manual parsing.

Manufacturer Specific Data Structure

The manufacturer specific data portion holds Keiser’s proprietary data structure. This section will require a custom parser to extract the data as data sizes vary, and some bitwise operations are required. The structure of the data might change with bike revisions, but the structure provided here is valid for all bikes in the build major 6 line. All two byte values are little-endian (LSB first, MSB second).

Keiser M3i (v6.21+) Data Structure

/* C/C++ Data Structure */
            {
            uint8_t BuildMajor;
            uint8_t BuildMinor;
            uint8_t DataType;
            uint8_t BikeId;
            uint16_t RPM;
            uint16_t HR;
            uint16_t Power;
            uint16_t Kcal;
            uint8_t Minutes;
            uint8_t Seconds;
            uint16_t Trip;
            uint8_t Gear;
            }
        

The manufacturer specific data section contains this data structure as a concatenated byte stream with a 2 byte prefix. The 2 byte prefix can be ignored as its value might change over time.

Attribute Type Description
Build Major 1 Byte Unsigned Integer The build major should be the primary means of determining the structure for the remainder of the byte stream. This indicates the build revision of the bike’s computer software. The current structure is supported for all bikes with build major 6, regardless of build minor. All build values referenced in documentation and viewed on devices are in HEX form.
Build Minor 1 Byte Unsigned Integer The build minor is meant for debugging and support purposes, and has no bearing on the data structure. All build values referenced in documentation and viewed on devices are in HEX form.
Data Type 1 Byte Unsigned Integer The data type byte contains information regarding the type of data being sent. The two potential data types are real time and average. A data type value of 0 indicates the data being sent is real time, however, the values for accumulated data fields (Kcal, Minutes, Seconds, and Trip) are dependent upon the interval status of the bike. If the rider is currently in an interval, the values will be for the duration of the interval, otherwise the values are for the duration of the entire ride.

A value between 128 and 255 indicates that an interval is currently active. The interval number is this number minus 128 (Ex: 0x84 = 132 = #4 In-Progress). A value of 1 to 99 indicates an interval has been completed and real time values are being averaged over the course of the interval. A value of 255 indicates the rider has stopped pedaling, and the real time values are being averaged over the course of the entire ride. A broadcast with data type indicating an interval or end of ride will not have any real time data. There will be no real time data broadcast during that broadcast window so data should extrapolated from if needed.
Bike Id 1 Byte Unsigned Integer The bike id byte contains the ordinal number assigned to the bike. This number is only unique to the collision domain of the bike (typically a room or facility). This number will typically be between 1 and 150 and should be the primary method of identifying the bike to the user. The UUID should still be the primary method of identifying and referencing bikes in software.
RPM 2 Byte Unsigned Integer The rpm bytes contain the bike’s rpm to a decimal precision. The value is transmitted as ten times the decimal precise value (10 x RPM). During total average mode, this value will be an average rpm over the course of the ride.
HR 2 Byte Unsigned Integer The heart rate bytes contain the users heartbeat to a decimal precision in beats per minute (bpm). The value is transmitted as ten times the decimal precise value (10 x HR). This value is dependent upon the rider having a 5KHz EM Heart Rate sensor (Polar or similar). A value of 0 indicates that either a heart rate sensor is not present, or is out of range. During total average mode, this value will be an average hear rate over the course of the ride.
Power 2 Byte Unsigned Integer The power bytes contain the riders power production in watts. This value is only single digit precise and has an accuracy of greater than 90%. During total average mode, this value will be an average of the power produced over the course of the ride.
Kcal 2 Byte Unsigned Integer The kilocalorie bytes contain the accumulated kilocalories burned during the ride or interval depending on data type. This value is calculated using the actual measured output of the rider, rather than heart rate. This method is independent of age or weight, but does assume a normal caloric burn efficiency.
Minutes 1 Byte Unsigned Integer The minutes byte contains the accumulated minutes spent in the current ride or interval depending on data type.
Seconds 1 Byte Unsigned Integer The seconds byte contains the seconds elapsed since the last minute.
Trip 2 Byte Unsigned Integer The trip bytes contain the distance travelled during the current data type. The value is transmitted as ten times the decimal precise value (10 x Distance). The 15 lowest bits contain the distance, with possible values range from 0 to 999. The highest bit (MSB) indicates the units used. A 1 indicates the units are metric (kilometers), while a 0 indicates the units are imperial (miles).
Gear 1 Byte Unsigned Integer The gear byte contains the current gear. This value is a relative resistance indicator and may not be equivalent between all models.

Manufacturer Specific Data

02 01 06 13 00 38 38 03 46 05 73 00 0D 00 04 27 01 00 0A

Data Breakdown

Data Attribute Value
02 01 Prefix Bits Ignore this data
06 Build Major 0x06 = 6
13 Build Minor 0x13 = 19
00 Data Type 0x00 = 0 (Real Time Data)
38 Bike Id 0x38 = 56
38 03 RPM 0x0338 = 824 (82.4 RPM)
46 05 HR 0x0546 = 1350 (135.0 BPM)
73 00 Power 0x0073 = 115 (115 watts)
0D 00 Kcal 0x000D = 13 (13 kilocalories)
04 Minutes 0x04 = 4
27 Seconds 0x27 = 39
01 00 Trip 0x0001 = 1 (0.1 miles)
0A Gear 0x0A = Gear 10

Development Tools

Name Description
M3i BLE Simulator Linux Bash script using HCI BLE device to simulate an M3i's BLE broadcast.
M3i Bluetooth LE Broadcast Parser Portable C# library for parsing broadcast packets into usable Broadcast objects.
Keiser Kit Cocoapod CocoaPod Library created by Ben Woodford for working with the M3i on iOS

M3i Documentation

Name Description
M3i Bike Settings Manual Describes procedure for setting bike distance to either miles or kilometers, and changing the bike identification number.
M3i Bike Video Tutorials Video tutorials instructing how to set the bike distance units and bike identification number.
M3i Seat Adjustment Manual Describes procedure for changing the height of the seat using the new plunger style seat adjustment.

Developer Support

We are here to help. If you are having trouble understanding the documentation or have a question, please feel free to contact us. We also want to hear what great things people are able to do with our products, so please let us know about your project.

Keiser Open Development
development@keiser.com
Toll-Free: +1 (800) 888-7009