Пример #1
0
 def test_sdk(self):
     res = {
         'lastPosition': {'type': 'Feature', 'geometry': {'type': 'Point', 'coordinates': [9.65457, 49.96119, 21]},
                          'properties': {'updatedAt': '2021-03-29T05:16:10Z', 'heading': 126,
                                         'type': 'Estimated'}}, 'preconditionning': {
             'airConditioning': {'updatedAt': '2021-04-01T16:17:01Z', 'status': 'Disabled', 'programs': [
                 {'enabled': False, 'slot': 1, 'recurrence': 'Daily', 'start': 'PT21H40M',
                  'occurence': {'day': ['Sat']}}]}},
         'energy': [{'updatedAt': '2021-02-23T22:29:03Z', 'type': 'Fuel', 'level': 0},
                    {'updatedAt': '2021-04-01T16:17:01Z', 'type': 'Electric', 'level': 70, 'autonomy': 192,
                     'charging': {'plugged': True, 'status': 'InProgress', 'remainingTime': 'PT0S',
                                  'chargingRate': 20, 'chargingMode': 'Slow', 'nextDelayedTime': 'PT21H30M'}}],
         'createdAt': '2021-04-01T16:17:01Z',
         'battery': {'voltage': 99, 'current': 0, 'createdAt': '2021-04-01T16:17:01Z'},
         'kinetic': {'createdAt': '2021-03-29T05:16:10Z', 'moving': False},
         'privacy': {'createdAt': '2021-04-01T16:17:01Z', 'state': 'None'},
         'service': {'type': 'Electric', 'updatedAt': '2021-02-23T21:10:29Z'}, '_links': {'self': {
             'href': 'https://api.groupe-psa.com/connectedcar/v4/user/vehicles/myid/status'},
             'vehicles': {
                 'href': 'https://api.groupe-psa.com/connectedcar/v4/user/vehicles/myid'}},
         'timed.odometer': {'createdAt': None, 'mileage': 1107.1}, 'updatedAt': '2021-04-01T16:17:01Z'}
     api = ApiClient()
     status: psacc.models.status.Status = api._ApiClient__deserialize(res, "Status")
     geocode_res = reverse_geocode.search([(status.last_position.geometry.coordinates[:2])[::-1]])[0]
     assert geocode_res["country_code"] == "DE"
     get_new_test_db()
     car = Car("XX", "vid", "Peugeot")
     car.status = status
     myp = MyPSACC.load_config(DATA_DIR + "config.json")
     myp.record_info(car)
     assert "features" in json.loads(Database.get_recorded_position())
     # electric should be first
     assert car.status.energy[0].type == 'Electric'
Пример #2
0
 def __init__(self, methodName='runTest'):
     super().__init__(methodName)
     self.test_online = os.environ.get("TEST_ONLINE", "0") == "1"
     self.vehicule_list = Cars()
     self.vehicule_list.extend([
         Car("VR3UHZKX", "vid", "Peugeot"),
         Car("VXXXXX", "XXXX", "Peugeot", label="SUV 3008")
     ])
Пример #3
0
 def call(self, car: Car, ext_temp: float = None):
     try:
         if self.token is None or len(self.token) == 0:
             logger.debug("No abrp token provided")
         elif car.vin in self.abrp_enable_vin:
             energy = car.status.get_energy('Electric')
             tlm = {"utc": int(datetime.timestamp(energy.updated_at)),
                    "soc": energy.level,
                    "speed": getattr(car.status.kinetic, "speed", None),
                    "car_model": car.get_abrp_name(),
                    "current": car.status.battery.current,
                    "is_charging": energy.charging.status == "InProgress",
                    "lat": car.status.last_position.geometry.coordinates[1],
                    "lon": car.status.last_position.geometry.coordinates[0],
                    "power": energy.consumption
                    }
             if ext_temp is not None:
                 tlm["ext_temp"] = ext_temp
             params = {"tlm": json.dumps(tlm), "token": self.token, "api_key": self.api_key}
             response = requests.request("POST", self.url, params=params, proxies=self.proxies,
                                         verify=self.proxies is None)
             logger.debug(response.text)
             return response.json()["status"] == "ok"
     except (AttributeError, IndexError, ValueError):
         logger.exception("abrp:")
     return False
Пример #4
0
def get_battery_curve_fig(row: dict, car: Car):
    start_date = dash_date_to_datetime(row["start_at"])
    stop_at = dash_date_to_datetime(row["stop_at"])
    conn = Database.get_db()
    res = Database.get_battery_curve(conn, start_date, stop_at, car.vin)
    conn.close()
    battery_curves = []
    if len(res) > 0:
        battery_capacity = res[-1]["level"] * car.battery_power / 100
        km_by_kw = 0.8 * res[-1]["autonomy"] / battery_capacity
        start = 0
        speeds = []

        def speed_in_kw_from_km(row):
            try:
                speed = row["rate"] / km_by_kw
                if speed > 0:
                    speeds.append(speed)
            except (KeyError, TypeError):
                pass

        for end in range(1, len(res)):
            start_level = res[start]["level"]
            end_level = res[end]["level"]
            diff_level = end_level - start_level
            diff_sec = (res[end]["date"] - res[start]["date"]).total_seconds()
            speed_in_kw_from_km(res[end - 1])
            if diff_sec > 0 and diff_level > 3:
                speed_in_kw_from_km(res[end])
                speed = car.get_charge_speed(diff_level, diff_sec)
                if len(speeds) > 0:
                    speed = mean([*speeds, speed])
                speed = round(speed * 2) / 2
                battery_curves.append({"level": start_level, "speed": speed})
                start = end
                speeds = []
        battery_curves.append({"level": row["end_level"], "speed": 0})
    else:
        speed = car.get_charge_speed(row["end_level"] - row["start_level"],
                                     (stop_at - start_date).total_seconds())
        battery_curves.append({"level": row["start_level"], "speed": speed})
        battery_curves.append({"level": row["end_level"], "speed": speed})
    fig = px.line(battery_curves, x="level", y="speed")
    fig.update_layout(xaxis_title="Battery %",
                      yaxis_title="Charging speed in kW")
    return html.Div(Graph(figure=fig))
Пример #5
0
 def get_vehicles(self):
     try:
         res = self.api().get_vehicles_by_device()
         for vehicle in res.embedded.vehicles:
             self.vehicles_list.add(Car(vehicle.vin, vehicle.id, vehicle.brand, vehicle.label))
         self.vehicles_list.save_cars()
     except (ApiException, InvalidHeader):
         logger.exception("get_vehicles:")
     return self.vehicles_list
Пример #6
0
def update_trips():
    global trips, chargings, cached_layout, min_date, max_date, min_millis, max_millis, step, marks
    logger.info("update_data")
    conn = Database.get_db(update_callback=False)
    Database.add_altitude_to_db(conn)
    conn.close()
    min_date = None
    max_date = None
    if CONFIG.is_good:
        car = CONFIG.myp.vehicles_list[0]  # todo handle multiple car
        try:
            trips_by_vin = Trips.get_trips(Cars([car]))
            trips = trips_by_vin[car.vin]
            assert len(trips) > 0
            min_date = trips[0].start_at
            max_date = trips[-1].start_at
            figures.get_figures(trips[0].car)
        except (AssertionError, KeyError):
            logger.debug("No trips yet")
            figures.get_figures(Car("vin", "vid", "brand"))
        try:
            chargings = Charging.get_chargings()
            assert len(chargings) > 0
            if min_date:
                min_date = min(min_date, chargings[0]["start_at"])
                max_date = max(max_date, chargings[-1]["start_at"])
            else:
                min_date = chargings[0]["start_at"]
                max_date = chargings[-1]["start_at"]
        except AssertionError:
            logger.debug("No chargings yet")
            if min_date is None:
                return
        # update for slider
        try:
            logger.debug("min_date:%s - max_date:%s", min_date, max_date)
            min_millis = web.utils.unix_time_millis(min_date)
            max_millis = web.utils.unix_time_millis(max_date)
            step = (max_millis - min_millis) / 100
            marks = web.utils.get_marks_from_start_end(min_date, max_date)
            cached_layout = None  # force regenerate layout
            figures.get_figures(car)
        except (ValueError, IndexError):
            logger.error("update_trips (slider): %s", exc_info=True)
        except AttributeError:
            logger.debug("position table is probably empty :", exc_info=True)
    return
