C2Bluetooth is a flutter package designed to provide an easy API for accessing data from Concept2 PM5 Indoor fitness machines via bluetooth. This library implements the Concept2 Performance Monitor Bluetooth Smart Communications Interface Definition Specification (newer versions are also available). It also relies heavily on the CSAFE specification from FitLinxx.
This is a relatively old screenshot of the included example app using an older version of the library to display the completed distance from a short 20-second test workout. Many improvements to expose more datapoints have been made since this screenshot was taken.
Currently this library supports a few basic features such as:
- retrieving workout summary information from the erg after a workout
- programming a workout into the erg
In the future, we hope to add support for things like:
- Streaming data during a workout
- updating the time on the erg
- updating the erg firmware
The docs
folder contains a few .md
(markdown) files that are meant to help explain the major components of the library. Within this folder is also a diagrams
folder that contains draw.io/diagrams.net
files that also hope to provide some other ways to understand how this library works. The easiest way to see these diagrams besides looking at any exported copies embedded in the markdown files is to open them in diagrams.net wither online or using their desktop app.
To install this package, just like any other flutter package, it needs to be included in your pubspec.yaml. Here are some templates for doing so:
Pub.dev version
To install from pub.dev, run the command flutter pub add c2bluetooth
or add the following to your dependencies in pubspec.yaml:
dependencies:
c2bluetooth: ^1.0.0
Alternative installation methods for development can be found in CONTRUBUTING.md
Similar to how the underlying bluetooth library works, pretty much everything begins with an instance of ErgBleManager()
. For a complete example, see the example app's main.dart file. Below are some of the key steps
ErgBleManager bleManager = ErgBleManager();
bleManager.init(); //ready to go!
Next, you need to start scanning for available devices. This uses a Stream to return an instance of the Ergometer
class for each erg found. Each of these instances represents an erg and should be stored for later reuse as these act as the base upon which everything else (retrieving data, sending workouts .etc) is based.
Important: Many of these setup steps will fail if bluetooth is off or if permissions are not correct. C2bluetooth leaves the responsibility of handling permissions up to applications implementing the library. This is mainly because different apps will want to handle the user experience of this differently.
Ergometer myErg;
bleManager.startErgScan().listen((erg) {
//your code for detecting an erg here.
myErg = erg
});
This block of code is where you can do things like:
- determine what erg(s) you want to work with (this can be based on name, user choice, or basicaly anything)
- store the erg instance somewhere more permanent, like the
myErg
variable to allow you to be able to access it after you stop scanning. - call
bleManager.stopErgScan()
if you know you are done scanning early. As an example, one way to immediately connect to the first erg found is to unconditionally callstopErgScan
within this function so the scan stops after the first erg is received. Don't forget to close the stream too!
Once you have the Ergometer
instance for the erg you want to connect to, you can call connectAndDiscover()
on it to connect.
await myErg.connectAndDiscover();
When you are done, make sure to disconnect from your erg:
await myErg.disconnectOrCancel();
To get data from the erg, use one of the methods available in the Ergometer
class as described below.
Concept2 offers various data via their Bluetooth interface which for our purposes are categorized as follows (from most to least granular):
- General status data think periodic snapshots of what the user sees on the monitor
- Stroke data a datapoint for each complete stroke taken [not yet implemented]
- Interval or split data a datapoint for each split or interval in the workout [not yet implemented]
- Workout Summary data data summarizing the entire workout after completion [not yet implemented]
When retrieving data, here are some things to keep in mind (based on information available in the Concept2 Bluetooth smart specification, rev 1.27):
- Bluetooth smart is a relatively low-bandwidth protocol. Under ideal conditions the maximum speed at which data can be received is about 1000 bytes per second for Android and about 640 bytes per second for iOS.
- iOS and Android have different limitations on various bluetooth parameters that affect things like bandwidth.
- Bluetooth is based on radio waves. Signal (and ultimately your bandwidth) can be impacted by things like other nearby bluetooth devices, physical obstacles, interference from other devices, and other things.
To Be Implemented/Documented
To Be Implemented/Documented
To Be Implemented/Documented
Workout summary data can be monitorForWorkoutSummary()
. This is a stream that returns a WorkoutSummary
object that allows you to access the data from a completed workout (this includes programmed pieces as well as "Just row" pieces that are longer than 1 minute)
myErg.monitorForWorkoutSummary().listen((workoutSummary) {
//do whatever here
});
Each workout summary is a flutter object that contains the following fields:
Future<DateTime> timestamp
Future<double> workTime
Future<double> workDistance
Future<int> avgSPM
Future<int> endHeartRate
Future<int> avgHeartRate
Future<int> minHeartRate
Future<int> maxHeartRate
Future<int> avgDragFactor
Future<int> recoveryHeartRate
Future<WorkoutType> workoutType
Future<double> avgPace
Future<IntervalType> intervalType
Future<int> intervalSize
Future<int> intervalCount
Future<int> totalCalories
Future<int> watts
Future<int> totalRestDistance
Future<int> intervalRestTime
Future<int> avgCalories
Futures are handy here since the erg can send back different data at different times. The primary reason for this is the recoveryHeartRate
field which the erg sends after the user has been resting for 1 minute. If the workout is cancelled or the erg is turned off before the end of this minute, the data may never arrive. See #10.
Overall this method of accessing workout summary data is not the most ideal, and is likely to change later if a better solution is found. See #11.
This is a list of projects built using c2Bluetooth. If you find or make something that is not on this list, send us a pull request!
- CrewLAB app (proprietary license)
If you are interested in making contributions to this library, please check out the CONTRIBUTING document, or learn how c2bluetooth works in the API document
This library was created for the rowing community with support and feedback from CrewLAB.
This library is licensed in a way that can be used within proprietary apps, as long as any changes you or your company make to this library are released and publicly accessible. Full legal details are available in the LICENSE file.