Send live Activity data to a smartphone through BLE

Former Member
Former Member

Hi,

For my use case I am trying to send live activity (e.g. run) data (e.g. current gps position, current speed) from a Garmin watch to an iOS smartphone. I don't want to implement a whole new Garmin wearable app for this, cause live data processing will be performed on a smartphone and default activities are perfectly fine for my needs.

I was thinking that it might be possible to read the data using iOS ConnectIQ SDK, but from my investigation it seems there's no direct way to get this data by using this API. For now it seems I will need to implement either a Data Field or a Background process to send this data over. What's the best approach to achieve this? Should I use Communications or BluetoothLowEnergy API? Many thanks for help in advance!

Architecture "diagram":

Garmin watch -> Sports Activity (e.g. run, cycling) ---------(Live activity data through BLE)--------> iPhone -> My iOS app 

  • Your best bet is probably a companion app for the iPhone.

    With BluetoothLowEnergy, you may not be able to talk to the phone at all, even if you write an iOS app for it.

    With this app, you can see what can be seen BLE wise in CIQ by default, and you won't see the phone:

    https://apps.garmin.com/en-US/developer/b73df9e6-4021-4059-b2e8-f9cfa04947c3/apps

  • Former Member
    0 Former Member over 4 years ago in reply to jim_m_58

    Yeah, I am aware that I need to implement an iOS app. On iOS there are basically 2 ways to connect to a Garmin device (both using BLE) - one is via ConnectIQ SDK and the other one is directly using CoreBluetooth BLE API.

    My current "research" shows that it's rather impossible to directly get any data from a built-in activity (e.g. run or bike) using ConnectIQ SDK. Two workarounds I was thinking about were:

    • Implementing a simple data field and send data using BluetoothLowEnergy module and receiving them using CoreBluetooth on an iPhone (as Communications module is not available for Data Fields)
    • Implementing a Background service running parallel to an activity and sending data to a phone using Communications module (and ConnectIQ SDK on an iPhone)

    Is any of these options feasible? Which approach should I take?

  • Couple of things.

    With Activity.Info you can get the data (the "info) parameter passed to compute()), and in a DF, you can do comm, but only from a background process, so you are limited to every 5 minutes.

    If you can find a way to talk to the iPhone with CIQ BLE, that might be better, but remember the phone must be the end that advertises.

  • Former Member
    0 Former Member over 4 years ago in reply to jim_m_58

    Isn't it possible, to execute a background process talking with a phone using communications from a data field more often than every 5 minutes?

  • Not using the Communications module.  It can only be used in a background service in a DF.

    Backgrounds can run at most every 5 minutes, and for at most, 30 seconds at a time.

  • Former Member
    0 Former Member over 4 years ago in reply to jim_m_58

    So I managed to establish a connection between my Garmin Vivoactive 3 Music and my iPhone, but I still have some issues to make it work.

    In this setup, my iPhone is acting as a virtual peripheral (I tried both my own app and LightBlue for debugging purposes) and I would like to enable my Vivoactive (acting as a center device) to read/write characteristics on it. I managed to search, find and pair a device, so that both:

    self.pairedDevice = BluetoothLowEnergy.pairDevice(scanResult);

    and

    BluetoothLowEnergy.getPairedDevices().next()

    don't return nulls.

    The problem I have is that this callback is never called:

    function onConnectedStateChanged(device, connectionState) {
        if (connectionState==BluetoothLowEnergy.CONNECTION_STATE_CONNECTED) {
      		displayString = "Connected";
      	}
      	if (connectionState==BluetoothLowEnergy.CONNECTION_STATE_DISCONNECTED) {
      		displayString = "Disconnected";
      	}
    }

    I already checked that BluetoothLowEnergy.getAvailableConnectionCount() is 3, so there should be no problem. Do you have any ideas on how I could force the connection?

  • When you do the pair device, you're not really connected until onConnectedStateChanged indicates you are.  The return from the call to pairDevice doesn't indicate you are actually connected.

    I've never really  looked at getPairedDevices(), but it returns an iterator.  Is there anything in that iterator? (you'll want to look at itterattor.next())

  • Former Member
    0 Former Member over 4 years ago in reply to jim_m_58

    Yes, when I call BluetoothLowEnergy.getPairedDevices().next(), I get the device to which I connected (my virtual peripheral iPhone), however if I call getServices() method on this device, the Service(s) iterator is empty. 

    As I wrote before - onConnectedStateChanged() is NEVER called for me and I have no idea why...

  • There is some reason the "other end" isn't connecting.  What do you see there?  You might have a device, but you really aren't connected until you get onConnectedStateChanged.  pairDevice() returns immediately, while actually pairing can take some time - even if it's only a second.  It's not a blocking call.

  • Former Member
    0 Former Member over 4 years ago in reply to jim_m_58

    Unfortunately iOS BLE API (CoreBluetooth) doesn't expose any callbacks when a central device wants to connect. As per this post: https://stackoverflow.com/a/51726721/1828352:

    If the central just connects and retrieves your services and characteristics then there is no indication on the peripheral side that it has connected.

    You only receive read, write and subscription requests via the relevant CBPeripheralManagerDelegate methods. This means that you only become aware of the central when it performs one of these actions

    Is there any way on the Garmin side to force the connection after pairing?