Esempio n. 1
0
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
Esempio n. 2
0
def get_altitude_fig(trip: Trip):
    conn = Database.get_db()
    res = list(map(list, conn.execute("SELECT mileage, altitude FROM position WHERE Timestamp>=? and Timestamp<=?;",
                                      (trip.start_at, trip.end_at)).fetchall()))
    start_mileage = res[0][0]
    for line in res:
        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))
Esempio n. 3
0
 def capture_diffs_in_battery_table(timestamp, data, data_previous):  # pylint: disable=unused-variable
     if timestamp is None:
         raise PreventUpdate
     diff_data = diff_dashtable(data, data_previous, "start_at")
     for changed_line in diff_data:
         if changed_line['column_name'] == 'price':
             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 ""
Esempio n. 4
0
 def set_default_price():
     if Charging.elec_price.is_enable():
         conn = Database.get_db()
         charge_list = list(
             map(
                 dict,
                 conn.execute("SELECT * FROM battery WHERE price IS NULL").
                 fetchall()))
         for charge in charge_list:
             charge["price"] = Charging.elec_price.get_price(
                 charge["start_at"], charge["stop_at"], charge["kw"])
             Database.set_chargings_price(conn, charge["start_at"],
                                          charge["price"])
         conn.close()
    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
Esempio n. 6
0
 def record_charging(
         car,
         charging_status,
         charge_date: datetime,
         level,
         latitude,  # pylint: disable=too-many-locals
         longitude,
         country_code,
         charging_mode,
         charging_rate,
         autonomy):
     conn = Database.get_db()
     charge_date = charge_date.replace(microsecond=0)
     if charging_status == "InProgress":
         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]
         try:
             conn.execute(
                 "INSERT INTO battery_curve(start_at,VIN,date,level,rate,autonomy) VALUES(?,?,?,?,?,?)",
                 (start_at, car.vin, charge_date, level, charging_rate,
                  autonomy))
         except IntegrityError:
             logger.debug("level already stored")
         if stop_at is not None:
             conn.execute(
                 "INSERT INTO battery(start_at,start_level,charging_mode,VIN) VALUES(?,?,?,?)",
                 (charge_date, level, charging_mode, car.vin))
         Ecomix.get_data_from_co2_signal(latitude, longitude, country_code)
     else:
         try:
             start_at, stop_at, start_level = conn.execute(
                 "SELECT start_at, stop_at, start_level from battery WHERE VIN=? ORDER BY start_at DESC limit 1",
                 (car.vin, )).fetchone()
             in_progress = stop_at is None
         except TypeError:
             logger.debug("battery table is probably empty :",
                          exc_info=True)
             in_progress = False
         if in_progress:
             co2_per_kw = Ecomix.get_co2_per_kw(start_at, charge_date,
                                                latitude, longitude,
                                                country_code)
             consumption_kw = (level -
                               start_level) / 100 * car.battery_power
             Charging.update_chargings(conn, start_at, charge_date, level,
                                       co2_per_kw, consumption_kw, car.vin)
     conn.commit()
     conn.close()
Esempio n. 7
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
Esempio n. 8
0
 def get_chargings(mini=None, maxi=None) -> List[dict]:
     conn = Database.get_db()
     if mini is not None:
         if maxi is not None:
             res = conn.execute(
                 "select * from battery WHERE start_at>=? and start_at<=?",
                 (mini, maxi)).fetchall()
         else:
             res = conn.execute("select * from battery WHERE start_at>=?",
                                (mini, )).fetchall()
     elif maxi is not None:
         res = conn.execute("select * from battery WHERE start_at<=?",
                            (maxi, )).fetchall()
     else:
         res = conn.execute("select * from battery").fetchall()
     conn.close()
     return list(map(dict, res))
