diff --git a/libs/charging.py b/libs/charging.py index 499ae92..50400f0 100644 --- a/libs/charging.py +++ b/libs/charging.py @@ -47,15 +47,14 @@ class Charging: Database.clean_battery(conn) @staticmethod - def record_charging(car, charging_status, charge_date: datetime, level, latitude, longitude, country_code, charging_mode): + def record_charging(car, charging_status, charge_date: datetime, level, latitude, longitude, country_code, + charging_mode): conn = Database.get_db() charge_date = charge_date.replace(microsecond=0) if charging_status == "InProgress": - res = conn.execute("SELECT stop_at, start_at FROM battery WHERE VIN=? ORDER BY start_at " - "DESC limit 1", (car.vin,)).fetchone() - in_progress = res and res[0] is None - if in_progress: - start_at = res[1] + stop_at, start_at = conn.execute("SELECT stop_at, start_at FROM battery WHERE VIN=? ORDER BY start_at " + "DESC limit 1", (car.vin,)).fetchone() or [False, None] + if stop_at is None: try: conn.execute("INSERT INTO battery_curve(start_at,VIN,date,level) VALUES(?,?,?,?)", (start_at, car.vin, charge_date, level)) diff --git a/my_psacc.py b/my_psacc.py index a53e35a..d0a3149 100644 --- a/my_psacc.py +++ b/my_psacc.py @@ -282,7 +282,7 @@ class MyPSACC: self.refresh_remote_token(force=True) logger.error("retry last request, token was expired") elif data["return_code"] == "300": - logger.error('%d', data["return_code"]) + logger.error('%s', data["return_code"]) elif data["return_code"] != "0": logger.error('%s : %s', data["return_code"], data["reason"]) if msg.topic.endswith("/VehicleState"): diff --git a/trip.py b/trip.py index 20cefbe..207e1a9 100644 --- a/trip.py +++ b/trip.py @@ -183,7 +183,7 @@ class Trips(list): if trip.distance > 0: trip.start_at = start["Timestamp"] trip.end_at = end["Timestamp"] - trip.add_points(end["longitude"], end["latitude"]) + trip.add_points(end["latitude"], end["longitude"]) if end["temperature"] is not None and start["temperature"] is not None: trip.add_temperature(end["temperature"]) trip.duration = (end["Timestamp"] - start["Timestamp"]).total_seconds() / 3600 @@ -205,9 +205,10 @@ class Trips(list): start = next_el trip = Trip() else: - trip.add_points(end["longitude"], end["latitude"]) + trip.add_points(end["latitude"], end["longitude"]) end = next_el trips_by_vin[vin] = trips + conn.close() return trips_by_vin def get_info(self): diff --git a/web/db.py b/web/db.py index 6654a23..50580ba 100644 --- a/web/db.py +++ b/web/db.py @@ -28,6 +28,21 @@ def new_convert_datetime_from_string(string): return datetime.fromisoformat(string) +class CustomSqliteConnection(sqlite3.Connection): + + def __init__(self, *args, **kwargs): # real signature unknown + super().__init__(*args, **kwargs) + self.callbacks = [] + + def execute_callbacks(self): + for callback in self.callbacks: + callback() + + def close(self): + if self.total_changes: + self.execute_callbacks() + super().close() + class Database: callback_fct: Callable[[], None] = lambda: None DEFAULT_DB_FILE = 'info.db' @@ -79,8 +94,6 @@ class Database: make_backup = False conn.execute("CREATE TABLE IF NOT EXISTS battery (start_at DATETIME PRIMARY KEY,stop_at DATETIME,VIN TEXT, " "start_level INTEGER, end_level INTEGER, co2 INTEGER, kw INTEGER);") - conn.execute("CREATE TEMP TRIGGER IF NOT EXISTS update_trigger AFTER INSERT ON position BEGIN " - "SELECT update_trips(); END;") conn.execute("""CREATE TABLE IF NOT EXISTS battery_curve (start_at DATETIME, VIN TEXT, date DATETIME, level INTEGER, UNIQUE(start_at, VIN, level));""") for table, columns in [["position", NEW_POSITION_COLUMNS], ["battery", NEW_BATTERY_COLUMNS]]: @@ -102,15 +115,15 @@ class Database: Database.db_initialized = True @staticmethod - def get_db(db_file=None, update_callback=True): + def get_db(db_file=None, update_callback=True) -> CustomSqliteConnection: if db_file is None: db_file = Database.DEFAULT_DB_FILE - conn = sqlite3.connect(db_file, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES) + conn = CustomSqliteConnection(db_file, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES) conn.row_factory = sqlite3.Row - if update_callback: - conn.create_function("update_trips", 0, Database.update_callback) if not Database.db_initialized: Database.init_db(conn) + if update_callback: + conn.callbacks.append(Database.callback_fct) return conn @staticmethod @@ -118,7 +131,6 @@ class Database: # delete charging longer than 17h conn.execute("DElETE FROM battery WHERE JULIANDAY(stop_at)-JULIANDAY(start_at)>0.7;") conn.execute("DELETE FROM battery WHERE start_level==end_level;") - conn.commit() @staticmethod def clean_position(conn): @@ -136,6 +148,7 @@ class Database: conn = Database.get_db() res = conn.execute("SELECT temperature FROM position WHERE VIN=? ORDER BY Timestamp DESC limit 1", (vin,)).fetchone() + conn.close() if res is None: return None return res[0] @@ -208,10 +221,10 @@ class Database: # pylint: disable=too-many-arguments @staticmethod def record_position(weather_api, vin, mileage, latitude, longitude, altitude, date, level, level_fuel, moving): - conn = Database.get_db() if mileage == 0: # fix a bug of the api logger.error("The api return a wrong mileage for %s : %f", vin, mileage) else: + conn = Database.get_db() if conn.execute("SELECT Timestamp from position where Timestamp=?", (date,)).fetchone() is None: temp = get_temp(latitude, longitude, weather_api) if level_fuel == 0: # fix fuel level not provided when car is off @@ -232,6 +245,8 @@ class Database: conn.commit() logger.info("new position recorded for %s", vin) Database.clean_position(conn) + conn.close() return True + conn.close() logger.debug("position already saved") return False diff --git a/web/figures.py b/web/figures.py index 7b079fd..f23110a 100644 --- a/web/figures.py +++ b/web/figures.py @@ -78,8 +78,8 @@ def get_figures(trips: Trips, charging: List[dict]): names = [] for trip in trips: for points in trip.positions: - lats = np.append(lats, points.longitude) - lons = np.append(lons, points.latitude) + lats = np.append(lats, points.latitude) + lons = np.append(lons, points.longitude) names = np.append(names, [str(trip.start_at)]) lats = np.append(lats, None) lons = np.append(lons, None) @@ -215,7 +215,9 @@ def __calculate_co2_per_kw(charging_data): def get_battery_curve_fig(row: dict, car: Car): start_date = Database.convert_datetime_from_string(row["start_at"]) stop_at = Database.convert_datetime_from_string(row["stop_at"]) - res = Database.get_battery_curve(Database.get_db(), start_date, car.vin) + conn = Database.get_db() + res = Database.get_battery_curve(conn, start_date, car.vin) + conn.close() res.insert(0, {"level": row["start_level"], "date": start_date}) res.append({"level": row["end_level"], "date": stop_at}) battery_curves = [] @@ -240,4 +242,5 @@ def get_altitude_fig(trip: Trip): line[0] = line[0] - start_mileage fig = px.line(res, x=0, y=1) fig.update_layout(xaxis_title="Distance km", yaxis_title="Altitude m") + conn.close() return html.Div(Graph(figure=fig)) diff --git a/web/views.py b/web/views.py index f18cac0..822f678 100644 --- a/web/views.py +++ b/web/views.py @@ -92,9 +92,11 @@ def create_callback(): # noqa: MC0001 diff_data = diff_dashtable(data, data_previous, "start_at") for changed_line in diff_data: if changed_line['column_name'] == 'price': - if not Database.set_chargings_price(Database.get_db(), changed_line['start_at'], + conn = Database.get_db() + if not Database.set_chargings_price( conn, changed_line['start_at'], changed_line['current_value']): logger.error("Can't find line to update in the database") + conn.close() return "" @dash_app.callback([Output("tab_battery_popup_graph", "children"), Output("tab_battery_popup", "is_open"), ], @@ -240,7 +242,9 @@ def after_request(response): def update_trips(): global trips, chargings, cached_layout, min_date, max_date, min_millis, max_millis, step, marks logger.info("update_data") - Database.add_altitude_to_db(Database.get_db(update_callback=False)) + conn = Database.get_db(update_callback=False) + Database.add_altitude_to_db(conn) + conn.close() min_date = None max_date = None try: