Developing a CIQ BLE Client for Treadmill and Fitness Equipment

I want to run on my smart treadmill and get EXACT speed and grade information via BLE.  Previously, I created an Arduino ESP-32 solution running as a BLE server that runs on the treadmill.  This server works well with Zwift etc, so I know it works.  Now the plan is to create a CLIENT on my fenix-5.  Eventually, I want to save and thereafter load my treadmill runs into Strava.  In the far away future, I would like to control my treadmill from the fenix-5 (using watch buttons to speed-up, tilt up etc) .  In the far,far,far away future, I would like to automatically adjust treadmill speed and grade based on complicated pre-planned-workouts (intervals, hill repeat etc).

REFERENCE INFO

GATT SERVICES

Plan to read data from:

  • Fitness Machine Service UUID: 0x1826
    • Fitness Machine Feature Characteristic 0x2acc 
    • Treadmill Data Characteristic 0x2acd
      • 2902 Enable Notify Descriptor 0x2902
        • This is required so client gets more than one data point.
    • Supported Speed Range Characteristic 0x2ad4
    • Supported Incline Range Characteristic 0x2ad5
  • Keep Alive UUID

Long Form "standard" UUIDs take the form of 

xxxxxxxx-0000-1000-8000-00805F9B34FB
where xxxxxxxx is the zero-padded short-form uuid (see above)
E.G. Fitness Machine Service long UUID would be 00001826-0000-1000-8000-00805F9B34FB

  • Well...   ummmm...  Maybe not as well as I thought.   Simply put, notifications aren’t getting processed.  The app is scanning and connecting, but notifications events aren’t getting processed by BLEdelegate.  Saving debug logs to a file is getting old... So, I took your awesome advice and ordered a usb dongle.   I’m gonna need to dive into the code a little more than I hoped.  

    We’ll get there

  • I use notifications a fair amount, and had no problem.  Make sure you enable them in your app, and on the server side, make sure you are sending them.  For me, I'll send them based on things like the state change of a switch, or value change of an input on the pi or on a time basis. 

    to enable for a characteristic:

    var cccd = char.getDescriptor(Ble.cccdUuid());
    cccd.requestWrite([0x01,0x00]b);

    And then you'll see  the notifies in the ble delegate with

    onCharacteristicChanged(char, value)

  • Ok.  So it works again.  The BLE Server was crashing and thereby sending no data. 

    No data-- no notifications...Duuuuuuug  My bad.

    I'm still gonna get the dongle,  though.   I think the example code is too disjointed for beginners, forcing a newbie developer to cut and paste code without really having a good idea about what is going on behind the scenes.  

    Eventually, I would like to create an environment where:

    • A BLE connection (the searching, the selecting, and returning a valid connection) can be made with a single call.
    • A Service can be instantiated with a single call, passing in (only a) 2 BYTE UUID for the service and a *pDelegate for asynchronous communication. 
    • Characteristics passed-into the Service with, (only their) their 2 byte UUID.

    Connecting to a BLE Server should be super-easy.  The heavy lifting, (and the fun stuff) after all, comes-in after the data has arrived.

    It also seems like the words "Profile" and the words "Service" get confused within the Garmin universe.  I may rename some of the classes-- but that may just be me.  

    Cheers!  Dongle On!

    When I get something useful for the community, I'll run it past ya and eventually put it up on Git.

  • Actually, profile and service have a meaning in BLE.  If you havent watch the video from the summit, that might help.

    https://forums.garmin.com/developer/connect-iq/b/news-announcements/posts/adding-bluetooth-connectivity-to-your-connect-iq-projects

    You have a device, and under that device you have one or more services, and under a service, one or more characteristics.  How that all fits together is the profile.

  • I agree, with you.  ...indeed-- from the googles...

    Profiles. A Profile doesn't actually exist on the BLE peripheral itself, it's simple a pre-defined collection of Services that has been compiled by either the Bluetooth SIG or by the peripheral designers. The Heart Rate Profile, for example, combines the Heart Rate Service and the Device Information Service.

    When I am reading from Stryd, (my) example, I read from multiple services.  I read from a RSC service (for foot pods), a Cycling Speed and Cadence Service and a Cycling Power Service.  I also read from a Device Information service and a Battery Service.  While there really isn't a published, standard Stryd profile.  It is implied in the program itself--  nothing more than a bunch of services and characteristics.  Again, the profile (however wacky it may be) is implied by the program  

    Rather than registering more than one profile to communicate with a single server, I would probably just create (implied in the code) a new profile, a super-set of both profiles' services and characteristics, communicating with this single server.

    What are your thoughts?

     

  • You're limited to 3 profiles in CIQ, and I use a profile per service.

  • I got the dongle.  It came without a lot of documentation... Do I need to flash it's firmware before it can successfully connect with CIQ?

  • Yes.  Here's a link to what's needed for the dongle.  The general directions are in the programmer's guide.

    developer.garmin.com/.../connectivity_1.0.0_usb_with_s132_5.1.0.zip

  • THANKS!  You are a lifesaver!