Пример #7
0
def get_battery_curve_fig(row: dict, car: Car):
    start_date = dash_date_to_datetime(row["start_at"])
    stop_at = dash_date_to_datetime(row["stop_at"])
    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 = []
    speed = 0
    for x in range(1, len(res)):
        start_level = res[x - 1]["level"]
        end_level = res[x]["level"]
        speed = car.get_charge_speed(start_level, end_level, (res[x]["date"] - res[x - 1]["date"]).total_seconds())
        battery_curves.append({"level": start_level, "speed": speed})
    battery_curves.append({"level": row["end_level"], "speed": speed})
    fig = px.line(battery_curves, x="level", y="speed")
    fig.update_layout(xaxis_title="Battery %", yaxis_title="Charging speed in kW")
    return html.Div(Graph(figure=fig))
Пример #8
0
    def test_battery_curve(self):
        from libs.car import Car
        from libs.charging import Charging
        try:
            os.remove("tmp.db")
        except:
            pass
        Database.DEFAULT_DB_FILE = "tmp.db"
        conn = Database.get_db()
        list(map(dict, conn.execute('PRAGMA database_list').fetchall()))
        vin = "VR3UHZKXZL"
        car = Car(vin, "id", "Peugeot")
        Charging.record_charging(car, "InProgress", date0, 50, latitude,
                                 longitude, "FR", "slow")
        Charging.record_charging(car, "InProgress", date1, 75, latitude,
                                 longitude, "FR", "slow")
        Charging.record_charging(car, "InProgress", date2, 85, latitude,
                                 longitude, "FR", "slow")
        Charging.record_charging(car, "InProgress", date3, 90, latitude,
                                 longitude, "FR", "slow")

        res = Database.get_battery_curve(Database.get_db(), date0, vin)
        assert len(res) == 3
Пример #9
0
from libs.car import Car, Cars
from libs.charging import Charging
from web.db import Database

DATA_DIR = os.path.dirname(os.path.realpath(__file__)) + "/data/"
latitude = 47.2183
longitude = -1.55362
date3 = datetime.utcnow().replace(2021, 3, 1, 12, 00, 00, 00, tzinfo=pytz.UTC)
date2 = date3 - timedelta(minutes=20)
date1 = date3 - timedelta(minutes=40)
date0 = date3 - timedelta(minutes=60)
date4 = date3 + timedelta(minutes=1)

vehicule_list = Cars()
vehicule_list.extend(
    [Car("VR3UHZKX", "vid", "Peugeot"), Car("VXXXXX", "XXXX", "Peugeot", label="SUV 3008 Hybrid 225")])
car = vehicule_list[0]
DB_DIR = DATA_DIR + "tmp.db"


def get_new_test_db():
    try:
        os.remove(DATA_DIR + "tmp.db")
    except FileNotFoundError:
        pass
    Database.DEFAULT_DB_FILE = DB_DIR
    Database.db_initialized = False
    conn = Database.get_db()
    return conn

