Skip to content

Instantly share code, notes, and snippets.

@tiago-peres
Last active July 5, 2025 15:22
Show Gist options
  • Save tiago-peres/62b7cc55f6a7f9eaf41655ebec6511f6 to your computer and use it in GitHub Desktop.
Save tiago-peres/62b7cc55f6a7f9eaf41655ebec6511f6 to your computer and use it in GitHub Desktop.
Import CSV Weight data into Garmin

I've used a Smart Scale since 2020 with its own app which eventually became Zepp Life.

Having acquired a Garmin a while ago, would be a pity to lose all that data.

The good news is that we can pull data from other accounts or activity trackers into Garmin Connect in the import page

https://connect.garmin.com/modern/import-data

So, I exported the Body data as CSV from Zepp Life.

The data looks like this

time,weight,height,bmi,fatRate,bodyWaterRate,boneMass,metabolism,muscleRate,visceralFat
2020-09-01 08:00:17+0000,83.6,186.0,24.1,0.0,0.0,0.0,0.0,0.0,0.0
2020-09-01 22:02:16+0000,82.8,186.0,23.9,0.0,0.0,0.0,0.0,0.0,0.0

After trying to import, realized that Garmin doesn't support uploading that file.

The question emerging is then which format does the CSV need have to be able to upload it in Garmin?

Thanks to someone in Reddit, found that it's something like this

Body
weight,bmi,fat,date,time
83.6,24.1,0.0,2020-09-01,08:00:17
82.8,23.9,0.0,2020-09-01,22:02:16

Eventually also found here as well.

So, initially created a simple Python script that reads weight and body composition data from a "zep_life.csv" file, and converted it into a CSV format that was ready to be imported into Garmin

This time I wasn't getting a warning anymore but it got stuck

image

as in, nothing seemed to have happend.

I figured it had to do with the size of the file.

So, instead of generating only one file, I generated one file per year and it worked

image

This is the used script

import csv
import datetime

INPUT_CSV = "zep_life.csv"

def zep_to_garmin_csv():
    """
    Reads a CSV file named "zep_life.csv" and writes multiple yearly CSVs named
    "garmin_ready_<year>.csv". Each output file has the first line "Body", 
    followed by "weight,bmi,fat,date,time" as headers. Rows are based on the 
    'time' field in the input, split by year.

    Usage:
        1. Place "zep_life.csv" in the same directory as this script.
        2. Run this script.
        3. For each year encountered in "zep_life.csv", a file named 
           "garmin_ready_<year>.csv" will be created.

    Requirements:
        - The input CSV must have the columns: "time", "weight", "bmi", "fatRate".
        - "time" must be in a format parseable by datetime.strptime with 
          "%Y-%m-%d %H:%M:%S%z".
        - "fatRate" of "null" or empty is replaced with "0.0".
    """
    yearly_writers = {}
    with open(INPUT_CSV, mode="r", encoding="utf-8-sig") as fin:
        reader = csv.DictReader(fin)
        for row in reader:
            raw_time = row.get("time", "").strip()
            weight_str = row.get("weight", "").strip()
            bmi_str = row.get("bmi", "").strip()
            fat_str = row.get("fatRate", "").strip()
            
            if not raw_time or not weight_str:
                continue

            try:
                dt = datetime.datetime.strptime(raw_time, "%Y-%m-%d %H:%M:%S%z")
            except ValueError:
                continue

            date_str = dt.strftime("%Y-%m-%d")  # "YYYY-MM-DD"
            time_str = dt.strftime("%H:%M:%S")  # "HH:MM:SS"
            
            if fat_str.lower() in ("null", ""):
                fat_str = "0.0"

            # If we haven't opened a file for this year yet, do so and write headers.
            year = dt.year
            if year not in yearly_writers:
                fout = open(f"garmin_ready_{year}.csv", "w", newline="", encoding="utf-8")
                writer = csv.writer(fout)
                
                # First line: "Body"
                writer.writerow(["Body"])
                
                # Second line: headers
                writer.writerow(["weight", "bmi", "fat", "date", "time"])
                
                # Store it in the dictionary
                yearly_writers[year] = (fout, writer)

            # Write the row to the proper year's CSV.
            _, csv_writer = yearly_writers[year]
            csv_writer.writerow([weight_str, bmi_str, fat_str, date_str, time_str])

    # Close all the files
    for fout, _ in yearly_writers.values():
        fout.close()

    print("Done! Split files by year.")


if __name__ == "__main__":
    zep_to_garmin_csv()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment