Data Field: AppBuilder

By user request, this app lets you define your own data field, based on a simple math formula like cadence / 2.

If you want to get fancy, there's conditional expressions (like IF in Excel), functions for data analysis (like MIN and AVG), and the data field can also display the text of your choice. The resulting data can be (optionally) written to the activity FIT file.

With AppBuilder, you can implement almost any field that involves math, such as: calculating normalized power and saving the data to the FIT activity file, showing the average pace for even-numbered laps, or recording the amount of time you sprinted.

Full documentation and examples here:
http://ciq-appbuilder.blogspot.com/

AppBuilder 5:
Now with new features! AppBuilder 5 is a completely new app, so please check it out in the store if you are interested in any of the new features.
https://apps.garmin.com/en-US/apps/fd690281-9c22-4fee-a81e-3b7f39aa67c5

- Store up to four formulas per app. Switch between formulas directly on the watch, without using a phone or PC. With four clone apps, you can store up to 16 formulas total
- User variables. Allows for powerful formulas where information can be stored at one point, like the start of a lap, and used later. e.g. Lap elevation change
- Improved timeavg() options. Allows for simpler, more flexible normalized power function
- More functions and variables

4 clones of AppBuilder are available in the store, so you can have 2 formulas in the same activity
  • Former Member
    Former Member over 7 years ago
    FlowState just tried the new formulas and seems to work. Though worth noting that it's still not exactly the same as native field. Native field just continues where it left, so for example if paused during the first 30s it will still start showing the value at around 30s mark where as with your workaround it waits another 30s, which I guess what was the main idea :)

    Another interesting note is that seems when you pause the activity the field seems to cling to last known value so it will show it even after pausing until 30s has passed until the value starts refreshing again, where as at activity start or laps (when set to wait) it will show "--" for the first 30s.

    Still seems to me that the Garmin native field implementation might not be that great. With your app the user has now more control. For example when using the 3rd example I now get similar lap values to what I get in TP if I want to look at that specific laps data.

    That's just first notes with limited testing, will continue testing and report if find anything new.
  • dobssi , sorry, muscle oxygen native data isn’t currently available to Connect IQ apps. Garmin is aware of the user interest, though.

    https://forums.garmin.com/forum/deve...-activity-info

    Maybe you can use the Humon data field instead.
    https://apps.garmin.com/en-US/apps/5...1-4152ab1b2ffe


    Thanks for the response. The Humon data field is identical to the native data so not really any point as it stands. What I am after is a way to use a CIQ datafield to show the current SMO2% trend.....kind of a simplified version of what their CIQ app does.
  • FlowState just tried the new formulas and seems to work. Though worth noting that it's still not exactly the same as native field. Native field just continues where it left, so for example if paused during the first 30s it will still start showing the value at around 30s mark where as with your workaround it waits another 30s, which I guess what was the main idea :)



    Hmm, thanks for the testing and feedback!

    Well, I never collect data for "analysis" (*) functions like AVG, TIMEAVG and MAX when the unit is paused. I used to, until it became clear that's not what most people want. Maybe to emulate the native behaviour, you need TIMEAVG to actually collect data while the unit is paused. This would obviously require code changes.

    * IOW, any functions which do calculations based on values which are collected over time. Same applies even to SUM, which just adds samples over time.

    I imagine that if people were calculating run power, and they jumped in a car while their activity was paused, they wouldn't like this behaviour. They would have to stand around for 30 seconds before starting to run again, in order to not pollute their recorded NP with bad data.

    Anyway, it goes to show that it's hard to decide on what the correct behaviour should be for these various functions. (Collect data while paused or not? Return data for rolling average when you don't have enough samples?)

    Another interesting note is that seems when you pause the activity the field seems to cling to last known value so it will show it even after pausing until 30s has passed until the value starts refreshing again, where as at activity start or laps (when set to wait) it will show "--" for the first 30s.


    Well, this should be expected, since is NP is defined as lap or activity average of power. Just because you are not currently changing the average, doesn't mean your average is now undefined. Just like if you pause your watch and look at native average speed or heart rate, it should remain unchanged, whether you pause your watch for 30 seconds or 1 hour.

    And by design of those formulas (but maybe not the native implementation), since I don't want to contribute to the NP for the first 29 seconds after pausing (because I don't have a 30-second rolling average yet), then I'd think the NP should remain frozen, just as the average HR should remain frozne while paused.


  • A few more notes, since I can't edit the above post.

    - Even Garmin doesn't update things like native max heart rate or cadence when the watch is paused. If they are gathering data for a rolling average while the watch is paused, I think that's a mistake. Of course the big difference is "max" would deal with a value you are looking at this second, while rolling average is looking at this second and the past 29 (or x) seconds.

    - At the start of the activity or lap, there hasn't been any data at all to contribute to the average, so "--" is displayed, meaning the average is undefined. When the activity is paused, we don't throw away all of the data since the start, just the data that's coming in while it's paused, so the situation seems slightly different to me.

    Hopefully I'm understanding what NP is supposed to be. At least the base formulas seem to match the native data, except in the special case of pausing the activity.

    Also, if you really wanted it to show "--" during the first 30 seconds after pausing, you could, but it would be a bit misleading. Average HR doesn't become blank while your activity is paused.

    Let me know if I understood the problem correctly, or if there's any other workaround that can be applied to make it closer to native behaviour. If I'm understanding the native behaviour with regard to pausing correctly, I don't like it. If you need a full 30 seconds of samples for the rolling average, then only samples taken when the watch is not paused should count, in my opinion.
  • Former Member
    Former Member over 7 years ago
    Not sure actually what's right operation, just noting the differences. The reasoning behind native field and pausing is also a mystery, haven't figured out yet at least :)

    As for NP, originally it's meant to be used for cycling. Because in cycling you have breaks when coasting etc. For running this is not the case in steady pace runs and actually very close to normal average power, but there can be some limited use as well, for example to show more realistic average power of run / walk intervals or other scenarios where you get noticeable drops in power.

    Just figured since NP works the same as average power even when there is no benefit, might just try and use it for running as well, and since TP calculates it for all activities with power meter.

    Anyway whatever the use case is now we have at least the basic formula, and some understanding how it behaves in different scenarios, user can then modify it to show the effect they want. :)
  • Former Member
    Former Member over 7 years ago
    And to clarify for me the operation was already satisfactory as it was. Sure the pausing brings additional question, so I leave it open for discussion. Someone may want to play with it further. I'm just not sure if I have currently time to do that. Still thanks for providing a workaround for pausing. I'm sure it will prove helpful for future use.

    Btw, the iOS app still crashes if I use IF in a formula, so I had to use separate laptop with Garmin express to try it out. I'm all in for the web app if it makes it easier to add features and entering formulas (the visible space is awfully short in both iOS connect mobile and Garmin express).

    Thanks for help so far and keep up the good work! :)
  • You're welcome!

    Okay, I changed the examples on the AppBuilder4 store page so they use IFS instead of IF. I assume that IF is causing a problem for the same reason that ALERT does -- it's a reserved javascript keyword. >_>. Unfortunately I test a lot in the app simulator, so I don't see all the iOS-specific bugs, even though I do own an iPhone.

    If anyone needs the native behaviour after unpausing, unfortunately I can't provide that right now.

    I suppose in a perfect world, TIMEAVG would be called ROLLINGAVG and have 2 additional options:
    1. Collect samples while paused [true/false]
    2. Calculate average while sample size less than window size [true/false]

    Then you could set 1. to true and 2. to false to get native behaviour. Unfortunately there is no workaround for 1.

    As always, the following formulas have square brackets instead of the necessary round brackets.
    See here for examples you can actually copy and paste:
    https://apps.garmin.com/en-US/apps/f...9a39e44e1b9f#0

    • Activity average as per native field
    • :

      AVG0[IFS[Timer GTE 30 and [Timer - MAX[IFS [PREV[timer] eq null, timer]] plus 1] gte 30, TIMEAVG0[Power,30]^4]]^0.25

      • Lap NP: Carries the rolling average over from prev lap [native Lap NP]
    • LAPAVG0[IFS[Timer GTE 30 and [Timer - MAX[IFS [PREV[timer] eq null, timer]] plus 1] gte 30, TIMEAVG0[Power,30]^4]]^0.25

      • Lap NP: Resets at start of each lap

      LAPAVG0[IFS[LapTime GTE 30 and [Timer - MAX[IFS [PREV[timer] eq null, timer]] plus 1] gte 30, TIMEAVG0[Power,30]^4]]^0.25
  • I added some function substitutions for IF and ALERT to the troubleshooting section in the second post, so you can actually use your iPhone to enter formulas that need those functions. Thanks again for letting me know about IF. I knew that ALERT didn't work in GCM iOS, but I didn't catch the same issue with IF.
    https://forums.garmin.com/forum/deve...31#post1227731

    Again, the brackets are wrong below, and must be replaced with round brackets if you actually want to use them in appbuilder. Guess I made a huge mistake in assuming that the GCM iOS app and Garmin forums would accept completely normal text before designing AppBuilder <_<.

    Issues with certain functions [IF, ALERT] on Garmin Connect Mobile - iPhone:
    - Unfortunately, IF and ALERT may not work when AppBuilder is configured through GCM on iPhone, due to issues beyond my control.
    - As a workaround, you can either configure through Garmin Express [PC/Mac], or use an equivalent formula:

    IF[X, Y, Z]
    is the same as
    IFS[X, Y, 1, Z]

    IF[X, Y, null]
    is the same as
    IFS[X, Y]

    ALERT[X]
    is the same as
    WHEN[X, 1, 1]

    ALERT[X, Y]
    is the same as
    WHEN[X, 1, 1, Y]

    ALERT[X, Y, Z]
    is the same as
    WHEN[X, 1, 1, Y, Z]
  • Hmm, I tried the new versions of my functions (with IFS and not IF) in iOS and it still doesn't work. As a matter of fact, unlike ALERT, IF doesn't fail in simple formulas.

    So something else is going on. Unfortunately, the only workaround I can suggest at the moment is to use Garmin Express. :(

    Edit:

    Okay, I found that text as simple as "if(b^c)" will cause the settings to fail. If you change the "if" or "^", then it's fine.

    Edit:

    Filed a bug report with Garmin. Note that 4 months after reporting the issue with ALERT, it still hasn't been fixed.

    Then again, pretty sure nobody else's app has this problem because nobody else would be using characters/strings like this in their app settings.
  • Former Member
    Former Member over 7 years ago
    Feature request: add the log functions LN(num) and/or LOG(num, base) that are available in the Connect IQ SDK Math module to the allowed syntax.

    Also, is it possible to detect when speed data is not available in the sensor data (other than detecting 0 values)?

    The reason I ask it that the Stages stationary bikes that I use at our gym only transmit Power and Cadence over Ant+, yet their head units also display speed and distance, which seem to be calculated. I've reverse engineered the curve they use to calculate the speed and distance based on the power values. I'd like to set up a data field that I could use for the Bike Indoors activity to perform this calculation and write the estimated speed and distance to the activity data. However, I'd like it to be smart enough that if I use my personal bike which DOES have a speed/cadence sensor but not power meter indoors on the trainer, the data field wouldn't do that estimation.