diff --git a/logger.py b/logger.py index e55f6bb5..03a91b0f 100644 --- a/logger.py +++ b/logger.py @@ -25,7 +25,8 @@ def flush(self): class CustomRotatingFileHandler(RotatingFileHandler): def doRollover(self): - format = "%Y-%m-%d_%H-%M-%S" + datetime_format = "%Y-%m-%d_%H-%M-%S" + if self.stream: self.stream.close() self.stream = None @@ -39,7 +40,7 @@ def doRollover(self): match = re.match(regex, f) if match: try: - date = datetime.strptime(match.group(1), format) + date = datetime.strptime(match.group(1), datetime_format) if date < cut_out_date: os.remove(f) except Exception: @@ -52,7 +53,7 @@ def doRollover(self): self.rotate( self.baseFilename, - f"{base_filename_no_ext}-{last_date.strftime(format)}{ext}", + f"{base_filename_no_ext}-{last_date.strftime(datetime_format)}{ext}", ) if not self.delay: self.stream = self._open() diff --git a/modules/config.py b/modules/config.py index 9c0d25bb..3f21d592 100644 --- a/modules/config.py +++ b/modules/config.py @@ -101,7 +101,6 @@ class Config: G_LOG_DIR = "log" G_LOG_DB = os.path.join(G_LOG_DIR, "log.db") G_LOG_DEBUG_FILE = os.path.join(G_LOG_DIR, "debug.log") - G_LOG_START_DATE = None # asyncio semaphore G_COROUTINE_SEM = 100 @@ -759,7 +758,7 @@ def __init__(self): def init_loop(self, call_from_gui=False): if self.G_GUI_MODE == "PyQt": if call_from_gui: - #asyncio.set_event_loop(self.loop) + # asyncio.set_event_loop(self.loop) # workaround for latest qasync and older version(~0.24.0) asyncio.events._set_running_loop(self.loop) self.start_coroutine() diff --git a/modules/logger/cython/logger_fit.pyx b/modules/logger/cython/logger_fit.pyx index d3c0f762..30d37a90 100644 --- a/modules/logger/cython/logger_fit.pyx +++ b/modules/logger/cython/logger_fit.pyx @@ -1,32 +1,15 @@ +# cython: c_string_type=unicode, c_string_encoding=utf8 + cdef extern from "logger_fit_c.hpp": - cdef bint write_log_c(const char* db_file) except + - #cdef bint write_log_c(const char* db_file) + cdef bint write_log_c(const char* db_file, const char* filename, const char* start_date, const char* end_date) except + cdef cppclass config: unsigned int G_UNIT_ID_HEX - char* G_LOG_START_DATE - char* G_LOG_DIR - char* G_UPLOAD_FILE cdef void set_config_c(const config& _cfg) - cdef char* get_upload_file_name_c() - cdef char* get_start_date_str_c() -def write_log_cython(str db_file): - py_byte_string = db_file.encode('UTF-8') - cdef char* c_db_file = py_byte_string - return write_log_c(c_db_file) +def write_log_cython(str db_file, str filename, str start_date, str end_date): + return write_log_c(db_file, filename, start_date, end_date) def set_config(G_CONFIG): cdef config cfg - py_byte_string = G_CONFIG.G_LOG_DIR.encode('UTF-8') - cfg.G_LOG_DIR = py_byte_string cfg.G_UNIT_ID_HEX = G_CONFIG.G_UNIT_ID_HEX set_config_c(cfg) - -def get_upload_file_name(): - return get_upload_file_name_c().decode('UTF-8') - -def get_start_date_str(): - return get_start_date_str_c().decode('UTF-8') - - - \ No newline at end of file diff --git a/modules/logger/cython/logger_fit_c.cpp b/modules/logger/cython/logger_fit_c.cpp index 782a090f..1fb0ddc2 100644 --- a/modules/logger/cython/logger_fit_c.cpp +++ b/modules/logger/cython/logger_fit_c.cpp @@ -2,14 +2,6 @@ void set_config_c(const config& _cfg) { cfg.G_UNIT_ID_HEX = _cfg.G_UNIT_ID_HEX; - cfg.G_LOG_DIR = strdup(_cfg.G_LOG_DIR); -} - -char* get_upload_file_name_c() { - return cfg.G_UPLOAD_FILE; -} -char* get_start_date_str_c() { - return cfg.G_LOG_START_DATE; } void reset() { @@ -414,7 +406,7 @@ bool get_summary(int lap_num, sqlite3 *db) { std::vector available_data; _ret_data[0].reserve(profile_indexes[message_num].size()); _ret_data[1].reserve(profile_indexes[message_num].size()); - + char _sql_ave[strlen(base_sql[message_num][0].c_str())+strlen(sql_items[message_num][0].c_str())+10]; char _sql_MAX_MIN[strlen(base_sql[message_num][1].c_str())+strlen(sql_items[message_num][1].c_str())+10]; if(message_num == 19) { @@ -454,9 +446,9 @@ bool get_summary(int lap_num, sqlite3 *db) { break; } } - + if(_ret_data[ave_or_MAX_MIN][index].is_null) continue; - + available_fields.push_back(i); available_data.push_back(convert_value(_ret_data[ave_or_MAX_MIN][index].data.c_str(), i)); } @@ -485,11 +477,10 @@ bool get_summary(int lap_num, sqlite3 *db) { return true; } -bool write_log_c(const char* db_file) { +bool write_log_c(const char* db_file, const char* filename, const char* start_date, const char* end_date) { sqlite3 *db; char *zErrMsg = 0; int rc, max_lap, rows, lap_lows; - char start_date[30], end_date[30]; std::vector _size; std::vector _data; reset(); @@ -502,13 +493,14 @@ bool write_log_c(const char* db_file) { rc = sqlite3_open(db_file, &db); if(rc) { return exit_with_error("Can't open database", db); } - //get start_date and end_date - message_num = 0; - rc = sqlite3_exec(db, "SELECT MIN(timestamp) FROM BIKECOMPUTER_LOG", parse_single_str, &start_date, &zErrMsg); - if(rc) { return exit_with_error("SQL error(start_date)", db); } + // we could have start/end made optional and.or validate they are correct here + // char start_date[30], end_date[30]; + // rc = sqlite3_exec(db, "SELECT MIN(timestamp) FROM BIKECOMPUTER_LOG", parse_single_str, &start_date, &zErrMsg); + // if(rc) { return exit_with_error("SQL error(start_date)", db); } + // rc = sqlite3_exec(db, "SELECT MAX(timestamp) FROM BIKECOMPUTER_LOG", parse_single_str, &end_date, &zErrMsg); + // if(rc) { return exit_with_error("SQL error(end_date)", db); } + time_t start_date_epoch = convert_value(start_date, 4); - rc = sqlite3_exec(db, "SELECT MAX(timestamp) FROM BIKECOMPUTER_LOG", parse_single_str, &end_date, &zErrMsg); - if(rc) { return exit_with_error("SQL error(end_date)", db); } time_t end_date_epoch = convert_value(end_date, 4); //file_id (message_num:0) @@ -575,22 +567,21 @@ bool write_log_c(const char* db_file) { if(!get_summary(lap_num, db)) return false; //printf("lap: %d\n", (int)crc16(fit_data)); } - - //make sesson summary + + //make session summary message_num = 18; if(!get_summary(0, db)) return false; //printf("session: %d\n", (int)crc16(fit_data)); - + //make activity message_num = 34; local_message_num = (local_message_num + 1)%16; local_num[local_message_num] = message_num; local_num_field[local_message_num] = {253,0,1,2,3,4,5}; - + //get offset of localtime (use lt.tm_gmtoff) - time_t lt_t = time(NULL); struct tm lt = {0}; - localtime_r(<_t, <); + localtime_r(&end_date_epoch, <); write_definition(); get_struct_def(_size, local_message_num, false); @@ -605,15 +596,10 @@ bool write_log_c(const char* db_file) { }; add_fit_data(fit_data, _data, _size); //printf("footer: %d\n", (int)crc16(fit_data)); - + sqlite3_close(db); //write fit file - time_t startdate_local_epoch = start_date_epoch+epoch_datetime_sec; - char startdate_local[20], filename[100], startdate_str[25]; - strftime(startdate_local, sizeof(startdate_local), "%Y-%m-%d_%H-%M-%S", localtime(&startdate_local_epoch)); - strftime(startdate_str, sizeof(startdate_str), "%Y-%m-%d_%H-%M-%S.fit", localtime(&startdate_local_epoch)); - sprintf(filename, "%s/%s", cfg.G_LOG_DIR, startdate_str); //make file header std::vector file_header, header_crc, total_crc; @@ -631,7 +617,7 @@ bool write_log_c(const char* db_file) { _data = {(unsigned int)crc16(file_header)}; _size = {2}; add_fit_data(header_crc, _data, _size); - + FILE *fp; if((fp=fopen(filename,"w")) != NULL ) { fwrite(file_header.data(), sizeof(uint8_t), file_header.size(), fp); @@ -656,25 +642,5 @@ bool write_log_c(const char* db_file) { reset(); - cfg.G_LOG_START_DATE = strdup(startdate_local); - cfg.G_UPLOAD_FILE = strdup(filename); - return true; } - -int main(int argc, char *argv[]) { - - if( argc!=2 ){ - fprintf(stderr, "Usage: %s DATABASE\n", argv[0]); - exit(1); - } - - cfg.G_UNIT_ID_HEX = 0; - const char* log_dir = "./"; - cfg.G_LOG_DIR = strdup(log_dir); - - bool res = !write_log_c(argv[1]); - - return (int)res; -} - diff --git a/modules/logger/cython/logger_fit_c.hpp b/modules/logger/cython/logger_fit_c.hpp index c9e1fbd9..b349313d 100644 --- a/modules/logger/cython/logger_fit_c.hpp +++ b/modules/logger/cython/logger_fit_c.hpp @@ -43,9 +43,6 @@ struct lap_summary_data{ struct config { unsigned int G_UNIT_ID_HEX = 0; - char* G_LOG_START_DATE; - char* G_LOG_DIR; - char* G_UPLOAD_FILE; }; static config cfg; @@ -54,8 +51,6 @@ constexpr double LAT_LON_CONST = ((unsigned int)(1 << 31))/180.0; //pow(2,31) / void set_config_c(const config& _cfg); void reset(); -char* get_upload_file_name_c(); -char* get_start_date_str_c(); inline uint8_t base_type_id_from_string(std::string base_type_name) { return base_type_id[base_type_name]; @@ -82,8 +77,6 @@ static int parse_records_message_num_20(void *user_data, int argc, char **argv, bool get_summary(int lap_num, sqlite3 *db); -bool write_log_c(const char* db_file); - -int main(int argc, char *argv[]); +bool write_log_c(const char* db_file, const char* filename, const char* start_date, const char* end_date); #endif diff --git a/modules/logger/logger_csv.py b/modules/logger/logger_csv.py index d04672f9..0675474a 100644 --- a/modules/logger/logger_csv.py +++ b/modules/logger/logger_csv.py @@ -1,52 +1,25 @@ -import datetime import os import sqlite3 import shutil -import time from modules.utils.cmd import exec_cmd from .logger import Logger -class config_local: - G_LOG_DB = "log/log.db" - G_LOG_DIR = "log" - - class LoggerCsv(Logger): - def write_log(self): - # get start date - ## SQLite - con = sqlite3.connect( - self.config.G_LOG_DB, - detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES, - ) - sqlite3.dbapi2.converters["DATETIME"] = sqlite3.dbapi2.converters["TIMESTAMP"] - cur = con.cursor() - cur.execute("SELECT timestamp, MIN(timestamp) FROM BIKECOMPUTER_LOG") - first_row = cur.fetchone() - if first_row is not None: - start_date = first_row[0] - else: - return False - - offset = time.localtime().tm_gmtoff - startdate_local = start_date + datetime.timedelta(seconds=offset) - self.config.G_LOG_START_DATE = startdate_local.strftime("%Y-%m-%d_%H-%M-%S") - filename = os.path.join( - self.config.G_LOG_DIR, f"{self.config.G_LOG_START_DATE}.csv" + def write_log(self, filename): + r = ( + "lap,timer,timestamp,total_timer_time,elapsed_time,heart_rate,speed,cadence,power,distance," + "accumulated_power,position_long,position_lat,raw_long,raw_lat,altitude,gps_altitude,course_altitude," + "dem_altitude,gps_speed,gps_distance,gps_mode,gps_used_sats,gps_total_sats,gps_epx,gps_epy,gps_epv," + "gps_pdop,gps_hdop,gps_vdop,total_ascent,total_descent,pressure,temperature,heading,gps_track," + "motion,acc_x,acc_y,acc_z,gyro_x,gyro_y,gyro_z,cpu_percent,light" ) - r = "\ -lap,timer,timestamp,total_timer_time,elapsed_time,heart_rate,speed,cadence,power,distance,accumulated_power,\ -position_long,position_lat,raw_long,raw_lat,altitude,gps_altitude,course_altitude,dem_altitude,gps_speed,gps_distance,gps_mode,gps_used_sats,gps_total_sats,gps_epx,gps_epy,gps_epv,gps_pdop,gps_hdop,gps_vdop,\ -total_ascent,total_descent,pressure,temperature,heading,gps_track,motion,acc_x,acc_y,acc_z,gyro_x,gyro_y,gyro_z,cpu_percent,light" # voltage_battery,current_battery,voltage_out,current_out,battery_percentage\ # " # if sqlite3 command exists, use this command (much faster) if shutil.which("sh") is not None and shutil.which("sqlite3"): - cur.close() - con.close() sql_cmd = ( "sqlite3 -header -csv " + self.config.G_LOG_DB @@ -58,21 +31,23 @@ def write_log(self): sqlite3_cmd = ["sh", "-c", sql_cmd] exec_cmd(sqlite3_cmd) else: - f = open(filename, "w", encoding="UTF-8") + con = sqlite3.connect( + self.config.G_LOG_DB, + detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES, + ) + sqlite3.dbapi2.converters["DATETIME"] = sqlite3.dbapi2.converters[ + "TIMESTAMP" + ] + cur = con.cursor() + + with open(filename, "w", encoding="UTF-8") as o: + # get Lap Records + o.write(r + "\n") - # get Lap Records - f.write(r + "\n") - for row in cur.execute("SELECT %s FROM BIKECOMPUTER_LOG" % r): - f.write(",".join(map(str, row)) + "\n") - f.close() + for row in cur.execute("SELECT %s FROM BIKECOMPUTER_LOG" % r): + o.write(",".join(map(str, row)) + "\n") cur.close() con.close() return True - - -if __name__ == "__main__": - c = config_local() - d = LoggerCsv(c) - d.write_log() diff --git a/modules/logger/logger_fit.py b/modules/logger/logger_fit.py index 886c2ca9..50ada8a7 100644 --- a/modules/logger/logger_fit.py +++ b/modules/logger/logger_fit.py @@ -1,8 +1,6 @@ -import os import sqlite3 import struct -import time -from datetime import datetime, timedelta +from datetime import datetime, timezone from logger import app_logger from modules.utils.date import datetime_myparser @@ -16,10 +14,8 @@ pyximport.install() from .cython.logger_fit import ( - write_log_cython, set_config, - get_upload_file_name, - get_start_date_str, + write_log_cython, ) MODE = "Cython" @@ -227,24 +223,27 @@ def write(self, out): self.fit_data.append(out) # referenced by https://opensource.quarq.us/fit_json/ - def write_log(self): + def write_log(self, filename, start_date, end_date): # try Cython if available/resolve to pure python if writing fails - if MODE == "Cython" and self.write_log_cython(): + if MODE == "Cython" and self.write_log_cython(filename, start_date, end_date): return True - return self.write_log_python() + return self.write_log_python(filename, start_date, end_date) - def write_log_cython(self): - res = write_log_cython(self.config.G_LOG_DB) + def write_log_cython(self, filename, start_date, end_date): + res = write_log_cython( + self.config.G_LOG_DB, + filename, + start_date.strftime("%Y-%m-%d_%H-%M-%S"), + end_date.strftime("%Y-%m-%d_%H-%M-%S"), + ) if res: - self.config.G_UPLOAD_FILE = get_upload_file_name() - self.config.G_LOG_START_DATE = get_start_date_str() + self.config.G_UPLOAD_FILE = filename return res - def write_log_python(self): + def write_log_python(self, filename, start_date, end_date): # make sure crc16 is imported is we resolve to using python code from .cython.crc16_p import crc16 - ## SQLite con = sqlite3.connect( self.config.G_LOG_DB, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES, @@ -252,22 +251,6 @@ def write_log_python(self): sqlite3.dbapi2.converters["DATETIME"] = sqlite3.dbapi2.converters["TIMESTAMP"] cur = con.cursor() - # get start_date - # get datetime object (timestamp) - cur.execute("SELECT timestamp, MIN(timestamp) FROM BIKECOMPUTER_LOG") - first_row = cur.fetchone() - if first_row is not None: - start_date = first_row[0] - else: - return False - # get end_date - cur.execute("SELECT timestamp, MAX(timestamp) FROM BIKECOMPUTER_LOG") - first_row = cur.fetchone() - if first_row is not None: - end_date = first_row[0] - else: - return False - local_message_num = 0 # file_id @@ -302,6 +285,7 @@ def write_log_python(self): message_num = 20 record_row = [] record_index = [] + for k, v in self.profile[message_num]["field"].items(): record_row.append(v[0]) record_index.append(k) @@ -390,8 +374,14 @@ def write_log_python(self): } self.write_definition(local_message_num) struct_def = self.get_struct_def(local_message_num) - offset = time.localtime().tm_gmtoff + offset = int( + end_date.replace(tzinfo=timezone.utc) + .astimezone() + .utcoffset() + .total_seconds() + ) end_date_epochtime = self.get_epoch_time(end_date) + self.write( struct.pack( struct_def, @@ -410,13 +400,6 @@ def write_log_python(self): ################ # write fit file ################ - - startdate_local = start_date + timedelta(seconds=offset) - self.config.G_LOG_START_DATE = startdate_local.strftime("%Y-%m-%d_%H-%M-%S") - filename = os.path.join( - self.config.G_LOG_DIR, f"{self.config.G_LOG_START_DATE}.fit" - ) - # filename = "test.fit" fd = open(filename, "wb") write_data = b"".join(self.fit_data) @@ -583,6 +566,11 @@ def get_summary(self, message_num, local_message_num, lap_num, cur): return local_message_num def get_epoch_time(self, nowdate): + if nowdate.tzinfo: + if nowdate.tzinfo == timezone.utc: + nowdate = nowdate.replace(tzinfo=None) + else: + raise ValueError(f"Incorrect date passed {nowdate}") seconds = int((nowdate - self.epoch_datetime).total_seconds()) return seconds diff --git a/modules/logger_core.py b/modules/logger_core.py index 6295218b..7e0c69fa 100644 --- a/modules/logger_core.py +++ b/modules/logger_core.py @@ -1,11 +1,11 @@ import os import sqlite3 import signal -import datetime import shutil import time import asyncio import traceback +from datetime import datetime, timedelta, timezone import numpy as np from crdp import rdp @@ -13,6 +13,7 @@ from logger import app_logger from modules.utils.cmd import exec_cmd from modules.utils.date import datetime_myparser +from modules.utils.timer import Timer class LoggerCore: @@ -156,10 +157,10 @@ async def restore_utc_time(self): if not self.sensor.sensor_gps.is_time_modified: delta = count + int(self.config.boot_time * 1.25) - utctime = datetime.datetime.strptime( + utctime = datetime.strptime( self.last_timestamp, "%Y-%m-%d %H:%M:%S.%f" - ) + datetime.timedelta(seconds=delta) - if utctime > datetime.datetime.utcnow(): + ) + timedelta(seconds=delta) + if utctime > datetime.utcnow(): datecmd = [ "sudo", "date", @@ -302,7 +303,7 @@ def count_up(self): self.count_up_lock = False def start_and_stop_manual(self): - time_str = datetime.datetime.now().strftime("%Y%m%d %H:%M:%S") + time_str = datetime.now().strftime("%Y%m%d %H:%M:%S") popup_extra = "" pre_status = self.config.G_MANUAL_STATUS @@ -314,7 +315,7 @@ def start_and_stop_manual(self): if self.config.gui is not None: self.config.gui.change_start_stop_button(self.config.G_MANUAL_STATUS) if self.values["start_time"] is None: - self.values["start_time"] = int(datetime.datetime.utcnow().timestamp()) + self.values["start_time"] = int(datetime.utcnow().timestamp()) if pre_status == "INIT" and not np.isnan( self.sensor.values["integrated"]["dem_altitude"] @@ -350,7 +351,7 @@ def start_and_stop_manual(self): def start_and_stop(self, status=None): if status is not None: self.config.G_STOPWATCH_STATUS = status - time_str = datetime.datetime.now().strftime("%Y%m%d %H:%M:%S") + time_str = datetime.now().strftime("%Y%m%d %H:%M:%S") if self.config.G_STOPWATCH_STATUS != "START": self.config.G_STOPWATCH_STATUS = "START" app_logger.info(f"->START {time_str}") @@ -374,7 +375,7 @@ def count_laps(self): self.average["lap"][k2]["count"] = 0 self.average["lap"][k2]["sum"] = 0 asyncio.create_task(self.record_log()) - time_str = datetime.datetime.now().strftime("%Y%m%d %H:%M:%S") + time_str = datetime.now().strftime("%Y%m%d %H:%M:%S") app_logger.info(f"->LAP:{self.values['lap']} {time_str}") # show message @@ -401,6 +402,32 @@ def count_laps(self): ), ) + def get_start_end_dates(self): + # get start date and end_date of the current log + start_date = end_date = None # UTC time + + con = sqlite3.connect( + self.config.G_LOG_DB, + detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES, + ) + sqlite3.dbapi2.converters["DATETIME"] = sqlite3.dbapi2.converters["TIMESTAMP"] + cur = con.cursor() + cur.execute( + 'SELECT MIN(timestamp) as "ts [timestamp]", MAX(timestamp) as "ts [timestamp]" FROM BIKECOMPUTER_LOG' + ) + first_row = cur.fetchone() + + if first_row is not None: + start_date, end_date = first_row + + start_date.replace(tzinfo=timezone.utc) + end_date.replace(tzinfo=timezone.utc) + + cur.close() + con.close() + + return start_date, end_date + def reset_count(self): if self.config.G_MANUAL_STATUS == "START" or self.values["count"] == 0: return @@ -412,35 +439,51 @@ def reset_count(self): self.cur.close() self.con.close() - t = datetime.datetime.now() + # get start date and end_date of the current log + start_date, end_date = self.get_start_end_dates() + + if start_date is None and end_date is None: + app_logger.info("No log found, nothing to write") + return + + start_date_local = start_date.astimezone().strftime("%Y-%m-%d_%H-%M-%S") + + filename = os.path.join(self.config.G_LOG_DB, start_date_local) + fit_text = f"Write fit({self.logger_fit.mode}):" + csv_text = f"Write csv{' ' * (len(self.logger_fit.mode) + 2)}:" + + timers = [ + Timer(auto_start=False, auto_log=True, text=f"{csv_text} {{:0.4f}} sec"), + Timer(auto_start=False, auto_log=True, text=f"{fit_text} {{:0.4f}} sec"), + Timer(auto_start=False, auto_log=True, text="DELETE : {:0.4f} sec"), + ] + if self.config.G_LOG_WRITE_CSV: - if not self.logger_csv.write_log(): - return - app_logger.info( - f"Write csv : {(datetime.datetime.now() - t).total_seconds()} sec" - ) + with timers[0]: + if not self.logger_csv.write_log(f"{filename}.csv"): + return + if self.config.G_LOG_WRITE_FIT: - if not self.logger_fit.write_log(): - return - app_logger.info( - f"Write fit({self.logger_fit.mode}) : {(datetime.datetime.now() - t).total_seconds()} sec" - ) + with timers[1]: + if not self.logger_fit.write_log( + f"{filename}.fit", start_date, end_date + ): + return # backup and reset database - t = datetime.datetime.now() - shutil.move( - self.config.G_LOG_DB, - self.config.G_LOG_DB + "-" + self.config.G_LOG_START_DATE, - ) + with timers[2]: + shutil.move( + self.config.G_LOG_DB, + f"{self.config.G_LOG_DB}-{start_date_local}", + ) - self.reset() + self.reset() - # restart db connect - # usage of sqlite3 is "insert" only, so check_same_thread=False - self.con = sqlite3.connect(self.config.G_LOG_DB, check_same_thread=False) - self.cur = self.con.cursor() - self.init_db() - app_logger.info(f"DELETE : {(datetime.datetime.now() - t).total_seconds()} sec") + # restart db connect + # usage of sqlite3 is "insert" only, so check_same_thread=False + self.con = sqlite3.connect(self.config.G_LOG_DB, check_same_thread=False) + self.cur = self.con.cursor() + self.init_db() # reset temporary values self.config.setting.reset_config_pickle() @@ -489,7 +532,14 @@ async def record_log(self): # update lap stats if value is not Null for k, v in value.items(): # skip when null value(np.nan) - if k not in ["heart_rate", "cadence", "speed", "power", "distance", "accumulated_power"]: + if k not in [ + "heart_rate", + "cadence", + "speed", + "power", + "distance", + "accumulated_power", + ]: continue if np.isnan(v): continue @@ -559,7 +609,7 @@ async def record_log(self): self.record_stats["lap_max"][k] = x2 ## SQLite - now_time = datetime.datetime.utcnow() + now_time = datetime.utcnow() # self.cur.execute("""\ sql = ( """\ @@ -670,7 +720,7 @@ def calc_gross(self): return # [s] self.values["elapsed_time"] = int( - datetime.datetime.utcnow().timestamp() - self.values["start_time"] + datetime.utcnow().timestamp() - self.values["start_time"] ) # gross_ave_spd @@ -871,11 +921,11 @@ def update_track(self, timestamp): lon = np.array([]) lat = np.array([]) timestamp_new = timestamp - # t = datetime.datetime.utcnow() + # t = datetime.utcnow() timestamp_delta = None if timestamp is not None: - timestamp_delta = (datetime.datetime.utcnow() - timestamp).total_seconds() + timestamp_delta = (datetime.utcnow() - timestamp).total_seconds() # make_tmp_db = False lat_raw = np.array([]) @@ -945,8 +995,8 @@ def update_track(self, timestamp): lon = lon_raw if timestamp is None: - timestamp_new = datetime.datetime.utcnow() + timestamp_new = datetime.utcnow() - # print("\tlogger_core : update_track(new) ", (datetime.datetime.utcnow()-t).total_seconds(), "sec") + # print("\tlogger_core : update_track(new) ", (datetime.utcnow()-t).total_seconds(), "sec") return timestamp_new, lon, lat diff --git a/tests/test_logger.py b/tests/test_logger.py index f5ce99c0..e030e913 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -1,4 +1,7 @@ +import os +import tempfile import unittest +from datetime import datetime, timezone from modules.logger.logger_csv import LoggerCsv from modules.logger.logger_fit import LoggerFit @@ -6,39 +9,54 @@ class LocalConfig: G_LOG_DB = "tests/data/log.db-Heart_of_St._Johns_Peninsula_Ride" - G_LOG_DIR = "/tmp" # nosec G_UNIT_ID_HEX = 0x12345678 - G_LOG_START_DATE = None - class TestLoggerCsv(unittest.TestCase): def test_write_log(self): config = LocalConfig() logger = LoggerCsv(config) - result = logger.write_log() + _, path = tempfile.mkstemp() + + try: + result = logger.write_log(path) + finally: + os.remove(path) + self.assertTrue(result) - self.assertEqual(config.G_LOG_START_DATE, "2023-09-28_22-39-13") class TestLoggerFit(unittest.TestCase): def test_write_logs(self): config = LocalConfig() logger = LoggerFit(config) - result = logger.write_log_cython() - self.assertTrue(result) - self.assertEqual(config.G_LOG_START_DATE, "2023-09-28_22-39-13") - filename = f"{config.G_LOG_DIR}/{config.G_LOG_START_DATE}.fit" + start = datetime(2023, 9, 28, 20, 39, 13, tzinfo=timezone.utc) + end = datetime(2023, 9, 28, 21, 10, 53, tzinfo=timezone.utc) - with open(filename, "rb") as f: - cython_data = f.read() + _, path = tempfile.mkstemp() - result = logger.write_log_python() - self.assertTrue(result) - self.assertEqual(config.G_LOG_START_DATE, "2023-09-28_22-39-13") + try: + result = logger.write_log_cython(path, start, end) + + self.assertTrue(result) + + with open(path, "rb") as f: + cython_data = f.read() + finally: + os.remove(path) + + _, path = tempfile.mkstemp() + + try: + result = logger.write_log_python(path, start, end) + + self.assertTrue(result) + + with open(path, "rb") as f: + python_data = f.read() - with open(filename, "rb") as f: - python_data = f.read() + finally: + os.remove(path) self.assertEqual(cython_data, python_data)