Esempio n. 9
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))
Esempio n. 10
0
    def test_record_position_charging(self):
        get_new_test_db()
        ElecPrice.CONFIG_FILENAME = DATA_DIR + "config.ini"
        car = self.vehicule_list[0]
        record_position()
        Database.add_altitude_to_db(Database.get_db())
        data = json.loads(Database.get_recorded_position())
        assert data["features"][1]["geometry"]["coordinates"] == [float(longitude), float(latitude)]
        trips = Trips.get_trips(self.vehicule_list)[car.vin]
        trip = trips[0]
        map(trip.add_temperature, [10, 13, 15])
        res = trip.get_info()
        assert compare_dict(res, {'consumption_km': 24.21052631578947,
                                  'start_at': date0,
                                  'consumption_by_temp': None,
                                  'positions': {'lat': [latitude], 'long': [longitude]},
                                  'duration': 40.0, 'speed_average': 28.5, 'distance': 19.0, 'mileage': 30.0,
                                  'altitude_diff': 2, 'id': 1, 'consumption': 4.6})

        Charging.elec_price = ElecPrice.read_config()
        start_level = 40
        end_level = 85
        Charging.record_charging(car, "InProgress", date0, start_level, latitude, longitude, None, "slow", 20, 60)
        Charging.record_charging(car, "InProgress", date1, 70, latitude, longitude, "FR", "slow", 20, 60)
        Charging.record_charging(car, "InProgress", date1, 70, latitude, longitude, "FR", "slow", 20, 60)
        Charging.record_charging(car, "InProgress", date2, 80, latitude, longitude, "FR", "slow", 20, 60)
        Charging.record_charging(car, "Stopped", date3, end_level, latitude, longitude, "FR", "slow", 20, 60)
        chargings = Charging.get_chargings()
        co2 = chargings[0]["co2"]
        assert isinstance(co2, float)
        assert compare_dict(chargings, [{'start_at': date0,
                                         'stop_at': date3,
                                         'VIN': 'VR3UHZKX',
                                         'start_level': 40,
                                         'end_level': 85,
                                         'co2': co2,
                                         'kw': 20.7,
                                         'price': 3.84,
                                         'charging_mode': 'slow'}])
        print()
        assert get_figures(car)
        row = {"start_at": date0.strftime('%Y-%m-%dT%H:%M:%S.000Z'),
               "stop_at": date3.strftime('%Y-%m-%dT%H:%M:%S.000Z'), "start_level": start_level, "end_level": end_level}
        assert get_battery_curve_fig(row, car) is not None
        assert get_altitude_fig(trip) is not None
Esempio n. 11
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))
Esempio n. 12
0
 def capture_diffs_in_battery_table(timestamp, data, data_previous):
     if timestamp is None:
         raise PreventUpdate
     diff_data = diff_dashtable(data, data_previous, "start_at")
     for changed_line in diff_data:
         if changed_line['column_name'] == 'price':
             conn = Database.get_db()
             if not Database.set_chargings_price(
                     conn,
                     dash_date_to_datetime(changed_line['start_at']),
                     changed_line['current_value']):
                 logger.error(
                     "Can't find line to update in the database")
             else:
                 logger.debug("update price %s of %s",
                              changed_line['current_value'],
                              changed_line['start_at'])
             conn.close()
     return ""  # don't need to update dashboard
Esempio n. 13
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
    try:
        trips_by_vin = Trips.get_trips(myp.vehicles_list)
        trips = next(iter(trips_by_vin.values()))  # todo handle multiple car
        assert len(trips) > 0
        min_date = trips[0].start_at
        max_date = trips[-1].start_at
    except (StopIteration, AssertionError):
        logger.debug("No trips yet")
    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 = figures.unix_time_millis(min_date)
        max_millis = figures.unix_time_millis(max_date)
        step = (max_millis - min_millis) / 100
        marks = figures.get_marks_from_start_end(min_date, max_date)
        cached_layout = None  # force regenerate layout
    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
