Scratching my head with FitContributions

I'm looking for a little help with FitContributions from a Datafield

I've created and initialized the fields, and I have the xml field definitions in resources

I see all of my field definition entries in the .fit export (using Fit2CSV tool)

I also see my RECORD type fields showing up in Connect with nice graphs

however, I'm not seeing any of my SESSION fields in Connect

using println I have confirmed that setData() is being called and data is written.

I'm not sure exactly how to interpret the fit.csv for SESSION data, but while I clearly see field_definition entries for all of my fields, I'm not seeing anything in the csv that I can readily determine to be my session data values

I'm updating my RECORD values in compute() and only writing data if the last value is different than the current value as recommended.

at what point should I update my SESSION type fields? I've tried updating them within onTimerStop() and onTimerReset() but neither place seems to provide me with any data in Connect

some reference points
in fitcontributions.xml I have entries like

    <fitContributions>
        <fitField id="7"
        displayInChart="false"
        sortOrder = "7"
        precision="0"
        dataLabel="@Strings.average_speed_label"
        unitLabel="@Strings.speed_units" />
    </fitContributions>
in Strings.xml I have

    <string id="average_speed_label">Avg Spd</string>
    <string id="speed_units">m/s</string>

I create the field like

        sAverageSpeed = dataField.createField("AvgSpd", 7, FitContributor.DATA_TYPE_UINT16, { :nativeNum=>14, :mesgType=>FitContributor.MESG_TYPE_SESSION, :units=>"m/s" });

and I update the field like this

        if (_ellipticalData._hasAvgSpeed) {
            _data = Math.floor(_ellipticalData._averageSpeed * 0.277778).toNumber();
            sAverageSpeed.setData(_data);
            System.println("Wrote Avg Speed");
        } else {
            System.println("_hasAvgSpeed: " + _ellipticalData._hasAvgSpeed);
        }


I can see in the logs that 'Wrote Avg Speed' was written, so setData() was called
Any thoughts on what I'm missing here?



  • The app needs to be installed from the app store to see any fitcontib data in Garmin Connect.  You can make it a beta so only you can install it.

  • The desired values of all your FIT fields have to be available *before* the related activity event: in the case of MESG_TYPE_SESSION, the end of the activity, and in the case of MESG_TYPE_LAP, the end of a lap.

    So if you only set the value for a MESG_TYPE_SESSION field in onTimerStop() and onTimerReset(), it's too late. Well, it's definitely too late at onTimerReset(), and now I *think* it's too late in onTimerStop(), based on what you said. (At one point I may have thought it might be possible to call setField for a MESG_TYPE_SESSION field in onTimerStop, but I haven't checked whether this is possible recently.)

    (EDIT: actually you can set MESG_TYPE_SESSION values in onTimerStop())

    Similarly, if you set the value for a MESG_TYPE_LAP field in onTimerLap(), it's also too late.

    The solution is to call setValue() for all types of FIT fields continuously (e.g. once per second). This pattern can be seen in the MoxyField SDK sample.

    This isn't a problem for your FIT data or battery life, because setValue only sets the next value to be written. The device decides whether that value will actually be written or not.

    e.g. if you call setValue 300 times in a 5-minute activity for a MESG_TYPE_SESSION field, it's ok, because only the 300th value will actually be written.

  • Also, a very useful tool for viewing FIT files is www.fitfileviewer.com

    It decodes a lot of things that fit2csv won't, and it presents your data in a much friendlier way. There's separate tables for the different categories of fit data (including session and record data), with descriptive column names.

  • Very helpful, thanks for that Fit viewer!

    Found the problem!

    I forgot to include

            displayInActivitySummary="true"
    in the fitfield entry, Doh!
  • Thanks for circling back and sharing the solution!

    My guess about not calling setValue at the right time was totally wrong. I should've known better, since I was almost 99% sure that it works in onTimerStop() for MESG_TYPE_SESSION, from previous experience and my own previous posts haha.

    (My comment about MESG_TYPE_LAP still stands, and ofc it doesn't hurt to set all 3 MESG_TYPE_* fields once per second. But it also doesn't hurt to only set MESG_TYPE_SESSION fields in onTimerStop(), since the end of an activity will always be preceded by onTimerStop().)