From 80b6b7bbef97c0f08914c61032610bdbe24ce79f Mon Sep 17 00:00:00 2001 From: ManuelW Date: Sat, 11 May 2024 08:03:49 +0200 Subject: [PATCH] initial --- ebike.db | Bin 0 -> 28672 bytes insertLoading.py | 153 +++++++++++++++++++++++++++++++++++++++++++++++ parseFitFiles.py | 121 +++++++++++++++++++++++++++++++++++++ 3 files changed, 274 insertions(+) create mode 100644 ebike.db create mode 100644 insertLoading.py create mode 100644 parseFitFiles.py diff --git a/ebike.db b/ebike.db new file mode 100644 index 0000000000000000000000000000000000000000..ebb9384922e63343b90053de22f4de709f0b8b77 GIT binary patch literal 28672 zcmeI)&rj1}7zgma8(SFxYVK00$>JC=ipZ&Xp|7x5HrXnA9pPf) z$%{e%3I7892lQY(=>Nchs|OFh{W0236i*!H_stsG=Xv)w&*y2DG-F*|sWxm*AGg}O z%%(-@l0=A9qEwQkgxF+%BjRsTY(rw}4JUTqNJuyLUydn1q{Qg4H2y~UIIfKzkB^UD zJ@1XkLjVF0fB*y_009U<00I{$&|OZ-=}d+kJh9oP#rbCA2{%k;vtUo2uWMypqk8#n zRioJ;k)@L(sq8&w^K44j9_dr!sM=y?qq&_;RcgAnpw*q2-m;lR>#VsgCjJ&LceZ%b zjwH$t7wGC!&do^FS(=-4eJ2vV&vx22Z=S|R@&|NCPESmbL)k6KtEk=B=bg}QB3e`^ z<5krN&P{7eI<2i$t8}eaSy|JZl1#_QFZ(p_C2Xf!!)$bH*4z?P1YR|qVSc?qe3!j2 zm?a2;5Zm82I-Wo@xYItZ)LV3mS*>=1cf#T2dS$U(-=Gh)jmfO2gqGLzrAkedyr|Xm z{78N_kxW-6h}3AB{6%Na61Rp1duF%XV=C!1`SPl`MoK~<-^ zdm@$TPemtn7o9o8ofKruU{|cv&AW5lNkPJ#bN9Q>`7?ybVu^6F^!i(|SZw)8k^Mbc zESA)3N7dex*qKwNMS5B+FUL|&VNQW+fvU52RMnjGPU5X|baeDq`Y<9oOO&6Icws;Q z0uX=z1Rwwb2tWV=5P$##ATWRe@pvlbegA(VDJKJ1AWDJ&1Rwwb2tWV=5P$##AOHaf z{GS2}iRV(`pGi3P|Kdmg7!ZH}1Rwwb2tWV=5P$##AOHaf46uOn|NprEAK(U~GzdTd z0uX=z1Rwwb2tWV=5P(2PK>4n`SKfsJ*o6QDAOHafKmY;|fB*y_009U<;35RB#D_Cv z*cs|v?>U9$^_U3CG9g5r=>?Zd^RGUM@wv3~RXjtmSiHP6be)KK?o$B&^c+F&`G3Cv DEZ~%S literal 0 HcmV?d00001 diff --git a/insertLoading.py b/insertLoading.py new file mode 100644 index 0000000..7f07d1a --- /dev/null +++ b/insertLoading.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from fitparse import FitFile +from datetime import datetime, timedelta +import os, sys, shutil +from os import walk +import csv +import pandas as pd + + +path = "/home/manuel/Dropbox/Apps/HealthFitExporter/" +#path = "/Users/manuel/Projekte/eBike-Influx-Calculation/" +ext = ('.fit') +csv_file = "/www/wwwroot/www.manuelw.de/ebike/ebike_data.csv" + +output = {} +fitData = {} +fitData["total_distance"] = 0 +fitData["total_ascent"] = 0 +fitData["avg_speed"] = 0 +fitData["avg_speed_count"] = 0 +fitFilesCount = 0 + +loading = sys.argv[1] +watt = sys.argv[2] +row = [] + +## +### auf neue Files überwachen +def main(): + f = [] + for base, dirs, files in os.walk(path): + files = [ fi for fi in files if fi.endswith(".fit") ] + if files: + processFIT(files) + +## +### parse FIT file und bestimme Handling +def processFIT(files): + global fitFilesCount + + print("Files:", len(files)) + fitFilesCount = len(files) + for filename in files: + #print(filename) + file = FitFile(path+filename) + for record in file.get_messages("session"): + ## nur wenn Radfahren + if record.get_value("sport") == "cycling": + ## Verarbeitung starten + doAll(file) + + showEnd() + readCSV() + deleteFiles() + + +## +### todo on all fit files +def doAll(file): + for record in file.get_messages("session"): + fitData["avg_cadence"] = record.get_value("avg_cadence") + #fitData["avg_speed"] += round(float(record.get_value("avg_speed")) / 0.27777777777778, 1) + fitData["avg_speed"] += record.get_value("avg_speed") + fitData["avg_speed_count"] +=1 + #fitData["total_ascent"] = float(record.get_value("total_ascent")) if record.get_value("total_ascent") != None else 0 + fitData["total_distance"] += float(round(record.get_value("total_distance") / 1000, 1)) + + fitData["avg_speed"] = round(float(fitData["avg_speed"] / fitData["avg_speed_count"]), 1) + doHealthFit(file, record.get_value("min_altitude")) + + +def doHealthFit(file, min_alt=0.0): + ### Kadenz + i=0 + cadence=0 + last_elev=min_alt + ges_elev=0.0 + + for record in file.get_messages("record"): + ## korrekte Kadenz ermitteln + if record.get_value("cadence") != None and record.get_value("cadence") > 0: + i+=1 + cadence += record.get_value("cadence") + + ## korrekte Höhenmeter ermitteln + if record.get_value("altitude") != None: + if record.get_value("altitude") > last_elev: + ges_elev += record.get_value("altitude") - last_elev + + last_elev = record.get_value("altitude") + + #fitData["avg_cadence"] = int(cadence/i) + fitData["total_ascent"] += round(float(ges_elev), 1) + fitData["total_ascent"] = round(float(fitData["total_ascent"]), 1) + + +def showEnd(): + print("Akku geladen",loading) + print("Ladung Wh",watt) + print("Total Range", fitData["total_distance"]) + print("Total Ascent", fitData["total_ascent"]) + print("AVG Speed", fitData["avg_speed"]) + + +def readCSV(): + global fitData, fitFilesCount + + with open(csv_file, "r", encoding="utf-8", errors="ignore") as scraped: + row = [] + try: + row.extend(scraped.readlines()[-1].replace("\n", "").split(",")) + row = row[0:-5] + dropCSV() + row.extend([fitData["total_distance"], fitData["total_ascent"], fitData["avg_speed"], watt, fitFilesCount]) + writeCSV(row) + + except: + print("EXCEPTION") + row.extend(["Date", "Loading", "Total Range", "Total Ascent", "AVG Speed", "Loaded Wh", "Fahrten"]) + writeCSV(row) + + +def writeCSV(row): + with open(csv_file, 'a', newline='') as csvfile: + spamwriter = csv.writer(csvfile, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL) + spamwriter.writerow(row) + spamwriter.writerow([datetime.today().strftime('%d-%m-%Y'), loading, 0, 0, 0, 0, 0]) + + +def dropCSV(): + df = pd.read_csv(csv_file, index_col='Date', on_bad_lines='skip') + df = df.iloc[:-1] + df.to_csv(csv_file, index=True) + + +def deleteFiles(): + for filename in os.listdir(path): + file_path = os.path.join(path, filename) + try: + if os.path.isfile(file_path) or os.path.islink(file_path): + os.unlink(file_path) + #print("lösche... test") + elif os.path.isdir(file_path): + shutil.rmtree(file_path) + except Exception as e: + print('Failed to delete %s. Reason: %s' % (file_path, e)) + + +if __name__ == '__main__': + main() + diff --git a/parseFitFiles.py b/parseFitFiles.py new file mode 100644 index 0000000..e604891 --- /dev/null +++ b/parseFitFiles.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +from fitparse import FitFile +from datetime import datetime +import inotify.adapters +import os, sys, shutil +import sqlite3 + + +path = "/home/manuel/Dropbox/Apps/HealthFitExporter/" +#path = "/Users/manuel/Projekte/eBike-Influx-Calculation/test/" +ext = ('.fit') +db_file = "/www/wwwroot/www.manuelw.de/ebike/ebike.db" +#db_file = "/Users/manuel/Projekte/eBike-Influx-Calculation/ebike.db" + +fitData = {} + +## +### auf neue Files überwachen +def main(): + i = inotify.adapters.InotifyTree(path) + + for event in i.event_gen(yield_nones=False): + (_, type_names, fpath, filename) = event + + if event != None: + print("PATH=[{}] FILENAME=[{}] EVENT_TYPES={}".format(path, filename, type_names)) + if type_names[0] == "IN_MOVED_TO": + if filename.endswith(ext): + processFIT(filename) + + pass + +## +### parse FIT file und bestimme Handling +def processFIT(filename): + file = FitFile(path+filename) + for record in file.get_messages("session"): + ## nur wenn Radfahren + if record.get_value("sport") == "cycling": + ## Verarbeitung starten + doAll(file) + + writeDB() + + +## +### todo on all fit files +def doAll(file): + global fitData + + for record in file.get_messages("session"): + fitData["avg_cadence"] = record.get_value("avg_cadence") + #fitData["avg_speed"] += round(float(record.get_value("avg_speed")) / 0.27777777777778, 1) + fitData["avg_speed"] = record.get_value("avg_speed") + #fitData["total_ascent"] = float(record.get_value("total_ascent")) if record.get_value("total_ascent") != None else 0 + fitData["total_distance"] = round(record.get_value("total_distance") / 1000, 1) + fitData["date"] = record.get_value("start_time").strftime("%d.%m.%Y") + fitData["total_calories"] = record.get_value("total_calories") + if record.get_value("max_altitude"): + fitData["max_altitude"] = round(float(record.get_value("max_altitude")), 1) + else: + fitData["max_altitude"] = 0 + fitData["max_heart_rate"] = record.get_value("max_heart_rate") + fitData["avg_heart_rate"] = record.get_value("avg_heart_rate") + + fitData["avg_speed"] = round(float(fitData["avg_speed"]), 1) + doHealthFit(file, record.get_value("min_altitude")) + + +def doHealthFit(file, min_alt=0.0): + global fitData + + ### Kadenz + i=0 + cadence=0 + last_elev=min_alt + ges_elev=0.0 + + for record in file.get_messages("record"): + ## korrekte Kadenz ermitteln + if record.get_value("cadence") != None and record.get_value("cadence") > 0: + i+=1 + cadence += record.get_value("cadence") + + ## korrekte Höhenmeter ermitteln + if record.get_value("altitude") != None: + if record.get_value("altitude") > last_elev: + ges_elev += record.get_value("altitude") - last_elev + + last_elev = record.get_value("altitude") + + #fitData["avg_cadence"] = int(cadence/i) + fitData["total_ascent"] = round(float(ges_elev), 1) + + +def writeDB(): + global fitData, db_file + + db = sqlite3.connect(db_file) + cursor = db.cursor() + + data = [fitData["date"], fitData["total_distance"], fitData["total_ascent"], fitData["max_altitude"], fitData["avg_speed"], + fitData["avg_heart_rate"], fitData["total_calories"]] + + cursor.executemany('INSERT INTO bike_drives VALUES (?)', data) + db.commit() + db.close() + + + #row.extend(["Date", "Total Distance", "Total Ascent", "Max Alt.", "AVG Speed", "AVG HR", "Calories"]) + #row.extend([fitData["date"], fitData["total_distance"], fitData["total_ascent"], fitData["max_altitude"], fitData["avg_speed"], + # fitData["avg_heart_rate"], fitData["total_calories"] ]) + + + +if __name__ == '__main__': + main() + + \ No newline at end of file