How to detect if LTE is connected for a watch face icon

With the va3 Music LTE, I put together a small function see if LTE is connected, as you can do with phoneCommetect for a Bluetooth connection.

Here is is:
function lteState() {
var state=null;
var ci=System.getDeviceSettings().connectionInfo[:lte];
if(ci!=null) {state=(ci.state==Sys.CONNECTION_STATE_CONNECTED) ? true:false;}
return state;
}

before using it, you do want to do a "has" similar to this. (I do it in initialize, and check the boolean before calling this function)

if(lSystem.getDeviceSettings() has :connectionInfo) {hasLTE=(lteState()!=null);}

It checks if connectionInfo is available, and if so calls lteState(). If that returns null, there's no LTE on the device;

I've only tested this in the sim, but I'm using it in watch faces today. The real test will be a user with a va3 Music LTE.
  • Thanks for that, Jim!

    I would like to point out a significant difference between phoneConnected and ConnectionInfo. phoneConnected is a boolean, and ConnectionInfo is a tri-state.

    ---

    , ConnectionInfo (new for CIQ 3.0.0) is a tri-state:
    CONNECTION_STATE_NOT_INITIALIZED = 0
    Indicates that the connection is not setup or is inactive.

    CONNECTION_STATE_NOT_CONNECTED = 1
    Indicates that the connection has been setup but is not in range.

    CONNECTION_STATE_CONNECTED = 2
    Indicates that the connection is available for use.


    ---

    EDIT: I read the docs incorrectly. NOT_INITIALIZED doesn't mean "connection disabled" (as I had wishfully assumed). When you disable bluetooth, the state is still NOT_CONNECTED, instead of NOT_INITIALIZED as I had hoped. I was hoping to use this to detect whether bluetooth was disabled, but I guess not.

    As Jim pointed out, CONNECTION_STATE_NOT_INITIALIZED probably means that you haven't paired a phone.
  • If you want all the states it's an easy change:
    function lteState() {
    var state=null;
    var ci=System.getDeviceSettings().connectionInfo[:lte];
    if(ci!=null) {state=ci.state;}
    return state;
    }

    This is actually 4 states. The three you note, plus null if LTE isn't available on the device. I went with a simpler approach, where it's show/don't show the icon and just used the 3.

    Where the var ci is set, in place of lte, bluetooth or wifi could also be used to get the same type of status for those.
  • As an aside, I'm wondering how connecting bluetooth headphones to watches that support them would interact with the bluetooth connection state? Not having any I've never tried this.

    Can headphones only be connected when the bluetooth state is enabled? (I'd expect so!)

    When headphones are connected does that change the bluetooth state to connected? Or is that just reserved for the phone connection?
  • You can't detect that headphones are connected from CIQ. The Bluetooth info is only being connected to the phone
  • Thanks again for all of that, Jim. I would never have even know about connectionInfo if not for this thread.

    I would like to suggest some alternate code which can be called without any (external) checks and does not require special code in initialize, so it's more or less self-contained. This code works for LTE, bluetooth and WiFi, and would work with future hypothetical connection types, without modification. It is slightly more inefficient than the way you suggested, of course.

    (Of course the flaw here is that you might want to know if connectionInfo is available beforehand, so in the case of bluetooth, you can fall back to phoneConnected for CIQ 1 and CIQ 2 watches. In that case, if this function returns null, you can check phoneConnected.)

    EDIT: Changed code to only do "has" check once. The original code would've done a "has" check for each connection type (up to 3), which is not efficient or necessary.

    EDIT: It's probably pointless to use this code, as you may never / rarely see the state CONNECTION_STATE_NOT_INITIALIZED, as it apparently doesn't mean "connection disabled" as I thought it did.

    // connectionType: :lte, :bluetooth, :wifi
    // Returns:
    // null, if DeviceSettings::connectionInfo not available or if given connection type does not exist
    // connectionState otherwise
    // (CONNECTION_STATE_NOT_INITIALIZED = 0,
    // CONNECTION_STATE_NOT_CONNECTED = 1,
    // CONNECTION_STATE_CONNECTED = 2)
    //
    // Example usage:
    // var lteState = getConnectionState(:lte);

    private var hasConnectionInfo = null;
    function getConnectionState(connectionType) {
    if (hasConnectionInfo == null) {
    hasConnectionInfo = System.getDeviceSettings() has :connectionInfo;
    }

    if (hasConnectionInfo) {
    var deviceSettings = System.getDeviceSettings();
    if (deviceSettings.connectionInfo[connectionType] != null) {
    return deviceSettings.connectionInfo[connectionType].state;
    }
    }
    return null;
    }
  • "has" is an expensive operation - it's got to scan a dictionary each time. That's why I separate the "has" check for something that's called frequently (like the state of an icon on a WF). I only do "has" checks once (usually initialize) - and that that won't change while an app is running - checking a boolean is cheaper. For bluetooth, you could always change what I do in initialize, so that for devices without connectionInfo never call the function instead of checking each time by calling the function:
    hasCI=(System.getDeviceSettings has :connectionInfo);
    if(useCI) {hasLTE=(commState(:lte)!=null);}


    if useCI is false, use phoneConnected for bluetooth state (save a function all). In my case, I always use phoneConnected, and only check for lte. I'm not sure saving the space for a wifi icon on a wf makes much sense as it's so rarely connected.
    I have a version of the function I posted that returns an array for all 3 connection types with the state for each if that should come in handy some time.

    There's also this code that can check for any connection for things like makeWebRequest. in this case it uses connectionAvailable instead of connectionInfo.
    https://www.garmin.com/en-US/blog/de...iq-app-to-lte/
  • jim_m_58 Yes, I realize "has" is expensive. My code only does the "has" check once for each connection type (although to be fair, it should only be once). It could be refined to only do the "has" check once, globally. As a matter of fact, I will make that refinement now.

    I just wanted to provide a self-contained, generic alternative. It's less efficient than your way, because:
    - You have to call the function every time
    - The function checks its own boolean variable twice: once for null (uninitialized) and once for true/false.

    So there's the overhead of a function call and an extra null check. But the "has" check is now done only once, instead of up to 3 times (for bluetooth, wifi and lte.)

    I think a self-contained function is better when modifying existing code, especially if it belongs to someone else, so you can make changes that are as minimal and localized as possible. If writing code from scratch, then certainly it's a matter of preference.

    I think people should use whichever version suits them the best. I'm sure 99% of people would opt for the simpler boolean version in the OP.
  • With a watchface, devs tend to want to be as battery friendly as possible, as it does run all day. Doing the has check in initialize is a way to call an expensive function once instead of around 1400 times a day. It's a trick to help with battery.

    Oh.. I did you change your post to only do the has check once? If so, please note it as a change in your post, as it muddies up the context of following posts.
  • Again, with a watch face that wants to be as battery cheap as possible, with your code, I'd just check "hasConnectionInfo" before calling the function to save the function call overhead. Making it work like doing the has check in initialize :)
    I'm not sure there's any real maintainability issue, but there is a performance one (though it is tiny)
    Here's now I actually use the function I posted. Doing it as I do I think it makes it a bit more readable at that level.
    if(hasLTE) {
    if (lteState()) {dc.drawText( iconX , iconY, iconfont, "1", Gfx.TEXT_JUSTIFY_RIGHT);}
    iconX=iconX-iconSpacing;
    }

    It does things like allow space for the icon only if there's a possibility it will be used - no sense making room on devices without LTE.. And no sense making a function call if you already know the result. When you do a WF, especially when you do things in onPartialUpdate, you want to be efficient (that 30ms power budget can be a killer!)