From fbc094f6edfa2a865813fc5366fb5d69be2a0ba8 Mon Sep 17 00:00:00 2001 From: jlayec Date: Sun, 7 Feb 2021 20:48:15 +0000 Subject: [PATCH 01/14] first evolution to manage hybrid cars --- MyPSACC.py | 39 ++++++++++++++++++++++++++++++++------- web/db.py | 14 +++++++++++++- web/figures.py | 2 +- 3 files changed, 46 insertions(+), 9 deletions(-) diff --git a/MyPSACC.py b/MyPSACC.py index 067674d..3ddb1e6 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -358,7 +358,12 @@ class MyPSACC: def get_charge_hour(self, vin): reg = r"PT([0-9]{1,2})H([0-9]{1,2})?" data = self.get_vehicle_info(vin) - hour_str = data.energy[0].charging.next_delayed_time + if data.energy[0].type == 'Electric': + hour_str = data.energy[0].charging.next_delayed_time + elif data.energy[1].type == 'Electric': + hour_str = data.energy[1].charging.next_delayed_time + else: + hour_str = '' hour = re.findall(reg, hour_str)[0] h = int(hour[0]) if hour[1] == '': @@ -369,7 +374,12 @@ class MyPSACC: def get_charge_status(self, vin): data = self.get_vehicle_info(vin) - status = data.energy[0].charging.status + if data.energy[0].type == 'Electric': + status = data.energy[0].charging.status + elif data.energy[1].type == 'Electric': + status = data.energy[1].charging.status + else: + status = '' return status def veh_charge_request(self, vin, hour, miinute, charge_type): @@ -466,8 +476,24 @@ class MyPSACC: latitude = status.last_position.geometry.coordinates[1] date = status.last_position.properties.updated_at mileage = status.timed_odometer.mileage - level = status.energy[0].level - charging_status = status.energy[0].charging.status + if status.energy[0].type == 'Electric': + level = status.energy[0].level + charging_status = status.energy[0].charging.status + charge_date = status.energy[0].updated_at + elif status.energy[1].type == 'Electric': + level = status.energy[1].level + charging_status = status.energy[1].charging.status + charge_date = status.energy[1].updated_at + else: + level = '' + charging_status = '' + charge_date = '' + if status.energy[0].type == 'Fuel': + level_fuel = status.energy[0].level + elif status.energy[1].type == 'Fuel': + level_fuel = status.energy[1].level + else: + level_fuel = '' moving = status.kinetic.moving conn = get_db() if mileage == 0: # fix a bug of the api @@ -487,8 +513,8 @@ class MyPSACC: logger.error(f"Unable to get temperature from openweathermap :{e}") conn.execute( - "INSERT INTO position(Timestamp,VIN,longitude,latitude,mileage,level, moving, temperature) VALUES(?,?,?,?,?,?,?,?)", - (date, vin, longitude, latitude, mileage, level, moving, temp)) + "INSERT INTO position(Timestamp,VIN,longitude,latitude,mileage,level,level_fuel,moving,temperature) VALUES(?,?,?,?,?,?,?,?,?)", + (date, vin, longitude, latitude, mileage, level, level_fuel, moving, temp)) conn.commit() logger.info(f"new position recorded for {vin}") @@ -505,7 +531,6 @@ class MyPSACC: logger.debug("position already saved") # todo handle battery status - charge_date = status.energy[0].updated_at if charging_status == "InProgress": try: in_progress = conn.execute("SELECT stop_at FROM battery WHERE VIN=? ORDER BY start_at DESC limit 1", diff --git a/web/db.py b/web/db.py index 962bdac..c9f3e34 100644 --- a/web/db.py +++ b/web/db.py @@ -18,7 +18,19 @@ def get_db(db_file=default_db_file): conn = sqlite3.connect(db_file, detect_types=sqlite3.PARSE_DECLTYPES | sqlite3.PARSE_COLNAMES) conn.row_factory = sqlite3.Row conn.execute("CREATE TABLE IF NOT EXISTS position (Timestamp DATETIME PRIMARY KEY, VIN TEXT, longitude REAL, " - "latitude REAL, mileage REAL, level INTEGER, moving BOOLEAN, temperature INTEGER);") + "latitude REAL, mileage REAL, level INTEGER, level_fuel INTEGER, moving BOOLEAN, temperature INTEGER);") + try: + conn.execute("ALTER TABLE position ADD level_fuel INTEGER;") + except: + pass + try: + conn.execute("ALTER TABLE position ADD moving BOOLEAN;") + except: + pass + try: + conn.execute("ALTER TABLE position ADD temperature INTEGER;") + except: + pass 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.create_function("update_trips", 0, update_callback) diff --git a/web/figures.py b/web/figures.py index d14f9c9..52ad244 100644 --- a/web/figures.py +++ b/web/figures.py @@ -113,4 +113,4 @@ def get_figures(trips: List[Trip], charging: List[dict]): charge_speed = 0 battery_info = html.Div(children=[html.P("Average gC02/kW: {:.1f}".format(co2_per_kw)), html.P("Average gC02/km: {:1f}".format(co2_per_km)), - html.P("Average Charge SPEED {:1f} kW/h".format(charge_speed))]) + html.P("Average Charge SPEED {:1f} kW/h".format(charge_speed))]) From 1b4dd7ccf951e316da789e5d3a745b7fb284926a Mon Sep 17 00:00:00 2001 From: jlayec Date: Sun, 7 Feb 2021 21:30:29 +0000 Subject: [PATCH 02/14] fix in case only one energy --- MyPSACC.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MyPSACC.py b/MyPSACC.py index 3ddb1e6..d2cbe7a 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -360,7 +360,7 @@ class MyPSACC: data = self.get_vehicle_info(vin) if data.energy[0].type == 'Electric': hour_str = data.energy[0].charging.next_delayed_time - elif data.energy[1].type == 'Electric': + elif len(data.energy) >= 2 and data.energy[1].type == 'Electric': hour_str = data.energy[1].charging.next_delayed_time else: hour_str = '' @@ -376,7 +376,7 @@ class MyPSACC: data = self.get_vehicle_info(vin) if data.energy[0].type == 'Electric': status = data.energy[0].charging.status - elif data.energy[1].type == 'Electric': + elif len(data.energy) >= 2 and data.energy[1].type == 'Electric': status = data.energy[1].charging.status else: status = '' @@ -480,7 +480,7 @@ class MyPSACC: level = status.energy[0].level charging_status = status.energy[0].charging.status charge_date = status.energy[0].updated_at - elif status.energy[1].type == 'Electric': + elif len(status.energy) >=2 and status.energy[1].type == 'Electric': level = status.energy[1].level charging_status = status.energy[1].charging.status charge_date = status.energy[1].updated_at @@ -490,7 +490,7 @@ class MyPSACC: charge_date = '' if status.energy[0].type == 'Fuel': level_fuel = status.energy[0].level - elif status.energy[1].type == 'Fuel': + elif len(status.energy) >= 2 and status.energy[1].type == 'Fuel': level_fuel = status.energy[1].level else: level_fuel = '' From d7adc4ee960cf75a233da5b93e0e1a35c89ae258 Mon Sep 17 00:00:00 2001 From: jlayec Date: Mon, 8 Feb 2021 20:28:46 +0000 Subject: [PATCH 03/14] update .gitignore with info.db and otp.bin --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2f69f23..0176c31 100644 --- a/.gitignore +++ b/.gitignore @@ -139,6 +139,8 @@ cython_debug/ .idea/ backup.ab +info.db +otp.bin charge_config1.json config.json test.json \ No newline at end of file From d00f23f178a0d7f998e6ff859e511f2f7c866dd7 Mon Sep 17 00:00:00 2001 From: jlayec Date: Wed, 10 Feb 2021 21:55:06 +0000 Subject: [PATCH 04/14] avoid fuel level 0 for hybrid cars + fix empty battery table --- .gitignore | 2 +- MyPSACC.py | 8 ++++++++ web/figures.py | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0176c31..739c14f 100644 --- a/.gitignore +++ b/.gitignore @@ -143,4 +143,4 @@ info.db otp.bin charge_config1.json config.json -test.json \ No newline at end of file +test.json diff --git a/MyPSACC.py b/MyPSACC.py index d2cbe7a..551b295 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -512,6 +512,14 @@ class MyPSACC: except Exception as e: logger.error(f"Unable to get temperature from openweathermap :{e}") + if level_fuel == 0: # fix fuel level not provided when car is off + try: + level_fuel = conn.execute("SELECT level_fuel FROM position WHERE level_fuel>0 AND VIN=? ORDER BY Timestamp DESC LIMIT 1",(vin,)).fetchone()[0] + logger.info(f"level_fuel fixed with last real value {level_fuel} for {vin}") + except TypeError: + level_fuel = '' + logger.info(f"level_fuel unfixed for {vin}") + conn.execute( "INSERT INTO position(Timestamp,VIN,longitude,latitude,mileage,level,level_fuel,moving,temperature) VALUES(?,?,?,?,?,?,?,?,?)", (date, vin, longitude, latitude, mileage, level, level_fuel, moving, temp)) diff --git a/web/figures.py b/web/figures.py index 52ad244..634d025 100644 --- a/web/figures.py +++ b/web/figures.py @@ -105,12 +105,16 @@ def get_figures(trips: List[Trip], charging: List[dict]): co2_per_kw = charging_data["co2"].sum() / charging_data["kw"].sum() except ZeroDivisionError: co2_per_kw = 0 + except KeyError: # when there is no data yet: + co2_per_kw = 0 co2_per_km = co2_per_kw * kw_per_km / 100 try: charge_speed = 3600 * charging_data["kw"].mean() / \ (charging_data["stop_at"] - charging_data["start_at"]).mean().total_seconds() except TypeError: # when there is no data yet: charge_speed = 0 + except KeyError: # when there is no data yet: + charge_speed = 0 battery_info = html.Div(children=[html.P("Average gC02/kW: {:.1f}".format(co2_per_kw)), html.P("Average gC02/km: {:1f}".format(co2_per_km)), html.P("Average Charge SPEED {:1f} kW/h".format(charge_speed))]) From 7e9f2e32376af4cd038918c55ea778af39f0523d Mon Sep 17 00:00:00 2001 From: jlayec Date: Thu, 11 Feb 2021 00:37:35 +0000 Subject: [PATCH 05/14] add get_energy() method to class Energy for hybrid cars --- MyPSACC.py | 47 +++++++++++++++++------------------------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/MyPSACC.py b/MyPSACC.py index 551b295..835f234 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -358,12 +358,7 @@ class MyPSACC: def get_charge_hour(self, vin): reg = r"PT([0-9]{1,2})H([0-9]{1,2})?" data = self.get_vehicle_info(vin) - if data.energy[0].type == 'Electric': - hour_str = data.energy[0].charging.next_delayed_time - elif len(data.energy) >= 2 and data.energy[1].type == 'Electric': - hour_str = data.energy[1].charging.next_delayed_time - else: - hour_str = '' + hour_str = data.get_energy('Electric').charging.next_delayed_time hour = re.findall(reg, hour_str)[0] h = int(hour[0]) if hour[1] == '': @@ -374,12 +369,7 @@ class MyPSACC: def get_charge_status(self, vin): data = self.get_vehicle_info(vin) - if data.energy[0].type == 'Electric': - status = data.energy[0].charging.status - elif len(data.energy) >= 2 and data.energy[1].type == 'Electric': - status = data.energy[1].charging.status - else: - status = '' + status = data.get_energy('Electric').charging.status return status def veh_charge_request(self, vin, hour, miinute, charge_type): @@ -476,25 +466,12 @@ class MyPSACC: latitude = status.last_position.geometry.coordinates[1] date = status.last_position.properties.updated_at mileage = status.timed_odometer.mileage - if status.energy[0].type == 'Electric': - level = status.energy[0].level - charging_status = status.energy[0].charging.status - charge_date = status.energy[0].updated_at - elif len(status.energy) >=2 and status.energy[1].type == 'Electric': - level = status.energy[1].level - charging_status = status.energy[1].charging.status - charge_date = status.energy[1].updated_at - else: - level = '' - charging_status = '' - charge_date = '' - if status.energy[0].type == 'Fuel': - level_fuel = status.energy[0].level - elif len(status.energy) >= 2 and status.energy[1].type == 'Fuel': - level_fuel = status.energy[1].level - else: - level_fuel = '' + level = status.get_energy('Electric').level + charging_status = status.get_energy('Electric').charging.status + charge_date = status.get_energy('Electric').updated_at + level_fuel = status.get_energy('Fuel').level moving = status.kinetic.moving + logger.info(f"vin:{vin} longitude:{longitude} latitude:{latitude} date:{date} mileage:{mileage} level:{level} charging_status:{charging_status} charge_date:{charge_date} level_fuel:{level_fuel} moving:{moving}") conn = get_db() if mileage == 0: # fix a bug of the api logger.error(f"The api return a wrong mileage for {vin} : {mileage}") @@ -651,3 +628,13 @@ class MyPeugeotEncoder(JSONEncoder): for el in ["client_id", "realm", "remote_refresh_token", "customer_id","weather_api"]: mpd[el] = data[el] return mpd + + +#add method to class Energy +def get_energy(self,energy_type): + for energy in self._energy: + if energy.type == energy_type: + return energy + return psac.models.energy.Energy(charging=psac.models.energy_charging.EnergyCharging()) + +psac.models.status.Status.get_energy = get_energy From be8e12a4ab6d0f795d22ee6add1f11dc4c3ac5ed Mon Sep 17 00:00:00 2001 From: jlayec Date: Thu, 11 Feb 2021 12:49:48 +0000 Subject: [PATCH 06/14] add offline mode limited to dashboard --- server.py | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/server.py b/server.py index 88f2950..b2fb1e0 100755 --- a/server.py +++ b/server.py @@ -26,7 +26,8 @@ def parse_args(): parser.add_argument("-r", "--record", help="save vehicle data to db", action='store_true') parser.add_argument("-m", "--mail", help="set the email address") parser.add_argument("-P", "--password", help="set the password") - parser.add_argument("--remote-disable", help="disable remote control") + parser.add_argument("--remote-disable", help="disable remote control", action='store_true') + parser.add_argument("--offline", help="offline limited mode", action='store_true') parser.add_argument("-b", "--base-path", help="base path for web app",default="/") parser.parse_args() return parser @@ -46,24 +47,27 @@ if __name__ == "__main__": atexit.register(web.app.myp.save_config) if args.record: web.app.myp.set_record(True) - try: - web.app.myp.manager._refresh_token() - except OAuthError: - if args.mail and args.password: - client_email = args.mail - client_password = args.password - else: - client_email = input("mypeugeot email: ") - client_password = input("mypeugeot password: ") - web.app.myp.connect(client_email, client_password) - logger.info(web.app.myp.get_vehicles()) + if args.offline: + logger.info("offline mode") + else: + try: + web.app.myp.manager._refresh_token() + except OAuthError: + if args.mail and args.password: + client_email = args.mail + client_password = args.password + else: + client_email = input("mypeugeot email: ") + client_password = input("mypeugeot password: ") + web.app.myp.connect(client_email, client_password) + logger.info(web.app.myp.get_vehicles()) t1 = Thread(target=start_app, args=["My car info", args.base_path, args.debug < 20, args.listen, int(args.port)]) t1.start() - if args.remote_disable: + if args.offline or args.remote_disable: logger.info("mqtt disabled") else: web.app.myp.start_mqtt() if args.charge_control: web.app.chc = ChargeControls.load_config(web.app.myp, name=args.charge_control) web.app.chc.start() - save_config(web.app.myp) \ No newline at end of file + save_config(web.app.myp) From 37cf1b22160dd52c4834280b4a77ffd894ecf650 Mon Sep 17 00:00:00 2001 From: jlayec Date: Thu, 11 Feb 2021 13:16:04 +0000 Subject: [PATCH 07/14] fix mqtt return_code 300 --- MyPSACC.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MyPSACC.py b/MyPSACC.py index 835f234..1d8fcc4 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -310,6 +310,8 @@ class MyPSACC: elif data["return_code"] == "400": self.refresh_remote_token(force=True) logger.error("retry last request, token was expired") + elif data["return_code"] == "300": + logger.error(f'{data["return_code"]}') else: logger.error(f'{data["return_code"]} : {data["reason"]}') else: From 78ce1262110ee21c9737fff1cfaa85fc27162043 Mon Sep 17 00:00:00 2001 From: jlayec Date: Fri, 12 Feb 2021 22:56:28 +0000 Subject: [PATCH 08/14] trip update for hybrid cars --- MyPSACC.py | 29 ++++++++++++++++++++++------- Trip.py | 14 ++++++++++++-- web/figures.py | 7 +++++-- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/MyPSACC.py b/MyPSACC.py index 1d8fcc4..e3f7605 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -29,7 +29,10 @@ import sqlite3 from web.db import get_db -BATTERY_POWER = 46 +BATTERY_POWER = 46 #e208 +FUEL_CAPACITY = 0 #e208 +#BATTERY_POWER = 10.8 #3008 +#FUEL_CAPACITY = 43 #3008 oauhth_url = {"clientsB2CPeugeot": "https://idpcvs.peugeot.com/am/oauth2/access_token", "clientsB2CCitroen": "https://idpcvs.citroen.com/am/oauth2/access_token", @@ -473,7 +476,7 @@ class MyPSACC: charge_date = status.get_energy('Electric').updated_at level_fuel = status.get_energy('Fuel').level moving = status.kinetic.moving - logger.info(f"vin:{vin} longitude:{longitude} latitude:{latitude} date:{date} mileage:{mileage} level:{level} charging_status:{charging_status} charge_date:{charge_date} level_fuel:{level_fuel} moving:{moving}") + logger.debug(f"vin:{vin} longitude:{longitude} latitude:{latitude} date:{date} mileage:{mileage} level:{level} charging_status:{charging_status} charge_date:{charge_date} level_fuel:{level_fuel} moving:{moving}") conn = get_db() if mileage == 0: # fix a bug of the api logger.error(f"The api return a wrong mileage for {vin} : {mileage}") @@ -574,15 +577,20 @@ class MyPSACC: tr = Trip() #res = list(map(dict,res)) for x in range(0, len(res) - 2): + logger.debug(f"{res[x]['Timestamp']} mileage : {res[x]['mileage']}") next_el = res[x + 2] if end["mileage"] - start["mileage"] == 0 or \ - (end["Timestamp"] - start["Timestamp"]).total_seconds() / 3600 > 3: + (end["Timestamp"] - start["Timestamp"]).total_seconds() / 3600 > 10: # condition useless ??? + logger.debug(f"restart trip") start = end tr = Trip() else: distance = next_el["mileage"] - end["mileage"] # km duration = (next_el["Timestamp"] - end["Timestamp"]).total_seconds() / 3600 - if (distance == 0 and duration > 0.08) or duration > 2: # check the speed to handle missing point + charge = next_el["level"] - end["level"] + refuel = next_el["level_fuel"] - end["level_fuel"] + if ((distance == 0 and duration > 0.08) or duration > 2 or # check the speed to handle missing point + refuel > 0 or (distance == 0 and charge > 0)): tr.distance = end["mileage"] - start["mileage"] # km if tr.distance > 0: tr.start_at = start["Timestamp"] @@ -593,11 +601,18 @@ class MyPSACC: diff_level = start["level"] - end["level"] tr.consumption = diff_level / 100 * BATTERY_POWER # kw tr.consumption_km = 100 * tr.consumption / tr.distance # kw/100 km - # logger.debug( - # f"Trip: {start['Timestamp']} {tr.distance:.1f}km {tr.duration:.2f}h {tr.speed_average:.2f} km/h {tr.consumption:.2f} kw {tr.consumption_km:.2f}kw/100km") + diff_level_fuel = start["level_fuel"] - end["level_fuel"] + tr.consumption_fuel = diff_level_fuel / 100 * FUEL_CAPACITY # L + tr.consumption_fuel_km = 100 * tr.consumption_fuel / tr.distance # L/100 km + tr.mileage = end["mileage"] + logger.debug( + f"Trip: {start['Timestamp']} {tr.distance:.1f}km {tr.duration:.2f}h {tr.speed_average:.0f}km/h " + f"{tr.consumption:.2f}kw {tr.consumption_km:.2f}kw/100km {tr.consumption_fuel:.2f}L {tr.consumption_fuel_km:.2f}L/100km {tr.mileage:.1f}km") # filter bad value - if tr.consumption_km < 70: + if tr.consumption_km < 70 and tr.consumption_fuel_km < 30: trips.append(tr) + else: + logger.debug(f"trip discarded") start = next_el tr = Trip() else: diff --git a/Trip.py b/Trip.py index 4a7ada7..05b94ca 100644 --- a/Trip.py +++ b/Trip.py @@ -31,8 +31,11 @@ class Trip: self.speed_average = None self.consumption = None self.consumption_km = None + self.consumption_fuel = None + self.consumption_fuel_km = None self.distance = None self.duration = None + self.mileage = None def add_points(self, longitude, latitude): self.positions.append(Points(longitude, latitude)) @@ -43,13 +46,20 @@ class Trip: 'consumption': self.consumption_km, } + def get_consumption_fuel(self): + return { + 'date': self.start_at, + 'consumption': self.consumption_fuel_km, + } + def to_geojson(self): multi_line_string = MultiLineString(tuple(map(list, self.positions))) return Feature(geometry=multi_line_string, properties={"start_at": self.start_at, "end_at": self.end_at, "average speed": self.speed_average, - "average consumption": self.consumption_km}) + "average consumption": self.consumption_km, + "average consumption fuel": self.consumption_fuel_km}) def get_info(self): res = {"start_at": self.start_at.astimezone(None).strftime("%x %X"), "end_at": self.end_at.astimezone(None).strftime("%x %X"), "duration": self.duration*60, - "speed_average": self.speed_average, "consumption_km": self.consumption_km, "distance": self.distance} + "speed_average": self.speed_average, "consumption_km": self.consumption_km, "consumption_fuel_km": self.consumption_fuel_km, "distance": self.distance, "mileage": self.mileage} return res diff --git a/web/figures.py b/web/figures.py index 634d025..c7c18ab 100644 --- a/web/figures.py +++ b/web/figures.py @@ -75,10 +75,13 @@ def get_figures(trips: List[Trip], charging: List[dict]): {'id': 'duration', 'name': 'duration', 'type': 'numeric', 'format': deepcopy(nb_format).symbol_suffix(" min").precision(0)}, {'id': 'speed_average', 'name': 'average speed', 'type': 'numeric', - 'format': deepcopy(nb_format).symbol_suffix(" km/h")}, + 'format': deepcopy(nb_format).symbol_suffix(" km/h").precision(0)}, {'id': 'consumption_km', 'name': 'average consumption', 'type': 'numeric', 'format': deepcopy(nb_format).symbol_suffix(" kw/100km")}, - {'id': 'distance', 'name': 'distance', 'type': 'numeric', 'format': nb_format.symbol_suffix(" km")}], + {'id': 'consumption_fuel_km', 'name': 'average consumption fuel', 'type': 'numeric', + 'format': deepcopy(nb_format).symbol_suffix(" L/100km")}, + {'id': 'distance', 'name': 'distance', 'type': 'numeric', 'format': nb_format.symbol_suffix(" km")}, + {'id': 'mileage', 'name': 'mileage', 'type': 'numeric', 'format': nb_format.symbol_suffix(" km")}], data=[tr.get_info() for tr in trips], ) # consumption_fig From 87a9c787b9c1d24b850257a2121077d194628249 Mon Sep 17 00:00:00 2001 From: jlayec Date: Sat, 13 Feb 2021 01:01:52 +0000 Subject: [PATCH 09/14] fix trip update for electric cars after modifications for hybrid cars --- MyPSACC.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/MyPSACC.py b/MyPSACC.py index e3f7605..ece8784 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -588,9 +588,12 @@ class MyPSACC: distance = next_el["mileage"] - end["mileage"] # km duration = (next_el["Timestamp"] - end["Timestamp"]).total_seconds() / 3600 charge = next_el["level"] - end["level"] - refuel = next_el["level_fuel"] - end["level_fuel"] + if next_el["level_fuel"] != None and end["level_fuel"] != None: + refuel = next_el["level_fuel"] - end["level_fuel"] + else: + refuel = None if ((distance == 0 and duration > 0.08) or duration > 2 or # check the speed to handle missing point - refuel > 0 or (distance == 0 and charge > 0)): + (refuel != None and refuel > 0) or (distance == 0 and charge > 0)): tr.distance = end["mileage"] - start["mileage"] # km if tr.distance > 0: tr.start_at = start["Timestamp"] @@ -601,15 +604,16 @@ class MyPSACC: diff_level = start["level"] - end["level"] tr.consumption = diff_level / 100 * BATTERY_POWER # kw tr.consumption_km = 100 * tr.consumption / tr.distance # kw/100 km - diff_level_fuel = start["level_fuel"] - end["level_fuel"] - tr.consumption_fuel = diff_level_fuel / 100 * FUEL_CAPACITY # L - tr.consumption_fuel_km = 100 * tr.consumption_fuel / tr.distance # L/100 km + if start["level_fuel"] != None and end["level_fuel"] != None: + diff_level_fuel = start["level_fuel"] - end["level_fuel"] + tr.consumption_fuel = round(diff_level_fuel / 100 * FUEL_CAPACITY,2) # L + tr.consumption_fuel_km = round(100 * tr.consumption_fuel / tr.distance,2) # L/100 km tr.mileage = end["mileage"] logger.debug( f"Trip: {start['Timestamp']} {tr.distance:.1f}km {tr.duration:.2f}h {tr.speed_average:.0f}km/h " - f"{tr.consumption:.2f}kw {tr.consumption_km:.2f}kw/100km {tr.consumption_fuel:.2f}L {tr.consumption_fuel_km:.2f}L/100km {tr.mileage:.1f}km") + f"{tr.consumption:.2f}kw {tr.consumption_km:.2f}kw/100km {tr.consumption_fuel}L {tr.consumption_fuel_km}L/100km {tr.mileage:.1f}km") # filter bad value - if tr.consumption_km < 70 and tr.consumption_fuel_km < 30: + if tr.consumption_km < 70 and (tr.consumption_fuel_km == None or tr.consumption_fuel_km < 30): trips.append(tr) else: logger.debug(f"trip discarded") From a9f1fa482da8802d22e1e8ad7aa286a3a5511c4e Mon Sep 17 00:00:00 2001 From: jlayec Date: Sat, 13 Feb 2021 10:52:11 +0000 Subject: [PATCH 10/14] small fix level_fuel 0 for hyrbrid cars --- MyPSACC.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MyPSACC.py b/MyPSACC.py index ece8784..2c0c694 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -499,7 +499,7 @@ class MyPSACC: level_fuel = conn.execute("SELECT level_fuel FROM position WHERE level_fuel>0 AND VIN=? ORDER BY Timestamp DESC LIMIT 1",(vin,)).fetchone()[0] logger.info(f"level_fuel fixed with last real value {level_fuel} for {vin}") except TypeError: - level_fuel = '' + level_fuel = None logger.info(f"level_fuel unfixed for {vin}") conn.execute( From 0cace9199582221a5c78cb062e3d3570c74c9796 Mon Sep 17 00:00:00 2001 From: jlayec Date: Sat, 13 Feb 2021 11:49:21 +0000 Subject: [PATCH 11/14] fix get_recorded_position() and add level_fuel for hybrid cars --- MyPSACC.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MyPSACC.py b/MyPSACC.py index 2c0c694..3dc3522 100644 --- a/MyPSACC.py +++ b/MyPSACC.py @@ -559,8 +559,8 @@ class MyPSACC: features_list = [] for row in res: feature = Feature(geometry=Point((row["longitude"], row["latitude"])), - properties={"vin": row["vin"], "date": row["Timestamp"], "mileage": row["mileage"], - "level": row["level"]}) + properties={"vin": row["vin"], "date": row["Timestamp"].strftime("%x %X"), "mileage": row["mileage"], + "level": row["level"],"level_fuel": row["level_fuel"]}) features_list.append(feature) feature_collection = FeatureCollection(features_list) conn.close() From 1c1b9dbfd16edbc92494d335619c35892c18e8d5 Mon Sep 17 00:00:00 2001 From: jlayec Date: Sun, 21 Feb 2021 21:58:14 +0000 Subject: [PATCH 12/14] update .gitignore with charge_config.json --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 739c14f..24a1e98 100644 --- a/.gitignore +++ b/.gitignore @@ -144,3 +144,4 @@ otp.bin charge_config1.json config.json test.json +charge_config.json From 782038be6186c1c8fc683d946c94b9988a72018b Mon Sep 17 00:00:00 2001 From: jlayec Date: Sun, 21 Feb 2021 22:44:22 +0000 Subject: [PATCH 13/14] use get_energy() method in ChargeControl.py for hybrid cars --- ChargeControl.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ChargeControl.py b/ChargeControl.py index e8e8cf1..0af5081 100644 --- a/ChargeControl.py +++ b/ChargeControl.py @@ -54,12 +54,12 @@ class ChargeControl: except ApiException: logger.error(traceback.format_exc()) if res is not None: - status = res.energy[0].charging.status - level = res.energy[0].level + status = res.get_energy('Electric').charging.status + level = res.get_energy('Electric').level logger.info(f"charging status of {self.vin} is {status}, battery level: {level}") if status == "InProgress": # force update if the car doesn't send info during 10 minutes - last_update = res.energy[0].updated_at + last_update = res.get_energy('Electric').updated_at if (datetime.utcnow().replace(tzinfo=pytz.UTC) - last_update).total_seconds() > 60 * 10: self.psacc.wakeup(self.vin) if (level >= self.percentage_threshold and self.retry_count < 2) or stop_charge: @@ -67,7 +67,7 @@ class ChargeControl: self.retry_count += 1 sleep(ChargeControl.MQTT_TIMEOUT) res = self.psacc.get_vehicle_info(self.vin) - status = res.energy[0].charging.status + status = res.get_energy('Electric').charging.status if status == "InProgress": logger.warn(f"retry to stop the charge of {self.vin}") self.psacc.charge_now(self.vin, False) From 4fb6c44ad26d7bfcf5fec7f498a8045be0fb3cf3 Mon Sep 17 00:00:00 2001 From: jlayec Date: Sun, 21 Feb 2021 22:49:20 +0000 Subject: [PATCH 14/14] fix charge_control web/callback --- server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server.py b/server.py index b2fb1e0..662751b 100755 --- a/server.py +++ b/server.py @@ -61,8 +61,6 @@ if __name__ == "__main__": client_password = input("mypeugeot password: ") web.app.myp.connect(client_email, client_password) logger.info(web.app.myp.get_vehicles()) - t1 = Thread(target=start_app, args=["My car info", args.base_path, args.debug < 20, args.listen, int(args.port)]) - t1.start() if args.offline or args.remote_disable: logger.info("mqtt disabled") else: @@ -71,3 +69,5 @@ if __name__ == "__main__": web.app.chc = ChargeControls.load_config(web.app.myp, name=args.charge_control) web.app.chc.start() save_config(web.app.myp) + t1 = Thread(target=start_app, args=["My car info", args.base_path, args.debug < 20, args.listen, int(args.port)]) + t1.start()