.fit file example compatible with Garmin Connect

I'm starting to integrate the .fit file format in my app. My app stores GPS information and other bike information during a ride.

In the SDK there is the example for create the Activity. But the file created with this example is not compatible with Garmin Connect. When I create it and I try to import it in Garmin Connect, the web site doesn't accept the file but the error is without any detail.

Is it possible to have an example in Java to how to create the .fit file for an activity "compatible" with Garmin Connect?

I'm able to create file compatible for Strava and other platform, but not for Garmin Connect.

Thanks a lot. 

  • I have found the solution by my self..
    The example file activity_developerdata.fit can be uploaded to Garmin Connect, so I checked every field created in activity_developerdata.csv and the respected code was easy to implement.

    This is the example code for Java

    public static long getDate() {
    Calendar d1 = new GregorianCalendar(1989, 11, 31, 0, 0, 0);
    Date today = new Date();
    long diff = Math.abs(today.getTime() - d1.getTime().getTime());
    return (diff/1000);
    }

    public void TestFIT() {
    FileEncoder encode;
    try {
    encode = new FileEncoder(new java.io.File("test" + android.text.format.DateFormat.format("_dd_HHmmss", new Date()).toString() + ".fit"), Fit.ProtocolVersion.V1_0);
    } catch (FitRuntimeException e) {
    System.err.println("Error opening file .fit");
    return;
    }

    long lStartTime = getDate();

    //Generate FileIdMessage
    //Data,0,file_id,type,"4",,manufacturer,"255",,product,"0",,time_created,"968191204",,serial_number,"468127667",,
    FileIdMesg fileIdMesg = new FileIdMesg(); // Every FIT file MUST contain a 'File ID' message as the first message
    fileIdMesg.setType(com.garmin.fit.File.ACTIVITY );
    fileIdMesg.setManufacturer(Manufacturer.DEVELOPMENT);
    fileIdMesg.setProduct(0);
    fileIdMesg.setTimeCreated(new com.garmin.fit.DateTime( lStartTime ));
    fileIdMesg.setSerialNumber(12345L);
    encode.write(fileIdMesg);

    // Data,0,device_info,device_index,"0",,manufacturer,"255",,product,"0",,product_name,"FIT Cookbook",,serial_number,"468127667",,software_version,"1.0",,timestamp,"968191204",s,
    com.garmin.fit.DeviceInfoMesg lDeviceInfo = new DeviceInfoMesg();
    lDeviceInfo.setDeviceIndex((short)0);
    lDeviceInfo.setManufacturer(Manufacturer.DEVELOPMENT);
    lDeviceInfo.setProduct(0);
    lDeviceInfo.setProductName("Test");
    lDeviceInfo.setSerialNumber(12345L);
    lDeviceInfo.setSoftwareVersion(1.0f);
    lDeviceInfo.setTimestamp(new com.garmin.fit.DateTime( lStartTime ));
    encode.write(lDeviceInfo);

    //Data,0,event,timestamp,"968191204",s,event,"0",,event_type,"0",,,,,,,,,,,,,,
    com.garmin.fit.EventMesg lEvent = new EventMesg();
    lEvent.setTimestamp(new com.garmin.fit.DateTime( lStartTime ));
    lEvent.setEvent(Event.TIMER /*0*/);
    lEvent.setEventType(EventType.START/* 0*/);
    encode.write(lEvent);

    // Data,0,developer_data_id,application_id,"3|2|1|0|5|4|7|6|8|9|10|11|12|13|14|15",,developer_data_index,"0",,application_version,"110",,,,,,,,,,,,,,
    byte[] appId = new byte[] {
    0x3, 0x2, 0x1, 0x0,
    0x5, 0x4, 0x7, 0x6,
    0x8, 0x9, 0x10, 0x11,
    0x12, 0x13, 0x14, 0x15
    };
    DeveloperDataIdMesg developerIdMesg = new DeveloperDataIdMesg();
    for(int i = 0; i < appId.length; i++)
    {
    developerIdMesg.setApplicationId(i, appId[i]);
    }
    developerIdMesg.setDeveloperDataIndex((short)0);
    developerIdMesg.setApplicationVersion((long)110);
    encode.write(developerIdMesg);

    // Skipped
    // Data,0,field_description,developer_data_index,"0",,field_definition_number,"0",,fit_base_type_id,"136",,field_name,"Doughnuts Earned",,units,"doughnuts",,native_mesg_num,"18",,,,,
    // Data,0,field_description,developer_data_index,"0",,field_definition_number,"1",,fit_base_type_id,"2",,field_name,"Heart Rate",,units,"bpm",,native_field_num,"3",,native_mesg_num,"20",,

    //Data,0,record,timestamp,"968191204",s,distance,"0.0",m,speed,"1.0",m/s,heart_rate,"126",bpm,cadence,"0",rpm,power,"150",watts,altitude,"127.0",m,enhanced_speed,"1.0",m/s,enhanced_altitude,"127.0",m,Heart Rate,"126",bpm,
    //Data,0,record,timestamp,"981301968",s,position_lat,"495280430",semicircles,position_long,"-872696681",semicircles,heart_rate,"122",bpm,cadence,"88",rpm,distance,"2080.0",m,ebike_battery_level,"50",percent,temperature,"0",C,,,,
    RecordMesg record = new RecordMesg();

    int ii;

    for (ii=0;ii<50;ii++) {

    DateTime d2 = new com.garmin.fit.DateTime( lStartTime + ii);
    record.setTimestamp(d2);
    record.setDistance(2080f+ii);
    record.setPositionLat(495280430 + ii*10);
    record.setPositionLong(-872696681 + ii*10);
    //record.setPositionLong(pow(2, 31) * (longitudeX) / 180.0);
    //record.setPositionLat(pow(2, 31) * (latitudeY) / 180.0);

    record.setHeartRate((short)100);
    record.setCadence((short) 88);
    record.setSpeed(2800f);
    record.setPower(100+ii);
    record.setAltitude((float)250+ii);
    record.setEbikeBatteryLevel((short)(50-ii));
    record.setTemperature((byte)(ii/2));

    encode.write(record);
    }

    // Data,0,event,timestamp,"968194805",s,event,"0",,event_type,"4",,,,,,,,,,,,,,,,,,,,,,,
    com.garmin.fit.EventMesg lEvent2 = new EventMesg();
    lEvent2.setTimestamp(new com.garmin.fit.DateTime( lStartTime + ii ));
    lEvent2.setEvent(Event.TIMER /*0*/);
    lEvent2.setEventType(EventType.STOP_ALL/* 4*/);
    encode.write(lEvent2);

    // Data,0,lap,timestamp,"968194805",s,start_time,"968191204",,total_elapsed_time,"3601.0",s,total_timer_time,"3601.0",s,,,,,,,,,,,,,,,,,,,
    com.garmin.fit.LapMesg lapMesg2 = new LapMesg();
    lapMesg2.setTimestamp(new com.garmin.fit.DateTime(lStartTime+ii));
    lapMesg2.setStartTime(new com.garmin.fit.DateTime(lStartTime));
    lapMesg2.setTotalElapsedTime((float)ii);
    lapMesg2.setTotalTimerTime((float)ii);
    encode.write(lapMesg2);


    //Data,0,session,timestamp,"968194805",s,start_time,"968191204",,total_elapsed_time,"3601.0",s,total_timer_time,"3601.0",s,sport,"2",,sub_sport,"46",,first_lap_index,"0",,num_laps,"1",,Doughnuts Earned,"3.0008333",doughnuts,,,,
    com.garmin.fit.SessionMesg sessionMesg = new SessionMesg();
    sessionMesg.setTimestamp(new com.garmin.fit.DateTime(lStartTime+ii));
    sessionMesg.setStartTime(new com.garmin.fit.DateTime(lStartTime));
    sessionMesg.setTotalElapsedTime((float)ii); //Total number of msec since timer started (includes pauses) - Todo: calculate paused time
    sessionMesg.setTotalTimerTime((float)ii); //Timer Time (excludes pauses)
    sessionMesg.setSport(Sport.CYCLING);
    sessionMesg.setFirstLapIndex(0);
    sessionMesg.setNumLaps(1);
    encode.write(sessionMesg);

    // Data,0,activity,timestamp,"968194805",,num_sessions,"1",,local_timestamp,"968169605",,,,,,,,,,,,,,,,,,,,,,,
    com.garmin.fit.ActivityMesg activityMesg = new com.garmin.fit.ActivityMesg();
    activityMesg.setTimestamp(new com.garmin.fit.DateTime(lStartTime+ii));
    activityMesg.setNumSessions(1); // Always 1 session (1 workout per file)
    activityMesg.setLocalTimestamp(new com.garmin.fit.DateTime(lStartTime+ii).getTimestamp());
    encode.write(activityMesg);

    try {
    encode.close();
    } catch (FitRuntimeException e) {
    System.err.println("Error closing encode.");
    return;
    }

    }

  • The Activity Encode recipe covers how to encode an activity file that is compatible with most platforms. The recipe code is in C# but the concepts apply to any language. The activity_developerdata.fit that is mentioned in this thread is the output of that recipe.
    https://developer.garmin.com/fit/cookbook/encoding-activity-files/

    The Activity File type documentation also provides a list of the required and option messages that are used in Activity Files.
    https://developer.garmin.com/fit/file-types/activity/