-
-
Notifications
You must be signed in to change notification settings - Fork 346
Useful import scripts
OliE edited this page Oct 22, 2025
·
10 revisions
by Martin1887 see https://github.com/oliexdev/openScale/issues/669
#!/usr/bin/python
import argparse
import csv
import datetime
OPENSCALE_HEADER = '"biceps","bone","caliper1","caliper2","caliper3","calories","chest","comment","dateTime","fat","hip","lbm","muscle","neck","thigh","visceralFat","waist","water","weight"'
_MIFIT_BODY_HEADER = 'timestamp,weight,height,bmi,fatRate,bodyWaterRate,boneMass,metabolism,muscleRate,visceralFat,impedance'
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('mifit_BODY_csv_file_path')
parser.add_argument('output_path')
args = parser.parse_args()
with open(args.mifit_BODY_csv_file_path, 'r') as inp:
reader = csv.DictReader(inp)
with open(args.output_path, 'w') as outp:
writer = csv.DictWriter(outp, OPENSCALE_HEADER.replace('"', '').split(','))
outp.write(f'{OPENSCALE_HEADER}\n')
for line in reader:
timestamp = int(line['timestamp'])
output_date = datetime.datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M')
weight = line['weight']
writer.writerow({'dateTime': output_date, 'weight': weight})
initial script by feclare see https://github.com/oliexdev/openScale/issues/28
modified script by abatula see https://github.com/oliexdev/openScale/issues/1050
#!/usr/bin/env python
"""
Simple script to transform libra csv file to openscale format
Optional argument to convert lbs to kg for correct import
Sample usage:
# Does not modify the Libra values
python libra_to_openscale.py Libra_2024-06-04.csv
# Convert Libra values from lbs to kg
python libra_to_openscale.py Libra_2024-06-04.csv lbs
"""
import sys
import csv
from dateutil.parser import parse
if len(sys.argv) < 2:
print('Missing file to transform')
sys.exit(1)
if (len(sys.argv) > 2) and (sys.argv[2] == 'lbs'):
print('Converting Libra data from lbs to kg')
weight_scalar = 0.453592
else:
print('Leaving Libra data as-is (kg)')
weight_scalar = 1
with open(sys.argv[1], 'r') as inputfile:
r = csv.reader(inputfile, delimiter=";")
lines = list(r)
with open('openScale_data_Libra.csv', 'w') as outputfile:
writer = csv.writer(outputfile, delimiter=",")
for w in lines:
if len(w) == 0 or w[0].startswith("#"):
continue
time = w[0]
weight_float = float(w[1]) * weight_scalar
weight = f'{weight_float:.1f}'
comment = w[5]
d = parse(time)
writer.writerow([d.strftime('%d.%m.%Y %H:%M'), weight, 0.0, 0.0, 0.0, 0.0, 0.0, comment])by jowlo see https://github.com/oliexdev/openScale/issues/777
#!/usr/bin/env python
"""
Simple script to transform openscale csv export files to a format accepted by garmin connect at
https://connect.garmin.com/modern/import-data
Note: When importing the language needs to be set to English, otherwise the import fails.
Set everything to metric units and to YYYY-MM-DD date format.
If you want to compute BMI for the file give your height (im meters) as second parameter.
"""
import sys
import csv
from dateutil.parser import parse
if len(sys.argv) < 2:
print ("Missing file to transform\n")
sys.exit(1)
bmi = lambda size: 0;
if len(sys.argv) == 3:
bmi = lambda weight: weight/(float(sys.argv[2])**2)
with open("openScale_garmin_connect_import.csv", "w") as outfile, open(sys.argv[1], "r") as infile:
reader = csv.DictReader(infile, delimiter=",")
writer = csv.writer(outfile, delimiter=",")
outfile.write("Body\n")
outfile.write("Date,Weight,BMI,Fat\n")
for row in reader:
writer.writerow([
parse(row["dateTime"]).strftime('%Y-%m-%d'),
row["weight"],
bmi(float(row["weight"])),
row["fat"]
])by antonmosich see https://github.com/oliexdev/openScale/issues/879
#!/usr/bin/python
import csv
import json
import datetime
import argparse
OPENSCALE_HEADER = '"biceps","bone","caliper1","caliper2","caliper3","calories","chest","comment","dateTime","fat","hip","lbm","muscle","neck","thigh","visceralFat","waist","water","weight"'
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument("input")
parser.add_argument("output")
args = parser.parse_args()
with open(args.input, 'r') as input_file:
input_json = json.load(input_file)
filtered = [entry for entry in input_json if "weight" in entry]
with open(args.output, 'w') as output_file:
writer = csv.DictWriter(output_file, OPENSCALE_HEADER.replace('"', '').split(','))
output_file.write(f'{OPENSCALE_HEADER}\n')
for entry in filtered:
timestamp = datetime.datetime.fromisoformat(entry['weight']['timestampGMT'].ljust(23,'0'))
weight = entry['weight']['weight'] / 1000
writer.writerow({'dateTime': timestamp, 'weight': weight})by sainigma see https://github.com/oliexdev/openScale/issues/1040
#!/usr/bin/env python
import csv
from dateutil.parser import parse
with open('Daily activity metrics.csv', newline='') as input_csv:
csv_reader = csv.reader(input_csv, delimiter=',')
rows = []
for row in csv_reader:
rows.append(row)
headers = rows[0]
data = rows[1:]
date_idx = headers.index('Date')
weight_idx = headers.index('Average weight (kg)')
with open('openscale_data.csv', 'w', newline='', encoding='utf-8') as output_csv:
output_writer = csv.writer(output_csv, delimiter=',')
output_writer.writerow(["dateTime", "weight"])
for fragment in data:
date = fragment[date_idx]
weight = fragment[weight_idx]
if (weight and date):
output_writer.writerow([parse(date).strftime('%d.%m.%Y 08:00'), round(float(weight), 2)])by MoralCode see https://github.com/oliexdev/openScale/issues/731
#!/usr/bin/python
# Usage: first run your apple health export through the scripts as documented in https://github.com/markwk/qs_ledger/tree/master/apple_health
# then run this script using the BodyMass.csv from this process to get an OpenScale csv
import argparse
import csv
import datetime
from dateutil.parser import parse as parsedate
OPENSCALE_HEADER = '"biceps","bone","caliper1","caliper2","caliper3","calories","chest","comment","dateTime","fat","hip","lbm","muscle","neck","thigh","visceralFat","waist","water","weight"'
OPENSCALE_HEADER = OPENSCALE_HEADER.replace('"', '')
_APPLE_QUANTIFIEDSELF_BODYMASS_HEADER = 'sourceName,sourceVersion,device,type,unit,creationDate,startDate,endDate,value'
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('apple_bodymass_csv_file_path')
parser.add_argument('output_path')
args = parser.parse_args()
with open(args.apple_bodymass_csv_file_path, 'r') as inp:
reader = csv.DictReader(inp)
with open(args.output_path, 'w') as outp:
writer = csv.DictWriter(outp, OPENSCALE_HEADER.split(','))
# outp.write(f'{OPENSCALE_HEADER}\n')
writer.writeheader()
for line in reader:
creationDate = line['creationDate']
output_date = parsedate(creationDate).strftime('%Y-%m-%d %H:%M')
weight = float(line['value'])
if line['unit'] == 'lb':
# convert to KG
weight = weight / 2.2
comment = "Imported from Apple Health export. Data originally from "
appname = line["sourceName"]
# make the apple health app name a little more obvious. by default its just "health"
if appname == "Health":
appname = "Apple Health"
comment += appname + " app"
appversion = line["sourceVersion"]
if appversion != "":
comment += " version " + appversion
writer.writerow({
'dateTime': output_date,
'weight': "{:.2f}".format(weight),
'comment': comment
})by sarika-03 see https://github.com/oliexdev/openScale/issues/728
import pandas as pd
input_file = "HealthCoach.xlsx"
df = pd.read_excel(input_file)
print("Columns in Excel file:", list(df.columns))
df.columns = df.columns.str.strip()
df_openscale = pd.DataFrame()
df_openscale['date'] = pd.to_datetime(
df['Date'].astype(str) + ' ' + df['Time'].astype(str),
dayfirst=True, errors='coerce'
).dt.strftime('%Y-%m-%d %H:%M:%S')
df_openscale['weight'] = df.get('Weight (kg)', None)
df_openscale['fat'] = df.get('Body Fat (%)', None)
df_openscale['fat_top'] = df.get('Body Fat (Top %)', None)
df_openscale['fat_bottom'] = df.get('Body Fat (Bottom %)', None)
df_openscale['water'] = df.get('Water (%)', None)
df_openscale['muscle'] = df.get('Muscle (%)', None)
df_openscale['muscle_top'] = df.get('Muscle (Top %)', None)
df_openscale['muscle_bottom'] = df.get('Muscle (Bottom %)', None)
df_openscale['bone'] = df.get('Bone (kg)', None)
df_openscale['bmi'] = df.get('BMI', None)
df_openscale['bmr'] = df.get('BMR (kcal)', None)
df_openscale['amr'] = df.get('AMR (kcal)', None)
df_openscale['activity_level'] = df.get('Activity Level', None)
output_file = "openScale_ready_data.csv"
df_openscale.to_csv(output_file, index=False)
print(f"\n Conversion complete! File saved as: {output_file}")by tomjelen see https://github.com/oliexdev/openScale/issues/1192
#!/usr/bin/python
"""
Fitbit to OpenScale Converter
Converts Fitbit weight export JSON files to OpenScale CSV format.
This script processes all weight-*.json files from a Fitbit data export
and converts them to a single CSV file compatible with OpenScale.
Usage:
python fitbit-to-openscale.py <fitbit_export_folder> <output_csv_file>
Example:
python fitbit-to-openscale.py "TomJelen/Personal & Account" openscale_weight_data.csv
"""
import argparse
import csv
import datetime
import json
import os
import glob
import sys
from pathlib import Path
# OpenScale CSV header - all supported fields
OPENSCALE_HEADER = '"biceps","bone","caliper1","caliper2","caliper3","calories","chest","comment","dateTime","fat","hip","lbm","muscle","neck","thigh","visceralFat","waist","water","weight"'
def find_weight_files(fitbit_folder):
"""
Find all weight-*.json files in the Fitbit export folder.
Args:
fitbit_folder (str): Path to the Fitbit export folder
Returns:
list: List of paths to weight JSON files
"""
if not os.path.exists(fitbit_folder):
raise FileNotFoundError(f"Fitbit export folder not found: {fitbit_folder}")
# Look for weight-*.json files
pattern = os.path.join(fitbit_folder, "weight-*.json")
weight_files = glob.glob(pattern)
if not weight_files:
raise FileNotFoundError(f"No weight-*.json files found in {fitbit_folder}")
print(f"Found {len(weight_files)} weight files")
return sorted(weight_files)
def parse_fitbit_json(file_path):
"""
Parse a single Fitbit weight JSON file and extract measurements.
Args:
file_path (str): Path to the JSON file
Returns:
list: List of measurement dictionaries
"""
try:
with open(file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
if not isinstance(data, list):
print(f"Warning: {file_path} does not contain a list, skipping")
return []
measurements = []
for entry in data:
if not isinstance(entry, dict):
continue
# Extract required fields
log_id = entry.get('logId')
weight = entry.get('weight')
fat = entry.get('fat')
# Skip entries without essential data
if log_id is None or weight is None:
continue
measurements.append({
'logId': log_id,
'weight': weight,
'fat': fat,
'bmi': entry.get('bmi'),
'source': entry.get('source', 'Unknown')
})
return measurements
except json.JSONDecodeError as e:
print(f"Error parsing JSON file {file_path}: {e}")
return []
except Exception as e:
print(f"Error reading file {file_path}: {e}")
return []
def convert_timestamp(log_id):
"""
Convert Fitbit logId (milliseconds since epoch) to OpenScale datetime format.
Args:
log_id (int): Fitbit logId timestamp in milliseconds
Returns:
str: Formatted datetime string (YYYY-MM-DD HH:MM)
"""
try:
# Convert milliseconds to seconds
timestamp_seconds = log_id / 1000.0
dt = datetime.datetime.fromtimestamp(timestamp_seconds)
return dt.strftime('%Y-%m-%d %H:%M')
except (ValueError, OSError) as e:
print(f"Error converting timestamp {log_id}: {e}")
return None
def process_all_weight_data(fitbit_folder):
"""
Process all weight JSON files and return sorted measurements.
Args:
fitbit_folder (str): Path to the Fitbit export folder
Returns:
list: List of all measurements sorted by datetime
"""
weight_files = find_weight_files(fitbit_folder)
all_measurements = []
for file_path in weight_files:
print(f"Processing {os.path.basename(file_path)}...")
measurements = parse_fitbit_json(file_path)
all_measurements.extend(measurements)
print(f"Total measurements found: {len(all_measurements)}")
# Convert timestamps and filter out invalid entries
valid_measurements = []
for measurement in all_measurements:
datetime_str = convert_timestamp(measurement['logId'])
if datetime_str:
measurement['dateTime'] = datetime_str
valid_measurements.append(measurement)
print(f"Valid measurements after timestamp conversion: {len(valid_measurements)}")
# Sort by datetime
valid_measurements.sort(key=lambda x: x['dateTime'])
return valid_measurements
def write_openscale_csv(measurements, output_path):
"""
Write measurements to OpenScale CSV format.
Note: Fitbit exports weight data in pounds regardless of user profile settings.
This function converts pounds to kilograms for OpenScale compatibility.
Args:
measurements (list): List of measurement dictionaries
output_path (str): Path to output CSV file
"""
# Define the field names in the order they appear in the header
fieldnames = ['biceps', 'bone', 'caliper1', 'caliper2', 'caliper3', 'calories',
'chest', 'comment', 'dateTime', 'fat', 'hip', 'lbm', 'muscle',
'neck', 'thigh', 'visceralFat', 'waist', 'water', 'weight']
try:
with open(output_path, 'w', newline='', encoding='utf-8') as csvfile:
# Write the header exactly as OpenScale expects it
csvfile.write(f'{OPENSCALE_HEADER}\n')
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
for measurement in measurements:
# Create a row with only the fields we have data for
row = {field: '' for field in fieldnames} # Initialize all fields as empty
# Fill in the fields we have data for
row['dateTime'] = measurement['dateTime']
# Convert weight from pounds to kilograms
# Fitbit exports weight in pounds regardless of user profile settings
weight_lbs = float(measurement['weight'])
weight_kg = weight_lbs / 2.20462 # Convert pounds to kilograms
row['weight'] = f'{weight_kg:.2f}' # Round to 2 decimal places
# Add fat percentage if available
if measurement.get('fat') is not None:
row['fat'] = measurement['fat']
# Add a comment with source information
source = measurement.get('source', 'Fitbit')
row['comment'] = f'Imported from {source} (converted from lbs)'
writer.writerow(row)
print(f"Successfully wrote {len(measurements)} measurements to {output_path}")
except Exception as e:
print(f"Error writing CSV file: {e}")
raise
def main():
"""Main function with argument parsing."""
parser = argparse.ArgumentParser(
description='Convert Fitbit weight export JSON files to OpenScale CSV format',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python fitbit-to-openscale.py "TomJelen/Personal & Account" openscale_weight_data.csv
python fitbit-to-openscale.py /path/to/fitbit/export output.csv
"""
)
parser.add_argument('fitbit_folder',
help='Path to Fitbit export folder containing weight-*.json files')
parser.add_argument('output_csv',
help='Path to output CSV file for OpenScale')
args = parser.parse_args()
try:
print("Fitbit to OpenScale Converter")
print("=" * 40)
print(f"Input folder: {args.fitbit_folder}")
print(f"Output file: {args.output_csv}")
print()
# Process all weight data
measurements = process_all_weight_data(args.fitbit_folder)
if not measurements:
print("No valid measurements found. Exiting.")
sys.exit(1)
# Write to OpenScale CSV format
write_openscale_csv(measurements, args.output_csv)
print()
print("Conversion completed successfully!")
print(f"You can now import {args.output_csv} into OpenScale.")
except Exception as e:
print(f"Error: {e}")
sys.exit(1)
if __name__ == '__main__':
main()