Пример #10
0
def get_figures(car: Car):
    global consumption_fig, consumption_df, trips_map, consumption_fig_by_speed, table_fig, info, \
        battery_table, consumption_fig_by_temp
    lats = [42, 41]
    lons = [1, 2]
    names = ["undefined", "undefined"]
    trips_map = px.line_mapbox(lat=lats, lon=lons, hover_name=names, zoom=12, mapbox_style="style.json")
    trips_map.add_trace(go.Scattermapbox(
        mode="markers",
        marker={"symbol": "marker", "size": 20},
        lon=[lons[0]], lat=[lats[0]],
        showlegend=False, name="Last Position"))
    # table
    nb_format = Format(precision=2, scheme=Scheme.fixed, symbol=Symbol.yes)  # pylint: disable=no-member
    style_cell_conditional = []
    if car.is_electric():
        style_cell_conditional.append({'if': {'column_id': 'consumption_fuel_km', }, 'display': 'None', })
    if car.is_thermal():
        style_cell_conditional.append({'if': {'column_id': 'consumption_km', }, 'display': 'None', })
    table_fig = dash_table.DataTable(
        id='trips-table',
        sort_action='custom',
        sort_by=[{'column_id': 'id', 'direction': 'desc'}],
        columns=[{'id': 'id', 'name': '#', 'type': 'numeric'},
                 {'id': 'start_at_str', 'name': 'start at', 'type': 'datetime'},
                 {'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").precision(0)},
                 {'id': 'consumption_km', 'name': 'average consumption', 'type': 'numeric',
                  'format': deepcopy(nb_format).symbol_suffix(" kWh/100km")},
                 {'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").precision(1)},
                 {'id': 'mileage', 'name': 'mileage', 'type': 'numeric',
                  'format': nb_format},
                 {'id': 'altitude_diff', 'name': 'Altitude diff', 'type': 'numeric',
                  'format': deepcopy(nb_format).symbol_suffix(" m").precision(0)}
                 ],
        style_data_conditional=[
            {
                'if': {'column_id': ['altitude_diff']},
                'color': 'dodgerblue',
                "text-decoration": "underline"
            }
        ],
        style_cell_conditional=style_cell_conditional,
        data=[],
        page_size=50
    )
    # consumption_fig
    consumption_fig = px.histogram(x=[0], y=[1], title='Consumption of the car',
                                   histfunc="avg")
    consumption_fig.update_layout(yaxis_title="Consumption kWh/100Km", xaxis_title="date")

    consumption_fig_by_speed = px.histogram(data_frame=[{"start_at": 1, "speed_average": 2}], x="start_at",
                                            y="speed_average", histfunc="avg",
                                            title="Consumption by speed")
    consumption_fig_by_speed.update_traces(xbins_size=15)
    consumption_fig_by_speed.update_layout(bargap=0.05)
    consumption_fig_by_speed.add_trace(go.Scatter(mode="markers", x=[0],
                                                  y=[0], name="Trips"))
    consumption_fig_by_speed.update_layout(xaxis_title="average Speed km/h", yaxis_title="Consumption kWh/100Km")

    # battery_table
    battery_table = dash_table.DataTable(
        id='battery-table',
        sort_action='custom',
        sort_by=[{'column_id': 'start_at_str', 'direction': 'desc'}],
        columns=[{'id': 'start_at_str', 'name': 'start at', 'type': 'datetime'},
                 {'id': 'stop_at_str', 'name': 'stop at', 'type': 'datetime'},
                 {'id': 'start_level', 'name': 'start level', 'type': 'numeric'},
                 {'id': 'end_level', 'name': 'end level', 'type': 'numeric'},
                 {'id': 'co2', 'name': 'CO2', 'type': 'numeric',
                  'format': deepcopy(nb_format).symbol_suffix(" g/kWh").precision(1)},
                 {'id': 'kw', 'name': 'consumption', 'type': 'numeric',
                  'format': deepcopy(nb_format).symbol_suffix(" kWh").precision(2)},
                 {'id': 'price', 'name': 'price', 'type': 'numeric',
                  'format': deepcopy(nb_format).symbol_suffix(" " + ElecPrice.currency).precision(2), 'editable': True}
                 ],
        data=[],
        style_data_conditional=[
            {
                'if': {'column_id': ['start_level', "end_level"]},
                'color': 'dodgerblue',
                "text-decoration": "underline"
            },
            {
                'if': {'column_id': 'price'},
                'backgroundColor': '#ABE2FB'
            }
        ],
    )
    consumption_fig_by_temp = px.histogram(x=[0], y=[0],
                                           histfunc="avg", title="Consumption by temperature")
    consumption_fig_by_temp.update_traces(xbins_size=2)
    consumption_fig_by_temp.update_layout(bargap=0.05)
    consumption_fig_by_temp.add_trace(
        go.Scatter(mode="markers", x=[0],
                   y=[0], name="Trips"))
    consumption_fig_by_temp.update_layout(xaxis_title="average temperature in °C",
                                          yaxis_title="Consumption kWh/100Km")
    return True
Пример #11
0
 def test_car(self):
     car1 = Car("VRAAAAAAA", "1sdfdksnfk222", "Peugeot", "208", 46, 0)
     car2 = Car("VR3UHZKX", "1sdfdksnfk222", "Peugeot")
     cars = Cars([car1, car2])
     cars.save_cars(name=DATA_DIR + "test_car.json")
     Cars.load_cars(name=DATA_DIR + "test_car.json")