Esempio n. 14
0
    def get_trips(vehicles_list: Cars) -> Dict[str, "Trips"]:  # noqa: MC0001
        # pylint: disable=too-many-locals,too-many-statements,too-many-nested-blocks,too-many-branches
        conn = Database.get_db()
        vehicles = conn.execute(
            "SELECT DISTINCT vin FROM position;").fetchall()
        trips_by_vin = {}
        for vin in vehicles:
            trips = Trips()
            vin = vin[0]
            res = conn.execute(
                'SELECT Timestamp, VIN, longitude, latitude, mileage, level, moving, temperature,'
                ' level_fuel, altitude FROM position WHERE VIN=? ORDER BY Timestamp',
                (vin, )).fetchall()
            if len(res) > 1:
                car = vehicles_list.get_car_by_vin(vin)
                assert car is not None
                trip_parser = TripParser(car)
                start = res[0]
                end = res[1]
                trip = Trip()
                # for debugging use this line res = list(map(dict,res))
                for x in range(0, len(res) - 2):
                    if logger.isEnabledFor(
                            logging.DEBUG
                    ):  # reduce execution time if debug disabled
                        logger.debugv("%s mileage:%.1f level:%s level_fuel:%s",
                                      res[x]['Timestamp'], res[x]['mileage'],
                                      res[x]['level'], res[x]['level_fuel'])
                    next_el = res[x + 2]
                    distance = 0
                    try:
                        distance = end["mileage"] - start["mileage"]
                    except TypeError:
                        logger.debug("Bad mileage value in DB")
                    duration = (end["Timestamp"] -
                                start["Timestamp"]).total_seconds() / 3600
                    try:
                        speed_average = distance / duration
                    except ZeroDivisionError:
                        speed_average = 0

                    if TripParser.is_low_speed(
                            speed_average, duration) or trip_parser.is_refuel(
                                start, end, distance):
                        start = end
                        trip = Trip()
                        logger.debugv(
                            "restart trip at {0[Timestamp]} mileage:{0[mileage]:.1f} level:{0[level]}"
                            " level_fuel:{0[level_fuel]}",
                            start,
                            style='{')
                    else:
                        distance = next_el["mileage"] - end["mileage"]  # km
                        duration = (next_el["Timestamp"] -
                                    end["Timestamp"]).total_seconds() / 3600
                        try:
                            speed_average = distance / duration
                        except ZeroDivisionError:
                            speed_average = 0
                        end_trip = False
                        if trip_parser.is_refuel(end, next_el, distance) or \
                                TripParser.is_low_speed(speed_average, duration):
                            end_trip = True
                        elif duration > 2:
                            end_trip = True
                            logger.debugv("too much time detected")
                        elif x == len(res) - 3:  # last record detected
                            # think if add point is needed
                            end = next_el
                            end_trip = True
                            logger.debugv("last position found")
                        if end_trip:
                            logger.debugv(
                                "stop trip at {0[Timestamp]} mileage:{0[mileage]:.1f} level:{0[level]}"
                                " level_fuel:{0[level_fuel]}",
                                end,
                                style='{')
                            trip.distance = end["mileage"] - start[
                                "mileage"]  # km
                            if trip.distance > 0:
                                trip.start_at = start["Timestamp"]
                                trip.end_at = end["Timestamp"]
                                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
                                trip.speed_average = trip.distance / trip.duration
                                diff_level, diff_level_fuel = trip_parser.get_level_consumption(
                                    start, end)
                                trip.set_altitude_diff(start["altitude"],
                                                       end["altitude"])
                                trip.car = car
                                if diff_level != 0:
                                    trip.set_consumption(diff_level)  # kw
                                if diff_level_fuel != 0:
                                    trip.set_fuel_consumption(diff_level_fuel)
                                trip.mileage = end["mileage"]
                                logger.debugv(
                                    "Trip: {0.start_at} -> {0.end_at} {0.distance:.1f}km {0.duration:.2f}h "
                                    "{0.speed_average:.0f}km/h {0.consumption:.2f}kWh "
                                    "{0.consumption_km:.2f}kWh/100km {0.consumption_fuel:.2f}L "
                                    "{0.consumption_fuel_km:.2f}L/100km {0.mileage:.1f}km",
                                    trip,
                                    style="{")
                                # filter bad value
                                trips.check_and_append(trip)
                            start = next_el
                            trip = Trip()
                        else:
                            trip.add_points(end["latitude"], end["longitude"])
                    end = next_el
                trips_by_vin[vin] = trips
        conn.close()
        return trips_by_vin
Esempio n. 15
0
 def get_chargings() -> List[dict]:
     conn = Database.get_db()
     res = conn.execute(
         "select * from battery ORDER BY start_at").fetchall()
     conn.close()
     return list(map(dict, res))
Esempio n. 16
0
 def test_battery_curve(self):
     get_new_test_db()
     record_charging()
     res = Database.get_battery_curve(Database.get_db(), date0, date4, self.vehicule_list[0].vin)
     assert len(res) == 3